Skip to content

Commit

Permalink
new lib for pdf creation
Browse files Browse the repository at this point in the history
  • Loading branch information
Akctarus committed Apr 23, 2024
1 parent 8d89dbd commit c4d522c
Show file tree
Hide file tree
Showing 18 changed files with 1,025 additions and 779 deletions.
3 changes: 2 additions & 1 deletion front/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@ag-media/react-pdf-table": "^1.0.1",
"@hookform/resolvers": "^3.3.4",
"@nivo/annotations": "^0.80.0",
"@nivo/core": "^0.80.0",
"@nivo/line": "^0.80.0",
"@nivo/tooltip": "^0.80.0",
"@openapi-contrib/openapi-schema-to-json-schema": "^5.1.0",
"@osrd-project/ui-icons": "^0.0.10",
"@react-pdf/renderer": "^3.4.2",
"@redux-devtools/extension": "^3.3.0",
"@reduxjs/toolkit": "^2.1.0",
"@rjsf/core": "^5.17.0",
Expand Down Expand Up @@ -72,7 +74,6 @@
"js-file-download": "^0.4.12",
"js-sha256": "^0.11.0",
"json-schema": "^0.4.0",
"jspdf": "^2.5.1",
"jwt-decode": "^4.0.0",
"license-checker-rseidelsohn": "~4.3.0",
"localforage": "^1.10.0",
Expand Down
15 changes: 13 additions & 2 deletions front/public/locales/en/stdcm-simulation-sheet.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,29 @@
"formattedDate": "{{year}}//{{month}}/{{day}} at {{hours}}:{{minutes}}",
"from": "from",
"km": "km",
"kmH": "km/h",
"maxLength": "max. length",
"maxSpeed": "max. speed",
"maxWeight": "max. weight",
"meters": "m",
"motif": "motif",
"numero": "",
"operationalPoint": "OP",
"passageStop": "passage",
"referenceEngine": "ref. engine",
"refEngine": "ref. engine",
"referenceEngine": "reference engine",
"referencePath": "Reference path",
"requestedRoute": "requested route",
"simulation": "Simulation",
"speedLimitByTag": "speed limit by tag",
"startStop": "start",
"stdcm": "ST DCM",
"stdcmCreation": "short term path creation",
"stdcmSimulationSheet": "Simulation report sheet",
"towedMaterial": "towed material",
"ton": "t",
"track": "Track",
"warningMessage": "This sheet has been generated by a simulation tool. It does not exempt the scheduler from the checks inherent in the STDCM layout.",
"weight": "weight"
"weight": "weight",
"withoutWarranty": "Path simulation without guaranteed availability"
}
15 changes: 13 additions & 2 deletions front/public/locales/fr/stdcm-simulation-sheet.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,29 @@
"formattedDate": "le {{day}}/{{month}}/{{year}} à {{hours}}:{{minutes}}",
"from": "du",
"km": "km",
"kmH": "km/h",
"maxLength": "longueur max.",
"maxSpeed": "vitesse max.",
"maxWeight": "tonnage max.",
"meters": "m",
"motif": "motif",
"numero": "",
"operationalPoint": "jalon",
"passageStop": "passage",
"referenceEngine": "engin de réf.",
"refEngine": "engin de réf.",
"referenceEngine": "engin de référence",
"referencePath": "Sillon de référence",
"requestedRoute": "parcours demandé",
"simulation": "Simulation",
"speedLimitByTag": "code de composition",
"startStop":"départ",
"stdcm": "ST DCM",
"stdcmCreation": "Création de sillon de dernière minute",
"stdcmSimulationSheet": "Fiche Simulation",
"towedMaterial": "matériel remorqué",
"ton": "t",
"track": "Voie",
"warningMessage": "Cette fiche a été générée par un outil de simulation. Elle ne dispense pas l’horairiste des vérifications inhérentes au tracé de SDM.",
"weight": "tonnage"
"weight": "tonnage",
"withoutWarranty": "Simulation de sillon sans garantie de disponibilité"
}
241 changes: 241 additions & 0 deletions front/src/applications/stdcm/components/SimulationReportSheet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
import React from 'react';

import { Table, TR, TH, TD } from '@ag-media/react-pdf-table';
import { Page, Text, Image, Document, View, Font } from '@react-pdf/renderer';
import { useTranslation } from 'react-i18next';

import iconAlert from 'assets/simulationSheet/icon_alert_fill.png';
import logoSNCF from 'assets/simulationSheet/logo_sncf_reseau.png';
import type { PostStdcmApiResponse, RollingStockWithLiveries } from 'common/api/osrdEditoastApi';

import styles from './SimulationReportStyleSheet';
import IBMPlexMonoBold from '../styles/fonts/IBM-Plex-Mono/IBMPlexMono-Bold.ttf';
import IBMPlexMonoRegular from '../styles/fonts/IBM-Plex-Mono/IBMPlexMono-Regular.ttf';
import IBMPlexSansBold from '../styles/fonts/IBM-Plex-Sans/IBMPlexSans-Bold.ttf';
import IBMPlexSansItalic from '../styles/fonts/IBM-Plex-Sans/IBMPlexSans-Italic.ttf';
import IBMPlexSansMedium from '../styles/fonts/IBM-Plex-Sans/IBMPlexSans-Medium.ttf';
import IBMPlexSansRegular from '../styles/fonts/IBM-Plex-Sans/IBMPlexSans-Regular.ttf';
import IBMPlexSansSemiBold from '../styles/fonts/IBM-Plex-Sans/IBMPlexSans-SemiBold.ttf';
import { formatDate, getStopTime } from '../utils';

interface Props {
stdcmData: PostStdcmApiResponse | null;
rollingStockData: RollingStockWithLiveries | undefined;
numero: string;
}

const SimulationReportSheet: React.FC<Props> = ({ stdcmData, rollingStockData, numero }) => {
const { t } = useTranslation('stdcm-simulation-sheet');

Font.register({
family: 'IBM Plex Sans',
fonts: [
{ src: IBMPlexSansRegular, fontWeight: 'normal' },
{ src: IBMPlexSansMedium, fontWeight: 'medium' },
{ src: IBMPlexSansSemiBold, fontWeight: 'semibold' },
{ src: IBMPlexSansBold, fontWeight: 'bold' },
{ src: IBMPlexSansItalic, fontStyle: 'italic' },
],
});

Font.register({
family: 'IBM Plex Mono',
fonts: [
{ src: IBMPlexMonoRegular, fontWeight: 'normal' },
{ src: IBMPlexMonoBold, fontWeight: 'bold' },
],
});

return (
<Document>
<Page wrap={false} style={styles.page} size={[1344]}>
<View style={styles.alertBanner}>
<Image src={iconAlert} style={styles.alertIcon} />
<Text style={styles.simulationTitle}>{t('simulation')}</Text>
<Text style={styles.message}>{t('warningMessage')}</Text>
</View>
<View>
<View style={styles.numberDateBanner}>
<View style={styles.stdcm}>
<Text style={styles.title}>{t('stdcm')}</Text>
<Text style={styles.creation}>{t('stdcmCreation')}</Text>
</View>
<View style={styles.numericInfo}>
<Text style={styles.number}>
{t('numero')}
{numero}
</Text>
<Text style={styles.creationDate}>{formatDate(stdcmData?.path.created)}</Text>
</View>
<Image src={logoSNCF} style={styles.sncfLogo} />
</View>
</View>
<View style={styles.rcInfo}>
<View>
<Text style={styles.rcName}>Super Fret</Text>
<Text style={styles.rcPerson}>Stéphanie Martin-Duclotte</Text>
</View>
<View>
<Text style={styles.phoneNumber}>04 12 34 56 78</Text>
<Text style={styles.mail}>stephanie.martin-duclotte@superfret.fr</Text>
</View>
<View style={styles.stdcmApplication}>
<Text style={styles.applicationDate}>{t('applicationDate')}</Text>
<Text style={styles.date}>vendredi 15 mars 2024</Text>
<Text style={styles.referencePath}>{t('referencePath')}</Text>
<Text style={styles.pathNumber}>n°123456</Text>
</View>
</View>
<View style={styles.convoyAndRoute}>
<View style={styles.convoy}>
<Text style={styles.convoyTitle}> {t('convoy')}</Text>
<Text style={styles.convoyInfo}>{t('speedLimitByTag')}</Text>
<Text>
{stdcmData?.simulation.speed_limit_tags === null
? '-'
: stdcmData?.simulation.speed_limit_tags}
</Text>
<Text style={styles.convoyInfo}>{t('towedMaterial')}</Text>
<Text>-</Text>
<Text style={styles.convoyInfo}>{t('maxSpeed')}</Text>
<Text>
{rollingStockData?.max_speed && rollingStockData?.max_speed * 3.6} {t('kmH')}
</Text>
<Text style={styles.convoyInfo}>{t('maxWeight')}</Text>
<Text>
{rollingStockData?.mass && Math.floor(rollingStockData?.mass / 1000)} {t('ton')}
</Text>
<Text style={styles.convoyInfo}>{t('referenceEngine')}</Text>
<Text>{rollingStockData?.metadata?.reference}</Text>
<Text style={styles.convoyInfo}>{t('maxLength')}</Text>
<Text>
{rollingStockData?.length} {t('meters')}
</Text>
</View>
<View style={styles.route}>
<Text style={styles.routeTitle}> {t('requestedRoute')}</Text>
<View style={styles.fromBanner}>
<Text style={styles.from}>{t('from')}</Text>
<Text>n°123456</Text>
</View>
<View style={styles.stopTableContainer}>
<Table style={styles.stopTable}>
<TH style={styles.stopTableTH}>
<TD aria-label="line-count" />
<TD>{t('operationalPoint')}</TD>
<TD>{t('code')}</TD>
<TD>{t('endStop')}</TD>
<TD>{t('startStop')}</TD>
<TD>{t('motif')}</TD>
</TH>
{stdcmData?.simulation.base.stops.map(
(stop, index) =>
(index === 0 || stop.duration > 0) && (
<TR key={index} style={styles.stopTableTbody}>
<TD style={styles.stopTableIndexColumn}>{index + 1}</TD>
<TD style={styles.stopTablePRColumn}>{stop.name || 'Unknown'}</TD>
<TD style={styles.stopTableCHColumn}>{stop.ch}</TD>
<TD style={styles.stopTableItalicColumn}>
{index === stdcmData.simulation.base.stops.length - 1
? getStopTime(stop.time)
: ''}
</TD>
<TD style={styles.stopTableStartColumn}>
{index === 0 ? getStopTime(stop.time) : ''}
</TD>
<TD style={styles.stopTableItalicColumn} aria-label="motif" />
</TR>
)
)}
</Table>
</View>
<View style={styles.forBanner}>
<Text>n°987654</Text>
<Text style={styles.for}>{t('for')}</Text>
</View>
</View>
</View>
<View style={styles.simulation}>
<Text style={styles.simulationUppercase}>{t('simulation')}</Text>
<Text style={styles.simulationLength}>
{Math.round((stdcmData?.path.length ?? 0) / 1000)}
{t('km')}
</Text>
<View style={styles.tableContainer}>
<Table style={styles.table}>
<TH style={styles.th}>
<TD aria-label="line-count" />
<TD>{t('operationalPoint')}</TD>
<TD>{t('code')}</TD>
<TD>{t('track')}</TD>
<TD>{t('endStop')}</TD>
<TD>{t('passageStop')}</TD>
<TD>{t('startStop')}</TD>
<TD>{t('weight')}</TD>
<TD>{t('referenceEngine')}</TD>
<TD>{t('conventionalSign')}</TD>
<TD>{t('crossedATE')}</TD>
</TH>
{stdcmData?.simulation.base.stops.map((stop, index) => (
<TR
key={index}
style={
stop.duration !== 0 && index !== stdcmData.simulation.base.stops.length - 1
? styles.blueRow
: styles.tbody
}
>
<TD style={styles.indexColumn}>{index + 1}</TD>
<TD style={styles.td}>
{index === 0 ||
stop.name !== stdcmData.simulation.base.stops[index - 1].name ||
index === stdcmData.simulation.base.stops.length - 1
? stop.name || 'Unknown'
: '='}
</TD>
<TD style={styles.chColumn}>{stop.ch}</TD>
<TD style={styles.td}>{stop.track_name}</TD>
<TD style={styles.stopColumn}>
{index === stdcmData.simulation.base.stops.length - 1 || stop.duration !== 0
? getStopTime(stop.time)
: ''}
</TD>
<TD
style={
stop.duration !== 0 && index !== stdcmData.simulation.base.stops.length - 1
? styles.blueStop
: styles.stopColumn
}
>
{index !== 0 && index !== stdcmData.simulation.base.stops.length - 1
? stop.duration !== 0
? getStopTime(stop.duration)
: getStopTime(stop.time)
: ''}
</TD>
<TD style={styles.stopColumn}>
{index === 0 ||
(stop.duration !== 0 && index !== stdcmData.simulation.base.stops.length - 1)
? getStopTime(stop.time + stop.duration)
: ''}
</TD>
<TD style={styles.td} aria-label="weight" />
<TD style={styles.td} aria-label="referenceEngine" />
<TD style={styles.td} aria-label="conventionalSign" />
<TD style={styles.td} aria-label="crossedATE" />
</TR>
))}
</Table>
<View style={styles.horizontalBar} />
</View>
</View>
<View style={styles.map} />
<View style={styles.warrantyBox}>
<Text style={styles.warrantyMessage}>{t('withoutWarranty')}</Text>
</View>
</Page>
</Document>
);
};

export default SimulationReportSheet;
Loading

0 comments on commit c4d522c

Please sign in to comment.