// ============================================ // GUILD CREATION WIZARD V2 - Ultimate Premium Experience // With Perks, Events, Achievements & More Gamification // ============================================ const { useState, useEffect, useRef } = React; // ============================================ // CONSTANTS // ============================================ const GUILD_CREATION_COST = 10000; // 100 coins in cents const GUILD_CATEGORIES = [ { id: 'competitive', name: 'Competitive', desc: 'Rankings & guild wars', icon: 'trophy', bonus: '+10% War XP' }, { id: 'social', name: 'Social', desc: 'Fun & friendship focused', icon: 'users', bonus: '+5 Max Members' }, { id: 'trading', name: 'Trading', desc: 'Economy & strategies', icon: 'coins', bonus: '+5% Treasury Bonus' }, { id: 'highroller', name: 'High Roller', desc: 'Big bets, big wins', icon: 'diamond', bonus: 'VIP Perks Unlocked' }, ]; // Extended color palette with text color for contrast const GUILD_COLORS = [ { color: '#5bffb2', name: 'Emerald', textColor: '#000' }, { color: '#8b5cf6', name: 'Royal Purple', textColor: '#fff' }, { color: '#f59e0b', name: 'Gold', textColor: '#000' }, { color: '#ef4444', name: 'Crimson', textColor: '#fff' }, { color: '#3b82f6', name: 'Sapphire', textColor: '#fff' }, { color: '#ec4899', name: 'Hot Pink', textColor: '#fff' }, { color: '#14b8a6', name: 'Teal', textColor: '#000' }, { color: '#f97316', name: 'Orange', textColor: '#000' }, { color: '#6366f1', name: 'Indigo', textColor: '#fff' }, { color: '#84cc16', name: 'Lime', textColor: '#000' }, { color: '#06b6d4', name: 'Cyan', textColor: '#000' }, { color: '#a855f7', name: 'Violet', textColor: '#fff' }, { color: '#f43f5e', name: 'Rose', textColor: '#fff' }, { color: '#22c55e', name: 'Green', textColor: '#000' }, { color: '#eab308', name: 'Yellow', textColor: '#000' }, { color: '#0ea5e9', name: 'Sky Blue', textColor: '#000' }, ]; // Gradient options for emblem backgrounds const GUILD_GRADIENTS = [ { id: 'emerald-purple', colors: ['#5bffb2', '#8b5cf6'], name: 'Emerald Purple', textColor: '#fff' }, { id: 'fire-gold', colors: ['#ef4444', '#f59e0b'], name: 'Fire Gold', textColor: '#fff' }, { id: 'ocean-deep', colors: ['#3b82f6', '#6366f1'], name: 'Ocean Deep', textColor: '#fff' }, { id: 'sunset', colors: ['#f97316', '#ec4899'], name: 'Sunset', textColor: '#fff' }, { id: 'aurora', colors: ['#14b8a6', '#5bffb2'], name: 'Aurora', textColor: '#000' }, { id: 'royal', colors: ['#8b5cf6', '#ec4899'], name: 'Royal', textColor: '#fff' }, { id: 'cyber', colors: ['#06b6d4', '#84cc16'], name: 'Cyber', textColor: '#000' }, { id: 'blood-moon', colors: ['#ef4444', '#a855f7'], name: 'Blood Moon', textColor: '#fff' }, ]; const GUILD_EMBLEMS = [ { id: 'swords', icon: 'swords', name: 'Crossed Swords' }, { id: 'shield', icon: 'shield', name: 'Shield' }, { id: 'crown', icon: 'crown', name: 'Crown' }, { id: 'star', icon: 'star', name: 'Star' }, { id: 'diamond', icon: 'diamond', name: 'Diamond' }, { id: 'fire', icon: 'fire', name: 'Fire' }, { id: 'bolt', icon: 'bolt', name: 'Lightning' }, { id: 'skull', icon: 'skull', name: 'Skull' }, { id: 'trophy', icon: 'trophy', name: 'Trophy' }, { id: 'target', icon: 'target', name: 'Target' }, { id: 'rocket', icon: 'rocket', name: 'Rocket' }, { id: 'sparkles', icon: 'sparkles', name: 'Sparkles' }, ]; const STARTER_PERKS = [ { id: 'treasury_boost', name: 'Treasury Boost', desc: 'Start with 500 coins in treasury', icon: 'coins', selected: true }, { id: 'recruitment_banner', name: 'Recruitment Banner', desc: 'Featured on guild listings for 24h', icon: 'megaphone', selected: false }, { id: 'war_ready', name: 'War Ready', desc: 'Skip cooldown for first guild war', icon: 'swords', selected: false }, { id: 'xp_boost', name: 'XP Boost', desc: '+25% guild XP for 7 days', icon: 'sparkles', selected: false }, ]; const EVENT_TEMPLATES = [ { id: 'war_night', name: 'War Night', desc: 'Coordinate guild wars together', icon: 'swords', time: 'Weekly' }, { id: 'jackpot_party', name: 'Jackpot Party', desc: 'Group jackpot sessions', icon: 'trophy', time: 'Daily' }, { id: 'trading_hour', name: 'Trading Hour', desc: 'Share tips & strategies', icon: 'coins', time: 'Weekly' }, { id: 'custom', name: 'Custom Event', desc: 'Create your own event', icon: 'calendar', time: 'Custom' }, ]; const WIZARD_STEPS = [ { id: 'basics', title: 'Foundation', subtitle: 'Name your guild', icon: 'flag' }, { id: 'identity', title: 'Identity', subtitle: 'Colors & emblem', icon: 'palette' }, { id: 'category', title: 'Category', subtitle: 'Choose your focus', icon: 'target' }, { id: 'story', title: 'Story', subtitle: 'Tell your tale', icon: 'scroll' }, { id: 'rules', title: 'Laws', subtitle: 'Set the rules', icon: 'gavel' }, { id: 'perks', title: 'Perks', subtitle: 'Starter bonuses', icon: 'gift' }, { id: 'event', title: 'First Event', subtitle: 'Plan your launch', icon: 'calendar' }, { id: 'review', title: 'Launch', subtitle: 'Create your guild', icon: 'rocket' }, ]; const ACHIEVEMENTS_PREVIEW = [ { name: 'Guild Founded', desc: 'Create your first guild', unlocked: true }, { name: 'First Blood', desc: 'Win your first guild war', unlocked: false }, { name: 'Full House', desc: 'Reach 10 members', unlocked: false }, { name: 'War Machine', desc: 'Win 10 guild wars', unlocked: false }, { name: 'Treasure Hoard', desc: 'Accumulate 10,000 in treasury', unlocked: false }, { name: 'Legendary', desc: 'Reach guild level 10', unlocked: false }, ]; // ============================================ // SVG ICONS // ============================================ const Icons = { trophy: , users: , coins: , star: , check: , x: , chevronLeft: , chevronRight: , shield: , crown: , diamond: , swords: , fire: , bolt: , skull: , scroll: , target: , sparkles: , calendar: , flag: , palette: , gavel: , gift: , rocket: , megaphone: , lock: , globe: , info: , }; const getIcon = (name) => Icons[name] || Icons.star; // Format coins const formatCoins = (cents) => ((cents || 0) / 100).toLocaleString('en-US', { minimumFractionDigits: 2 }); // ============================================ // MAIN WIZARD COMPONENT // ============================================ function GuildCreateWizard({ user, onClose, onSuccess }) { const [step, setStep] = useState(0); const [creating, setCreating] = useState(false); const [error, setError] = useState(''); const [showConfetti, setShowConfetti] = useState(false); // Form data const [formData, setFormData] = useState({ name: '', tag: '', category: '', primaryColor: '#5bffb2', secondaryColor: '#8b5cf6', useGradient: false, selectedGradient: null, emblem: 'shield', description: '', mission: '', slogan: '', rules: '', welcomeMessage: 'Welcome to the guild! Check out our rules and introduce yourself.', isPublic: true, minLevel: 1, requireApproval: false, selectedPerks: ['treasury_boost'], firstEvent: null, eventName: '', eventDesc: '', }); // Helper to get the current emblem background (color or gradient) const getEmblemBackground = () => { if (formData.useGradient && formData.selectedGradient) { const gradient = GUILD_GRADIENTS.find(g => g.id === formData.selectedGradient); if (gradient) { return `linear-gradient(135deg, ${gradient.colors[0]}, ${gradient.colors[1]})`; } } return formData.primaryColor; }; // Helper to get text color for current selection const getEmblemTextColor = () => { if (formData.useGradient && formData.selectedGradient) { const gradient = GUILD_GRADIENTS.find(g => g.id === formData.selectedGradient); return gradient ? gradient.textColor : '#fff'; } const color = GUILD_COLORS.find(c => c.color === formData.primaryColor); return color ? color.textColor : '#000'; }; const userBalance = user.balance || user.coins || 0; const canCreate = userBalance >= GUILD_CREATION_COST; const updateField = (field, value) => { setFormData(prev => ({ ...prev, [field]: value })); setError(''); }; const togglePerk = (perkId) => { setFormData(prev => { const perks = prev.selectedPerks.includes(perkId) ? prev.selectedPerks.filter(p => p !== perkId) : [...prev.selectedPerks, perkId].slice(0, 2); // Max 2 perks return { ...prev, selectedPerks: perks }; }); }; const validateStep = () => { switch (step) { case 0: // Basics if (formData.name.length < 3 || formData.name.length > 32) { setError('Guild name must be 3-32 characters'); return false; } if (formData.tag && (formData.tag.length < 2 || formData.tag.length > 6)) { setError('Guild tag must be 2-6 characters'); return false; } break; case 2: // Category if (!formData.category) { setError('Please select a guild category'); return false; } break; case 3: // Story if (formData.description.length < 20) { setError('Tell us more about your guild (at least 20 characters)'); return false; } if (formData.mission.length < 10) { setError('Add a mission statement (at least 10 characters)'); return false; } break; case 4: // Rules if (formData.rules.length < 10) { setError('Add at least one rule (10+ characters)'); return false; } break; } return true; }; const nextStep = () => { if (validateStep()) { setStep(prev => Math.min(prev + 1, WIZARD_STEPS.length - 1)); setError(''); } }; const prevStep = () => { setStep(prev => Math.max(prev - 1, 0)); setError(''); }; const createGuild = async () => { if (!canCreate) { setError(`Not enough coins! You need 100 coins, you have ${formatCoins(userBalance)}`); return; } setCreating(true); setError(''); try { // Determine the color to send (gradient or solid) let colorToSend = formData.primaryColor; if (formData.useGradient && formData.selectedGradient) { const gradient = GUILD_GRADIENTS.find(g => g.id === formData.selectedGradient); if (gradient) { // Send as special format: gradient:color1,color2 colorToSend = `gradient:${gradient.colors.join(',')}`; } } const res = await fetch('/api/guilds/create', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ name: formData.name, tag: formData.tag.toUpperCase() || undefined, description: formData.description, is_public: formData.isPublic, mission: formData.mission, rules: formData.rules, welcome_message: formData.welcomeMessage, primary_color: colorToSend, emblem: formData.emblem, category: formData.category, min_level: formData.minLevel, slogan: formData.slogan, require_approval: formData.requireApproval, starter_perks: formData.selectedPerks, first_event: formData.firstEvent ? { type: formData.firstEvent, name: formData.eventName, description: formData.eventDesc } : null, }) }); // Check if response is JSON const contentType = res.headers.get('content-type'); if (!contentType || !contentType.includes('application/json')) { if (res.status === 401) { setError('Session expired. Please refresh and log in again.'); } else if (res.status >= 500) { setError('Server error. Please try again later.'); } else { setError(`Error ${res.status}: Failed to create guild.`); } setCreating(false); return; } const data = await res.json(); if (res.ok) { setShowConfetti(true); setTimeout(() => { onSuccess(data.guild); }, 2000); } else { setError(data.detail || data.message || 'Failed to create guild'); } } catch (err) { console.error('Guild creation error:', err); setError('Network error. Please check your connection and try again.'); } setCreating(false); }; // ============================================ // STEP RENDERS // ============================================ const renderBasicsStep = () => (
{Icons.flag}

Choose Your Guild Name

Pick a name that strikes fear into enemies and inspires allies!

updateField('name', e.target.value)} maxLength={32} />
{formData.name.length}/32 {formData.name.length >= 3 && {Icons.check} Valid}
updateField('tag', e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, ''))} maxLength={6} />
[{formData.tag || 'TAG'}] {formData.name || 'Guild Name'}
2-6 characters. Auto-generated if left blank.
{Icons.info}
Pro Tip: Memorable guild names often reference strength, unity, or legendary themes. Your tag will appear before member names in chat!
); const renderIdentityStep = () => (
{getIcon(formData.emblem)}

Design Your Identity

Choose colors and an emblem that represents your guild

{/* Color Mode Toggle */}
{!formData.useGradient ? (
{GUILD_COLORS.map(({ color, name, textColor }) => ( ))}
) : (
{GUILD_GRADIENTS.map(({ id, colors, name, textColor }) => ( ))}
)}
{GUILD_EMBLEMS.map(({ id, icon, name }) => ( ))}
{getIcon(formData.emblem)}

[{formData.tag || 'TAG'}] {formData.name || 'Your Guild'}

This is how your guild will appear

); const renderCategoryStep = () => (
{Icons.target}

Choose Your Path

What will your guild focus on? Each category provides unique bonuses!

{GUILD_CATEGORIES.map(cat => ( ))}
); const renderStoryStep = () => (
{Icons.scroll}

Tell Your Story

What makes your guild special? What are you fighting for?

updateField('slogan', e.target.value)} maxLength={50} />
updateField('mission', e.target.value)} maxLength={100} /> What is your guild's primary goal?