Files

155 lines
4.5 KiB
TypeScript

import {
Document,
Page,
Text,
View,
StyleSheet,
pdf
} from "@react-pdf/renderer";
import type { getBriefingPdfData } from "@/lib/pdf-data";
type PdfData = Awaited<ReturnType<typeof getBriefingPdfData>>;
const styles = StyleSheet.create({
page: {
padding: 32,
fontSize: 10,
color: "#1f2933",
fontFamily: "Helvetica"
},
title: {
fontSize: 20,
marginBottom: 6,
fontWeight: 700
},
subtitle: {
fontSize: 10,
color: "#52606d",
marginBottom: 16
},
section: {
marginTop: 16,
paddingTop: 10,
borderTop: "1 solid #d9e2ec"
},
sectionTitle: {
fontSize: 13,
fontWeight: 700,
marginBottom: 8
},
question: {
marginBottom: 10
},
label: {
fontWeight: 700,
marginBottom: 3
},
answer: {
color: "#52606d",
lineHeight: 1.5
},
meta: {
marginBottom: 4
}
});
function selectedText(value: unknown) {
return Array.isArray(value)
? value.filter((item): item is string => typeof item === "string").join(", ")
: "";
}
function opcoesTexto(opcoes: unknown, selecionadas: unknown) {
const options = Array.isArray(opcoes)
? opcoes.filter((item): item is string => typeof item === "string")
: [];
const selected = Array.isArray(selecionadas)
? selecionadas.filter((item): item is string => typeof item === "string")
: [];
if (options.length === 0) {
return selected.join(", ");
}
return options
.map((opcao) => `${selected.includes(opcao) ? "☒" : "☐"} ${opcao}`)
.join(" ");
}
function respostaTexto(resposta: {
texto: string | null;
complemento: string | null;
selecionadas: unknown;
}) {
const partes = [
resposta.texto?.trim(),
selectedText(resposta.selecionadas),
resposta.complemento?.trim() ? `Complemento: ${resposta.complemento.trim()}` : ""
].filter(Boolean);
return partes.join(" | ");
}
function BriefingPdfDocument({ data }: { data: PdfData }) {
return (
<Document>
<Page size="A4" style={styles.page}>
<Text style={styles.title}>{data.briefing.titulo}</Text>
<Text style={styles.subtitle}>Briefing de Site | SeConectai</Text>
<View>
<Text style={styles.meta}>Cliente: {data.briefing.cliente.nomeCompleto}</Text>
<Text style={styles.meta}>E-mail: {data.briefing.cliente.user.email}</Text>
<Text style={styles.meta}>WhatsApp: {data.briefing.cliente.whatsapp}</Text>
<Text style={styles.meta}>CPF: {data.cpfMascarado}</Text>
<Text style={styles.meta}>Status: {data.briefing.status}</Text>
<Text style={styles.meta}>
Enviado em: {data.briefing.enviadoEm ? data.briefing.enviadoEm.toLocaleString("pt-BR") : "Nao enviado"}
</Text>
</View>
{data.secoes.map((secao) => (
<View key={secao.id} style={styles.section} wrap={false}>
<Text style={styles.sectionTitle}>{secao.ordem}. {secao.titulo}</Text>
{secao.perguntas.map((pergunta) => {
const resposta = pergunta.respostas[0];
const texto =
resposta && (pergunta.tipo === "RADIO" || pergunta.tipo === "CHECKBOX")
? [
opcoesTexto(pergunta.opcoes, resposta.selecionadas),
resposta.complemento?.trim() ? `Complemento: ${resposta.complemento.trim()}` : ""
].filter(Boolean).join(" | ")
: resposta
? respostaTexto(resposta)
: "";
return (
<View key={pergunta.id} style={styles.question}>
<Text style={styles.label}>{pergunta.rotulo}</Text>
<Text style={styles.answer}>{texto || "Sem resposta informada."}</Text>
{pergunta.anexos.length > 0 ? (
<Text style={styles.answer}>
Anexos: {pergunta.anexos.map((anexo) => anexo.nomeOriginal).join(", ")}
</Text>
) : null}
</View>
);
})}
</View>
))}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Confirmacao do cliente</Text>
<Text style={styles.answer}>
Confirmado em: {data.briefing.confirmadoEm ? data.briefing.confirmadoEm.toLocaleString("pt-BR") : "Nao confirmado"}
</Text>
</View>
</Page>
</Document>
);
}
export async function gerarBriefingPdfBuffer(data: PdfData) {
return pdf(<BriefingPdfDocument data={data} />).toBuffer();
}