feat: Modularize event management system - 98.7% reduction in main file size

BREAKING CHANGES:
- Refactored monolithic manage.astro (7,623 lines) into modular architecture
- Original file backed up as manage-old.astro

NEW ARCHITECTURE:
 5 Utility Libraries:
  - event-management.ts: Event data operations & formatting
  - ticket-management.ts: Ticket CRUD operations & sales data
  - seating-management.ts: Seating map management & layout generation
  - sales-analytics.ts: Sales metrics, reporting & data export
  - marketing-kit.ts: Marketing asset generation & social media

 5 Shared Components:
  - TicketTypeModal.tsx: Reusable ticket type creation/editing
  - SeatingMapModal.tsx: Advanced seating map editor with drag-and-drop
  - EmbedCodeModal.tsx: Widget embedding with customization
  - OrdersTable.tsx: Comprehensive orders table with sorting/pagination
  - AttendeesTable.tsx: Attendee management with export capabilities

 11 Tab Components:
  - TicketsTab.tsx: Ticket management with card/list views
  - VenueTab.tsx: Seating map management & venue configuration
  - OrdersTab.tsx: Sales data & order management
  - AttendeesTab.tsx: Attendee check-in & management
  - PresaleTab.tsx: Presale code generation & tracking
  - DiscountTab.tsx: Discount code management
  - AddonsTab.tsx: Add-on product management
  - PrintedTab.tsx: Printed ticket barcode management
  - SettingsTab.tsx: Event configuration & custom fields
  - MarketingTab.tsx: Marketing kit with social media templates
  - PromotionsTab.tsx: Campaign & promotion management

 4 Infrastructure Components:
  - TabNavigation.tsx: Responsive tab navigation system
  - EventManagement.tsx: Main orchestration component
  - EventHeader.astro: Event information header
  - QuickStats.astro: Statistics dashboard

BENEFITS:
- 98.7% reduction in main file size (7,623 → ~100 lines)
- Dramatic improvement in maintainability and team collaboration
- Component-level testing now possible
- Reusable components across multiple features
- Lazy loading support for better performance
- Full TypeScript support with proper interfaces
- Separation of concerns: business logic separated from UI

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-08 18:30:26 -06:00
parent 23f190c7a7
commit e8b95231b7
76 changed files with 26728 additions and 7101 deletions

View File

@@ -0,0 +1,54 @@
-- Add image_url column to events table
ALTER TABLE events ADD COLUMN image_url TEXT;
-- Create storage bucket for event images
INSERT INTO storage.buckets (id, name, public)
VALUES ('event-images', 'event-images', true);
-- Create storage policy for authenticated users to upload event images
CREATE POLICY "Users can upload event images" ON storage.objects
FOR INSERT WITH CHECK (
bucket_id = 'event-images' AND
auth.uid() IS NOT NULL
);
-- Create storage policy for public read access to event images
CREATE POLICY "Public read access to event images" ON storage.objects
FOR SELECT USING (bucket_id = 'event-images');
-- Create storage policy for users to delete their own event images
CREATE POLICY "Users can delete their own event images" ON storage.objects
FOR DELETE USING (
bucket_id = 'event-images' AND
auth.uid() IS NOT NULL
);
-- Update RLS policy for events to include image_url in SELECT
DROP POLICY IF EXISTS "Users can view events in their organization" ON events;
CREATE POLICY "Users can view events in their organization" ON events
FOR SELECT USING (
organization_id IN (
SELECT organization_id FROM users WHERE user_id = auth.uid()
)
);
-- Update RLS policy for events to include image_url in INSERT
DROP POLICY IF EXISTS "Users can create events in their organization" ON events;
CREATE POLICY "Users can create events in their organization" ON events
FOR INSERT WITH CHECK (
organization_id IN (
SELECT organization_id FROM users WHERE user_id = auth.uid()
)
);
-- Update RLS policy for events to include image_url in UPDATE
DROP POLICY IF EXISTS "Users can update events in their organization" ON events;
CREATE POLICY "Users can update events in their organization" ON events
FOR UPDATE USING (
organization_id IN (
SELECT organization_id FROM users WHERE user_id = auth.uid()
)
);
-- Add index on image_url for faster queries
CREATE INDEX IF NOT EXISTS idx_events_image_url ON events(image_url) WHERE image_url IS NOT NULL;

View File

@@ -0,0 +1,203 @@
-- Marketing Kit support for Event Marketing Toolkit
-- This migration adds tables to store marketing kit assets and templates
-- Table to store marketing kit assets for each event
CREATE TABLE IF NOT EXISTS marketing_kit_assets (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
event_id UUID NOT NULL REFERENCES events(id) ON DELETE CASCADE,
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
asset_type TEXT NOT NULL CHECK (asset_type IN ('social_post', 'flyer', 'email_template', 'qr_code')),
platform TEXT, -- For social posts: 'facebook', 'instagram', 'twitter', 'linkedin'
title TEXT NOT NULL,
content TEXT, -- JSON content for templates/configs
image_url TEXT, -- Generated image URL
download_url TEXT, -- Direct download URL for assets
file_format TEXT, -- 'png', 'jpg', 'html', 'txt', etc.
dimensions JSON, -- {"width": 1080, "height": 1080} for images
generated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
expires_at TIMESTAMP WITH TIME ZONE, -- For temporary download links
metadata JSON, -- Additional configuration/settings
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Table to store reusable marketing templates
CREATE TABLE IF NOT EXISTS marketing_templates (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
template_type TEXT NOT NULL CHECK (template_type IN ('social_post', 'flyer', 'email_template')),
platform TEXT, -- For social posts: 'facebook', 'instagram', 'twitter', 'linkedin'
name TEXT NOT NULL,
description TEXT,
template_data JSON NOT NULL, -- Template configuration and layout
preview_image_url TEXT,
is_default BOOLEAN DEFAULT false,
is_active BOOLEAN DEFAULT true,
created_by UUID REFERENCES users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Table to track marketing kit generations and downloads
CREATE TABLE IF NOT EXISTS marketing_kit_generations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
event_id UUID NOT NULL REFERENCES events(id) ON DELETE CASCADE,
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
generated_by UUID REFERENCES users(id),
generation_type TEXT NOT NULL CHECK (generation_type IN ('full_kit', 'individual_asset')),
assets_included TEXT[], -- Array of asset types included
zip_file_url TEXT, -- URL to download complete kit
zip_expires_at TIMESTAMP WITH TIME ZONE,
generation_status TEXT DEFAULT 'pending' CHECK (generation_status IN ('pending', 'processing', 'completed', 'failed')),
error_message TEXT,
download_count INTEGER DEFAULT 0,
last_downloaded_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Indexes for performance
CREATE INDEX IF NOT EXISTS idx_marketing_kit_assets_event_id ON marketing_kit_assets(event_id);
CREATE INDEX IF NOT EXISTS idx_marketing_kit_assets_org_id ON marketing_kit_assets(organization_id);
CREATE INDEX IF NOT EXISTS idx_marketing_kit_assets_type ON marketing_kit_assets(asset_type);
CREATE INDEX IF NOT EXISTS idx_marketing_templates_org_id ON marketing_templates(organization_id);
CREATE INDEX IF NOT EXISTS idx_marketing_templates_type ON marketing_templates(template_type);
CREATE INDEX IF NOT EXISTS idx_marketing_kit_generations_event_id ON marketing_kit_generations(event_id);
CREATE INDEX IF NOT EXISTS idx_marketing_kit_generations_org_id ON marketing_kit_generations(organization_id);
-- RLS Policies for multi-tenant security
ALTER TABLE marketing_kit_assets ENABLE ROW LEVEL SECURITY;
ALTER TABLE marketing_templates ENABLE ROW LEVEL SECURITY;
ALTER TABLE marketing_kit_generations ENABLE ROW LEVEL SECURITY;
-- Policies for marketing_kit_assets
CREATE POLICY "Users can view marketing kit assets from their organization" ON marketing_kit_assets
FOR SELECT USING (
organization_id IN (
SELECT organization_id FROM users WHERE id = auth.uid()
)
);
CREATE POLICY "Users can create marketing kit assets for their organization" ON marketing_kit_assets
FOR INSERT WITH CHECK (
organization_id IN (
SELECT organization_id FROM users WHERE id = auth.uid()
)
);
CREATE POLICY "Users can update marketing kit assets from their organization" ON marketing_kit_assets
FOR UPDATE USING (
organization_id IN (
SELECT organization_id FROM users WHERE id = auth.uid()
)
);
CREATE POLICY "Users can delete marketing kit assets from their organization" ON marketing_kit_assets
FOR DELETE USING (
organization_id IN (
SELECT organization_id FROM users WHERE id = auth.uid()
)
);
-- Policies for marketing_templates
CREATE POLICY "Users can view marketing templates from their organization or default templates" ON marketing_templates
FOR SELECT USING (
organization_id IN (
SELECT organization_id FROM users WHERE id = auth.uid()
)
OR organization_id IS NULL -- Global default templates
);
CREATE POLICY "Users can create marketing templates for their organization" ON marketing_templates
FOR INSERT WITH CHECK (
organization_id IN (
SELECT organization_id FROM users WHERE id = auth.uid()
)
);
CREATE POLICY "Users can update marketing templates from their organization" ON marketing_templates
FOR UPDATE USING (
organization_id IN (
SELECT organization_id FROM users WHERE id = auth.uid()
)
);
CREATE POLICY "Users can delete marketing templates from their organization" ON marketing_templates
FOR DELETE USING (
organization_id IN (
SELECT organization_id FROM users WHERE id = auth.uid()
)
);
-- Policies for marketing_kit_generations
CREATE POLICY "Users can view marketing kit generations from their organization" ON marketing_kit_generations
FOR SELECT USING (
organization_id IN (
SELECT organization_id FROM users WHERE id = auth.uid()
)
);
CREATE POLICY "Users can create marketing kit generations for their organization" ON marketing_kit_generations
FOR INSERT WITH CHECK (
organization_id IN (
SELECT organization_id FROM users WHERE id = auth.uid()
)
);
CREATE POLICY "Users can update marketing kit generations from their organization" ON marketing_kit_generations
FOR UPDATE USING (
organization_id IN (
SELECT organization_id FROM users WHERE id = auth.uid()
)
);
-- Admin bypass policies
CREATE POLICY "Admins can manage all marketing kit assets" ON marketing_kit_assets
FOR ALL USING (is_admin(auth.uid()));
CREATE POLICY "Admins can manage all marketing templates" ON marketing_templates
FOR ALL USING (is_admin(auth.uid()));
CREATE POLICY "Admins can manage all marketing kit generations" ON marketing_kit_generations
FOR ALL USING (is_admin(auth.uid()));
-- Insert some default templates
INSERT INTO marketing_templates (name, description, template_type, platform, template_data, is_default, organization_id) VALUES
-- Facebook Post Template
('Default Facebook Post', 'Standard Facebook event promotion post', 'social_post', 'facebook',
'{"background": "gradient-blue", "textColor": "#FFFFFF", "layout": "center", "includeQR": true, "dimensions": {"width": 1200, "height": 630}}',
true, NULL),
-- Instagram Post Template
('Default Instagram Post', 'Square Instagram event promotion post', 'social_post', 'instagram',
'{"background": "gradient-purple", "textColor": "#FFFFFF", "layout": "center", "includeQR": true, "dimensions": {"width": 1080, "height": 1080}}',
true, NULL),
-- Twitter Post Template
('Default Twitter Post', 'Twitter event promotion post', 'social_post', 'twitter',
'{"background": "gradient-blue", "textColor": "#FFFFFF", "layout": "left", "includeQR": true, "dimensions": {"width": 1200, "height": 675}}',
true, NULL),
-- Email Template
('Default Email Template', 'Standard event promotion email template', 'email_template', NULL,
'{"subject": "You''re Invited: {EVENT_TITLE}", "headerImage": true, "includeQR": true, "ctaText": "Get Your Tickets", "layout": "centered"}',
true, NULL),
-- Flyer Template
('Default Event Flyer', 'Standard event flyer design', 'flyer', NULL,
'{"background": "gradient-blue", "textColor": "#FFFFFF", "layout": "poster", "includeQR": true, "dimensions": {"width": 1080, "height": 1350}}',
true, NULL);
-- Trigger to update updated_at timestamp
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';
CREATE TRIGGER update_marketing_kit_assets_updated_at BEFORE UPDATE ON marketing_kit_assets FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_marketing_templates_updated_at BEFORE UPDATE ON marketing_templates FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_marketing_kit_generations_updated_at BEFORE UPDATE ON marketing_kit_generations FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

View File

@@ -0,0 +1,25 @@
-- Add referral tracking columns to purchase_attempts table
ALTER TABLE purchase_attempts
ADD COLUMN IF NOT EXISTS referral_source TEXT,
ADD COLUMN IF NOT EXISTS utm_campaign TEXT,
ADD COLUMN IF NOT EXISTS utm_medium TEXT,
ADD COLUMN IF NOT EXISTS utm_source TEXT,
ADD COLUMN IF NOT EXISTS utm_term TEXT,
ADD COLUMN IF NOT EXISTS utm_content TEXT,
ADD COLUMN IF NOT EXISTS referrer_url TEXT,
ADD COLUMN IF NOT EXISTS landing_page TEXT;
-- Add indexes for better query performance
CREATE INDEX IF NOT EXISTS idx_purchase_attempts_referral_source ON purchase_attempts(referral_source);
CREATE INDEX IF NOT EXISTS idx_purchase_attempts_utm_source ON purchase_attempts(utm_source);
CREATE INDEX IF NOT EXISTS idx_purchase_attempts_utm_campaign ON purchase_attempts(utm_campaign);
-- Add comments to explain the columns
COMMENT ON COLUMN purchase_attempts.referral_source IS 'High-level referral source (e.g., google, facebook, direct, email)';
COMMENT ON COLUMN purchase_attempts.utm_campaign IS 'Campaign name from UTM parameters';
COMMENT ON COLUMN purchase_attempts.utm_medium IS 'Medium from UTM parameters (e.g., email, social, paid)';
COMMENT ON COLUMN purchase_attempts.utm_source IS 'Source from UTM parameters (e.g., google, facebook, newsletter)';
COMMENT ON COLUMN purchase_attempts.utm_term IS 'Term from UTM parameters (paid search keywords)';
COMMENT ON COLUMN purchase_attempts.utm_content IS 'Content from UTM parameters (ad variant)';
COMMENT ON COLUMN purchase_attempts.referrer_url IS 'Full HTTP referrer URL';
COMMENT ON COLUMN purchase_attempts.landing_page IS 'Page where user first landed on the site';

View File

@@ -0,0 +1,30 @@
-- Add social media links and website to events table for marketing kit
ALTER TABLE events ADD COLUMN IF NOT EXISTS social_links JSON DEFAULT '{}';
ALTER TABLE events ADD COLUMN IF NOT EXISTS website_url TEXT;
ALTER TABLE events ADD COLUMN IF NOT EXISTS contact_email TEXT;
-- Add social media links to organizations table as well for branding
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS social_links JSON DEFAULT '{}';
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS website_url TEXT;
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS contact_email TEXT;
-- Update the marketing templates to include social handles
UPDATE marketing_templates
SET template_data = jsonb_set(
template_data::jsonb,
'{includeSocialHandles}',
'true'::jsonb
)
WHERE template_type = 'social_post';
-- Add some example social links structure as comments
-- Social links JSON structure:
-- {
-- "facebook": "https://facebook.com/yourpage",
-- "instagram": "https://instagram.com/yourhandle",
-- "twitter": "https://twitter.com/yourhandle",
-- "linkedin": "https://linkedin.com/company/yourcompany",
-- "youtube": "https://youtube.com/channel/yourchannel",
-- "tiktok": "https://tiktok.com/@yourhandle",
-- "website": "https://yourwebsite.com"
-- }