Initial SeConectai briefing system
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
import Link from "next/link";
|
||||
import { adicionarNotaInternaAction, mudarStatusAction, reabrirBriefingAction } from "@/app/(admin)/admin/actions";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { getBriefingAdmin } from "@/lib/admin-service";
|
||||
import { formatFileSize } from "@/lib/format";
|
||||
|
||||
function respostaTexto(resposta: {
|
||||
texto: string | null;
|
||||
complemento: string | null;
|
||||
selecionadas: unknown;
|
||||
}) {
|
||||
const partes: string[] = [];
|
||||
const selecionadas = Array.isArray(resposta.selecionadas)
|
||||
? resposta.selecionadas.filter((item): item is string => typeof item === "string")
|
||||
: [];
|
||||
|
||||
if (resposta.texto?.trim()) partes.push(resposta.texto.trim());
|
||||
if (selecionadas.length > 0) partes.push(selecionadas.join(", "));
|
||||
if (resposta.complemento?.trim()) partes.push(`Complemento: ${resposta.complemento.trim()}`);
|
||||
|
||||
return partes.join(" | ");
|
||||
}
|
||||
|
||||
export default async function BriefingAdminPage({ params }: { params: { id: string } }) {
|
||||
const { briefing, secoes } = await getBriefingAdmin(params.id);
|
||||
|
||||
return (
|
||||
<main className="container py-8">
|
||||
<div className="mb-8 flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div>
|
||||
<Badge variant="muted">{briefing.status}</Badge>
|
||||
<h1 className="mt-3 text-3xl font-semibold">{briefing.titulo}</h1>
|
||||
<p className="mt-2 text-sm text-muted-foreground">
|
||||
{briefing.cliente.nomeCompleto} | {briefing.cliente.user.email}
|
||||
</p>
|
||||
</div>
|
||||
<Button asChild variant="outline">
|
||||
<Link href="/admin">Voltar</Link>
|
||||
</Button>
|
||||
<Button asChild>
|
||||
<a href={`/api/briefings/${briefing.id}/pdf`}>Baixar PDF</a>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-6 lg:grid-cols-[1fr_360px]">
|
||||
<div className="space-y-4">
|
||||
{secoes.map((secao) => (
|
||||
<Card key={secao.id}>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">{secao.ordem}. {secao.titulo}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{secao.perguntas.map((pergunta) => {
|
||||
const resposta = pergunta.respostas[0];
|
||||
const texto = resposta ? respostaTexto(resposta) : "";
|
||||
|
||||
return (
|
||||
<div key={pergunta.id} className="rounded-md border p-3">
|
||||
<p className="text-sm font-medium">{pergunta.rotulo}</p>
|
||||
<p className="mt-2 whitespace-pre-wrap text-sm leading-6 text-muted-foreground">
|
||||
{texto || "Sem resposta informada."}
|
||||
</p>
|
||||
{pergunta.anexos.length > 0 ? (
|
||||
<ul className="mt-3 space-y-1 text-sm">
|
||||
{pergunta.anexos.map((anexo) => (
|
||||
<li key={anexo.id}>
|
||||
<a className="text-primary hover:underline" href={`/api/anexos/${anexo.id}`}>
|
||||
{anexo.nomeOriginal} ({formatFileSize(anexo.tamanho)})
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<aside className="space-y-4 lg:sticky lg:top-6 lg:self-start">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Acoes</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<form action={mudarStatusAction} className="grid gap-3">
|
||||
<input type="hidden" name="briefingId" value={briefing.id} />
|
||||
<select name="status" defaultValue={briefing.status} className="h-10 rounded-md border bg-background px-3 text-sm">
|
||||
<option value="ENVIADO">ENVIADO</option>
|
||||
<option value="EM_ANALISE">EM_ANALISE</option>
|
||||
<option value="CONCLUIDO">CONCLUIDO</option>
|
||||
</select>
|
||||
<Button type="submit">Atualizar status</Button>
|
||||
</form>
|
||||
<form action={reabrirBriefingAction}>
|
||||
<input type="hidden" name="briefingId" value={briefing.id} />
|
||||
<Button type="submit" variant="outline" className="w-full">Reabrir para edicao</Button>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Nota interna</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<form action={adicionarNotaInternaAction} className="space-y-3">
|
||||
<input type="hidden" name="briefingId" value={briefing.id} />
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="texto">Texto</Label>
|
||||
<Textarea id="texto" name="texto" required />
|
||||
</div>
|
||||
<Button type="submit">Adicionar nota</Button>
|
||||
</form>
|
||||
<div className="space-y-3">
|
||||
{briefing.notasInternas.map((nota) => (
|
||||
<div key={nota.id} className="rounded-md border p-3">
|
||||
<p className="text-sm leading-6">{nota.texto}</p>
|
||||
<p className="mt-2 text-xs text-muted-foreground">
|
||||
{nota.admin.email} | {nota.criadoEm.toLocaleString("pt-BR")}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</aside>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user