"use client" import { useEffect, useState } from "react" import { useRouter } from "next/navigation" import { Button } from "@/components/ui/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { Badge } from "@/components/ui/badge" import { Input } from "@/components/ui/input" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { adminAccessApi, adminAuditApi, adminCompaniesApi, adminJobsApi, adminTagsApi, type AdminCompany, type AdminJob, type AdminLoginAudit, type AdminRoleAccess, type AdminTag, } from "@/lib/api" import { getCurrentUser, isAdminUser } from "@/lib/auth" import { toast } from "sonner" import { Archive, CheckCircle, Copy, PauseCircle, Plus, RefreshCw, XCircle } from "lucide-react" const auditDateFormatter = new Intl.DateTimeFormat("pt-BR", { dateStyle: "short", timeStyle: "short", timeZone: "UTC", }) const jobStatusBadge: Record = { draft: { label: "Draft", variant: "outline" }, review: { label: "Review", variant: "secondary" }, published: { label: "Published", variant: "default" }, paused: { label: "Paused", variant: "outline" }, expired: { label: "Expired", variant: "destructive" }, archived: { label: "Archived", variant: "outline" }, reported: { label: "Reported", variant: "destructive" }, open: { label: "Open", variant: "default" }, closed: { label: "Closed", variant: "outline" }, } export default function BackofficePage() { const router = useRouter() const [roles, setRoles] = useState([]) const [audits, setAudits] = useState([]) const [companies, setCompanies] = useState([]) const [jobs, setJobs] = useState([]) const [tags, setTags] = useState([]) const [loading, setLoading] = useState(true) const [creatingTag, setCreatingTag] = useState(false) const [tagForm, setTagForm] = useState({ name: "", category: "area" as "area" | "level" | "stack" }) useEffect(() => { const user = getCurrentUser() if (!isAdminUser(user)) { router.push("/dashboard") return } loadBackoffice() }, [router]) const loadBackoffice = async () => { try { setLoading(true) const [rolesData, auditData, companiesData, jobsData, tagsData] = await Promise.all([ adminAccessApi.listRoles(), adminAuditApi.listLogins(20), adminCompaniesApi.list(false), adminJobsApi.list({ status: "review", limit: 10 }), adminTagsApi.list(), ]) setRoles(rolesData) setAudits(auditData) setCompanies(companiesData.data || []) setJobs(jobsData.data || []) setTags(tagsData) } catch (error) { console.error("Error loading backoffice:", error) toast.error("Failed to load backoffice data") } finally { setLoading(false) } } const handleApproveCompany = async (companyId: string) => { try { await adminCompaniesApi.updateStatus(companyId, { verified: true }) toast.success("Company approved") loadBackoffice() } catch (error) { console.error("Error approving company:", error) toast.error("Failed to approve company") } } const handleDeactivateCompany = async (companyId: string) => { try { await adminCompaniesApi.updateStatus(companyId, { active: false }) toast.success("Company deactivated") loadBackoffice() } catch (error) { console.error("Error deactivating company:", error) toast.error("Failed to deactivate company") } } const handleJobStatus = async (jobId: string, status: string) => { try { await adminJobsApi.updateStatus(jobId, status) toast.success("Job status updated") loadBackoffice() } catch (error) { console.error("Error updating job status:", error) toast.error("Failed to update job status") } } const handleDuplicateJob = async (jobId: string) => { try { await adminJobsApi.duplicate(jobId) toast.success("Job duplicated as draft") loadBackoffice() } catch (error) { console.error("Error duplicating job:", error) toast.error("Failed to duplicate job") } } const handleCreateTag = async () => { if (!tagForm.name.trim()) { toast.error("Tag name is required") return } try { setCreatingTag(true) await adminTagsApi.create({ name: tagForm.name.trim(), category: tagForm.category }) toast.success("Tag created") setTagForm({ name: "", category: "area" }) loadBackoffice() } catch (error) { console.error("Error creating tag:", error) toast.error("Failed to create tag") } finally { setCreatingTag(false) } } const handleToggleTag = async (tag: AdminTag) => { try { await adminTagsApi.update(tag.id, { active: !tag.active }) toast.success("Tag updated") loadBackoffice() } catch (error) { console.error("Error updating tag:", error) toast.error("Failed to update tag") } } if (loading) { return (
) } return (

Backoffice

Controle administrativo do GoHorse Jobs

Gestão de usuários & acesso Perfis, permissões e ações disponíveis no RBAC. Perfil Descrição Ações principais {roles.map((role) => ( {role.role} {role.description}
{role.actions.map((action) => ( {action} ))}
))}
Auditoria de login Histórico recente de acessos ao painel administrativo. Usuário Roles IP Data {audits.map((audit) => ( {audit.identifier} {audit.roles} {audit.ipAddress || "-"} {auditDateFormatter.format(new Date(audit.createdAt))} ))}
Empresas pendentes Aprovação e verificação de empresas. Empresa Email Status Ações {companies.length === 0 && ( Nenhuma empresa pendente. )} {companies.map((company) => ( {company.name} {company.email || "-"} {company.verified ? ( Verificada ) : ( Pendente )} ))}
Moderação de vagas Fluxo: rascunho → revisão → publicada → expirada/arquivada. Título Empresa Status Ações {jobs.length === 0 && ( Nenhuma vaga aguardando revisão. )} {jobs.map((job) => { const statusConfig = jobStatusBadge[job.status] || { label: job.status, variant: "outline" } return ( {job.title} {job.companyName || "-"} {statusConfig.label} ) })}
Tags e categorias Áreas, níveis e stacks customizáveis.
setTagForm({ ...tagForm, name: event.target.value })} />
Tag Categoria Status Ações {tags.map((tag) => ( {tag.name} {tag.category} {tag.active ? ( Ativa ) : ( Inativa )} ))}
) }