@movalib/movalib-commons 1.64.9 → 1.65.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.development CHANGED
@@ -1,5 +1,2 @@
1
- HTTPS=true
2
- SSL_CRT_FILE=/Users/Dimitri/localhost.pem
3
- SSL_KEY_FILE=/Users/Dimitri/localhost-key.pem
4
- REACT_APP_API_URL=https://localhost:8443/api
5
- REACT_APP_MOVALIB_APP_URL=https://localhost:3001
1
+ HTTPS=false
2
+ REACT_APP_MOVALIB_APP_URL=http://localhost:3001
package/devIndex.tsx CHANGED
@@ -1,32 +1,31 @@
1
- import React, { CSSProperties, Fragment, useEffect, useState } from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import { createRoot } from 'react-dom/client';
3
3
  // Import des composants de la bibliothèque
4
- import MovaLogin from './src/MovaLogin';
5
- import { AddressFieldName, MovaLoginForm, MovaUserSignUpForm } from './src/helpers/Types';
6
- import { MovaAppType } from './src/helpers/Enums';
7
- import { ThemeProvider, darken } from '@mui/material/styles';
8
- import theme from './theme'; // Import du thème personnalisé
9
- import MovaSignUp from './src/MovaSignUp';
10
- import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
4
+ import { Alert, Box, Button, Container, SelectChangeEvent } from '@mui/material';
5
+ import { ThemeProvider } from '@mui/material/styles';
11
6
  import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
12
- import DatePicker from '@mui/lab/DatePicker';
7
+ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
13
8
  import frLocale from 'date-fns/locale/fr';
14
- import QRCode from './src/QRCode';
15
- import { Alert, Box, Button, Container, SelectChangeEvent, Typography } from '@mui/material';
16
- import GarageService from './src/services/GarageService';
17
- import AuthenticationService from './src/services/AuthenticationService';
18
- import Logger from './src/helpers/Logger';
19
- import Garage from './src/models/Garage';
20
- import ScheduleFields, { DaySchedule } from './src/ScheduleFields';
21
- import Schedule from './src/models/Schedule';
22
- import { flexCenter, formatVehicleTire } from './src/helpers/Tools';
23
9
  import AccountValidation from './src/AccountValidation';
10
+ import AddressFields from './src/AddressFields';
24
11
  import VehiclePlateField from './src/components/vehicle/VehiclePlateField';
25
12
  import GaragePLV from './src/GaragePLV';
26
- import AddressFields from './src/AddressFields';
27
- import IbanInput from './src/IbanInput';
28
13
  import GenderSelector from './src/GenderSelector';
14
+ import { MovaAppType } from './src/helpers/Enums';
15
+ import Logger from './src/helpers/Logger';
16
+ import { flexCenter, formatVehicleTire } from './src/helpers/Tools';
17
+ import { AddressFieldName, MovaLoginForm, MovaUserSignUpForm } from './src/helpers/Types';
18
+ import IbanInput from './src/IbanInput';
19
+ import Garage from './src/models/Garage';
20
+ import Schedule from './src/models/Schedule';
21
+ import MovaLogin from './src/MovaLogin';
22
+ import MovaSignUp from './src/MovaSignUp';
29
23
  import MovaVehicleTireField from "./src/MovaVehicleTireField";
24
+ import QRCode from './src/QRCode';
25
+ import ScheduleFields, { DaySchedule } from './src/ScheduleFields';
26
+ import AuthenticationService from './src/services/AuthenticationService';
27
+ import GarageService from './src/services/GarageService';
28
+ import theme from './theme'; // Import du thème personnalisé
30
29
 
31
30
  const App = () => {
32
31
 
@@ -78,7 +77,7 @@ const App = () => {
78
77
  const getQRCodeData = ():string => {
79
78
  // On renvoie les données pour le QR Code, l'url change selon l'environnement (variables d'environnement)
80
79
  //return `https://app.movalib.com/#/garage/2?redirect=garage`;
81
- return `https://app.movalib.com/#/garage/9`;
80
+ return `https://movalib.com/info-contact-agiless-2/`;
82
81
  }
83
82
 
84
83
  const handleScheduleChange = (schedule: DaySchedule[]) => {
package/dist/devIndex.js CHANGED
@@ -41,29 +41,29 @@ var jsx_runtime_1 = require("react/jsx-runtime");
41
41
  var react_1 = __importStar(require("react"));
42
42
  var client_1 = require("react-dom/client");
43
43
  // Import des composants de la bibliothèque
44
- var MovaLogin_1 = __importDefault(require("./src/MovaLogin"));
45
- var Enums_1 = require("./src/helpers/Enums");
44
+ var material_1 = require("@mui/material");
46
45
  var styles_1 = require("@mui/material/styles");
47
- var theme_1 = __importDefault(require("./theme")); // Import du thème personnalisé
48
- var MovaSignUp_1 = __importDefault(require("./src/MovaSignUp"));
49
- var LocalizationProvider_1 = require("@mui/x-date-pickers/LocalizationProvider");
50
46
  var AdapterDateFns_1 = require("@mui/x-date-pickers/AdapterDateFns");
47
+ var LocalizationProvider_1 = require("@mui/x-date-pickers/LocalizationProvider");
51
48
  var fr_1 = __importDefault(require("date-fns/locale/fr"));
52
- var QRCode_1 = __importDefault(require("./src/QRCode"));
53
- var material_1 = require("@mui/material");
54
- var GarageService_1 = __importDefault(require("./src/services/GarageService"));
55
- var AuthenticationService_1 = __importDefault(require("./src/services/AuthenticationService"));
56
- var Logger_1 = __importDefault(require("./src/helpers/Logger"));
57
- var ScheduleFields_1 = __importDefault(require("./src/ScheduleFields"));
58
- var Schedule_1 = __importDefault(require("./src/models/Schedule"));
59
- var Tools_1 = require("./src/helpers/Tools");
60
49
  var AccountValidation_1 = __importDefault(require("./src/AccountValidation"));
50
+ var AddressFields_1 = __importDefault(require("./src/AddressFields"));
61
51
  var VehiclePlateField_1 = __importDefault(require("./src/components/vehicle/VehiclePlateField"));
62
52
  var GaragePLV_1 = __importDefault(require("./src/GaragePLV"));
63
- var AddressFields_1 = __importDefault(require("./src/AddressFields"));
64
- var IbanInput_1 = __importDefault(require("./src/IbanInput"));
65
53
  var GenderSelector_1 = __importDefault(require("./src/GenderSelector"));
54
+ var Enums_1 = require("./src/helpers/Enums");
55
+ var Logger_1 = __importDefault(require("./src/helpers/Logger"));
56
+ var Tools_1 = require("./src/helpers/Tools");
57
+ var IbanInput_1 = __importDefault(require("./src/IbanInput"));
58
+ var Schedule_1 = __importDefault(require("./src/models/Schedule"));
59
+ var MovaLogin_1 = __importDefault(require("./src/MovaLogin"));
60
+ var MovaSignUp_1 = __importDefault(require("./src/MovaSignUp"));
66
61
  var MovaVehicleTireField_1 = __importDefault(require("./src/MovaVehicleTireField"));
62
+ var QRCode_1 = __importDefault(require("./src/QRCode"));
63
+ var ScheduleFields_1 = __importDefault(require("./src/ScheduleFields"));
64
+ var AuthenticationService_1 = __importDefault(require("./src/services/AuthenticationService"));
65
+ var GarageService_1 = __importDefault(require("./src/services/GarageService"));
66
+ var theme_1 = __importDefault(require("./theme")); // Import du thème personnalisé
67
67
  var App = function () {
68
68
  Logger_1.default.enableLogging();
69
69
  // Chargement de données garage de test
@@ -105,7 +105,7 @@ var App = function () {
105
105
  var getQRCodeData = function () {
106
106
  // On renvoie les données pour le QR Code, l'url change selon l'environnement (variables d'environnement)
107
107
  //return `https://app.movalib.com/#/garage/2?redirect=garage`;
108
- return "https://app.movalib.com/#/garage/9";
108
+ return "https://movalib.com/info-contact-agiless-2/";
109
109
  };
110
110
  var handleScheduleChange = function (schedule) {
111
111
  if (schedule) {
package/dist/index.d.ts CHANGED
@@ -57,7 +57,7 @@ export { deleteCookie, readCookie } from "./src/helpers/CookieUtils";
57
57
  export { formatDateByTimezone, getLongFormattedDateTime, } from "./src/helpers/DateUtils";
58
58
  export { capitalizeFirstLetter, findScheduleByDayOfWeek, flexLeftRow, formatPhoneNumber, formatVehiclePlate, formatVehicleTire, getApplicationShortLabel, getApplicationsShortLabels, getDayOfWeekLabel, getFormattedIntervals, getFormattedSchedule, isEmpty, isSafariOniOS, validateField, } from "./src/helpers/Tools";
59
59
  export { validateEmail, validatePhoneNumber, validateText, } from "./src/helpers/Validator";
60
- export { APIMethod, CountryCode, CustomerType, DateFormatTypes, DayOfWeek, DigitalPassportIndex, DocumentState, DocumentType, EventState, EventType, Gender, MovaAppType, OrderPreference, OrderState, PartsApplicationType, PrestationState, PrestationType, ProductType, RegistrationState, RoleType, SlotAlgorithm, SubscriptionPaymentInterval, SubscriptionState, SubscriptionType, VehiclePlateFormat as VehiclePlateType, } from "./src/helpers/Enums";
60
+ export { APIMethod, CountryCode, CustomerType, DateFormatTypes, DayOfWeek, DigitalPassportIndex, DocumentState, DocumentType, EventState, EventType, Gender, MovaAppType, OrderPreference, OrderState, PartsApplicationType, PrestationState, PrestationType, ProductType, RegistrationState, RoleType, SecondaryPartsApplicationType, SlotAlgorithm, SubscriptionPaymentInterval, SubscriptionState, SubscriptionType, VehiclePlateFormat as VehiclePlateType, } from "./src/helpers/Enums";
61
61
  export { openDialogPrint } from "./src/utils/DialogPrint";
62
62
  export { getQrCodeBase64 } from "./src/utils/getQRCodeBase64";
63
63
  export { StyledToggleButton, StyledToggleButtonGroup, } from "./src/style/styled";
package/dist/index.js CHANGED
@@ -5,8 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.Supplier = exports.Subscription = exports.Schedule = exports.Role = exports.Product = exports.Prestation = exports.Operation = exports.LoanVehicle = exports.Garage = exports.Event = exports.Employee = exports.Document = exports.Customer = exports.CategoryPrestation = exports.Address = exports.Absence = exports.Logger = exports.TestButton = exports.ScheduleFields = exports.QRCode = exports.MovaVehicleTireField = exports.MovaSnackbar = exports.MovaSignUp = exports.MovaLogin = exports.MovaDigitalPassport = exports.MovaDialog = exports.MovaCopyright = exports.Loader = exports.IbanInput = exports.GenderSelector = exports.GaragePLV = exports.DialogForgotPassword = exports.ConfirmationDialog = exports.regexPlate = exports.oldRegexPlate = exports.VehiclePlateField = exports.VehicleFullCard = exports.ActivateAccount = exports.QrCodePLVContainer = exports.PrintSize = exports.PLVComponent = exports.MovaTableBack = exports.MovaTable = exports.LinkedDocumentDialog = exports.AddressFields = exports.AccountValidation = exports.VehicleService = exports.UserService = exports.GarageService = exports.AuthenticationService = void 0;
8
- exports.SubscriptionState = exports.SubscriptionPaymentInterval = exports.SlotAlgorithm = exports.RoleType = exports.RegistrationState = exports.ProductType = exports.PrestationType = exports.PrestationState = exports.PartsApplicationType = exports.OrderState = exports.OrderPreference = exports.MovaAppType = exports.Gender = exports.EventType = exports.EventState = exports.DocumentType = exports.DocumentState = exports.DigitalPassportIndex = exports.DayOfWeek = exports.DateFormatTypes = exports.CustomerType = exports.CountryCode = exports.APIMethod = exports.validateText = exports.validatePhoneNumber = exports.validateEmail = exports.validateField = exports.isSafariOniOS = exports.isEmpty = exports.getFormattedSchedule = exports.getFormattedIntervals = exports.getDayOfWeekLabel = exports.getApplicationsShortLabels = exports.getApplicationShortLabel = exports.formatVehicleTire = exports.formatVehiclePlate = exports.formatPhoneNumber = exports.flexLeftRow = exports.findScheduleByDayOfWeek = exports.capitalizeFirstLetter = exports.getLongFormattedDateTime = exports.formatDateByTimezone = exports.readCookie = exports.deleteCookie = exports.request = exports.API_BASE_URL = exports.VehicleTire = exports.VehicleGarage = exports.Vehicle = exports.User = void 0;
9
- exports.StyledToggleButtonGroup = exports.StyledToggleButton = exports.getQrCodeBase64 = exports.openDialogPrint = exports.VehiclePlateType = exports.SubscriptionType = void 0;
8
+ exports.SubscriptionPaymentInterval = exports.SlotAlgorithm = exports.SecondaryPartsApplicationType = exports.RoleType = exports.RegistrationState = exports.ProductType = exports.PrestationType = exports.PrestationState = exports.PartsApplicationType = exports.OrderState = exports.OrderPreference = exports.MovaAppType = exports.Gender = exports.EventType = exports.EventState = exports.DocumentType = exports.DocumentState = exports.DigitalPassportIndex = exports.DayOfWeek = exports.DateFormatTypes = exports.CustomerType = exports.CountryCode = exports.APIMethod = exports.validateText = exports.validatePhoneNumber = exports.validateEmail = exports.validateField = exports.isSafariOniOS = exports.isEmpty = exports.getFormattedSchedule = exports.getFormattedIntervals = exports.getDayOfWeekLabel = exports.getApplicationsShortLabels = exports.getApplicationShortLabel = exports.formatVehicleTire = exports.formatVehiclePlate = exports.formatPhoneNumber = exports.flexLeftRow = exports.findScheduleByDayOfWeek = exports.capitalizeFirstLetter = exports.getLongFormattedDateTime = exports.formatDateByTimezone = exports.readCookie = exports.deleteCookie = exports.request = exports.API_BASE_URL = exports.VehicleTire = exports.VehicleGarage = exports.Vehicle = exports.User = void 0;
9
+ exports.StyledToggleButtonGroup = exports.StyledToggleButton = exports.getQrCodeBase64 = exports.openDialogPrint = exports.VehiclePlateType = exports.SubscriptionType = exports.SubscriptionState = void 0;
10
10
  // Export des services
11
11
  var AuthenticationService_1 = require("./src/services/AuthenticationService");
12
12
  Object.defineProperty(exports, "AuthenticationService", { enumerable: true, get: function () { return __importDefault(AuthenticationService_1).default; } });
@@ -166,6 +166,7 @@ Object.defineProperty(exports, "PrestationType", { enumerable: true, get: functi
166
166
  Object.defineProperty(exports, "ProductType", { enumerable: true, get: function () { return Enums_1.ProductType; } });
167
167
  Object.defineProperty(exports, "RegistrationState", { enumerable: true, get: function () { return Enums_1.RegistrationState; } });
168
168
  Object.defineProperty(exports, "RoleType", { enumerable: true, get: function () { return Enums_1.RoleType; } });
169
+ Object.defineProperty(exports, "SecondaryPartsApplicationType", { enumerable: true, get: function () { return Enums_1.SecondaryPartsApplicationType; } });
169
170
  Object.defineProperty(exports, "SlotAlgorithm", { enumerable: true, get: function () { return Enums_1.SlotAlgorithm; } });
170
171
  Object.defineProperty(exports, "SubscriptionPaymentInterval", { enumerable: true, get: function () { return Enums_1.SubscriptionPaymentInterval; } });
171
172
  Object.defineProperty(exports, "SubscriptionState", { enumerable: true, get: function () { return Enums_1.SubscriptionState; } });
@@ -12,6 +12,16 @@ export declare enum SubscriptionState {
12
12
  PAUSED = "PAUSED",
13
13
  CANCELED = "CANCELED"
14
14
  }
15
+ export declare enum SecondaryPartsApplicationType {
16
+ HOOD = "HOOD",
17
+ ROOF = "ROOF",
18
+ DOOR = "DOOR",
19
+ FENDER = "FENDER",
20
+ JAMB = "JAMB",
21
+ UNDERBODY = "UNDERBODY",
22
+ BUMPER = "BUMPER",
23
+ TRUNK = "TRUNK"
24
+ }
15
25
  export declare enum CountryCode {
16
26
  FR = "FR"
17
27
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RoleType = exports.MovaAppType = exports.DocumentType = exports.QuoteState = exports.DocumentState = exports.DayOfWeek = exports.EventType = exports.EventState = exports.DigitalPassportIndex = exports.Gender = exports.DateFormatTypes = exports.APIMethod = exports.PartsApplicationType = exports.ProductType = exports.OrderPreference = exports.OrderState = exports.SlotAlgorithm = exports.VehiclePlateFormat = exports.RegistrationState = exports.SubscriptionPaymentInterval = exports.PrestationType = exports.PrestationState = exports.CountryCode = exports.SubscriptionState = exports.SubscriptionType = exports.CustomerType = void 0;
3
+ exports.RoleType = exports.MovaAppType = exports.DocumentType = exports.QuoteState = exports.DocumentState = exports.DayOfWeek = exports.EventType = exports.EventState = exports.DigitalPassportIndex = exports.Gender = exports.DateFormatTypes = exports.APIMethod = exports.PartsApplicationType = exports.ProductType = exports.OrderPreference = exports.OrderState = exports.SlotAlgorithm = exports.VehiclePlateFormat = exports.RegistrationState = exports.SubscriptionPaymentInterval = exports.PrestationType = exports.PrestationState = exports.CountryCode = exports.SecondaryPartsApplicationType = exports.SubscriptionState = exports.SubscriptionType = exports.CustomerType = void 0;
4
4
  var CustomerType;
5
5
  (function (CustomerType) {
6
6
  CustomerType["INDIVIDUAL"] = "INDIVIDUAL";
@@ -18,6 +18,17 @@ var SubscriptionState;
18
18
  SubscriptionState["PAUSED"] = "PAUSED";
19
19
  SubscriptionState["CANCELED"] = "CANCELED";
20
20
  })(SubscriptionState = exports.SubscriptionState || (exports.SubscriptionState = {}));
21
+ var SecondaryPartsApplicationType;
22
+ (function (SecondaryPartsApplicationType) {
23
+ SecondaryPartsApplicationType["HOOD"] = "HOOD";
24
+ SecondaryPartsApplicationType["ROOF"] = "ROOF";
25
+ SecondaryPartsApplicationType["DOOR"] = "DOOR";
26
+ SecondaryPartsApplicationType["FENDER"] = "FENDER";
27
+ SecondaryPartsApplicationType["JAMB"] = "JAMB";
28
+ SecondaryPartsApplicationType["UNDERBODY"] = "UNDERBODY";
29
+ SecondaryPartsApplicationType["BUMPER"] = "BUMPER";
30
+ SecondaryPartsApplicationType["TRUNK"] = "TRUNK";
31
+ })(SecondaryPartsApplicationType = exports.SecondaryPartsApplicationType || (exports.SecondaryPartsApplicationType = {}));
21
32
  var CountryCode;
22
33
  (function (CountryCode) {
23
34
  CountryCode["FR"] = "FR";
@@ -1,7 +1,8 @@
1
1
  import { CSSProperties } from "react";
2
+ import Operation from "../models/Operation";
2
3
  import Schedule from "../models/Schedule";
3
4
  import VehicleTire from "../models/VehicleTire";
4
- import { DayOfWeek, PartsApplicationType } from "./Enums";
5
+ import { DayOfWeek, PartsApplicationType, SecondaryPartsApplicationType } from "./Enums";
5
6
  import { MovaFormField, MovaInterval } from "./Types";
6
7
  export declare const getApplicationsShortLabels: (applications: PartsApplicationType[] | undefined) => string;
7
8
  export declare const flexStart: CSSProperties;
@@ -20,7 +21,8 @@ export declare const getDayOfWeek: (index: number) => DayOfWeek | undefined;
20
21
  export declare const getFrenchDayLabel: (day: DayOfWeek | undefined) => "Lundi" | "Mardi" | "Mercredi" | "Jeudi" | "Vendredi" | "Samedi" | "Dimanche" | undefined;
21
22
  export declare const flexLeftRow: CSSProperties;
22
23
  export declare const capitalizeFirstLetter: (str: string) => string;
23
- export declare const getApplicationShortLabel: (application: PartsApplicationType | undefined) => "" | "AV" | "AR" | "AV + AR" | "G" | "D" | "G + D" | "AVG" | "AVD" | "ARG" | "ARD";
24
+ export declare const getApplicationShortLabel: (application: PartsApplicationType | undefined) => "" | "AVG" | "AVD" | "ARG" | "ARD" | "AV" | "AR" | "G" | "D" | "AV + AR" | "G + D";
25
+ export declare const getApplicationSecondaryLabel: (secondaryApplication: SecondaryPartsApplicationType) => string;
24
26
  export declare const flexEnd: CSSProperties;
25
27
  export declare const flexCenter: CSSProperties;
26
28
  export declare const isEmpty: (data: Object) => boolean;
@@ -36,3 +38,8 @@ export declare const formatVehicleTireStr: (input: string) => string;
36
38
  * @returns {MovaFormField} - Le champ de formulaire avec les propriétés `error` et `isValid` mises à jour.
37
39
  */
38
40
  export declare const validateField: (field: MovaFormField | undefined, validator: (value: string) => boolean, errorMsg: string) => MovaFormField;
41
+ export declare function buildSelectedOperationsLabel(selectedOperationIds: number[], allOperations: Operation[], options?: {
42
+ prestationName?: string;
43
+ }): string;
44
+ export declare function hasSecondaryApplication(items: Operation[], ids: number[], needle: string, caseInsensitive?: boolean): boolean;
45
+ export declare function buildPositionsLabelFromShorts(selectedOperationIds: number[], allOperations: Operation[]): string;
@@ -1,9 +1,18 @@
1
1
  "use strict";
2
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
3
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
4
+ if (ar || !(i in from)) {
5
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
6
+ ar[i] = from[i];
7
+ }
8
+ }
9
+ return to.concat(ar || Array.prototype.slice.call(from));
10
+ };
2
11
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
13
  };
5
14
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.validateField = exports.formatVehicleTireStr = exports.formatVehicleTire = exports.formatVehiclePlate = exports.isEmpty = exports.flexCenter = exports.flexEnd = exports.getApplicationShortLabel = exports.capitalizeFirstLetter = exports.flexLeftRow = exports.getFrenchDayLabel = exports.getDayOfWeek = exports.findScheduleByDayOfWeek = exports.formatTime = exports.getFormattedIntervals = exports.getFormattedSchedule = exports.formatPhoneNumber = exports.getDayOfWeekIndex = exports.getDayOfWeekLabel = exports.FR_WEEK_DAYS = exports.isInvalidPhoneNumber = exports.isInvalidMobileNumber = exports.isSafariOniOS = exports.flexStart = exports.getApplicationsShortLabels = void 0;
15
+ exports.buildPositionsLabelFromShorts = exports.hasSecondaryApplication = exports.buildSelectedOperationsLabel = exports.validateField = exports.formatVehicleTireStr = exports.formatVehicleTire = exports.formatVehiclePlate = exports.isEmpty = exports.flexCenter = exports.flexEnd = exports.getApplicationSecondaryLabel = exports.getApplicationShortLabel = exports.capitalizeFirstLetter = exports.flexLeftRow = exports.getFrenchDayLabel = exports.getDayOfWeek = exports.findScheduleByDayOfWeek = exports.formatTime = exports.getFormattedIntervals = exports.getFormattedSchedule = exports.formatPhoneNumber = exports.getDayOfWeekIndex = exports.getDayOfWeekLabel = exports.FR_WEEK_DAYS = exports.isInvalidPhoneNumber = exports.isInvalidMobileNumber = exports.isSafariOniOS = exports.flexStart = exports.getApplicationsShortLabels = void 0;
7
16
  var max_1 = __importDefault(require("libphonenumber-js/max"));
8
17
  var Enums_1 = require("./Enums");
9
18
  var getApplicationsShortLabels = function (applications) {
@@ -252,6 +261,27 @@ var getApplicationShortLabel = function (application) {
252
261
  return "";
253
262
  };
254
263
  exports.getApplicationShortLabel = getApplicationShortLabel;
264
+ var getApplicationSecondaryLabel = function (secondaryApplication) {
265
+ switch (secondaryApplication) {
266
+ case Enums_1.SecondaryPartsApplicationType.HOOD:
267
+ return "Capot";
268
+ case Enums_1.SecondaryPartsApplicationType.ROOF:
269
+ return "Toit";
270
+ case Enums_1.SecondaryPartsApplicationType.DOOR:
271
+ return "Portière";
272
+ case Enums_1.SecondaryPartsApplicationType.TRUNK:
273
+ return "Coffre";
274
+ case Enums_1.SecondaryPartsApplicationType.FENDER:
275
+ return "Aile";
276
+ case Enums_1.SecondaryPartsApplicationType.JAMB:
277
+ return "Montant";
278
+ case Enums_1.SecondaryPartsApplicationType.UNDERBODY:
279
+ return "Bas de caisse";
280
+ case Enums_1.SecondaryPartsApplicationType.BUMPER:
281
+ return "Pare-chocs";
282
+ }
283
+ };
284
+ exports.getApplicationSecondaryLabel = getApplicationSecondaryLabel;
255
285
  exports.flexEnd = {
256
286
  display: "flex",
257
287
  justifyContent: "end",
@@ -357,3 +387,156 @@ var validateField = function (field, validator, errorMsg) {
357
387
  }
358
388
  };
359
389
  exports.validateField = validateField;
390
+ function shortFromApplication(app) {
391
+ var A = (app || "").toUpperCase();
392
+ var has = function (s) { return A.includes(s); };
393
+ if (has("FT") && has("LT"))
394
+ return "AVG";
395
+ if (has("FT") && has("RT"))
396
+ return "AVD";
397
+ if (has("RR") && has("LT"))
398
+ return "ARG";
399
+ if (has("RR") && has("RT"))
400
+ return "ARD";
401
+ if (has("FT"))
402
+ return "AV";
403
+ if (has("RR"))
404
+ return "AR";
405
+ if (has("LT"))
406
+ return "G";
407
+ if (has("RT"))
408
+ return "D";
409
+ return "";
410
+ }
411
+ var CATEGORY = {
412
+ DOOR: { title: "PORTE", useApp: true },
413
+ FENDER: { title: "AILE", useApp: true },
414
+ JAMB: { title: "MONTANT", useApp: true },
415
+ UNDERBODY: { title: "BAS DE CAISSE", useApp: true },
416
+ BUMPER: { title: "PARE-CHOCS", useApp: true },
417
+ HOOD: { title: "CAPOT", useApp: false },
418
+ TRUNK: { title: "COFFRE", useApp: false },
419
+ ROOF: { title: "TOIT", useApp: false },
420
+ };
421
+ function buildSelectedOperationsLabel(selectedOperationIds, allOperations, options) {
422
+ var _a, _b;
423
+ if (options === void 0) { options = {}; }
424
+ var prestationName = options.prestationName;
425
+ var byId = new Map(allOperations.map(function (o) { return [o.id, o]; }));
426
+ var groups = new Map(); // key = secondaryApplication UPPER
427
+ for (var _i = 0, selectedOperationIds_1 = selectedOperationIds; _i < selectedOperationIds_1.length; _i++) {
428
+ var id = selectedOperationIds_1[_i];
429
+ var op = byId.get(id);
430
+ if (!op)
431
+ continue;
432
+ var key = (op.secondaryApplication || "OTHER").toUpperCase();
433
+ var cfg = (_a = CATEGORY[key]) !== null && _a !== void 0 ? _a : { title: key, useApp: true };
434
+ if (!groups.has(key)) {
435
+ groups.set(key, cfg.useApp
436
+ ? {
437
+ kind: "withApp",
438
+ key: key,
439
+ title: cfg.title,
440
+ counts: new Map(),
441
+ }
442
+ : { kind: "single", key: key, title: cfg.title, seen: false });
443
+ }
444
+ var g = groups.get(key);
445
+ if (g.kind === "withApp") {
446
+ var label = shortFromApplication(op.application) || op.application || "";
447
+ if (label)
448
+ g.counts.set(label, ((_b = g.counts.get(label)) !== null && _b !== void 0 ? _b : 0) + 1);
449
+ }
450
+ else {
451
+ g.seen = true; // HOOD/TRUNK/ROOF -> présent une fois, sans compteur
452
+ }
453
+ }
454
+ // Ordre des catégories dans le rendu final
455
+ var desiredOrder = [
456
+ "DOOR",
457
+ "FENDER",
458
+ "HOOD",
459
+ "BUMPER",
460
+ "TRUNK",
461
+ "ROOF",
462
+ "JAMB",
463
+ "UNDERBODY",
464
+ ];
465
+ var weight = function (key) {
466
+ var idx = desiredOrder.indexOf(key);
467
+ return idx === -1 ? Number.MAX_SAFE_INTEGER : idx;
468
+ };
469
+ // Construire les segments
470
+ var segments = [];
471
+ var _loop_1 = function (g) {
472
+ if (g.kind === "withApp") {
473
+ var order_1 = ["AV", "AR", "AVG", "AVD", "ARG", "ARD", "G", "D"];
474
+ var parts = Array.from(g.counts.entries())
475
+ .sort(function (a, b) { return order_1.indexOf(a[0]) - order_1.indexOf(b[0]); })
476
+ .map(function (_a) {
477
+ var lbl = _a[0], n = _a[1];
478
+ return (n > 1 ? "".concat(lbl, " (x").concat(n, ")") : lbl);
479
+ });
480
+ if (parts.length)
481
+ segments.push("".concat(g.title, " ").concat(parts.join(" + ")));
482
+ }
483
+ else {
484
+ if (g.seen)
485
+ segments.push(g.title); // capot / toit / coffre (sans position, sans xN)
486
+ }
487
+ };
488
+ for (var _c = 0, _d = Array.from(groups.values()).sort(function (a, b) { return weight(a.key) - weight(b.key); }); _c < _d.length; _c++) {
489
+ var g = _d[_c];
490
+ _loop_1(g);
491
+ }
492
+ return __spreadArray([prestationName], segments, true).filter(Boolean).join(" , ");
493
+ }
494
+ exports.buildSelectedOperationsLabel = buildSelectedOperationsLabel;
495
+ function hasSecondaryApplication(items, ids, needle, caseInsensitive) {
496
+ var _a;
497
+ if (caseInsensitive === void 0) { caseInsensitive = false; }
498
+ var byId = new Map(items.map(function (it) { return [it.id, it]; }));
499
+ var target = caseInsensitive ? needle.toLowerCase() : needle;
500
+ for (var _i = 0, ids_1 = ids; _i < ids_1.length; _i++) {
501
+ var id = ids_1[_i];
502
+ var it = byId.get(id);
503
+ if (!it)
504
+ continue;
505
+ var value = ((_a = it.secondaryApplication) !== null && _a !== void 0 ? _a : "");
506
+ if ((caseInsensitive ? value.toLowerCase() : value) === target)
507
+ return true;
508
+ }
509
+ return false;
510
+ }
511
+ exports.hasSecondaryApplication = hasSecondaryApplication;
512
+ var ORDER = ["AVG", "AVD", "ARG", "ARD", "AV", "AR", "G", "D"];
513
+ function buildPositionsLabelFromShorts(selectedOperationIds, allOperations) {
514
+ var _a, _b;
515
+ // index
516
+ var byId = new Map(allOperations.map(function (o) { return [o.id, o]; }));
517
+ // collecte des tokens (AV, AR, AVG, …)
518
+ var tokens = new Set();
519
+ for (var _i = 0, selectedOperationIds_2 = selectedOperationIds; _i < selectedOperationIds_2.length; _i++) {
520
+ var id = selectedOperationIds_2[_i];
521
+ var appCode = (_b = (_a = byId.get(id)) === null || _a === void 0 ? void 0 : _a.application) === null || _b === void 0 ? void 0 : _b.toUpperCase();
522
+ if (!appCode)
523
+ continue;
524
+ var appEnum = appCode;
525
+ if (!appEnum)
526
+ continue;
527
+ var short = (0, exports.getApplicationShortLabel)(appEnum); // ex: "AV + AR" ou "AVG"
528
+ if (!short)
529
+ continue;
530
+ // ⚠️ splitter par " + " (pas par caractère) pour éviter "a + v"
531
+ for (var _c = 0, _d = short.split(" + "); _c < _d.length; _c++) {
532
+ var t = _d[_c];
533
+ var s = t.trim();
534
+ if (s)
535
+ tokens.add(s);
536
+ }
537
+ }
538
+ // tri esthétique
539
+ var parts = Array.from(tokens).sort(function (a, b) { return ORDER.indexOf(a) - ORDER.indexOf(b); });
540
+ return parts.join(" + ");
541
+ }
542
+ exports.buildPositionsLabelFromShorts = buildPositionsLabelFromShorts;
@@ -65,5 +65,6 @@ export default class Garage {
65
65
  establishmentRegistrationNumber?: string;
66
66
  reopeningDate?: Date;
67
67
  targetMargin?: number;
68
- constructor(id: string, adminId: string, name: string, address: Address, workforce: number, prestations: Prestation[], schedules: Schedule[], contactPhone: string, prestationCategories: CategoryPrestation[], dayPeriodFastServiceExcluded: boolean, loanerVehicleFastServiceExcluded: boolean, fastServiceThreshold: number, timezone: string, vehicles?: VehicleGarage[], contactEmail?: string, logo?: string, suppliers?: Supplier[], documents?: Document[], subscriptions?: Subscription[], loanerVehicleActive?: boolean, loanerVehicleRequestActive?: boolean, customStyle?: string, subscription?: Subscription, partialWorkforce?: number, mailCustomization?: boolean, billingActive?: boolean, billingToken?: string, billingSimulationActive?: boolean, appId?: number, establishmentRegistrationNumber?: string, companyRegistrationNumber?: string, quoteRequestStart?: Date, reopeningDate?: Date, targetMargin?: number, demoBillingActive?: boolean);
68
+ onlyBilling?: boolean;
69
+ constructor(id: string, adminId: string, name: string, address: Address, workforce: number, prestations: Prestation[], schedules: Schedule[], contactPhone: string, prestationCategories: CategoryPrestation[], dayPeriodFastServiceExcluded: boolean, loanerVehicleFastServiceExcluded: boolean, fastServiceThreshold: number, timezone: string, vehicles?: VehicleGarage[], contactEmail?: string, logo?: string, suppliers?: Supplier[], documents?: Document[], subscriptions?: Subscription[], loanerVehicleActive?: boolean, loanerVehicleRequestActive?: boolean, customStyle?: string, subscription?: Subscription, partialWorkforce?: number, mailCustomization?: boolean, billingActive?: boolean, billingToken?: string, billingSimulationActive?: boolean, appId?: number, establishmentRegistrationNumber?: string, companyRegistrationNumber?: string, quoteRequestStart?: Date, reopeningDate?: Date, targetMargin?: number, demoBillingActive?: boolean, onlyBilling?: boolean);
69
70
  }
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  var Garage = /** @class */ (function () {
4
- function Garage(id, adminId, name, address, workforce, prestations, schedules, contactPhone, prestationCategories, dayPeriodFastServiceExcluded, loanerVehicleFastServiceExcluded, fastServiceThreshold, timezone, vehicles, contactEmail, logo, suppliers, documents, subscriptions, loanerVehicleActive, loanerVehicleRequestActive, customStyle, subscription, partialWorkforce, mailCustomization, billingActive, billingToken, billingSimulationActive, appId, establishmentRegistrationNumber, companyRegistrationNumber, quoteRequestStart, reopeningDate, targetMargin, demoBillingActive) {
4
+ function Garage(id, adminId, name, address, workforce, prestations, schedules, contactPhone, prestationCategories, dayPeriodFastServiceExcluded, loanerVehicleFastServiceExcluded, fastServiceThreshold, timezone, vehicles, contactEmail, logo, suppliers, documents, subscriptions, loanerVehicleActive, loanerVehicleRequestActive, customStyle, subscription, partialWorkforce, mailCustomization, billingActive, billingToken, billingSimulationActive, appId, establishmentRegistrationNumber, companyRegistrationNumber, quoteRequestStart, reopeningDate, targetMargin, demoBillingActive, onlyBilling) {
5
+ if (onlyBilling === void 0) { onlyBilling = false; }
5
6
  this.id = id;
6
7
  this.adminId = adminId;
7
8
  this.name = name;
@@ -37,6 +38,7 @@ var Garage = /** @class */ (function () {
37
38
  this.reopeningDate = reopeningDate;
38
39
  this.targetMargin = targetMargin;
39
40
  this.demoBillingActive = demoBillingActive;
41
+ this.onlyBilling = onlyBilling;
40
42
  }
41
43
  return Garage;
42
44
  }());
@@ -1,11 +1,13 @@
1
- import { PartsApplicationType } from "../helpers/Enums";
1
+ import { PartsApplicationType, SecondaryPartsApplicationType } from "../helpers/Enums";
2
2
  import Product from "./Product";
3
3
  export default class Operation {
4
4
  id: number;
5
5
  code: string;
6
6
  name: string;
7
7
  description: string;
8
+ prestationId: number;
8
9
  application?: PartsApplicationType;
9
10
  products?: Product[];
10
- constructor(id: number, code: string, name: string, description: string, application: PartsApplicationType, products: Product[]);
11
+ secondaryApplication?: SecondaryPartsApplicationType;
12
+ constructor(id: number, code: string, name: string, description: string, application: PartsApplicationType, products: Product[], prestationId: number, secondaryApplication?: SecondaryPartsApplicationType);
11
13
  }
@@ -1,13 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  var Operation = /** @class */ (function () {
4
- function Operation(id, code, name, description, application, products) {
4
+ function Operation(id, code, name, description, application, products, prestationId, secondaryApplication) {
5
+ this.prestationId = prestationId;
5
6
  this.id = id;
6
7
  this.code = code;
7
8
  this.name = name;
8
9
  this.description = description;
9
10
  this.application = application;
10
11
  this.products = products;
12
+ this.secondaryApplication = secondaryApplication;
11
13
  }
12
14
  return Operation;
13
15
  }());
@@ -28,5 +28,6 @@ export default class Prestation {
28
28
  multipleApplication: boolean;
29
29
  operationsVisible: boolean;
30
30
  categoryCode: string;
31
- constructor(id: number, code: string, name: string, description: string, category: string, downtime: number, appointmentDelay: number, position: number, active: boolean, state: PrestationState, multipleApplication: boolean, operationsVisible: boolean, categoryCode: string, availableOnline: boolean, operations?: Operation[]);
31
+ secondaryMultipleApplication: boolean;
32
+ constructor(id: number, code: string, name: string, description: string, category: string, downtime: number, appointmentDelay: number, position: number, active: boolean, state: PrestationState, multipleApplication: boolean, operationsVisible: boolean, categoryCode: string, availableOnline: boolean, operations?: Operation[], secondaryMultipleApplication?: boolean);
32
33
  }
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  var Prestation = /** @class */ (function () {
4
- function Prestation(id, code, name, description, category, downtime, appointmentDelay, position, active, state, multipleApplication, operationsVisible, categoryCode, availableOnline, operations) {
4
+ function Prestation(id, code, name, description, category, downtime, appointmentDelay, position, active, state, multipleApplication, operationsVisible, categoryCode, availableOnline, operations, secondaryMultipleApplication) {
5
+ if (secondaryMultipleApplication === void 0) { secondaryMultipleApplication = false; }
5
6
  this.id = id;
6
7
  this.code = code;
7
8
  this.name = name;
@@ -17,6 +18,7 @@ var Prestation = /** @class */ (function () {
17
18
  this.state = state;
18
19
  this.categoryCode = categoryCode;
19
20
  this.availableOnline = availableOnline;
21
+ this.secondaryMultipleApplication = secondaryMultipleApplication;
20
22
  }
21
23
  return Prestation;
22
24
  }());
package/index.ts CHANGED
@@ -126,6 +126,7 @@ export {
126
126
  ProductType,
127
127
  RegistrationState,
128
128
  RoleType,
129
+ SecondaryPartsApplicationType,
129
130
  SlotAlgorithm,
130
131
  SubscriptionPaymentInterval,
131
132
  SubscriptionState,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@movalib/movalib-commons",
3
- "version": "1.64.9",
3
+ "version": "1.65.0",
4
4
  "description": "Bibliothèque d'objets communs à l'ensemble des projets React de Movalib",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -14,7 +14,16 @@ export enum SubscriptionState {
14
14
  PAUSED = "PAUSED",
15
15
  CANCELED = "CANCELED",
16
16
  }
17
-
17
+ export enum SecondaryPartsApplicationType {
18
+ HOOD = "HOOD",
19
+ ROOF = "ROOF",
20
+ DOOR = "DOOR",
21
+ FENDER = "FENDER",
22
+ JAMB = "JAMB",
23
+ UNDERBODY = "UNDERBODY",
24
+ BUMPER = "BUMPER",
25
+ TRUNK = "TRUNK",
26
+ }
18
27
  export enum CountryCode {
19
28
  FR = "FR",
20
29
  }
@@ -239,7 +248,7 @@ export enum QuoteState {
239
248
  QUOTE_SENT = "QUOTE_SENT",
240
249
  QUOTE_ACCEPTED = "QUOTE_ACCEPTED",
241
250
  QUOTE_REJECTED = "QUOTE_REJECTED",
242
- QUOTE_CANCELLED = "CANCELLED"
251
+ QUOTE_CANCELLED = "CANCELLED",
243
252
  }
244
253
 
245
254
  export enum DocumentType {
@@ -1,8 +1,14 @@
1
1
  import parsePhoneNumberFromString from "libphonenumber-js/max";
2
2
  import { CSSProperties } from "react";
3
+ import Operation from "../models/Operation";
3
4
  import Schedule from "../models/Schedule";
4
5
  import VehicleTire from "../models/VehicleTire";
5
- import { DayOfWeek, PartsApplicationType, VehiclePlateFormat } from "./Enums";
6
+ import {
7
+ DayOfWeek,
8
+ PartsApplicationType,
9
+ SecondaryPartsApplicationType,
10
+ VehiclePlateFormat,
11
+ } from "./Enums";
6
12
  import { MovaFormField, MovaInterval } from "./Types";
7
13
 
8
14
  export const getApplicationsShortLabels = (
@@ -278,6 +284,29 @@ export const getApplicationShortLabel = (
278
284
  return "";
279
285
  };
280
286
 
287
+ export const getApplicationSecondaryLabel = (
288
+ secondaryApplication: SecondaryPartsApplicationType
289
+ ): string => {
290
+ switch (secondaryApplication) {
291
+ case SecondaryPartsApplicationType.HOOD:
292
+ return "Capot";
293
+ case SecondaryPartsApplicationType.ROOF:
294
+ return "Toit";
295
+ case SecondaryPartsApplicationType.DOOR:
296
+ return "Portière";
297
+ case SecondaryPartsApplicationType.TRUNK:
298
+ return "Coffre";
299
+ case SecondaryPartsApplicationType.FENDER:
300
+ return "Aile";
301
+ case SecondaryPartsApplicationType.JAMB:
302
+ return "Montant";
303
+ case SecondaryPartsApplicationType.UNDERBODY:
304
+ return "Bas de caisse";
305
+ case SecondaryPartsApplicationType.BUMPER:
306
+ return "Pare-chocs";
307
+ }
308
+ };
309
+
281
310
  export const flexEnd: CSSProperties = {
282
311
  display: "flex",
283
312
  justifyContent: "end",
@@ -294,12 +323,14 @@ export const isEmpty = (data: Object): boolean => {
294
323
  return Object.keys(data).length === 0;
295
324
  };
296
325
 
297
- export const formatVehiclePlate = (input: string | undefined, isForeignPlate: boolean): string => {
326
+ export const formatVehiclePlate = (
327
+ input: string | undefined,
328
+ isForeignPlate: boolean
329
+ ): string => {
298
330
  if (input) {
299
-
300
331
  let plateFormat: VehiclePlateFormat | null = null;
301
332
 
302
- if(isForeignPlate) {
333
+ if (isForeignPlate) {
303
334
  // Plaque étrangère
304
335
  plateFormat = VehiclePlateFormat.FOREIGN;
305
336
  } else if (/^[A-Za-z]/.test(input)) {
@@ -338,7 +369,6 @@ export const formatVehiclePlate = (input: string | undefined, isForeignPlate: bo
338
369
 
339
370
  case VehiclePlateFormat.FOREIGN: {
340
371
  // On retourne la plaque telle qu'enregistrée par l'utilisateur, ras
341
-
342
372
  }
343
373
  }
344
374
  return cleanedInput;
@@ -397,3 +427,175 @@ export const validateField = (
397
427
  return { value: "", error: "", isValid: true };
398
428
  }
399
429
  };
430
+
431
+ function shortFromApplication(app: string): string {
432
+ const A = (app || "").toUpperCase();
433
+ const has = (s: string) => A.includes(s);
434
+ if (has("FT") && has("LT")) return "AVG";
435
+ if (has("FT") && has("RT")) return "AVD";
436
+ if (has("RR") && has("LT")) return "ARG";
437
+ if (has("RR") && has("RT")) return "ARD";
438
+ if (has("FT")) return "AV";
439
+ if (has("RR")) return "AR";
440
+ if (has("LT")) return "G";
441
+ if (has("RT")) return "D";
442
+ return "";
443
+ }
444
+
445
+ const CATEGORY: Record<string, { title: string; useApp: boolean }> = {
446
+ DOOR: { title: "PORTE", useApp: true },
447
+ FENDER: { title: "AILE", useApp: true },
448
+ JAMB: { title: "MONTANT", useApp: true },
449
+ UNDERBODY: { title: "BAS DE CAISSE", useApp: true },
450
+ BUMPER: { title: "PARE-CHOCS", useApp: true },
451
+ HOOD: { title: "CAPOT", useApp: false }, // pas de position ni (xN)
452
+ TRUNK: { title: "COFFRE", useApp: false },
453
+ ROOF: { title: "TOIT", useApp: false },
454
+ };
455
+
456
+ // Discriminated union pour bien typer les groupes
457
+ type GroupWithApp = {
458
+ kind: "withApp";
459
+ key: string;
460
+ title: string;
461
+ counts: Map<string, number>;
462
+ };
463
+ type GroupSingle = {
464
+ kind: "single";
465
+ key: string;
466
+ title: string;
467
+ seen: boolean;
468
+ };
469
+ type Group = GroupWithApp | GroupSingle;
470
+
471
+ export function buildSelectedOperationsLabel(
472
+ selectedOperationIds: number[],
473
+ allOperations: Operation[],
474
+ options: { prestationName?: string } = {}
475
+ ): string {
476
+ const { prestationName } = options;
477
+
478
+ const byId = new Map<number, Operation>(allOperations.map((o) => [o.id, o]));
479
+ const groups = new Map<string, Group>(); // key = secondaryApplication UPPER
480
+
481
+ for (const id of selectedOperationIds) {
482
+ const op = byId.get(id);
483
+ if (!op) continue;
484
+
485
+ const key = (op.secondaryApplication || "OTHER").toUpperCase();
486
+ const cfg = CATEGORY[key] ?? { title: key, useApp: true };
487
+
488
+ if (!groups.has(key)) {
489
+ groups.set(
490
+ key,
491
+ cfg.useApp
492
+ ? {
493
+ kind: "withApp",
494
+ key,
495
+ title: cfg.title,
496
+ counts: new Map<string, number>(),
497
+ }
498
+ : { kind: "single", key, title: cfg.title, seen: false }
499
+ );
500
+ }
501
+
502
+ const g = groups.get(key)!;
503
+
504
+ if (g.kind === "withApp") {
505
+ const label =
506
+ shortFromApplication(op.application as string) || op.application || "";
507
+ if (label) g.counts.set(label, (g.counts.get(label) ?? 0) + 1);
508
+ } else {
509
+ g.seen = true; // HOOD/TRUNK/ROOF -> présent une fois, sans compteur
510
+ }
511
+ }
512
+
513
+ // Ordre des catégories dans le rendu final
514
+ const desiredOrder = [
515
+ "DOOR",
516
+ "FENDER",
517
+ "HOOD",
518
+ "BUMPER",
519
+ "TRUNK",
520
+ "ROOF",
521
+ "JAMB",
522
+ "UNDERBODY",
523
+ ];
524
+ const weight = (key: string) => {
525
+ const idx = desiredOrder.indexOf(key);
526
+ return idx === -1 ? Number.MAX_SAFE_INTEGER : idx;
527
+ };
528
+
529
+ // Construire les segments
530
+ const segments: string[] = [];
531
+
532
+ for (const g of Array.from(groups.values()).sort(
533
+ (a, b) => weight(a.key) - weight(b.key)
534
+ )) {
535
+ if (g.kind === "withApp") {
536
+ const order = ["AV", "AR", "AVG", "AVD", "ARG", "ARD", "G", "D"];
537
+ const parts = Array.from(g.counts.entries())
538
+ .sort((a, b) => order.indexOf(a[0]) - order.indexOf(b[0]))
539
+ .map(([lbl, n]) => (n > 1 ? `${lbl} (x${n})` : lbl));
540
+ if (parts.length) segments.push(`${g.title} ${parts.join(" + ")}`);
541
+ } else {
542
+ if (g.seen) segments.push(g.title); // capot / toit / coffre (sans position, sans xN)
543
+ }
544
+ }
545
+
546
+ return [prestationName, ...segments].filter(Boolean).join(" , ");
547
+ }
548
+
549
+ export function hasSecondaryApplication(
550
+ items: Operation[],
551
+ ids: number[],
552
+ needle: string,
553
+ caseInsensitive = false
554
+ ): boolean {
555
+ const byId = new Map<number, Operation>(items.map((it) => [it.id, it]));
556
+ const target = caseInsensitive ? needle.toLowerCase() : needle;
557
+
558
+ for (const id of ids) {
559
+ const it = byId.get(id);
560
+ if (!it) continue;
561
+ const value = (it.secondaryApplication ?? "") as string;
562
+ if ((caseInsensitive ? value.toLowerCase() : value) === target) return true;
563
+ }
564
+ return false;
565
+ }
566
+
567
+ const ORDER = ["AVG", "AVD", "ARG", "ARD", "AV", "AR", "G", "D"];
568
+
569
+ export function buildPositionsLabelFromShorts(
570
+ selectedOperationIds: number[],
571
+ allOperations: Operation[]
572
+ ): string {
573
+ // index
574
+ const byId = new Map<number, Operation>(allOperations.map((o) => [o.id, o]));
575
+
576
+ // collecte des tokens (AV, AR, AVG, …)
577
+ const tokens = new Set<string>();
578
+
579
+ for (const id of selectedOperationIds) {
580
+ const appCode = byId.get(id)?.application?.toUpperCase();
581
+ if (!appCode) continue;
582
+
583
+ const appEnum = appCode as PartsApplicationType;
584
+ if (!appEnum) continue;
585
+
586
+ const short = getApplicationShortLabel(appEnum); // ex: "AV + AR" ou "AVG"
587
+ if (!short) continue;
588
+
589
+ // ⚠️ splitter par " + " (pas par caractère) pour éviter "a + v"
590
+ for (const t of short.split(" + ")) {
591
+ const s = t.trim();
592
+ if (s) tokens.add(s);
593
+ }
594
+ }
595
+
596
+ // tri esthétique
597
+ const parts = Array.from(tokens).sort(
598
+ (a, b) => ORDER.indexOf(a) - ORDER.indexOf(b)
599
+ );
600
+ return parts.join(" + ");
601
+ }
@@ -71,6 +71,7 @@ export default class Garage {
71
71
  establishmentRegistrationNumber?: string;
72
72
  reopeningDate?: Date;
73
73
  targetMargin?: number;
74
+ onlyBilling?: boolean;
74
75
  constructor(
75
76
  id: string,
76
77
  adminId: string,
@@ -106,7 +107,8 @@ export default class Garage {
106
107
  quoteRequestStart?: Date,
107
108
  reopeningDate?: Date,
108
109
  targetMargin?: number,
109
- demoBillingActive?: boolean
110
+ demoBillingActive?: boolean,
111
+ onlyBilling: boolean = false
110
112
  ) {
111
113
  this.id = id;
112
114
  this.adminId = adminId;
@@ -143,5 +145,6 @@ export default class Garage {
143
145
  this.reopeningDate = reopeningDate;
144
146
  this.targetMargin = targetMargin;
145
147
  this.demoBillingActive = demoBillingActive;
148
+ this.onlyBilling = onlyBilling;
146
149
  }
147
150
  }
@@ -1,23 +1,38 @@
1
- import { PartsApplicationType } from "../helpers/Enums";
1
+ import {
2
+ PartsApplicationType,
3
+ SecondaryPartsApplicationType,
4
+ } from "../helpers/Enums";
2
5
  import Product from "./Product";
3
6
 
4
7
  export default class Operation {
8
+ // Properties
9
+ id: number;
10
+ code: string;
11
+ name: string;
12
+ description: string;
13
+ prestationId: number;
14
+ // Eventuelle application de l'opération (avant, arrière)
15
+ application?: PartsApplicationType;
16
+ products?: Product[];
17
+ secondaryApplication?: SecondaryPartsApplicationType;
5
18
 
6
- // Properties
7
- id: number;
8
- code: string;
9
- name: string;
10
- description: string;
11
- // Eventuelle application de l'opération (avant, arrière)
12
- application?: PartsApplicationType;
13
- products?: Product[];
14
-
15
- constructor(id:number, code: string, name:string, description: string, application: PartsApplicationType, products: Product[]) {
16
- this.id = id;
17
- this.code = code;
18
- this.name = name;
19
- this.description = description;
20
- this.application = application;
21
- this.products = products;
22
- }
23
- }
19
+ constructor(
20
+ id: number,
21
+ code: string,
22
+ name: string,
23
+ description: string,
24
+ application: PartsApplicationType,
25
+ products: Product[],
26
+ prestationId: number,
27
+ secondaryApplication?: SecondaryPartsApplicationType
28
+ ) {
29
+ this.prestationId = prestationId;
30
+ this.id = id;
31
+ this.code = code;
32
+ this.name = name;
33
+ this.description = description;
34
+ this.application = application;
35
+ this.products = products;
36
+ this.secondaryApplication = secondaryApplication;
37
+ }
38
+ }
@@ -2,57 +2,73 @@ import { PrestationState } from "../helpers/Enums";
2
2
  import Operation from "./Operation";
3
3
 
4
4
  export default class Prestation {
5
+ // Properties
6
+ id: number;
7
+ code: string;
8
+ name: string;
9
+ description: string;
10
+ category: string;
11
+ /**
12
+ * Durée d'immobilisation pour cette prestation (en jours)
13
+ */
14
+ downtime: number;
15
+ /**
16
+ * Délai avant prise de rendez-vous pour cette prestation (en jours)
17
+ */
18
+ appointmentDelay: number;
19
+ /**
20
+ * Opérations inhérentes à cette prestation
21
+ */
22
+ operations?: Operation[];
23
+ /**
24
+ * La notion de position (ou d'ordre) peut être utile à l'affichage d'une liste de prestation par exemple
25
+ */
26
+ position: number;
27
+ availableOnline: boolean;
5
28
 
6
- // Properties
7
- id: number;
8
- code: string;
9
- name: string;
10
- description: string;
11
- category: string;
12
- /**
13
- * Durée d'immobilisation pour cette prestation (en jours)
14
- */
15
- downtime: number;
16
- /**
17
- * Délai avant prise de rendez-vous pour cette prestation (en jours)
18
- */
19
- appointmentDelay: number;
20
- /**
21
- * Opérations inhérentes à cette prestation
22
- */
23
- operations?: Operation[];
24
- /**
25
- * La notion de position (ou d'ordre) peut être utile à l'affichage d'une liste de prestation par exemple
26
- */
27
- position: number;
28
- availableOnline: boolean;
29
+ active: boolean;
29
30
 
30
- active:boolean;
31
+ state: PrestationState;
31
32
 
32
- state: PrestationState;
33
+ multipleApplication: boolean;
33
34
 
34
- multipleApplication: boolean;
35
+ operationsVisible: boolean;
36
+ categoryCode: string;
37
+ secondaryMultipleApplication: boolean;
35
38
 
36
- operationsVisible: boolean;
37
- categoryCode: string;
38
-
39
- constructor(id:number, code: string, name:string, description: string, category:string,
40
- downtime:number, appointmentDelay: number, position: number, active: boolean, state: PrestationState,
41
- multipleApplication: boolean, operationsVisible: boolean,categoryCode: string, availableOnline:boolean, operations?: Operation[]) {
42
- this.id = id;
43
- this.code = code;
44
- this.name = name;
45
- this.description = description;
46
- this.category = category;
47
- this.downtime = downtime;
48
- this.appointmentDelay = appointmentDelay;
49
- this.position = position;
50
- this.active = active;
51
- this.multipleApplication = multipleApplication;
52
- this.operationsVisible = operationsVisible;
53
- this.operations = operations;
54
- this.state = state;
55
- this.categoryCode = categoryCode;
56
- this.availableOnline = availableOnline;
57
- }
58
- }
39
+ constructor(
40
+ id: number,
41
+ code: string,
42
+ name: string,
43
+ description: string,
44
+ category: string,
45
+ downtime: number,
46
+ appointmentDelay: number,
47
+ position: number,
48
+ active: boolean,
49
+ state: PrestationState,
50
+ multipleApplication: boolean,
51
+ operationsVisible: boolean,
52
+ categoryCode: string,
53
+ availableOnline: boolean,
54
+ operations?: Operation[],
55
+ secondaryMultipleApplication: boolean = false
56
+ ) {
57
+ this.id = id;
58
+ this.code = code;
59
+ this.name = name;
60
+ this.description = description;
61
+ this.category = category;
62
+ this.downtime = downtime;
63
+ this.appointmentDelay = appointmentDelay;
64
+ this.position = position;
65
+ this.active = active;
66
+ this.multipleApplication = multipleApplication;
67
+ this.operationsVisible = operationsVisible;
68
+ this.operations = operations;
69
+ this.state = state;
70
+ this.categoryCode = categoryCode;
71
+ this.availableOnline = availableOnline;
72
+ this.secondaryMultipleApplication = secondaryMultipleApplication;
73
+ }
74
+ }
package/webpack.config.js CHANGED
@@ -1,53 +1,53 @@
1
- const HtmlWebpackPlugin = require('html-webpack-plugin');
2
- const path = require('path');
3
- const webpack = require('webpack');
1
+ const HtmlWebpackPlugin = require("html-webpack-plugin");
2
+ const path = require("path");
3
+ const webpack = require("webpack");
4
4
 
5
5
  module.exports = {
6
- mode: 'development', // ou 'production' ou 'none'
7
- module: {
8
- rules: [
9
- {
10
- test: /\.css$/i,
11
- use: ['style-loader', 'css-loader'],
12
- },
13
- {
14
- test: /\.tsx?$/,
15
- use: 'ts-loader',
16
- exclude: /node_modules/,
17
- },
6
+ mode: "development", // ou 'production' ou 'none'
7
+ module: {
8
+ rules: [
9
+ {
10
+ test: /\.css$/i,
11
+ use: ["style-loader", "css-loader"],
12
+ },
13
+ {
14
+ test: /\.tsx?$/,
15
+ use: "ts-loader",
16
+ exclude: /node_modules/,
17
+ },
18
+ {
19
+ test: /\.(png|jpg|gif|svg)$/,
20
+ use: [
18
21
  {
19
- test: /\.(png|jpg|gif|svg)$/,
20
- use: [
21
- {
22
- loader: 'file-loader',
23
- options: {
24
- name: '[name].[ext]',
25
- outputPath: 'images/',
26
- },
27
- },
28
- ],
22
+ loader: "file-loader",
23
+ options: {
24
+ name: "[name].[ext]",
25
+ outputPath: "images/",
26
+ },
29
27
  },
30
- ],
28
+ ],
31
29
  },
32
- resolve: {
33
- extensions: ['.tsx', '.ts', '.js'],
34
- },
35
- plugins: [
36
- new HtmlWebpackPlugin({
37
- template: path.resolve(__dirname, 'public', 'index.html'), // Chemin vers votre fichier HTML de base
38
- }),
39
- new webpack.DefinePlugin({
40
- 'process.env.REACT_APP_API_URL': JSON.stringify(process.env.REACT_APP_API_URL),
41
- 'process.env.REACT_APP_MOVALIB_APP_URL': JSON.stringify(process.env.REACT_APP_MOVALIB_APP_URL)
42
- }),
43
- ],
30
+ ],
31
+ },
32
+ resolve: {
33
+ extensions: [".tsx", ".ts", ".js"],
34
+ },
35
+ plugins: [
36
+ new HtmlWebpackPlugin({
37
+ template: path.resolve(__dirname, "public", "index.html"), // Chemin vers votre fichier HTML de base
38
+ }),
39
+ new webpack.DefinePlugin({
40
+ "process.env.REACT_APP_API_URL": JSON.stringify(
41
+ process.env.REACT_APP_API_URL
42
+ ),
43
+ "process.env.REACT_APP_MOVALIB_APP_URL": JSON.stringify(
44
+ process.env.REACT_APP_MOVALIB_APP_URL
45
+ ),
46
+ }),
47
+ ],
44
48
 
45
- devServer: {
46
- https: {
47
- cert: path.resolve(__dirname, '/Users/Dimitri/localhost.pem'),
48
- key: path.resolve(__dirname, '/Users/Dimitri/localhost-key.pem'),
49
- },
50
- open: true,
51
- port: 8080, // ou un autre port si nécessaire
52
- },
53
- };
49
+ devServer: {
50
+ open: true,
51
+ port: 8080, // ou un autre port si nécessaire
52
+ },
53
+ };