Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
},
"dependencies": {
"@ag-media/react-pdf-table": "^2.0.3",
"@inseefr/lunatic": "^3.6.15",
"@react-pdf/renderer": "^4.3.0",
"@react-pdf/stylesheet": "^6.1.0",
"dotenv": "^17.2.1",
Expand All @@ -38,5 +39,8 @@
"react-error-boundary": "^6.0.0",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1"
},
"volta": {
"node": "24.7.0"
}
}
29 changes: 29 additions & 0 deletions patches/@react-pdf__render.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
diff --git a/lib/index.js b/lib/index.js
index e4df914a22d4b13d26feb12ac0433c02f5861c12..3fc04e1b8a61b9c5910cfea10bc37e517dde6208 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -2055,19 +2055,15 @@ const addNodeBookmark = (ctx, node, pageNumber, registry) => {
return;
node.children.forEach((child) => addNodeBookmark(ctx, child, pageNumber, registry));
};
-const addBookmarks = (ctx, root) => {
- const registry = {};
- const pages = root.children || [];
- pages.forEach((page, i) => {
- addNodeBookmark(ctx, page, i, registry);
- });
-};

const render = (ctx, doc) => {
const pages = doc.children || [];
const options = { imageCache: new Map(), fieldSets: [] };
- pages.forEach((page) => renderNode(ctx, page, options));
- addBookmarks(ctx, doc);
+ const registry = {};
+ pages.forEach((page, index) => {
+ renderNode(ctx, page, options);
+ addNodeBookmark(ctx, page, index, registry);
+ });
ctx.end();
return ctx;
};
1,619 changes: 1,483 additions & 136 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
patchedDependencies:
'@react-pdf/render': patches/@react-pdf__render.patch
16 changes: 16 additions & 0 deletions src/components/CheckboxBoolean.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { LunaticComponentProps } from "../types";
import { ValueWithLabel } from "./ValueWithLabel";
import { Text } from "@react-pdf/renderer";
import { styles } from "./styles";

type Props = LunaticComponentProps<"CheckboxBoolean">;

export function CheckboxBoolean({ interpret, label, response }: Props) {
return (
<ValueWithLabel label={interpret(label)}>
<Text style={styles.answer}>
{interpret(response.name) ? "Oui" : "Non"}
</Text>
</ValueWithLabel>
);
}
22 changes: 22 additions & 0 deletions src/components/CheckboxGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { LunaticComponentProps } from "../types";
import { ValueWithLabel } from "./ValueWithLabel";
import { Text, View } from "@react-pdf/renderer";
import { styles } from "./styles";

type Props = LunaticComponentProps<"CheckboxGroup">;

export function CheckboxGroup({ interpret, label, responses }: Props) {
return (
<ValueWithLabel label={interpret(label)}>
<View>
{responses
.filter((r) => interpret(r.response.name))
.map((r, k) => (
<Text style={styles.answer} key={r.id}>
- {interpret(r.label)}
</Text>
))}
</View>
</ValueWithLabel>
);
}
19 changes: 0 additions & 19 deletions src/components/DummyPdf.tsx

This file was deleted.

44 changes: 44 additions & 0 deletions src/components/Duration.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { LunaticComponentProps } from "../types";
import { ValueWithLabel } from "./ValueWithLabel";
import { styles } from "./styles";
import { Text } from "@react-pdf/renderer";

type Props = LunaticComponentProps<"Duration">;

function periodToString(duration?: string): string | null {
if (!duration) {
return null;
}
const regex =
/^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/;
const match = regex.exec(duration);

if (!match) {
throw new Error(`Durée ISO 8601 invalide : ${duration}`);
}

const [_, years, months, days, hours, minutes, seconds] = match;

const parts: string[] = [];

if (years) parts.push(`${years} ${Number(years) > 1 ? "ans" : "an"}`);
if (months) parts.push(`${months} mois`); // 'mois' same plural otherwise : ${Number(months) > 1 ? "mois" : "mois"}
if (days) parts.push(`${days} ${Number(days) > 1 ? "jours" : "jour"}`);
if (hours) parts.push(`${hours} ${Number(hours) > 1 ? "heures" : "heure"}`);
if (minutes)
parts.push(`${minutes} ${Number(minutes) > 1 ? "minutes" : "minute"}`);
if (seconds)
parts.push(`${seconds} ${Number(seconds) > 1 ? "secondes" : "seconde"}`);

return parts.join(" ");
}

export function Duration({ interpret, label, response }: Props) {
return (
<ValueWithLabel label={interpret(label)}>
<Text style={styles.answer}>
{periodToString(interpret(response.name) as string)}
</Text>
</ValueWithLabel>
);
}
3 changes: 3 additions & 0 deletions src/components/Empty.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function Empty() {
return null;
}
12 changes: 0 additions & 12 deletions src/components/FirstPage.tsx

This file was deleted.

17 changes: 17 additions & 0 deletions src/components/Input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { LunaticComponentProps } from '../types';
import { ValueWithLabel } from './ValueWithLabel';
import { Text } from '@react-pdf/renderer';
import { styles } from './styles';

type Props = LunaticComponentProps<'InputNumber'>;

export function Input({ interpret, label, response, unit }: Props) {
return (
<ValueWithLabel label={interpret(label)}>
<Text style={styles.answer}>
{interpret(response.name) ?? '__'}{' '}
{typeof unit === 'string' ? unit : interpret(unit)}
</Text>
</ValueWithLabel>
);
}
60 changes: 60 additions & 0 deletions src/components/Loop.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import type { LunaticComponentProps, VTLExpression } from "../types";
import { LunaticComponents } from "./LunaticComponent";
import { Text, View } from "@react-pdf/renderer";
import { forceInt } from "../utils/number";
import { decorateInterpretIteration } from "../utils/vtl";
import { styles } from "./styles";
import { hasResponse } from "../utils/lunatic";

type Props = LunaticComponentProps<"Loop"> & { iterations?: VTLExpression };

export function Loop({
id,
label,
interpret,
components,
iterations: iterationsExpr,
}: Props) {
if (components.length === 0) {
return null;
}

const getIterations = () => {
// We have an iteration expression we can use to resolve the number of iteration
if (iterationsExpr) {
return forceInt(
interpret(iterationsExpr),
`Cannot interpret ${iterationsExpr} to get loop size ${label}`
);
}

// Otherwise, look for the first variable inside the children
for (const component of components) {
if (hasResponse(component)) {
// @ts-expect-error component.response is a known value
const value = interpret(component.response);
if (Array.isArray(value)) {
return value.length;
}
}
}
return 0;
};

return (
<>
{Array.from({ length: getIterations() }).map((_, k) => {
const interpretAtIteration = decorateInterpretIteration(interpret, [k]);
return (
<View key={`${id}-${k}`}>
<Text style={styles.h3}>Iteration #{k + 1}</Text>
<LunaticComponents
components={components}
interpret={interpretAtIteration}
/>
</View>
);
})}
</>
);
}
Loading