diff --git a/components/clients/ShareReviewDialog.tsx b/components/clients/ShareReviewDialog.tsx index 23dccf2..aa5371d 100644 --- a/components/clients/ShareReviewDialog.tsx +++ b/components/clients/ShareReviewDialog.tsx @@ -1,4 +1,4 @@ -"use client"; +"use client"; import { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; @@ -233,12 +233,12 @@ export function ShareReviewDialog({ {errors.projectId &&

{errors.projectId.message}

} - {/* Episode filter — only shown when the project has episodes */} + {/* Episode filter — only shown when the project has episodes */} {!loadingEpisodes && episodes.length > 0 && (
{episodes.map((ep) => { @@ -337,248 +337,3 @@ export function ShareReviewDialog({ ); } - - -const schema = z.object({ - projectId: z.string().min(1, "Select a project"), - label: z.string().min(1, "Label is required"), - email: z.string().email("Invalid email"), - expiresInDays: z.number().int().positive().default(30), - password: z.string().optional(), -}); - -type FormValues = z.infer; - -interface Project { - id: string; - name: string; - code: string; -} - -interface ShareReviewDialogProps { - children: React.ReactNode; - clientId: string; - clientEmail: string; - projects: Project[]; -} - -export function ShareReviewDialog({ - children, - clientEmail, - projects, -}: ShareReviewDialogProps) { - const [open, setOpen] = useState(false); - const [loading, setLoading] = useState(false); - const [portalUrl, setPortalUrl] = useState(null); - const [isPasswordProtected, setIsPasswordProtected] = useState(false); - const [copied, setCopied] = useState(false); - const [showPassword, setShowPassword] = useState(false); - const { toast } = useToast(); - const router = useRouter(); - - const { - register, - handleSubmit, - watch, - setValue, - reset, - formState: { errors }, - } = useForm({ - resolver: zodResolver(schema), - defaultValues: { - projectId: projects[0]?.id ?? "", - label: "Review Round 1", - email: clientEmail, - expiresInDays: 30, - password: "", - }, - }); - - const handleCopy = async () => { - if (!portalUrl) return; - await navigator.clipboard.writeText(portalUrl); - setCopied(true); - setTimeout(() => setCopied(false), 2000); - }; - - const handleReset = () => { - setPortalUrl(null); - setIsPasswordProtected(false); - reset({ - projectId: projects[0]?.id ?? "", - label: "Review Round 1", - email: clientEmail, - expiresInDays: 30, - password: "", - }); - }; - - const onSubmit = async (values: FormValues) => { - setLoading(true); - try { - const res = await fetch("/api/review-sessions", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - ...values, - password: values.password?.trim() || undefined, - }), - }); - if (!res.ok) { - const err = await res.json().catch(() => ({})); - throw new Error(err.error ?? "Failed to create review link"); - } - const data = await res.json(); - setPortalUrl(data.portalUrl); - setIsPasswordProtected(!!(values.password?.trim())); - router.refresh(); - } catch (e) { - toast({ - title: "Failed to create review link", - description: e instanceof Error ? e.message : undefined, - variant: "destructive", - }); - } finally { - setLoading(false); - } - }; - - return ( - { - if (!o) { setPortalUrl(null); } - setOpen(o); - }} - > - {children} - - - Share Review Link - - - {portalUrl ? ( -
-

- Your review link is ready. Copy it and share it with your client. -

- {isPasswordProtected && ( -
- - This link is password protected. Share the password separately. -
- )} -
- - {portalUrl} - -
- - - - -
- ) : ( -
-
- - - {errors.projectId &&

{errors.projectId.message}

} -
-
- - - {errors.label &&

{errors.label.message}

} -
-
- - - {errors.email &&

{errors.email.message}

} -
-
- - -
-
- -
- - -
-
- - - - -
- )} -
-
- ); -}