Skip to content

Commit

Permalink
front: create stdcm simulation sheet
Browse files Browse the repository at this point in the history
  • Loading branch information
Akctarus committed Apr 25, 2024
1 parent 11da135 commit c43cd24
Show file tree
Hide file tree
Showing 22 changed files with 1,345 additions and 19 deletions.
2 changes: 2 additions & 0 deletions front/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"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",
Expand All @@ -11,6 +12,7 @@
"@openapi-contrib/openapi-schema-to-json-schema": "^5.1.0",
"@osrd-project/ui-core": "^0.0.21",
"@osrd-project/ui-icons": "^0.0.21",
"@react-pdf/renderer": "^3.4.2",
"@redux-devtools/extension": "^3.3.0",
"@reduxjs/toolkit": "^2.1.0",
"@rjsf/core": "^5.17.0",
Expand Down
38 changes: 38 additions & 0 deletions front/public/locales/en/stdcm-simulation-sheet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"applicationDate": "Application date",
"code": "CH",
"conventionalSign": "conv. sign",
"convoy": "convoy",
"crossedATE": "crossed ATE",
"endStop": "end",
"for": "for",
"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",
"number": "",
"operationalPoint": "OP",
"passageStop": "passage",
"refEngine": "ref. engine",
"referenceEngine": "reference engine",
"referencePath": "Reference path",
"requestedRoute": "requested route",
"serviceStop": "Service stop",
"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",
"withoutWarranty": "Path simulation without guaranteed availability"
}
3 changes: 2 additions & 1 deletion front/public/locales/en/stdcm.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
"stdcmError": "Calculation error for last minute train path.",
"stdcmErrorNoPaths": "Incompatibility with other train paths.",
"stdcmNoResults": "No path found",
"stdcmResults": "Results"
"stdcmResults": "Results",
"stdcmSimulationReport": "Path simulation report"
}
38 changes: 38 additions & 0 deletions front/public/locales/fr/stdcm-simulation-sheet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"applicationDate": "Date d'application",
"code": "CH",
"conventionalSign": "signe conv.",
"convoy": "convoi",
"crossedATE": "ATE croisé",
"endStop": "arrivée",
"for": "pour",
"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",
"number": "",
"operationalPoint": "jalon",
"passageStop": "passage",
"refEngine": "engin de réf.",
"referenceEngine": "engin de référence",
"referencePath": "Sillon de référence",
"requestedRoute": "parcours demandé",
"serviceStop": "Arrêt de service",
"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",
"withoutWarranty": "Simulation de sillon sans garantie de disponibilité"
}
3 changes: 2 additions & 1 deletion front/public/locales/fr/stdcm.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
"stdcmError": "Erreur de calcul Sillon de dernière minute",
"stdcmErrorNoPaths": "Incompatibilité avec d'autres sillons.",
"stdcmNoResults": "Aucun sillon trouvé",
"stdcmResults": "Résultats"
"stdcmResults": "Résultats",
"stdcmSimulationReport": "Fiche de simulation du sillon"
}
272 changes: 272 additions & 0 deletions front/src/applications/stdcm/components/SimulationReportSheet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
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 IBMPlexMonoBold from 'assets/simulationSheet/fonts/IBM-Plex-Mono/IBMPlexMono-Bold.ttf';
import IBMPlexMonoMedium from 'assets/simulationSheet/fonts/IBM-Plex-Mono/IBMPlexMono-Medium.ttf';
import IBMPlexMonoRegular from 'assets/simulationSheet/fonts/IBM-Plex-Mono/IBMPlexMono-Regular.ttf';
import IBMPlexSansBold from 'assets/simulationSheet/fonts/IBM-Plex-Sans/IBMPlexSans-Bold.ttf';
import IBMPlexSansItalic from 'assets/simulationSheet/fonts/IBM-Plex-Sans/IBMPlexSans-Italic.ttf';
import IBMPlexSansMedium from 'assets/simulationSheet/fonts/IBM-Plex-Sans/IBMPlexSans-Medium.ttf';
import IBMPlexSansRegular from 'assets/simulationSheet/fonts/IBM-Plex-Sans/IBMPlexSans-Regular.ttf';
import IBMPlexSansSemiBold from 'assets/simulationSheet/fonts/IBM-Plex-Sans/IBMPlexSans-SemiBold.ttf';
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 { formatDate, formatDay, getStopDurationTime, getStopTime } from '../utils';

interface SimulationReportSheetProps {
stdcmData: PostStdcmApiResponse | null;
rollingStockData: RollingStockWithLiveries | undefined;
number: string;
mapCanvas?: string;
}

const SimulationReportSheet: React.FC<SimulationReportSheetProps> = ({
stdcmData,
rollingStockData,
number,
mapCanvas,
}) => {
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: IBMPlexMonoMedium, fontWeight: 'medium' },
{ 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('number')}
{number}
</Text>
<Text style={styles.creationDate}>{formatDate(stdcmData?.path.created)}</Text>
</View>
<Image src={logoSNCF} style={styles.sncfLogo} />
</View>
</View>
<View style={styles.rcInfo}>
<View style={styles.rcBox}>
<Text style={styles.rcName}>Super Fret</Text>
<Text style={styles.rcPersonName}>Stéphanie Martin-Duclotte</Text>
</View>
<View style={styles.rcBox}>
<Text style={styles.rcPhoneNumber}>04 12 34 56 78</Text>
<Text style={styles.rcMail}>stephanie.martin-duclotte@superfret.fr</Text>
</View>
<View style={styles.rcBox}>
<View style={styles.stdcmApplication}>
<Text style={styles.applicationDate}>{t('applicationDate')}</Text>
<Text style={styles.date}>{formatDay()}</Text>
<Text style={styles.referencePath}>{t('referencePath')}</Text>
<Text style={styles.pathNumber}>n°123456</Text>
</View>
</View>
</View>
<View style={styles.convoyAndRoute}>
<View style={styles.convoy}>
<Text style={styles.convoyTitle}> {t('convoy')}</Text>
<View style={styles.convoyInfo}>
<View style={styles.convoyInfoBox1}>
<Text style={styles.convoyInfoTitles}>{t('speedLimitByTag')}</Text>
<Text style={styles.convoyInfoData}>
{stdcmData?.simulation.speed_limit_tags === null
? '-'
: stdcmData?.simulation.speed_limit_tags}
</Text>
<Text style={styles.convoyInfoTitles}>{t('towedMaterial')}</Text>
<Text style={styles.convoyInfoData}>-</Text>
<Text style={styles.convoyInfoTitles}>{t('maxSpeed')}</Text>
<Text style={styles.convoyInfoData}>
{rollingStockData?.max_speed && rollingStockData?.max_speed * 3.6} {t('kmH')}
</Text>
</View>
<View style={styles.convoyInfoBox2}>
<Text style={styles.convoyInfoTitles}>{t('maxWeight')}</Text>
<Text style={styles.convoyInfoData}>
{rollingStockData?.mass && Math.floor(rollingStockData?.mass / 1000)} {t('ton')}
</Text>
<Text style={styles.convoyInfoTitles}>{t('referenceEngine')}</Text>
<Text style={styles.convoyInfoData}>{rollingStockData?.metadata?.reference}</Text>
<Text style={styles.convoyInfoTitles}>{t('maxLength')}</Text>
<Text style={styles.convoyInfoData}>
{rollingStockData?.length} {t('meters')}
</Text>
</View>
</View>
</View>
<View style={styles.route}>
<Text style={styles.routeTitle}> {t('requestedRoute')}</Text>
<View style={styles.fromBanner}>
<View style={styles.fromBox}>
<Text style={styles.from}>{t('from')}</Text>
</View>
<Text style={styles.fromNumber}>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}>
{index === 0 || index === stdcmData.simulation.base.stops.length - 1
? t('serviceStop')
: ''}
</TD>
</TR>
)
)}
</Table>
</View>
<View style={styles.forBanner}>
<Text style={styles.forNumber}>n°987654</Text>
<View style={styles.forBox}>
<Text style={styles.for}>{t('for')}</Text>
</View>
</View>
</View>
</View>
<View style={styles.simulation}>
<View style={styles.simulationContainer}>
<Text style={styles.simulationUppercase}>{t('simulation')}</Text>
<Text style={styles.simulationLength}>
{Math.round((stdcmData?.path.length ?? 0) / 1000)}
{t('km')}
</Text>
</View>
<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
}
>
{
// eslint-disable-next-line no-nested-ternary
index !== 0 && index !== stdcmData.simulation.base.stops.length - 1
? stop.duration !== 0
? getStopDurationTime(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}>
<Image src={mapCanvas} />
</View>
<View style={styles.warrantyBox}>
<Text style={styles.warrantyMessage}>{t('withoutWarranty')}</Text>
</View>
</Page>
</Document>
);
};

export default SimulationReportSheet;
Loading

0 comments on commit c43cd24

Please sign in to comment.