← back to IWasCute

src/components/licensor/ReviewSubmit.tsx

360 lines

'use client'

import { useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import {
  ChevronLeft,
  Camera,
  Copyright,
  ShieldCheck,
  CheckCircle2,
  Loader2,
  AlertCircle,
  ExternalLink,
} from 'lucide-react'
import clsx from 'clsx'
import type { PhotoFile } from './PhotoUpload'
import type { CopyrightData } from './CopyrightInfo'
import type { LikenessData } from './LikenessRelease'

interface ReviewSubmitProps {
  photos: PhotoFile[]
  copyrightInfo: CopyrightData
  likenessRelease: LikenessData
  onBack: () => void
}

type SubmitState = 'idle' | 'submitting' | 'success' | 'error'

function SectionCard({
  icon,
  title,
  children,
}: {
  icon: React.ReactNode
  title: string
  children: React.ReactNode
}) {
  return (
    <div
      className="rounded-3xl overflow-hidden"
      style={{ border: '1px solid var(--color-cream-dark)', background: 'rgba(255,255,255,0.6)' }}
    >
      <div
        className="flex items-center gap-3 px-6 py-4 border-b"
        style={{ borderColor: 'var(--color-cream-dark)', background: 'rgba(255,255,255,0.4)' }}
      >
        <div
          className="w-8 h-8 rounded-xl flex items-center justify-center"
          style={{ background: 'var(--color-peach)' }}
        >
          {icon}
        </div>
        <h3 className="text-sm font-bold tracking-wide" style={{ color: 'var(--color-brown)' }}>
          {title}
        </h3>
      </div>
      <div className="px-6 py-5">{children}</div>
    </div>
  )
}

function ReviewRow({ label, value }: { label: string; value: string | React.ReactNode }) {
  return (
    <div className="flex items-start justify-between gap-4 py-2.5 border-b last:border-b-0" style={{ borderColor: 'var(--color-cream-dark)' }}>
      <span className="text-sm shrink-0" style={{ color: 'var(--color-warm-gray)' }}>
        {label}
      </span>
      <span className="text-sm font-medium text-right" style={{ color: 'var(--color-brown)' }}>
        {value}
      </span>
    </div>
  )
}

const RELATIONSHIP_LABELS: Record<string, string> = {
  parent: 'My parent',
  family: 'Other family member',
  professional: 'Professional photographer',
  unknown: "Don't know",
}

const PERMISSION_LABELS: Record<string, string> = {
  yes: 'Yes — has permission',
  no: 'No explicit permission',
  deceased: 'Photographer deceased',
}

export default function ReviewSubmit({
  photos,
  copyrightInfo,
  likenessRelease,
  onBack,
}: ReviewSubmitProps) {
  const [submitState, setSubmitState] = useState<SubmitState>('idle')
  const [errorMsg, setErrorMsg] = useState('')

  const usageTypes = [
    likenessRelease.editorial && 'Editorial',
    likenessRelease.commercial && 'Commercial',
    likenessRelease.aiTraining && 'AI Training',
  ]
    .filter(Boolean)
    .join(', ')

  const handleSubmit = async () => {
    setSubmitState('submitting')
    setErrorMsg('')

    // Simulated async submission
    await new Promise((r) => setTimeout(r, 2200))

    // In production: POST to /api/licensor/submit with FormData
    const success = Math.random() > 0.05 // 95% success rate for demo
    if (success) {
      setSubmitState('success')
    } else {
      setSubmitState('error')
      setErrorMsg('Something went wrong. Please try again.')
    }
  }

  if (submitState === 'success') {
    return (
      <motion.div
        initial={{ opacity: 0, scale: 0.96 }}
        animate={{ opacity: 1, scale: 1 }}
        transition={{ type: 'spring', stiffness: 300, damping: 28 }}
        className="flex flex-col items-center justify-center gap-8 py-16 text-center"
      >
        <motion.div
          initial={{ scale: 0 }}
          animate={{ scale: 1 }}
          transition={{ type: 'spring', stiffness: 300, damping: 22, delay: 0.1 }}
          className="w-24 h-24 rounded-full flex items-center justify-center"
          style={{ background: 'var(--color-sage)' }}
        >
          <CheckCircle2 size={48} style={{ color: 'white' }} />
        </motion.div>

        <div className="flex flex-col gap-3 max-w-md">
          <h2 className="text-3xl font-black tracking-tighter" style={{ color: 'var(--color-brown)' }}>
            You&apos;re in the queue!
          </h2>
          <p className="text-base leading-relaxed" style={{ color: 'var(--color-warm-gray)' }}>
            Your {photos.length} photo{photos.length !== 1 ? 's' : ''}{' '}
            {photos.length !== 1 ? 'have' : 'has'} been submitted for rights review. We&apos;ll
            notify you by email when they&apos;re cleared for licensing.
          </p>
        </div>

        <div
          className="w-full max-w-sm rounded-3xl p-6 flex flex-col gap-3"
          style={{ background: 'var(--color-cream-dark)' }}
        >
          <p className="text-xs font-bold tracking-widest uppercase" style={{ color: 'var(--color-warm-gray)' }}>
            What happens next
          </p>
          {[
            { step: '1', text: 'Rights review (24–48 hours)' },
            { step: '2', text: 'Copyright clearance notification' },
            { step: '3', text: 'Photos go live in marketplace' },
            { step: '4', text: 'Royalties deposited when licensed' },
          ].map(({ step, text }) => (
            <div key={step} className="flex items-center gap-3">
              <div
                className="w-6 h-6 rounded-full flex items-center justify-center shrink-0 text-xs font-bold"
                style={{ background: 'var(--color-peach)', color: 'var(--color-brown)' }}
              >
                {step}
              </div>
              <p className="text-sm" style={{ color: 'var(--color-brown)' }}>
                {text}
              </p>
            </div>
          ))}
        </div>

        <a
          href="/dashboard"
          className="inline-flex items-center gap-2 px-8 py-3.5 rounded-3xl text-sm font-semibold tracking-wide transition-all hover:scale-105"
          style={{ background: 'var(--color-peach)', color: 'var(--color-brown)' }}
        >
          Go to My Dashboard
          <ExternalLink size={14} />
        </a>
      </motion.div>
    )
  }

  return (
    <div className="flex flex-col gap-6">
      {/* Header */}
      <div>
        <h2
          className="text-2xl md:text-3xl font-bold tracking-tight"
          style={{ color: 'var(--color-brown)' }}
        >
          Review &amp; Submit
        </h2>
        <p className="mt-2 text-base" style={{ color: 'var(--color-warm-gray)' }}>
          Please review everything below before submitting for rights review.
        </p>
      </div>

      {/* Photos section */}
      <SectionCard icon={<Camera size={16} style={{ color: 'var(--color-brown)' }} />} title={`${photos.length} Photo${photos.length !== 1 ? 's' : ''}`}>
        <div
          className="flex gap-2 flex-wrap"
        >
          {photos.map((photo, i) => (
            <div
              key={photo.id}
              className="relative rounded-xl overflow-hidden"
              style={{ width: 72, height: 72, flexShrink: 0 }}
            >
              {/* eslint-disable-next-line @next/next/no-img-element */}
              <img
                src={photo.preview}
                alt={`Photo ${i + 1}`}
                className="w-full h-full object-cover"
              />
            </div>
          ))}
        </div>
      </SectionCard>

      {/* Copyright section */}
      <SectionCard
        icon={<Copyright size={16} style={{ color: 'var(--color-brown)' }} />}
        title="Copyright Information"
      >
        <ReviewRow
          label="Photographer"
          value={RELATIONSHIP_LABELS[copyrightInfo.relationship] ?? copyrightInfo.relationship}
        />
        {copyrightInfo.photographer && (
          <ReviewRow label="Name" value={copyrightInfo.photographer} />
        )}
        {copyrightInfo.year && (
          <ReviewRow label="Year taken" value={copyrightInfo.year} />
        )}
        <ReviewRow
          label="Permission"
          value={PERMISSION_LABELS[copyrightInfo.hasPermission] ?? copyrightInfo.hasPermission}
        />
        {copyrightInfo.hasPermission === 'deceased' && (
          <ReviewRow
            label="Estate rights"
            value={copyrightInfo.estateRights ? 'Has evidence' : 'No evidence'}
          />
        )}
      </SectionCard>

      {/* Likeness section */}
      <SectionCard
        icon={<ShieldCheck size={16} style={{ color: 'var(--color-brown)' }} />}
        title="Likeness Release"
      >
        <ReviewRow label="Subject confirmed" value={likenessRelease.isSubject ? 'Yes' : 'No'} />
        <ReviewRow label="Age confirmed (18+)" value={likenessRelease.isAdult ? 'Yes' : 'No'} />
        <ReviewRow label="Licensed for" value={usageTypes || 'None selected'} />
        <ReviewRow
          label="Signed by"
          value={
            <span className="signature-field text-base">
              {likenessRelease.signature}
            </span>
          }
        />
        <ReviewRow label="Date" value={likenessRelease.date} />
      </SectionCard>

      {/* Legal notice */}
      <div
        className="flex items-start gap-3 p-4 rounded-2xl text-xs leading-relaxed"
        style={{ background: 'rgba(61, 64, 91, 0.05)', border: '1px solid var(--color-cream-dark)' }}
        role="note"
      >
        <AlertCircle size={14} className="shrink-0 mt-0.5" style={{ color: 'var(--color-warm-gray)' }} />
        <p style={{ color: 'var(--color-warm-gray)' }}>
          By submitting, you certify that all information above is accurate and that you have the
          legal authority to license these photos. False submissions may result in account termination
          and legal liability.
        </p>
      </div>

      {/* Error */}
      <AnimatePresence>
        {submitState === 'error' && (
          <motion.div
            initial={{ opacity: 0, y: -8 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -8 }}
            className="flex items-center gap-3 p-4 rounded-2xl"
            style={{ background: 'rgba(255, 181, 167, 0.2)', border: '1px solid var(--color-peach)' }}
            role="alert"
          >
            <AlertCircle size={16} style={{ color: 'var(--color-peach-dark)' }} />
            <p className="text-sm font-medium" style={{ color: 'var(--color-brown)' }}>
              {errorMsg}
            </p>
          </motion.div>
        )}
      </AnimatePresence>

      {/* Navigation */}
      <div className="flex items-center justify-between pt-2">
        <button
          onClick={onBack}
          disabled={submitState === 'submitting'}
          className={clsx(
            'flex items-center gap-2 px-6 py-3 rounded-3xl text-sm font-semibold tracking-wide',
            'transition-all hover:scale-105 disabled:opacity-40 disabled:cursor-not-allowed'
          )}
          style={{
            background: 'var(--color-cream-dark)',
            color: 'var(--color-warm-gray)',
          }}
        >
          <ChevronLeft size={16} />
          Back
        </button>

        <motion.button
          whileHover={submitState === 'idle' ? { scale: 1.03 } : {}}
          whileTap={submitState === 'idle' ? { scale: 0.97 } : {}}
          onClick={handleSubmit}
          disabled={submitState === 'submitting'}
          className={clsx(
            'flex items-center gap-2.5 px-8 py-3.5 rounded-3xl text-sm font-semibold tracking-wide',
            'transition-all duration-200',
            submitState === 'submitting' && 'cursor-not-allowed'
          )}
          style={{
            background:
              submitState === 'error'
                ? 'var(--color-peach-dark)'
                : 'var(--color-peach)',
            color: 'var(--color-brown)',
          }}
        >
          {submitState === 'submitting' ? (
            <>
              <Loader2 size={16} className="animate-spin" />
              Submitting…
            </>
          ) : submitState === 'error' ? (
            'Try Again'
          ) : (
            <>
              <CheckCircle2 size={16} />
              Submit for Review
            </>
          )}
        </motion.button>
      </div>
    </div>
  )
}