← back to My Childhood Pics

components/ui/childhood-photo-recreator.tsx

512 lines

"use client"

import type React from "react"
import { useState, useEffect, useCallback } from "react"
import Image from "next/image"
import {
  MessageCircle,
  Sparkles,
  Wand2,
  Loader2,
  AlertCircle,
  Upload,
  User,
  Users,
  MapPin,
  Download,
  RefreshCw,
  Check,
} from "lucide-react"

import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Textarea } from "@/components/ui/textarea"
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import { Label } from "@/components/ui/label"

type UploadMode = "person1" | "person2" | "environment"

interface GenerationSettings {
  person1Image: string | null
  person2Image: string | null
  environmentImage: string | null
  selectedEnvironment: string
  customPrompt: string
  style: string
  lighting: string
}

interface SuggestedEnvironment {
  id: string
  name: string
  image: string
  description: string
}

const suggestedEnvironments: SuggestedEnvironment[] = [
  {
    id: "beach",
    name: "Tropical Beach",
    image: "https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=400",
    description: "Sandy beach with crystal clear water and palm trees"
  },
  {
    id: "mountain",
    name: "Mountain Vista",
    image: "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=400",
    description: "Majestic mountain peaks with scenic views"
  },
  {
    id: "city",
    name: "Urban Cityscape",
    image: "https://images.unsplash.com/photo-1449824913935-59a10b8d2000?w=400",
    description: "Modern city skyline with bustling streets"
  },
  {
    id: "forest",
    name: "Enchanted Forest",
    image: "https://images.unsplash.com/photo-1448375240586-882707db888b?w=400",
    description: "Dense forest with sunlight streaming through trees"
  },
  {
    id: "paris",
    name: "Paris, France",
    image: "https://images.unsplash.com/photo-1502602898657-3e91760cbb34?w=400",
    description: "Romantic Parisian streets with Eiffel Tower"
  },
  {
    id: "tokyo",
    name: "Tokyo, Japan",
    image: "https://images.unsplash.com/photo-1540959733332-eab4deabeeaf?w=400",
    description: "Vibrant Tokyo streets with neon lights"
  },
  {
    id: "desert",
    name: "Desert Dunes",
    image: "https://images.unsplash.com/photo-1509316785289-025f5b846b35?w=400",
    description: "Golden sand dunes under clear blue sky"
  },
  {
    id: "garden",
    name: "Botanical Garden",
    image: "https://images.unsplash.com/photo-1585320806297-9794b3e4eeae?w=400",
    description: "Beautiful garden with colorful flowers"
  },
]

export function ChildhoodPhotoRecreator() {
  const [mode, setMode] = useState<UploadMode>("person1")
  const [isGenerating, setIsGenerating] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [generatedImage, setGeneratedImage] = useState<string | null>(null)
  const [progress, setProgress] = useState(0)
  const [dragActive, setDragActive] = useState(false)

  const [settings, setSettings] = useState<GenerationSettings>({
    person1Image: null,
    person2Image: null,
    environmentImage: null,
    selectedEnvironment: "",
    customPrompt: "",
    style: "realistic",
    lighting: "natural",
  })

  // Handle file upload
  const handleFileUpload = useCallback((files: FileList | null, uploadMode: UploadMode) => {
    if (files && files[0]) {
      const file = files[0]
      const reader = new FileReader()

      reader.onload = (e) => {
        const result = e.target?.result as string
        if (uploadMode === "person1") {
          setSettings(prev => ({ ...prev, person1Image: result }))
        } else if (uploadMode === "person2") {
          setSettings(prev => ({ ...prev, person2Image: result }))
        } else {
          setSettings(prev => ({ ...prev, environmentImage: result, selectedEnvironment: "custom" }))
        }
      }

      reader.readAsDataURL(file)
    }
  }, [])

  // Handle drag and drop
  const handleDrag = useCallback((e: React.DragEvent) => {
    e.preventDefault()
    e.stopPropagation()
    if (e.type === "dragenter" || e.type === "dragover") {
      setDragActive(true)
    } else if (e.type === "dragleave") {
      setDragActive(false)
    }
  }, [])

  const handleDrop = useCallback((e: React.DragEvent, uploadMode: UploadMode) => {
    e.preventDefault()
    e.stopPropagation()
    setDragActive(false)

    if (e.dataTransfer.files && e.dataTransfer.files[0]) {
      handleFileUpload(e.dataTransfer.files, uploadMode)
    }
  }, [handleFileUpload])

  // Generate recreation
  const handleGenerate = async () => {
    if (!settings.person1Image) {
      setError("Please upload at least one person's photo")
      return
    }

    if (!settings.selectedEnvironment && !settings.environmentImage) {
      setError("Please select or upload an environment")
      return
    }

    setIsGenerating(true)
    setError(null)
    setProgress(0)

    try {
      // Simulate progress
      const interval = setInterval(() => {
        setProgress(prev => Math.min(prev + 10, 90))
      }, 300)

      // Simulate API call
      await new Promise(resolve => setTimeout(resolve, 3000))

      clearInterval(interval)
      setProgress(100)

      // Set a generated image (in real app, this would come from API)
      setGeneratedImage("https://images.unsplash.com/photo-1516627145497-ae6968895b74?w=800")

    } catch (err) {
      setError("Failed to generate recreation. Please try again.")
    } finally {
      setIsGenerating(false)
      setProgress(0)
    }
  }

  const getUploadAreaContent = () => {
    const currentImage = mode === "person1" ? settings.person1Image :
                        mode === "person2" ? settings.person2Image :
                        settings.environmentImage

    if (currentImage) {
      return (
        <div className="relative w-full h-full">
          <Image
            src={currentImage}
            alt={`Uploaded ${mode}`}
            fill
            className="object-cover rounded-lg"
          />
          <button
            onClick={() => {
              if (mode === "person1") setSettings(prev => ({ ...prev, person1Image: null }))
              else if (mode === "person2") setSettings(prev => ({ ...prev, person2Image: null }))
              else setSettings(prev => ({ ...prev, environmentImage: null }))
            }}
            className="absolute top-2 right-2 p-2 bg-red-500 text-white rounded-full hover:bg-red-600 transition-colors"
          >
            <RefreshCw className="w-4 h-4" />
          </button>
        </div>
      )
    }

    return (
      <div className="flex flex-col items-center justify-center h-full p-8 text-center">
        <Upload className={`w-12 h-12 mb-4 ${dragActive ? 'text-violet-500' : 'text-zinc-400'}`} />
        <p className="text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1">
          {mode === "person1" ? "Upload Person 1 Photo" :
           mode === "person2" ? "Upload Person 2 Photo (Optional)" :
           "Upload Custom Environment (Optional)"}
        </p>
        <p className="text-xs text-zinc-500">
          Drag & drop or click to upload
        </p>
        <p className="text-xs text-zinc-400 mt-2">
          JPG, PNG up to 10MB
        </p>
      </div>
    )
  }

  return (
    <div className="w-full max-w-6xl mx-auto space-y-6">
      {/* Header */}
      <div className="text-center space-y-2">
        <h1 className="text-4xl font-bold bg-gradient-to-r from-violet-500 to-fuchsia-500 bg-clip-text text-transparent">
          Childhood Photo Recreator
        </h1>
        <p className="text-zinc-600 dark:text-zinc-400">
          Upload your childhood photos and recreate them in amazing new environments
        </p>
      </div>

      <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
        {/* Upload Section */}
        <Card className="border-zinc-200 dark:border-zinc-800">
          <CardContent className="p-6">
            <div className="space-y-4">
              {/* Upload Mode Tabs */}
              <Tabs value={mode} onValueChange={(value) => setMode(value as UploadMode)}>
                <TabsList className="grid grid-cols-3 w-full">
                  <TabsTrigger value="person1" className="flex items-center gap-2">
                    <User className="w-4 h-4" />
                    <span>Person 1</span>
                    {settings.person1Image && <Check className="w-3 h-3 text-green-500" />}
                  </TabsTrigger>
                  <TabsTrigger value="person2" className="flex items-center gap-2">
                    <Users className="w-4 h-4" />
                    <span>Person 2</span>
                    {settings.person2Image && <Check className="w-3 h-3 text-green-500" />}
                  </TabsTrigger>
                  <TabsTrigger value="environment" className="flex items-center gap-2">
                    <MapPin className="w-4 h-4" />
                    <span>Environment</span>
                    {(settings.environmentImage || settings.selectedEnvironment) && <Check className="w-3 h-3 text-green-500" />}
                  </TabsTrigger>
                </TabsList>
              </Tabs>

              {/* Upload Area */}
              <div
                className={`relative h-64 border-2 border-dashed rounded-lg transition-colors ${
                  dragActive ? 'border-violet-500 bg-violet-50 dark:bg-violet-900/10' : 'border-zinc-300 dark:border-zinc-700'
                }`}
                onDragEnter={handleDrag}
                onDragLeave={handleDrag}
                onDragOver={handleDrag}
                onDrop={(e) => handleDrop(e, mode)}
              >
                <input
                  type="file"
                  accept="image/*"
                  onChange={(e) => handleFileUpload(e.target.files, mode)}
                  className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
                />
                {getUploadAreaContent()}
              </div>

              {/* Environment Selection (only show in environment mode) */}
              {mode === "environment" && (
                <div className="space-y-3">
                  <Label className="text-sm font-medium">Or Choose Suggested Environment</Label>
                  <div className="grid grid-cols-2 gap-2 max-h-48 overflow-y-auto">
                    {suggestedEnvironments.map((env) => (
                      <button
                        key={env.id}
                        onClick={() => setSettings(prev => ({
                          ...prev,
                          selectedEnvironment: env.id,
                          environmentImage: null
                        }))}
                        className={`relative h-24 rounded-lg overflow-hidden border-2 transition-all ${
                          settings.selectedEnvironment === env.id
                            ? 'border-violet-500 ring-2 ring-violet-500/20'
                            : 'border-zinc-200 dark:border-zinc-700 hover:border-violet-300'
                        }`}
                      >
                        <Image
                          src={env.image}
                          alt={env.name}
                          fill
                          className="object-cover"
                        />
                        <div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent" />
                        <div className="absolute bottom-1 left-2 right-2">
                          <p className="text-xs text-white font-medium truncate">{env.name}</p>
                        </div>
                        {settings.selectedEnvironment === env.id && (
                          <div className="absolute top-1 right-1 bg-violet-500 rounded-full p-1">
                            <Check className="w-3 h-3 text-white" />
                          </div>
                        )}
                      </button>
                    ))}
                  </div>
                </div>
              )}

              {/* Settings */}
              <div className="space-y-3 border-t pt-4">
                <div className="grid grid-cols-2 gap-3">
                  <div>
                    <Label className="text-xs">Style</Label>
                    <Select value={settings.style} onValueChange={(value) => setSettings(prev => ({ ...prev, style: value }))}>
                      <SelectTrigger className="h-8 text-xs">
                        <SelectValue />
                      </SelectTrigger>
                      <SelectContent>
                        <SelectItem value="realistic">Realistic</SelectItem>
                        <SelectItem value="artistic">Artistic</SelectItem>
                        <SelectItem value="cartoon">Cartoon</SelectItem>
                        <SelectItem value="vintage">Vintage</SelectItem>
                      </SelectContent>
                    </Select>
                  </div>
                  <div>
                    <Label className="text-xs">Lighting</Label>
                    <Select value={settings.lighting} onValueChange={(value) => setSettings(prev => ({ ...prev, lighting: value }))}>
                      <SelectTrigger className="h-8 text-xs">
                        <SelectValue />
                      </SelectTrigger>
                      <SelectContent>
                        <SelectItem value="natural">Natural</SelectItem>
                        <SelectItem value="studio">Studio</SelectItem>
                        <SelectItem value="dramatic">Dramatic</SelectItem>
                        <SelectItem value="soft">Soft</SelectItem>
                      </SelectContent>
                    </Select>
                  </div>
                </div>

                <div>
                  <Label className="text-xs">Additional Instructions (Optional)</Label>
                  <Textarea
                    value={settings.customPrompt}
                    onChange={(e) => setSettings(prev => ({ ...prev, customPrompt: e.target.value }))}
                    placeholder="E.g., Make us look older, add sunset, include props..."
                    className="h-16 text-xs resize-none"
                  />
                </div>
              </div>

              {/* Generate Button */}
              <Button
                onClick={handleGenerate}
                disabled={isGenerating || !settings.person1Image || (!settings.selectedEnvironment && !settings.environmentImage)}
                className="w-full bg-gradient-to-r from-violet-500 to-fuchsia-500 hover:from-violet-600 hover:to-fuchsia-600"
              >
                {isGenerating ? (
                  <>
                    <Loader2 className="w-4 h-4 mr-2 animate-spin" />
                    Recreating... {progress}%
                  </>
                ) : (
                  <>
                    <Sparkles className="w-4 h-4 mr-2" />
                    Generate Recreation
                  </>
                )}
              </Button>

              {error && (
                <div className="p-3 bg-red-50 dark:bg-red-900/10 border border-red-200 dark:border-red-800 rounded-lg">
                  <p className="text-sm text-red-600 dark:text-red-400 flex items-center gap-2">
                    <AlertCircle className="w-4 h-4" />
                    {error}
                  </p>
                </div>
              )}
            </div>
          </CardContent>
        </Card>

        {/* Result Section */}
        <Card className="border-zinc-200 dark:border-zinc-800">
          <CardContent className="p-6">
            <div className="space-y-4">
              <h3 className="text-lg font-semibold">Your Recreated Photo</h3>

              {generatedImage ? (
                <div className="space-y-4">
                  <div className="relative aspect-square rounded-lg overflow-hidden bg-zinc-100 dark:bg-zinc-800">
                    <Image
                      src={generatedImage}
                      alt="Recreated photo"
                      fill
                      className="object-cover"
                    />
                  </div>

                  <div className="flex gap-2">
                    <Button variant="outline" className="flex-1">
                      <RefreshCw className="w-4 h-4 mr-2" />
                      Regenerate
                    </Button>
                    <Button className="flex-1 bg-gradient-to-r from-violet-500 to-fuchsia-500 hover:from-violet-600 hover:to-fuchsia-600">
                      <Download className="w-4 h-4 mr-2" />
                      Download
                    </Button>
                  </div>

                  <div className="grid grid-cols-2 gap-4 pt-4 border-t">
                    <div className="text-center">
                      <p className="text-xs text-zinc-500 mb-1">Original</p>
                      <div className="grid grid-cols-2 gap-1">
                        {settings.person1Image && (
                          <div className="relative aspect-square rounded overflow-hidden">
                            <Image
                              src={settings.person1Image}
                              alt="Person 1"
                              fill
                              className="object-cover"
                            />
                          </div>
                        )}
                        {settings.person2Image && (
                          <div className="relative aspect-square rounded overflow-hidden">
                            <Image
                              src={settings.person2Image}
                              alt="Person 2"
                              fill
                              className="object-cover"
                            />
                          </div>
                        )}
                      </div>
                    </div>
                    <div className="text-center">
                      <p className="text-xs text-zinc-500 mb-1">Environment</p>
                      <div className="relative aspect-square rounded overflow-hidden">
                        {settings.environmentImage ? (
                          <Image
                            src={settings.environmentImage}
                            alt="Custom environment"
                            fill
                            className="object-cover"
                          />
                        ) : settings.selectedEnvironment ? (
                          <Image
                            src={suggestedEnvironments.find(e => e.id === settings.selectedEnvironment)?.image || ""}
                            alt="Selected environment"
                            fill
                            className="object-cover"
                          />
                        ) : (
                          <div className="w-full h-full bg-zinc-200 dark:bg-zinc-700" />
                        )}
                      </div>
                    </div>
                  </div>
                </div>
              ) : (
                <div className="h-96 flex flex-col items-center justify-center text-center p-8 bg-zinc-50 dark:bg-zinc-800/50 rounded-lg">
                  <div className="w-16 h-16 mb-4 rounded-full bg-gradient-to-r from-violet-500/20 to-fuchsia-500/20 flex items-center justify-center">
                    <Wand2 className="w-8 h-8 text-violet-500" />
                  </div>
                  <p className="text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-2">
                    Your recreation will appear here
                  </p>
                  <p className="text-xs text-zinc-500 max-w-xs">
                    Upload photos of 1-2 people and select an environment to create your magical recreation
                  </p>
                </div>
              )}
            </div>
          </CardContent>
        </Card>
      </div>
    </div>
  )
}