diff --git a/src/app/setup/SetupClient.tsx b/src/app/setup/SetupClient.tsx new file mode 100644 index 0000000..df0a86c --- /dev/null +++ b/src/app/setup/SetupClient.tsx @@ -0,0 +1,406 @@ +"use client"; + +import React, { useState } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { + Building2, + Palette, + User, + ArrowRight, + ArrowLeft, + CheckCircle2, + CloudUpload, + Globe, + Layout, + Loader2, + ShieldCheck +} from "lucide-react"; +import { uploadFile } from "@/app/actions/upload"; +import { createOrganization } from "@/app/actions/setup"; +import { useRouter } from "next/navigation"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Alert, AlertDescription } from "@/components/ui/alert"; + +export default function SetupClient() { + const router = useRouter(); + const [step, setStep] = useState(1); + const [isUploading, setIsUploading] = useState(false); + const [isSubmitting, setIsSubmitting] = useState(false); + const totalSteps = 3; + + // Form State + const [formData, setFormData] = useState({ + name: "", + cnpj: "", + logoUrl: "", + primaryColor: "#2563eb", + adminName: "", + adminEmail: "", + adminPassword: "", + confirmPassword: "" + }); + + const handleChange = (e: React.ChangeEvent) => { + setFormData(prev => ({ ...prev, [e.target.name]: e.target.value })); + }; + + const handleFileUpload = async (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + + setIsUploading(true); + const data = new FormData(); + data.append("file", file); + + const result = await uploadFile(data); + if (result.success && result.url) { + setFormData(prev => ({ ...prev, logoUrl: result.url || "" })); + } else { + alert("Erro ao fazer upload da logo"); + } + setIsUploading(false); + }; + + const handleSubmit = async () => { + if (formData.adminPassword !== formData.confirmPassword) { + alert("As senhas não coincidem!"); + return; + } + + setIsSubmitting(true); + const result = await createOrganization(formData); + + if (result.success) { + router.push("/dashboard"); + router.refresh(); + } else { + alert(result.error || "Erro ao finalizar instalação"); + setIsSubmitting(false); + } + }; + + const nextStep = () => { + if (step === totalSteps) { + handleSubmit(); + } else { + setStep((s) => Math.min(s + 1, totalSteps)); + } + }; + + const prevStep = () => setStep((s) => Math.max(s - 1, 1)); + + return ( +
+
+ {/* Header Section */} +
+ + + + Instalação do Portal + + + + Configuração Master + + + Este portal está cru. Vamos realizar o setup inicial da sua organização. + +
+ + {/* Progress Bar */} +
+
+ {[1, 2, 3].map((i) => ( +
= i ? "bg-blue-600 text-white shadow-lg shadow-blue-200" : "bg-white text-slate-400 border border-slate-200" + }`} + > + {step > i ? : {i}} +
+ ))} +
+
+ +
+ + {/* Form Card */} + + + + {step === 1 && ( + +
+
+ +
+
+

Identidade da Organização

+

Defina o nome oficial e a logo que aparecerá no portal.

+
+
+ +
+
+ + +
+
+ + +
+
+ +
+ + {isUploading ? ( +
+ +

Enviando...

+
+ ) : formData.logoUrl ? ( +
+ Logo +

✓ Logo enviada com sucesso!

+
+ ) : ( + <> + +

Arraste sua logo ou clique para buscar

+

PNG, JPG até 5MB

+ + )} +
+
+
+
+ )} + + {step === 2 && ( + +
+
+ +
+
+

Personalização Visual

+

Adapte o portal às cores da sua marca.

+
+
+ +
+
+ +
+ +
+

Selecione o tom da marca

+

Isso aplicará o tema dinâmico.

+
+
+
+
+ +
+ + Detectado via domínio atual +
+
+
+ +
+

+ + Preview em tempo real +

+
+
+
+
+
+ +
+
+ + )} + + {step === 3 && ( + +
+
+ +
+
+

Administrador Master

+

Crie a conta que terá controle total sobre o portal.

+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + + + Ao concluir, o banco de dados será populado e este ambiente será bloqueado para novos setups. + + +
+ )} + + +
+ + +
+ + + + {/* Footer Support */} +
+ Portal de Transparência • v1.0 • Setup de Instalação +
+
+
+ ); +} diff --git a/src/app/setup/page.tsx b/src/app/setup/page.tsx index 2c61386..4f05c59 100644 --- a/src/app/setup/page.tsx +++ b/src/app/setup/page.tsx @@ -1,406 +1,16 @@ -"use client"; +import { prisma } from "@/lib/db"; +import { redirect } from "next/navigation"; +import SetupClient from "./SetupClient"; -import React, { useState } from "react"; -import { motion, AnimatePresence } from "framer-motion"; -import { - Building2, - Palette, - User, - ArrowRight, - ArrowLeft, - CheckCircle2, - CloudUpload, - Globe, - Layout, - Loader2, - ShieldCheck -} from "lucide-react"; -import { uploadFile } from "@/app/actions/upload"; -import { createOrganization } from "@/app/actions/setup"; -import { useRouter } from "next/navigation"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; -import { Alert, AlertDescription } from "@/components/ui/alert"; +export default async function SetupPage() { + // Verifica se já existe alguma organização cadastrada + const existingOrg = await prisma.organization.findFirst(); -export default function SetupPage() { - const router = useRouter(); - const [step, setStep] = useState(1); - const [isUploading, setIsUploading] = useState(false); - const [isSubmitting, setIsSubmitting] = useState(false); - const totalSteps = 3; + // Se já existe, redireciona para o login (setup já foi feito) + if (existingOrg) { + redirect("/"); + } - // Form State - const [formData, setFormData] = useState({ - name: "", - cnpj: "", - logoUrl: "", - primaryColor: "#2563eb", - adminName: "", - adminEmail: "", - adminPassword: "", - confirmPassword: "" - }); - - const handleChange = (e: React.ChangeEvent) => { - setFormData(prev => ({ ...prev, [e.target.name]: e.target.value })); - }; - - const handleFileUpload = async (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (!file) return; - - setIsUploading(true); - const data = new FormData(); - data.append("file", file); - - const result = await uploadFile(data); - if (result.success && result.url) { - setFormData(prev => ({ ...prev, logoUrl: result.url || "" })); - } else { - alert("Erro ao fazer upload da logo"); - } - setIsUploading(false); - }; - - const handleSubmit = async () => { - if (formData.adminPassword !== formData.confirmPassword) { - alert("As senhas não coincidem!"); - return; - } - - setIsSubmitting(true); - const result = await createOrganization(formData); - - if (result.success) { - router.push("/dashboard"); - router.refresh(); - } else { - alert(result.error || "Erro ao finalizar instalação"); - setIsSubmitting(false); - } - }; - - const nextStep = () => { - if (step === totalSteps) { - handleSubmit(); - } else { - setStep((s) => Math.min(s + 1, totalSteps)); - } - }; - - const prevStep = () => setStep((s) => Math.max(s - 1, 1)); - - return ( -
-
- {/* Header Section */} -
- - - - Instalação do Portal - - - - Configuração Master - - - Este portal está cru. Vamos realizar o setup inicial da sua organização. - -
- - {/* Progress Bar */} -
-
- {[1, 2, 3].map((i) => ( -
= i ? "bg-blue-600 text-white shadow-lg shadow-blue-200" : "bg-white text-slate-400 border border-slate-200" - }`} - > - {step > i ? : {i}} -
- ))} -
-
- -
- - {/* Form Card */} - - - - {step === 1 && ( - -
-
- -
-
-

Identidade da Organização

-

Defina o nome oficial e a logo que aparecerá no portal.

-
-
- -
-
- - -
-
- - -
-
- -
- - {isUploading ? ( -
- -

Enviando...

-
- ) : formData.logoUrl ? ( -
- Logo -

✓ Logo enviada com sucesso!

-
- ) : ( - <> - -

Arraste sua logo ou clique para buscar

-

PNG, JPG até 5MB

- - )} -
-
-
-
- )} - - {step === 2 && ( - -
-
- -
-
-

Personalização Visual

-

Adapte o portal às cores da sua marca.

-
-
- -
-
- -
- -
-

Selecione o tom da marca

-

Isso aplicará o tema dinâmico.

-
-
-
-
- -
- - Detectado via domínio atual -
-
-
- -
-

- - Preview em tempo real -

-
-
-
-
-
- -
-
- - )} - - {step === 3 && ( - -
-
- -
-
-

Administrador Master

-

Crie a conta que terá controle total sobre o portal.

-
-
- -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - - - - Ao concluir, o banco de dados será populado e este ambiente será bloqueado para novos setups. - - -
- )} - - -
- - -
- - - - {/* Footer Support */} -
- Portal de Transparência • v1.0 • Setup de Instalação -
-
-
- ); + // Se não existe, mostra o setup + return ; }