diff --git a/src/components/wizard/branding/actions.ts b/src/components/wizard/branding/actions.ts deleted file mode 100644 index e235c8f..0000000 --- a/src/components/wizard/branding/actions.ts +++ /dev/null @@ -1,62 +0,0 @@ -"use server"; - -import { z } from "zod"; -import { brandingSchema } from "./validation"; - -export type BrandingFormData = z.infer; - -// Simple action response type for wizard branding -export type ActionResponse = { - success: boolean; - data?: T; - error?: string; -}; - -export async function updateBranding( - data: BrandingFormData -): Promise> { - try { - const validatedData = brandingSchema.parse(data); - - // In a real app, you would save this to a database - // For now, we'll just return the validated data - return { - success: true, - data: validatedData, - }; - } catch (error) { - if (error instanceof z.ZodError) { - return { - success: false, - error: error.errors[0]?.message || "Validation failed", - }; - } - - return { - success: false, - error: "Failed to update branding", - }; - } -} - -export async function getBranding(): Promise> { - try { - // In a real app, you would fetch this from a database - // For now, return default values - return { - success: true, - data: { - logoUrl: "", - brandName: "", - primaryColor: "#000000", - secondaryColor: "#ffffff", - tagline: "", - }, - }; - } catch (error) { - return { - success: false, - error: "Failed to fetch branding", - }; - } -} diff --git a/src/components/wizard/branding/card.tsx b/src/components/wizard/branding/card.tsx deleted file mode 100644 index 730fe28..0000000 --- a/src/components/wizard/branding/card.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { Palette, Image } from "lucide-react"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; - -interface BrandingCardProps { - logoUrl?: string; - brandName: string; - tagline?: string; - primaryColor?: string; - secondaryColor?: string; - className?: string; -} - -export function BrandingCard({ - logoUrl, - brandName, - tagline, - primaryColor = "#000000", - secondaryColor = "#ffffff", - className -}: BrandingCardProps) { - return ( - - - - - School Branding - - - -
- {/* Brand Preview */} -
-
- {logoUrl ? ( - School Logo - ) : ( -
- -
- )} -
-

{brandName || "School Name"}

- {tagline && ( -

{tagline}

- )} -
-
-
- - {/* Color Palette */} -
-
-
-
- Primary -
- {primaryColor} -
- -
-
-
- Secondary -
- {secondaryColor} -
-
- - {!brandName && ( -
-

- Please set your school branding to continue setup -

-
- )} -
- - - ); -} diff --git a/src/components/wizard/branding/constants.ts b/src/components/wizard/branding/constants.ts deleted file mode 100644 index 35b5008..0000000 --- a/src/components/wizard/branding/constants.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { ColorOption, StyleOption } from './types'; - -export const COLOR_OPTIONS: ColorOption[] = [ - { id: 'slate', name: 'Slate', color: '#0f172a', description: 'Professional and modern' }, - { id: 'blue', name: 'Blue', color: '#1d4ed8', description: 'Trustworthy and calm' }, - { id: 'green', name: 'Green', color: '#15803d', description: 'Growth and learning' }, - { id: 'yellow', name: 'Yellow', color: '#facc15', description: 'Energy and creativity' }, - { id: 'orange', name: 'Orange', color: '#ea580c', description: 'Friendly and confident' }, - { id: 'rose', name: 'Rose', color: '#e11d48', description: 'Passion and energy' }, - { id: 'purple', name: 'Purple', color: '#7e22ce', description: 'Wisdom and dignity' }, -] as const; - -export const RADIUS_OPTIONS: StyleOption[] = [ - { id: 'none', label: 'no', description: 'Sharp corners' }, - { id: 'sm', label: 'sm', description: 'Subtle rounding' }, - { id: 'md', label: 'md', description: 'Medium rounding' }, - { id: 'lg', label: 'lg', description: 'Soft rounding' }, -] as const; - -export const SHADOW_OPTIONS: StyleOption[] = [ - { id: 'none', label: 'no', description: 'No shadow' }, - { id: 'sm', label: 'sm', description: 'Subtle shadow' }, - { id: 'md', label: 'md', description: 'Medium shadow' }, - { id: 'lg', label: 'lg', description: 'Large shadow' }, -] as const; - -export const LOGO_LIMITS = { - MAX_SIZE: 2 * 1024 * 1024, // 2MB - ALLOWED_TYPES: ['image/jpeg', 'image/png', 'image/svg+xml'], - MAX_DIMENSIONS: { - width: 800, - height: 800, - }, -} as const; - -export const BRANDING_MESSAGES = { - LOGO_TOO_LARGE: `Logo file must be smaller than ${LOGO_LIMITS.MAX_SIZE / (1024 * 1024)}MB`, - INVALID_FILE_TYPE: 'Logo must be JPG, PNG, or SVG', - DIMENSIONS_TOO_LARGE: `Logo dimensions cannot exceed ${LOGO_LIMITS.MAX_DIMENSIONS.width}x${LOGO_LIMITS.MAX_DIMENSIONS.height}px`, - PRIMARY_COLOR_REQUIRED: 'Please select a primary color', - INVALID_COLOR: 'Please select a valid color', - INVALID_URL: 'Please enter a valid URL', -} as const; \ No newline at end of file diff --git a/src/components/wizard/branding/content.tsx b/src/components/wizard/branding/content.tsx deleted file mode 100644 index fa3c60e..0000000 --- a/src/components/wizard/branding/content.tsx +++ /dev/null @@ -1,288 +0,0 @@ -"use client"; - -import React, { useState, useEffect } from 'react'; -import { useRouter, useParams } from 'next/navigation'; -import { Upload, Palette, Square, Circle } from 'lucide-react'; -import Image from 'next/image'; -import { useListing } from '@/components/onboarding/use-listing'; -import { useHostValidation } from '@/components/onboarding/host-validation-context'; -import { Button } from "@/components/ui/button"; -import { cn } from "@/lib/utils"; -import { COLOR_OPTIONS, RADIUS_OPTIONS, SHADOW_OPTIONS } from './constants'; - -interface BrandingContentProps { - dictionary?: any; -} - -export default function BrandingContent({ dictionary }: BrandingContentProps) { - const dict = dictionary?.onboarding || {}; - const router = useRouter(); - const params = useParams(); - const { setCustomNavigation } = useHostValidation(); - const { listing, updateListingData } = useListing(); - const [logo, setLogo] = useState(); - const [primaryColor, setPrimaryColor] = useState('#0f172a'); // Default dark color - const [borderRadius, setBorderRadius] = useState<'none' | 'sm' | 'md' | 'lg'>('md'); - const [shadow, setShadow] = useState<'none' | 'sm' | 'md' | 'lg'>('md'); - - // Get the ID from the URL params - const id = params?.id as string; - - // Load existing data from listing - useEffect(() => { - if (listing) { - if (listing.logoUrl !== undefined && listing.logoUrl !== null) setLogo(listing.logoUrl); - if (listing.primaryColor) setPrimaryColor(listing.primaryColor); - if (listing.borderRadius && ['none', 'sm', 'md', 'lg'].includes(listing.borderRadius)) { - setBorderRadius(listing.borderRadius as 'none' | 'sm' | 'md' | 'lg'); - } - if (listing.shadow && ['none', 'sm', 'md', 'lg'].includes(listing.shadow)) { - setShadow(listing.shadow as 'none' | 'sm' | 'md' | 'lg'); - } - } - }, [listing]); - - const handleBack = () => { - router.push(`/onboarding/${id}/description`); - }; - - const handleNext = async () => { - try { - await updateListingData({ - logoUrl: logo, - primaryColor, - borderRadius, - shadow - }); - router.push(`/onboarding/${id}/import`); - } catch (error) { - console.error('Error updating branding:', error); - } - }; - - const handleLogoUpload = (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (file) { - const reader = new FileReader(); - reader.onloadend = () => { - setLogo(reader.result as string); - }; - reader.readAsDataURL(file); - } - }; - - // Set custom navigation in context - useEffect(() => { - setCustomNavigation({ - onBack: handleBack, - onNext: handleNext, - nextDisabled: !logo - }); - - return () => { - setCustomNavigation(undefined); - }; - }, [logo]); - - return ( -
-
- {/* Left side - Text content and controls */} -
-
-

- {dict.schoolBranding || "Create your school's"} -
- {dict.brandIdentity || "brand identity"} -

-

- {dict.brandingDescription || "Upload your logo and customize your school's visual style."} -

-
- - {/* Style Controls */} -
- {/* Color Selection */} -
- -
- {COLOR_OPTIONS.map((option) => ( -
-
- -
- - {/* Border Radius Selection */} -
- -
- {RADIUS_OPTIONS.map((option) => ( - - ))} -
-
- -
- - {/* Shadow Selection */} -
- -
- {SHADOW_OPTIONS.map((option) => ( - - ))} -
-
-
-
- - {/* Right side - Logo Upload and Preview */} -
- {logo === undefined ? ( - // Initial large upload box -
-
- - -
-

{dict.uploadSchoolLogo || "Upload your school logo"}

-

- {dict.logoFileTypes || "SVG, PNG, JPG (max. 800x800px)"} -

-
- - - {logo && ( -

- {dict.fileSelected || "File selected"} -

- )} -
-
-
-
- ) : ( - // Logo preview -
- School logo - -
- )} -
-
-
- ); -} diff --git a/src/components/wizard/branding/form.tsx b/src/components/wizard/branding/form.tsx deleted file mode 100644 index 1c6d97a..0000000 --- a/src/components/wizard/branding/form.tsx +++ /dev/null @@ -1,188 +0,0 @@ -"use client"; - -import { useState, useTransition } from "react"; -import { useForm } from "react-hook-form"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { Upload, Palette } from "lucide-react"; -import { Button } from "@/components/ui/button"; -import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; -import { Textarea } from "@/components/ui/textarea"; -import { brandingSchema, type BrandingFormData } from "./validation"; -import { updateBranding } from "./actions"; -import { useTranslations } from '@/lib/use-translations'; - -interface BrandingFormProps { - initialData?: Partial; - onSuccess?: () => void; -} - -export function BrandingForm({ initialData, onSuccess }: BrandingFormProps) { - const { t } = useTranslations(); - const [isPending, startTransition] = useTransition(); - const [error, setError] = useState(""); - - const form = useForm({ - resolver: zodResolver(brandingSchema), - defaultValues: { - logoUrl: initialData?.logoUrl || "", - primaryColor: initialData?.primaryColor || "#000000", - secondaryColor: initialData?.secondaryColor || "#ffffff", - brandName: initialData?.brandName || "", - tagline: initialData?.tagline || "", - }, - }); - - const handleSubmit = (data: BrandingFormData) => { - startTransition(async () => { - try { - setError(""); - const result = await updateBranding(data); - - if (result.success) { - onSuccess?.(); - } else { - setError(result.error || "Failed to update branding"); - } - } catch (err) { - setError("An unexpected error occurred"); - } - }); - }; - - return ( -
-
- - {error && ( -
- {error} -
- )} - - ( - - {t.wizard.branding.brandName} - - - - - - )} - /> - - ( - - {t.wizard.branding.tagline} - -