Skip to content

Commit

Permalink
feat: add pdf layout
Browse files Browse the repository at this point in the history
  • Loading branch information
ledouxm committed May 8, 2024
1 parent 03d659c commit 130e0d5
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 63 deletions.
1 change: 0 additions & 1 deletion packages/backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ const debug = makeDebug("index");

const start = async () => {
await registerViteHmrServerRestart();
console.log(ENV.DATABASE_URL);

debug("Starting fastify server");
const fastifyInstance = await initFastify();
Expand Down
31 changes: 6 additions & 25 deletions packages/frontend/scripts/treeParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import { fr } from "@codegouvfr/react-dsfr";

export const parseTree = async (css: string) => {
const variables = getColorVariablesFromFr();
await fs.writeFile(
"./dsfr-variables.json",
JSON.stringify(variables, null, 2),
);
await fs.writeFile("./dsfr-variables.json", JSON.stringify(variables, null, 2));

const ast = cssTree.parse(css, {
parseValue: true,
Expand All @@ -18,9 +15,7 @@ export const parseTree = async (css: string) => {
enter: (node, item, list) => {
if (node.property.startsWith("--")) {
const varName = node.property.slice(2);
const shouldRemove = variables.some(
(v) => v.toReplace === "--" + varName,
);
const shouldRemove = variables.some((v) => v.toReplace === "--" + varName);
if (shouldRemove) list.remove(item);
}
},
Expand All @@ -30,15 +25,9 @@ export const parseTree = async (css: string) => {
visit: "Function",
enter: (node) => {
if (node.name === "var") {
if (
node.name === "var" &&
node.children.size === 1 &&
node.children.first?.type === "Identifier"
) {
if (node.name === "var" && node.children.size === 1 && node.children.first?.type === "Identifier") {
const child = node.children.first;
const matchingPandaVariable = variables.find(
(v) => v.toReplace === child.name,
);
const matchingPandaVariable = variables.find((v) => v.toReplace === child.name);
if (matchingPandaVariable) {
child.name = matchingPandaVariable.pandaName;
}
Expand All @@ -49,7 +38,6 @@ export const parseTree = async (css: string) => {

// find :root and extract its content
const root = cssTree.find(ast, (node) => {});
console.log(root);
const patchedCss = cssTree.generate(ast);
await fs.writeFile("./public/dsfr/dsfr-patched.css", patchedCss);
};
Expand All @@ -61,10 +49,7 @@ const getColorVariablesFromFr = () => {
const darkFr = fr.colors.getHex({ isDark: true });

const variables = dotPaths.map((path) => {
const toReplace = pathWithDots(fr.colors, path).slice(
"var(".length,
-")".length,
);
const toReplace = pathWithDots(fr.colors, path).slice("var(".length, -")".length);

const lightValue = pathWithDots(lightFr, path);
const darkValue = pathWithDots(darkFr, path);
Expand All @@ -79,11 +64,7 @@ const getColorVariablesFromFr = () => {
};

const formatName = (name: string) => {
const parts = name
.split(".")
.map((part) =>
part.startsWith("_") ? part.slice(1).replace("_", "-") : part,
);
const parts = name.split(".").map((part) => (part.startsWith("_") ? part.slice(1).replace("_", "-") : part));
parts.shift();
if (parts[-1] === "default") parts.pop();

Expand Down
3 changes: 1 addition & 2 deletions packages/frontend/src/components/chips/SpaceTypeChips.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ export const SpaceTypeChips = (props: FlexProps) => {

const selected = useWatch({ control: form.control, name: "projectSpaceType" })?.split(",") ?? [];

const chipOptions = useChipOptions("contacts-utiles", true);
const chipOptions = useChipOptions("type-espace");
const options: ChipGroupOption[] = (chipOptions ?? []).map((chip) => ({
label: chip.value,
key: chip.value,
}));

return (
<ChipGroup
isMulti
options={options}
value={selected}
{...props}
Expand Down
1 change: 0 additions & 1 deletion packages/frontend/src/features/ReportList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export const MyReports = () => {
);

const chips = useLiveQuery(db.chip.liveMany());
console.log(chips);

if (myReports.error) {
console.error(myReports.error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ export const ServiceInstructeurSelect = () => {
};

const A = forwardRef((props, ref) => {
console.log(props);
return <Input ref={ref} label="Service instructeur*" nativeInputProps={props} />;
});

Expand Down
6 changes: 3 additions & 3 deletions packages/frontend/src/features/chips/useChipOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ import { useLiveQuery } from "electric-sql/react";
import { db } from "../../db";
import { groupBy } from "pastable";

export const useChipOptions = (key: string) => {
export const useChipOptions = (key?: string) => {
const user = useUser()!;

// retrieve all chips with the given key
const decisionsChipsQuery = useLiveQuery(
db.chip.liveMany({
where: {
key,
...(key ? { key } : {}),
udap_id: { in: ["ALL", user.udap.id] },
},
}),
);

const grouped = groupBy(decisionsChipsQuery.results ?? [], "value");
const grouped = groupBy(decisionsChipsQuery.results ?? [], (item) => `${item.key}-${item.value}`);

// keep only the most specific chip for each value
return Object.values(grouped).map((value) => {
Expand Down
2 changes: 0 additions & 2 deletions packages/frontend/src/routes/edit.$reportId.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,6 @@ const WithReport = ({ report }: { report: Report }) => {
}, [report]);

const onSubmit = (values: Report) => {
console.log(values);

navigate({
to: "/export/$reportId",
params: {
Expand Down
113 changes: 85 additions & 28 deletions packages/frontend/src/routes/export.$reportId.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,41 @@ import { db } from "../db";
import { Flex, styled } from "#styled-system/jsx";
import { Document, Page, Text, View, StyleSheet, type Styles } from "@react-pdf/renderer";
import { PDFViewer } from "@react-pdf/renderer";
import type { Report } from "@cr-vif/electric-client/frontend";
import type { Report, Udap } from "@cr-vif/electric-client/frontend";
import { TextEditor, textEditorClassName } from "../features/text-editor/TextEditor";
import { useState } from "react";
import Html from "react-pdf-html";
import useDebounce from "react-use/lib/useDebounce";
import type { ReportWithUser } from "../features/ReportList";
import { useChipOptions } from "../features/chips/useChipOptions";
import { Chip } from "@cr-vif/electric-client/frontend";
import { useUser } from "../contexts/AuthContext";

const ExportPdf = () => {
const { reportId } = Route.useParams();
const { results: report } = useLiveQuery(db.report.liveUnique({ where: { id: reportId } }));
const { results: report } = useLiveQuery(db.report.liveUnique({ where: { id: reportId }, include: { user: true } }));
const chipOptions = useChipOptions();

return <Flex direction="column">{report ? <WithReport report={report} /> : null}</Flex>;
return (
<Flex direction="column">
{report && chipOptions?.length ? <WithReport report={report} chipOptions={chipOptions} /> : null}
</Flex>
);
};

const WithReport = ({ report }: { report: Report }) => {
const [value, setValue] = useState(getReportHtmlString(report));
const WithReport = ({ report, chipOptions }: { report: ReportWithUser; chipOptions: Chip[] }) => {
const { udap } = useUser()!;
const [value, setValue] = useState(getReportHtmlString(report, chipOptions, udap as Udap));
const [debouncedValue, setDebouncedValue] = useState(value);

useDebounce(() => void console.log(value) || setDebouncedValue(value), 1000, [value]);
console.log(debouncedValue);
useDebounce(() => setDebouncedValue(value), 1000, [value, chipOptions]);
return (
<Flex direction="column">
<TextEditor defaultValue={value} onChange={(e) => setValue(e)} />

<PDFViewer>
<Document>
<Page size="A4" style={styles.page}>
<Page size="A4">
<Html>{`
<html>
<body>
Expand Down Expand Up @@ -70,28 +79,76 @@ const WithReport = ({ report }: { report: Report }) => {
);
};

const getReportHtmlString = (report: ReportWithUser) => {
return `<p>
<span>Objet : ${report.title}</span><br/>
<span>Votre interlocuteur : ${report.user?.name ?? report.createdByEmail.split("@")[0]}</span><br/>
<span>Demandeur : ${report.applicantName}</span><br/>
<span>Adresse du projet : ${report.applicantAddress}</span><br/>
<span>Ref cadastrale : ${report.projectCadastralRef}</span>
</p>`;
const getReportHtmlString = (report: ReportWithUser, chipOptions: Chip[], udap: Udap) => {
const spaceType = chipOptions.find((chip) => chip.key === "type-espace" && chip.value === report.projectSpaceType);
const decision = chipOptions.find((chip) => chip.key === "decision" && chip.value === report.decision);
const contacts = report.contacts ? getMultipleChips(chipOptions, "contacts-utiles", report.contacts) : [];
const furtherInfos = report.furtherInformation
? getMultipleChips(chipOptions, "bonnes-pratiques", report.furtherInformation)
: [];

return minifyHtml(`
<p>
Objet : ${report.title}<br/>
Votre interlocuteur : ${report.user?.name ?? report.createdByEmail.split("@")[0]}<br/>
Demandeur : ${report.applicantName}<br/>
Adresse du projet : ${report.applicantAddress}<br/>
Ref cadastrale : ${report.projectCadastralRef}<br/>
</p>
<p>${spaceType?.text}</p>
<p>${decision?.text}</p>
<p>
<strong>Précisions : </strong>
<span>${report.precisions}</span>
</p>
<p>
<strong>Contacts utiles : </strong><br/>
Vous pouvez contacter le service de la collectivité en charge de l’instruction de votre dossier : TODO (quelles informations afficher ?)<br/><br/>
${contacts.map((contact) => `<span>${contact}</span>`).join("<br/><br/>")}
Nous contacter : ${udap.name}, ${udap.email}, ${udap.phone}
</p>
<p>
<strong>Pour aller plus loin</strong><br/>
${furtherInfos.map((furtherInfo) => `<span>${furtherInfo}</span>`).join("<br/><br/>")}
</p>
<p>
Ce compte rendu ne remplace pas la demande d’autorisation de travaux.
</p>
`);
};

const styles = StyleSheet.create({
page: {
flexDirection: "row",
backgroundColor: "white",
color: "black",
},
section: {
margin: 10,
padding: 10,
flexGrow: 1,
},
});
const getMultipleChips = (chipOptions: Chip[], key: string, values: string) => {
return values
.split(",")
.map((value) => {
const chip = chipOptions.find((chip) => chip.key === key && chip.value === value);
return chip?.text;
})
.filter(Boolean);
};

function minifyHtml(htmlString: string) {
return htmlString.split("\n").join("").split(" ").join("");
}

// const styles = StyleSheet.create({
// page: {
// flexDirection: "row",
// backgroundColor: "white",
// color: "black",
// },
// section: {
// margin: 10,
// padding: 10,
// flexGrow: 1,
// },
// });

export const Route = createFileRoute("/export/$reportId")({
component: () => <ExportPdf />,
Expand Down

0 comments on commit 130e0d5

Please sign in to comment.