@movalib/movalib-commons 1.59.39 → 1.60.1

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/devIndex.tsx CHANGED
@@ -26,7 +26,6 @@ import GaragePLV from './src/GaragePLV';
26
26
  import AddressFields from './src/AddressFields';
27
27
  import IbanInput from './src/IbanInput';
28
28
  import GenderSelector from './src/GenderSelector';
29
- import {VehicleTire} from "./index";
30
29
  import MovaVehicleTireField from "./src/MovaVehicleTireField";
31
30
 
32
31
  const App = () => {
@@ -27,7 +27,9 @@ var DialogForgotPassword = function (_a) {
27
27
  return ((0, jsx_runtime_1.jsxs)(material_1.Dialog, __assign({ open: openForgotPassword, onClose: handleOnClose, "aria-labelledby": "forgot-password-dialog-title", "aria-describedby": "forgot-password-dialog-description" }, { children: [(0, jsx_runtime_1.jsx)(material_1.DialogTitle, __assign({ id: "forgot-password-title" }, { children: "R\u00E9cup\u00E9ration du mot de passe" })), (0, jsx_runtime_1.jsxs)(material_1.DialogContent, { children: [(0, jsx_runtime_1.jsx)(material_1.DialogContentText, __assign({ id: "forgot-password-dialog-description", sx: { mb: 2 } }, { children: movaAppType === Enums_1.MovaAppType.GARAGE ?
28
28
  "Saisissez votre email pour procéder à la réinitialisation de votre mot de passe."
29
29
  :
30
- "Saisissez votre n° de téléphone ou votre email pour procéder à la réinitialisation de votre mot de passe." })), (0, jsx_runtime_1.jsx)(material_1.TextField, { margin: "normal", autoFocus: true, required: true, fullWidth: true, id: movaAppType === Enums_1.MovaAppType.GARAGE ? "email" : "phoneNumberEmail", label: movaAppType === Enums_1.MovaAppType.GARAGE ? "Adresse email" : "N° de téléphone ou adresse email", name: movaAppType === Enums_1.MovaAppType.GARAGE ? "email" : "phoneNumberEmail", autoComplete: "email", onChange: function (e) { return handleInputChange(e); }, value: movaAppType === Enums_1.MovaAppType.GARAGE ? form.email.value : form.phoneNumberEmail.value, error: movaAppType === Enums_1.MovaAppType.GARAGE ? !form.email.isValid : !form.phoneNumberEmail.isValid, helperText: movaAppType === Enums_1.MovaAppType.GARAGE ? form.email.error : form.phoneNumberEmail.error })] }), (0, jsx_runtime_1.jsx)(material_1.DialogActions, { children: (0, jsx_runtime_1.jsx)(material_1.Button, __assign({ onClick: function (e) { return handleSubmitForgotPassword(e); }, color: "primary", disabled: movaAppType === Enums_1.MovaAppType.GARAGE ? !(form.email.value && (0, Validator_1.validateEmail)(form.email.value))
30
+ "Saisissez votre n° de téléphone ou votre email pour procéder à la réinitialisation de votre mot de passe." })), (0, jsx_runtime_1.jsx)(material_1.TextField, { margin: "normal", autoFocus: true, required: true, fullWidth: true, id: movaAppType === Enums_1.MovaAppType.GARAGE ? "email" : "phoneNumberEmail", label: movaAppType === Enums_1.MovaAppType.GARAGE ? "Adresse email" : "N° de téléphone ou adresse email", name: movaAppType === Enums_1.MovaAppType.GARAGE ? "email" : "phoneNumberEmail", autoComplete: "email", onChange: function (e) { return handleInputChange(e); }, value: movaAppType === Enums_1.MovaAppType.GARAGE ? form.email.value : form.phoneNumberEmail.value, error: movaAppType === Enums_1.MovaAppType.GARAGE ? !form.email.isValid : !form.phoneNumberEmail.isValid, helperText: movaAppType === Enums_1.MovaAppType.GARAGE
31
+ ? form.email.error
32
+ : form.phoneNumberEmail.error || "Saisir l’indicatif pour un numéro étranger (ex : +32 …)" })] }), (0, jsx_runtime_1.jsx)(material_1.DialogActions, { children: (0, jsx_runtime_1.jsx)(material_1.Button, __assign({ onClick: function (e) { return handleSubmitForgotPassword(e); }, color: "primary", disabled: movaAppType === Enums_1.MovaAppType.GARAGE ? !(form.email.value && (0, Validator_1.validateEmail)(form.email.value))
31
33
  : !(form.phoneNumberEmail.value), sx: { ml: 1 } }, { children: "Envoyer ma demande" })) })] })));
32
34
  };
33
35
  exports.default = DialogForgotPassword;
@@ -1,7 +1,7 @@
1
- import { FunctionComponent, ReactNode } from "react";
2
1
  import { AlertColor } from "@mui/material";
3
- import { MovaLoginForm } from "./helpers/Types";
2
+ import { FunctionComponent, ReactNode } from "react";
4
3
  import { MovaAppType } from "./helpers/Enums";
4
+ import { MovaLoginForm } from "./helpers/Types";
5
5
  /**
6
6
  * Propriétés du composant
7
7
  * movaAppType : type d'application Movalib au sein de laquelle le composant est injectée
@@ -51,25 +51,26 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
51
51
  };
52
52
  Object.defineProperty(exports, "__esModule", { value: true });
53
53
  var jsx_runtime_1 = require("react/jsx-runtime");
54
- var react_1 = require("react");
54
+ var Visibility_1 = __importDefault(require("@mui/icons-material/Visibility"));
55
+ var VisibilityOff_1 = __importDefault(require("@mui/icons-material/VisibilityOff"));
55
56
  var lab_1 = require("@mui/lab");
56
- var logo_large_border_png_1 = __importDefault(require("./assets/images/logo/logo_large_border.png"));
57
- var logo_pro_large_border_png_1 = __importDefault(require("./assets/images/logo/logo_pro_large_border.png"));
57
+ var material_1 = require("@mui/material");
58
+ var InputAdornment_1 = __importDefault(require("@mui/material/InputAdornment"));
59
+ var libphonenumber_js_1 = require("libphonenumber-js");
60
+ var react_1 = require("react");
61
+ var react_router_dom_1 = require("react-router-dom");
62
+ var DialogForgotPassword_1 = __importDefault(require("./DialogForgotPassword"));
63
+ var MovaCopyright_1 = __importDefault(require("./MovaCopyright"));
64
+ var leaf_green_large_png_1 = __importDefault(require("./assets/images/leaf_green_large.png"));
65
+ var leaf_pink_large_png_1 = __importDefault(require("./assets/images/leaf_pink_large.png"));
58
66
  var logo_admin_large_png_1 = __importDefault(require("./assets/images/logo/logo_admin_large.png"));
67
+ var logo_large_border_png_1 = __importDefault(require("./assets/images/logo/logo_large_border.png"));
59
68
  var logo_large_dm_png_1 = __importDefault(require("./assets/images/logo/logo_large_dm.png"));
69
+ var logo_pro_large_border_png_1 = __importDefault(require("./assets/images/logo/logo_pro_large_border.png"));
60
70
  var logo_pro_large_dm_png_1 = __importDefault(require("./assets/images/logo/logo_pro_large_dm.png"));
61
- var leaf_green_large_png_1 = __importDefault(require("./assets/images/leaf_green_large.png"));
62
- var leaf_pink_large_png_1 = __importDefault(require("./assets/images/leaf_pink_large.png"));
63
- var material_1 = require("@mui/material");
64
- var MovaCopyright_1 = __importDefault(require("./MovaCopyright"));
65
71
  var Enums_1 = require("./helpers/Enums");
66
- var Validator_1 = require("./helpers/Validator");
67
72
  var Tools_1 = require("./helpers/Tools");
68
- var react_router_dom_1 = require("react-router-dom");
69
- var InputAdornment_1 = __importDefault(require("@mui/material/InputAdornment"));
70
- var Visibility_1 = __importDefault(require("@mui/icons-material/Visibility"));
71
- var VisibilityOff_1 = __importDefault(require("@mui/icons-material/VisibilityOff"));
72
- var DialogForgotPassword_1 = __importDefault(require("./DialogForgotPassword"));
73
+ var Validator_1 = require("./helpers/Validator");
73
74
  // Permet de centrer le contenu de l'application
74
75
  var styles = {
75
76
  display: 'flex',
@@ -125,8 +126,23 @@ var MovaLogin = function (_a) {
125
126
  // Validator pour l'email
126
127
  newForm.email = (0, Tools_1.validateField)(form.email, Validator_1.validateEmail, 'Adresse email invalide');
127
128
  }
129
+ /* if(movaAppType === MovaAppType.INDIVIDUAL){
130
+ newForm.phoneNumberEmail = validateField(form.phoneNumberEmail, value => !!value, 'Champ obligatoire');
131
+ } */
128
132
  if (movaAppType === Enums_1.MovaAppType.INDIVIDUAL) {
129
- newForm.phoneNumberEmail = (0, Tools_1.validateField)(form.phoneNumberEmail, function (value) { return !!value; }, 'Champ obligatoire');
133
+ newForm.phoneNumberEmail = (0, Tools_1.validateField)(form.phoneNumberEmail, function (value) {
134
+ var _a;
135
+ if (!value)
136
+ return false;
137
+ // Si c’est un email valide => OK
138
+ if ((0, Validator_1.validateEmail)(value))
139
+ return true;
140
+ // Remplace 00 par + si le numéro commence par 00 (pour compatibilité avec libphonenumber-js)
141
+ var normalizedValue = value.startsWith('00') ? value.replace(/^00/, '+') : value;
142
+ // Si le numéro commence par + ou 00, tentative de parsing direct. Format local, Pays par défaut : FR
143
+ var phoneNumber = (0, libphonenumber_js_1.parsePhoneNumberFromString)(normalizedValue, normalizedValue.startsWith('+') || normalizedValue.startsWith('00') ? undefined : 'FR');
144
+ return (_a = phoneNumber === null || phoneNumber === void 0 ? void 0 : phoneNumber.isValid()) !== null && _a !== void 0 ? _a : false;
145
+ }, 'Email ou numéro de téléphone invalide');
130
146
  }
131
147
  newForm.password = (0, Tools_1.validateField)(form.password, function (value) { return !!value; }, 'Champ obligatoire');
132
148
  // Validator pour le mot de passe
@@ -217,20 +233,23 @@ var MovaLogin = function (_a) {
217
233
  </Dialog>
218
234
  );
219
235
  } */
220
- return ((0, jsx_runtime_1.jsxs)("div", __assign({ style: styles }, { children: [(0, jsx_runtime_1.jsx)("img", { src: leaf_green_large_png_1.default, style: { position: 'fixed',
236
+ return ((0, jsx_runtime_1.jsxs)("div", __assign({ style: styles }, { children: [(0, jsx_runtime_1.jsx)("img", { src: leaf_green_large_png_1.default, style: {
237
+ position: 'fixed',
221
238
  float: 'left',
222
239
  width: '250px',
223
240
  height: '400px',
224
241
  top: '-20%',
225
242
  left: '0%',
226
243
  opacity: '0.3',
227
- zIndex: -8 }, alt: 'Feuille Verte Movalib' }), (0, jsx_runtime_1.jsxs)(material_1.Container, __assign({ component: "main", maxWidth: "xs" }, { children: [(0, jsx_runtime_1.jsx)(material_1.CssBaseline, {}), (0, jsx_runtime_1.jsxs)(material_1.Box, __assign({ sx: {
244
+ zIndex: -8
245
+ }, alt: 'Feuille Verte Movalib' }), (0, jsx_runtime_1.jsxs)(material_1.Container, __assign({ component: "main", maxWidth: "xs" }, { children: [(0, jsx_runtime_1.jsx)(material_1.CssBaseline, {}), (0, jsx_runtime_1.jsxs)(material_1.Box, __assign({ sx: {
228
246
  marginTop: 6,
229
247
  display: 'flex',
230
248
  flexDirection: 'column',
231
249
  alignItems: 'center',
232
250
  } }, { children: [(0, jsx_runtime_1.jsx)("img", { src: getMovaLogo(), style: { width: '80%' } }), headerText && (0, jsx_runtime_1.jsx)(material_1.Typography, __assign({ variant: "button", sx: { pt: 3, width: '100%' } }, { children: headerText })), (0, jsx_runtime_1.jsx)("br", {})] })), (0, jsx_runtime_1.jsxs)(material_1.Box, __assign({ component: "form", onSubmit: handleSubmit, noValidate: true, sx: { mt: 1 } }, { children: [movaAppType === Enums_1.MovaAppType.INDIVIDUAL &&
233
- (0, jsx_runtime_1.jsx)(material_1.TextField, { margin: "normal", required: true, fullWidth: true, id: "phoneNumberEmail", label: "N\u00B0 de t\u00E9l\u00E9phone ou adresse email", name: "phoneNumberEmail", autoFocus: true, onChange: function (e) { return handleInputChange(e); }, value: form.phoneNumberEmail.value, error: !form.phoneNumberEmail.isValid, helperText: form.phoneNumberEmail.error, sx: {
251
+ (0, jsx_runtime_1.jsx)(material_1.TextField, { margin: "normal", required: true, fullWidth: true, id: "phoneNumberEmail", label: "N\u00B0 de t\u00E9l\u00E9phone ou adresse email", name: "phoneNumberEmail", autoFocus: true, onChange: function (e) { return handleInputChange(e); }, value: form.phoneNumberEmail.value, error: !form.phoneNumberEmail.isValid, helperText: form.phoneNumberEmail.error ||
252
+ "Saisir l’indicatif pour un numéro étranger (ex : +32 …)", sx: {
234
253
  '& .MuiOutlinedInput-notchedOutline': {
235
254
  borderColor: darkMode ? 'white' : 'default', // Couleur de la bordure
236
255
  }
@@ -246,13 +265,15 @@ var MovaLogin = function (_a) {
246
265
  borderColor: darkMode ? 'white' : 'default', // Couleur de la bordure
247
266
  }
248
267
  } }), (0, jsx_runtime_1.jsx)(material_1.FormControlLabel, { control: (0, jsx_runtime_1.jsx)(material_1.Checkbox, { value: "remember", color: "primary" }), label: "Se souvenir de moi" }), (0, jsx_runtime_1.jsx)(lab_1.LoadingButton, __assign({ loading: loading, type: "submit", fullWidth: true, variant: "contained", sx: { mt: 3, mb: 2, backgroundColor: darkMode ? theme.palette.primary.dark : theme.palette.primary.main } }, { children: (0, jsx_runtime_1.jsx)("span", { children: "Se connecter" }) })), movaAppType === Enums_1.MovaAppType.INDIVIDUAL && (0, jsx_runtime_1.jsx)(material_1.Button, __assign({ fullWidth: true, variant: "outlined", onClick: function (e) { return handleOnClickSignUp(); }, sx: { mb: 2, color: theme.palette.primary.dark } }, { children: (0, jsx_runtime_1.jsx)("span", { children: "CR\u00C9ER MON COMPTE" }) })), alertMessage && alertSeverity && (0, jsx_runtime_1.jsx)(material_1.Alert, __assign({ severity: alertSeverity, sx: { mb: 2 } }, { children: alertMessage })), (0, jsx_runtime_1.jsx)(material_1.Grid, __assign({ container: true }, { children: (0, jsx_runtime_1.jsx)(material_1.Grid, __assign({ item: true, xs: true }, { children: (0, jsx_runtime_1.jsx)(material_1.Link, __assign({ variant: "body2", color: "text.secondary", onClick: function (e) { return handleOnClickForgotPassword(); }, sx: { cursor: 'pointer' } }, { children: "Mot de passe oubli\u00E9 ?" })) })) }))] })), (0, jsx_runtime_1.jsx)(MovaCopyright_1.default, { sx: { mt: 8, mb: 1 } }), version && (0, jsx_runtime_1.jsx)(material_1.Typography, __assign({ variant: 'body2', color: theme.palette.grey[200], sx: { textAlign: 'center' } }, { children: version })), openForgotPassword &&
249
- (0, jsx_runtime_1.jsx)(DialogForgotPassword_1.default, { openForgotPassword: openForgotPassword, setOpenForgotPassword: setOpenForgotPassword, movaAppType: movaAppType, form: form, handleInputChange: handleInputChange, handleSubmitForgotPassword: handleSubmitForgotPassword })] })), (0, jsx_runtime_1.jsx)("img", { src: leaf_pink_large_png_1.default, style: { position: 'fixed',
268
+ (0, jsx_runtime_1.jsx)(DialogForgotPassword_1.default, { openForgotPassword: openForgotPassword, setOpenForgotPassword: setOpenForgotPassword, movaAppType: movaAppType, form: form, handleInputChange: handleInputChange, handleSubmitForgotPassword: handleSubmitForgotPassword })] })), (0, jsx_runtime_1.jsx)("img", { src: leaf_pink_large_png_1.default, style: {
269
+ position: 'fixed',
250
270
  float: 'right',
251
271
  width: '250px',
252
272
  height: '400px',
253
273
  bottom: '-20%',
254
274
  right: '0%',
255
275
  opacity: '0.3',
256
- zIndex: '-10' }, alt: 'Feuille Rose Movalib' })] })));
276
+ zIndex: '-10'
277
+ }, alt: 'Feuille Rose Movalib' })] })));
257
278
  };
258
279
  exports.default = MovaLogin;
@@ -70,6 +70,7 @@ var Visibility_1 = __importDefault(require("@mui/icons-material/Visibility"));
70
70
  var VisibilityOff_1 = __importDefault(require("@mui/icons-material/VisibilityOff"));
71
71
  var Info_1 = __importDefault(require("@mui/icons-material/Info"));
72
72
  var UserService_1 = __importDefault(require("./services/UserService"));
73
+ var libphonenumber_js_1 = require("libphonenumber-js");
73
74
  // ATTENTION : s'assurer de la présence des documents suivants à la racine du composant porteur (dossier 'public')
74
75
  var CGUPath = "https://s3.eu-west-3.amazonaws.com/legal.movalib.com/Movalib_CGU.pdf";
75
76
  // Permet de centrer le contenu de l'application
@@ -119,13 +120,20 @@ var MovaSignUp = function (_a) {
119
120
  var fieldValue = e.target.value;
120
121
  // On autorise uniquement les chiffre pour le n° de téléphone
121
122
  if (fieldName == "phoneNumber") {
122
- fieldValue = fieldValue.replace(/[^0-9]/g, '');
123
- // Limiter la longueur à 10 caractères
124
- if (fieldValue.length > 10) {
125
- fieldValue = fieldValue.substring(0, 10);
123
+ // Nettoyage : on autorise chiffres + éventuellement un "+" en début
124
+ var cleaned = fieldValue.trim().replace(/[^\d+]/g, '');
125
+ // Normalisation : 0033... → +33...
126
+ if (cleaned.startsWith('00')) {
127
+ cleaned = cleaned.replace(/^00/, '+');
126
128
  }
127
- if (fieldValue.length === 10) {
128
- UserService_1.default.existsByPhoneNumber(fieldValue).then(function (response) {
129
+ // Parsing avec FR par défaut si local
130
+ var parsed = (0, libphonenumber_js_1.parsePhoneNumberFromString)(cleaned, cleaned.startsWith('+') ? undefined : 'FR');
131
+ // Mise à jour du champ
132
+ if (parsed === null || parsed === void 0 ? void 0 : parsed.isValid()) {
133
+ var e164 = parsed.number; // format +33...
134
+ //fieldValue = e164;
135
+ // Vérification de l'existence du compte
136
+ UserService_1.default.existsByPhoneNumber(e164).then(function (response) {
129
137
  if (response && response.data) {
130
138
  if (response.data.isActive === false) {
131
139
  setUserExist(true);
@@ -143,6 +151,7 @@ var MovaSignUp = function (_a) {
143
151
  });
144
152
  }
145
153
  else {
154
+ // Si numéro invalide ou incomplet, on réinitialise les flags
146
155
  setUserExist(false);
147
156
  setUserIsAlreadyActive(false);
148
157
  }
@@ -254,7 +263,8 @@ var MovaSignUp = function (_a) {
254
263
  '& .MuiOutlinedInput-notchedOutline': {
255
264
  borderColor: darkMode ? 'white' : 'default', // Couleur de la bordure
256
265
  }
257
- } }), usePhoneNumber && (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(material_1.TextField, { type: "tel", margin: "normal", required: true, fullWidth: true, id: "phoneNumber", label: "N\u00B0 de t\u00E9l\u00E9phone", name: "phoneNumber", autoComplete: "tel", disabled: userToEdit && userToEdit.phoneNumber ? true : false, onChange: function (e) { return handleInputChange(e); }, value: userForm.phoneNumber.value, error: Boolean(userForm.phoneNumber.error), helperText: userForm.phoneNumber.error, InputProps: {
266
+ } }), usePhoneNumber && (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(material_1.TextField, { type: "tel", margin: "normal", required: true, fullWidth: true, id: "phoneNumber", label: "N\u00B0 de t\u00E9l\u00E9phone", name: "phoneNumber", autoComplete: "tel", disabled: userToEdit && userToEdit.phoneNumber ? true : false, onChange: function (e) { return handleInputChange(e); }, value: userForm.phoneNumber.value, error: Boolean(userForm.phoneNumber.error), helperText: userForm.phoneNumber.error ||
267
+ "Saisir l’indicatif pour un numéro étranger (ex : +32 …)", InputProps: {
258
268
  endAdornment: ((0, jsx_runtime_1.jsx)(InputAdornment_1.default, __assign({ position: "end" }, { children: !userExist && (0, jsx_runtime_1.jsx)(material_1.IconButton, __assign({ edge: "end", onClick: function () { return setOpenPhoneNumberInfo(!openPhoneNumberInfo); } }, { children: (0, jsx_runtime_1.jsx)(Info_1.default, {}) })) }))),
259
269
  } }), openPhoneNumberInfo && !userExist && (0, jsx_runtime_1.jsx)(material_1.Alert, __assign({ severity: "info", variant: 'standard' }, { children: "Entrez le num\u00E9ro de t\u00E9l\u00E9phone que vous avez utilis\u00E9 pour r\u00E9server, afin de suivre facilement vos rendez-vous." })), userExist && (0, jsx_runtime_1.jsx)(material_1.Alert, __assign({ severity: "success", variant: 'standard' }, { children: "Rendez-vous trouv\u00E9(s) pour ce num\u00E9ro ! Vous pourrez le(s) consulter apr\u00E8s avoir cr\u00E9\u00E9 votre compte." })), userIsAlreadyActive && (0, jsx_runtime_1.jsx)(material_1.Alert, __assign({ severity: "error", sx: { marginTop: '5px' }, variant: 'standard' }, { children: "Il semble qu\u2019un compte existe d\u00E9j\u00E0 avec ce num\u00E9ro. Connectez-vous ou utilisez \"Mot de passe oubli\u00E9\" pour y acc\u00E9der facilement." }))] }), (0, jsx_runtime_1.jsx)(material_1.TextField, { margin: "normal", required: true, fullWidth: true, id: "email", label: "Adresse email", name: "email", autoComplete: "email", disabled: userToEdit && userToEdit.email ? true : false, onChange: function (e) { return handleInputChange(e); }, value: userForm.email.value, error: !userForm.email.isValid, helperText: userForm.email.error, sx: {
260
270
  '& .MuiOutlinedInput-notchedOutline': {
@@ -1,11 +1,12 @@
1
- import VehicleTire from "../models/VehicleTire";
2
- import { MovaFormField, MovaInterval } from "./Types";
3
1
  import { CSSProperties } from "react";
4
- import { DayOfWeek, PartsApplicationType } from "./Enums";
5
2
  import Schedule from "../models/Schedule";
3
+ import VehicleTire from "../models/VehicleTire";
4
+ import { DayOfWeek, PartsApplicationType } from "./Enums";
5
+ import { MovaFormField, MovaInterval } from "./Types";
6
6
  export declare const getApplicationsShortLabels: (applications: PartsApplicationType[] | undefined) => string;
7
7
  export declare const flexStart: CSSProperties;
8
8
  export declare const isSafariOniOS: () => boolean;
9
+ export declare const isInvalidMobileNumber: (phoneNumber?: string) => boolean;
9
10
  export declare const FR_WEEK_DAYS: string[];
10
11
  export declare const getDayOfWeekLabel: (day: DayOfWeek) => string | undefined;
11
12
  export declare const getDayOfWeekIndex: (day: DayOfWeek) => number;
@@ -1,28 +1,67 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateField = exports.formatVehicleTireStr = exports.formatVehicleTire = exports.formatFrenchVehiclePlate = 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.isSafariOniOS = exports.flexStart = exports.getApplicationsShortLabels = void 0;
6
+ exports.validateField = exports.formatVehicleTireStr = exports.formatVehicleTire = exports.formatFrenchVehiclePlate = 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.isInvalidMobileNumber = exports.isSafariOniOS = exports.flexStart = exports.getApplicationsShortLabels = void 0;
7
+ var max_1 = __importDefault(require("libphonenumber-js/max"));
4
8
  var Enums_1 = require("./Enums");
5
9
  var getApplicationsShortLabels = function (applications) {
6
10
  if (!applications) {
7
- return '';
11
+ return "";
8
12
  }
9
- return applications.map(exports.getApplicationShortLabel).join(' + ');
13
+ return applications.map(exports.getApplicationShortLabel).join(" + ");
10
14
  };
11
15
  exports.getApplicationsShortLabels = getApplicationsShortLabels;
12
16
  exports.flexStart = {
13
- display: 'flex',
14
- justifyContent: 'start',
15
- alignItems: 'center'
17
+ display: "flex",
18
+ justifyContent: "start",
19
+ alignItems: "center",
16
20
  };
17
21
  var isSafariOniOS = function () {
18
22
  var userAgent = window.navigator.userAgent;
19
- var iOS = !!userAgent.match(/iPad/i) || !!userAgent.match(/iPhone/i) || !!userAgent.match(/iPod/i);
23
+ var iOS = !!userAgent.match(/iPad/i) ||
24
+ !!userAgent.match(/iPhone/i) ||
25
+ !!userAgent.match(/iPod/i);
20
26
  var webkit = !!userAgent.match(/WebKit/i);
21
27
  var criOS = !!userAgent.match(/CriOS/i);
22
28
  return iOS && webkit && !criOS;
23
29
  };
24
30
  exports.isSafariOniOS = isSafariOniOS;
25
- exports.FR_WEEK_DAYS = ['Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche'];
31
+ var isInvalidMobileNumber = function (phoneNumber) {
32
+ var _a;
33
+ if (phoneNumber === void 0) { phoneNumber = ""; }
34
+ if (!phoneNumber || typeof phoneNumber !== "string")
35
+ return true;
36
+ // Nettoyage : supprime les espaces et convertit "00..." en "+..."
37
+ var cleaned = phoneNumber.replace(/\s+/g, "").replace(/^00/, "+");
38
+ // Si le numéro ne commence pas par +, on assume que c'est un numéro local français
39
+ var cleanedPhoneNumber = cleaned.startsWith("+")
40
+ ? cleaned
41
+ : "+33".concat(cleaned.replace(/^0/, ""));
42
+ try {
43
+ var parsed = (0, max_1.default)(cleanedPhoneNumber);
44
+ var type = (_a = parsed === null || parsed === void 0 ? void 0 : parsed.getType) === null || _a === void 0 ? void 0 : _a.call(parsed);
45
+ console.log(type);
46
+ console.log(parsed === null || parsed === void 0 ? void 0 : parsed.isValid());
47
+ console.log(["MOBILE", "MOBILE_OR_FIXED_LINE"].includes(type || ""));
48
+ return !((parsed === null || parsed === void 0 ? void 0 : parsed.isValid()) &&
49
+ ["MOBILE", "MOBILE_OR_FIXED_LINE"].includes(type || ""));
50
+ }
51
+ catch (_b) {
52
+ return true;
53
+ }
54
+ };
55
+ exports.isInvalidMobileNumber = isInvalidMobileNumber;
56
+ exports.FR_WEEK_DAYS = [
57
+ "Lundi",
58
+ "Mardi",
59
+ "Mercredi",
60
+ "Jeudi",
61
+ "Vendredi",
62
+ "Samedi",
63
+ "Dimanche",
64
+ ];
26
65
  var getDayOfWeekLabel = function (day) {
27
66
  if (day) {
28
67
  return exports.FR_WEEK_DAYS[(0, exports.getDayOfWeekIndex)(day)];
@@ -84,8 +123,12 @@ var sortMovaIntervals = function (intervals) {
84
123
  if (intervals) {
85
124
  return intervals.sort(function (a, b) {
86
125
  // Convertir en Date si nécessaire
87
- var startTimeA = a.startTime instanceof Date ? a.startTime : new Date(a.startTime);
88
- var startTimeB = b.startTime instanceof Date ? b.startTime : new Date(b.startTime);
126
+ var startTimeA = a.startTime instanceof Date
127
+ ? a.startTime
128
+ : new Date(a.startTime);
129
+ var startTimeB = b.startTime instanceof Date
130
+ ? b.startTime
131
+ : new Date(b.startTime);
89
132
  // Gérer les valeurs nulles
90
133
  if (startTimeA === null && startTimeB === null)
91
134
  return 0;
@@ -106,32 +149,46 @@ var findScheduleByDayOfWeek = function (schedules, dayIndex) {
106
149
  exports.findScheduleByDayOfWeek = findScheduleByDayOfWeek;
107
150
  var getDayOfWeek = function (index) {
108
151
  switch (index) {
109
- case 0: return Enums_1.DayOfWeek.MONDAY;
110
- case 1: return Enums_1.DayOfWeek.TUESDAY;
111
- case 2: return Enums_1.DayOfWeek.WEDNESDAY;
112
- case 3: return Enums_1.DayOfWeek.THURSDAY;
113
- case 4: return Enums_1.DayOfWeek.FRIDAY;
114
- case 5: return Enums_1.DayOfWeek.SATURDAY;
115
- case 6: return Enums_1.DayOfWeek.SUNDAY;
152
+ case 0:
153
+ return Enums_1.DayOfWeek.MONDAY;
154
+ case 1:
155
+ return Enums_1.DayOfWeek.TUESDAY;
156
+ case 2:
157
+ return Enums_1.DayOfWeek.WEDNESDAY;
158
+ case 3:
159
+ return Enums_1.DayOfWeek.THURSDAY;
160
+ case 4:
161
+ return Enums_1.DayOfWeek.FRIDAY;
162
+ case 5:
163
+ return Enums_1.DayOfWeek.SATURDAY;
164
+ case 6:
165
+ return Enums_1.DayOfWeek.SUNDAY;
116
166
  }
117
167
  };
118
168
  exports.getDayOfWeek = getDayOfWeek;
119
169
  var getFrenchDayLabel = function (day) {
120
170
  switch (day) {
121
- case Enums_1.DayOfWeek.MONDAY: return 'Lundi';
122
- case Enums_1.DayOfWeek.TUESDAY: return 'Mardi';
123
- case Enums_1.DayOfWeek.WEDNESDAY: return 'Mercredi';
124
- case Enums_1.DayOfWeek.THURSDAY: return 'Jeudi';
125
- case Enums_1.DayOfWeek.FRIDAY: return 'Vendredi';
126
- case Enums_1.DayOfWeek.SATURDAY: return 'Samedi';
127
- case Enums_1.DayOfWeek.SUNDAY: return 'Dimanche';
171
+ case Enums_1.DayOfWeek.MONDAY:
172
+ return "Lundi";
173
+ case Enums_1.DayOfWeek.TUESDAY:
174
+ return "Mardi";
175
+ case Enums_1.DayOfWeek.WEDNESDAY:
176
+ return "Mercredi";
177
+ case Enums_1.DayOfWeek.THURSDAY:
178
+ return "Jeudi";
179
+ case Enums_1.DayOfWeek.FRIDAY:
180
+ return "Vendredi";
181
+ case Enums_1.DayOfWeek.SATURDAY:
182
+ return "Samedi";
183
+ case Enums_1.DayOfWeek.SUNDAY:
184
+ return "Dimanche";
128
185
  }
129
186
  };
130
187
  exports.getFrenchDayLabel = getFrenchDayLabel;
131
188
  exports.flexLeftRow = {
132
- display: 'flex',
133
- justifyContent: 'start',
134
- alignItems: 'center'
189
+ display: "flex",
190
+ justifyContent: "start",
191
+ alignItems: "center",
135
192
  };
136
193
  var capitalizeFirstLetter = function (str) {
137
194
  if (str.length === 0) {
@@ -145,30 +202,40 @@ exports.capitalizeFirstLetter = capitalizeFirstLetter;
145
202
  var getApplicationShortLabel = function (application) {
146
203
  if (application) {
147
204
  switch (application) {
148
- case Enums_1.PartsApplicationType.FRONT: return "AV";
149
- case Enums_1.PartsApplicationType.REAR: return "AR";
150
- case Enums_1.PartsApplicationType.FRONT_REAR: return "AV + AR";
151
- case Enums_1.PartsApplicationType.LEFT: return "G";
152
- case Enums_1.PartsApplicationType.RIGHT: return "D";
153
- case Enums_1.PartsApplicationType.LEFT_RIGHT: return "G + D";
154
- case Enums_1.PartsApplicationType.FRONT_LEFT: return "AVG";
155
- case Enums_1.PartsApplicationType.FRONT_RIGHT: return "AVD";
156
- case Enums_1.PartsApplicationType.REAR_LEFT: return "ARG";
157
- case Enums_1.PartsApplicationType.REAR_RIGHT: return "ARD";
205
+ case Enums_1.PartsApplicationType.FRONT:
206
+ return "AV";
207
+ case Enums_1.PartsApplicationType.REAR:
208
+ return "AR";
209
+ case Enums_1.PartsApplicationType.FRONT_REAR:
210
+ return "AV + AR";
211
+ case Enums_1.PartsApplicationType.LEFT:
212
+ return "G";
213
+ case Enums_1.PartsApplicationType.RIGHT:
214
+ return "D";
215
+ case Enums_1.PartsApplicationType.LEFT_RIGHT:
216
+ return "G + D";
217
+ case Enums_1.PartsApplicationType.FRONT_LEFT:
218
+ return "AVG";
219
+ case Enums_1.PartsApplicationType.FRONT_RIGHT:
220
+ return "AVD";
221
+ case Enums_1.PartsApplicationType.REAR_LEFT:
222
+ return "ARG";
223
+ case Enums_1.PartsApplicationType.REAR_RIGHT:
224
+ return "ARD";
158
225
  }
159
226
  }
160
227
  return "";
161
228
  };
162
229
  exports.getApplicationShortLabel = getApplicationShortLabel;
163
230
  exports.flexEnd = {
164
- display: 'flex',
165
- justifyContent: 'end',
166
- alignItems: 'center'
231
+ display: "flex",
232
+ justifyContent: "end",
233
+ alignItems: "center",
167
234
  };
168
235
  exports.flexCenter = {
169
- display: 'flex',
170
- justifyContent: 'center',
171
- alignItems: 'center'
236
+ display: "flex",
237
+ justifyContent: "center",
238
+ alignItems: "center",
172
239
  };
173
240
  var isEmpty = function (data) {
174
241
  return Object.keys(data).length === 0;
@@ -187,7 +254,7 @@ var formatFrenchVehiclePlate = function (input) {
187
254
  plateFormat = Enums_1.VehiclePlateFormat.FRENCH_OLD;
188
255
  }
189
256
  // Supprimer tous les caractères non alphanumériques
190
- var cleanedInput = input.replace(/[^A-Z0-9]/gi, '').toUpperCase();
257
+ var cleanedInput = input.replace(/[^A-Z0-9]/gi, "").toUpperCase();
191
258
  switch (plateFormat) {
192
259
  case Enums_1.VehiclePlateFormat.FRENCH_NEW: {
193
260
  // Ajouter des tirets aux positions appropriées
@@ -214,18 +281,21 @@ var formatVehicleTire = function (vehicleTire) {
214
281
  var concatened = "".concat(vehicleTire.width).concat(vehicleTire.height).concat(vehicleTire.diameter).concat(vehicleTire.speedIndex);
215
282
  return (0, exports.formatVehicleTireStr)(concatened);
216
283
  }
217
- return '';
284
+ return "";
218
285
  };
219
286
  exports.formatVehicleTire = formatVehicleTire;
220
287
  var formatVehicleTireStr = function (input) {
221
- var formatted = input.toUpperCase().replace(/[^0-9A-QS-Za-qs-z]/g, '').slice(0, 7);
288
+ var formatted = input
289
+ .toUpperCase()
290
+ .replace(/[^0-9A-QS-Za-qs-z]/g, "")
291
+ .slice(0, 7);
222
292
  if (formatted.length > 3) {
223
293
  formatted = "".concat(formatted.substring(0, 3), " / ").concat(formatted.substring(3));
224
294
  }
225
295
  var indexOfRraw = input.indexOf("R");
226
- var toAdd = indexOfRraw !== -1 ? input.substring(indexOfRraw + 3) : '';
296
+ var toAdd = indexOfRraw !== -1 ? input.substring(indexOfRraw + 3) : "";
227
297
  if (toAdd.length > 0) {
228
- toAdd = ' ' + toAdd;
298
+ toAdd = " " + toAdd;
229
299
  }
230
300
  if (formatted.length > 8) {
231
301
  formatted = "".concat(formatted.substring(0, 8), " R").concat(formatted.substring(8)).concat(toAdd);
@@ -246,10 +316,10 @@ var validateField = function (field, validator, errorMsg) {
246
316
  return { value: field.value, error: errorMsg, isValid: false };
247
317
  }
248
318
  else if (field) {
249
- return { value: field.value, error: '', isValid: true };
319
+ return { value: field.value, error: "", isValid: true };
250
320
  }
251
321
  else {
252
- return { value: '', error: '', isValid: true };
322
+ return { value: "", error: "", isValid: true };
253
323
  }
254
324
  };
255
325
  exports.validateField = validateField;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.validateEmail = exports.validateText = exports.validatePhoneNumber = void 0;
4
+ var Tools_1 = require("./Tools");
4
5
  /**
5
6
  * Un email valide
6
7
  */
@@ -31,10 +32,10 @@ var userNameRegex = /^[a-z0-9_-]{3,20}$/;
31
32
  */
32
33
  var textRegex = /^[a-zA-Z0-9\s.,!?'"()+=-_-éèçà]+$/;
33
34
  function validatePhoneNumber(phoneNumber) {
34
- if (phoneNumber === null || phoneNumber === undefined || phoneNumber === '') {
35
+ if (phoneNumber === null || phoneNumber === undefined || phoneNumber === "") {
35
36
  return false;
36
37
  }
37
- return phoneNumberRegex.test(phoneNumber);
38
+ return !(0, Tools_1.isInvalidMobileNumber)(phoneNumber);
38
39
  }
39
40
  exports.validatePhoneNumber = validatePhoneNumber;
40
41
  function validateText(text) {
package/index.ts CHANGED
@@ -31,7 +31,7 @@ export { default as ActivateAccount } from './src/components/singup/ActivateAcco
31
31
  export { QrCodePLVContainer } from './src/components/QrCodePLVContainer/QrCodePLVContainer';
32
32
  export { PLVComponent, PrintSize } from './src/components/QrCodePLVContainer/PLVComponent';
33
33
  export {LinkedDocumentDialog} from './src/components/LinkedDocumentDialog';
34
- export { default as MovaTable } from './src/components/MovaTable/MovaTable'
34
+ export { default as MovaTable } from './src/components/MovaTable/MovaTable';
35
35
 
36
36
  // Export des classes
37
37
  export { default as Subscription } from './src/models/Subscription';
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@movalib/movalib-commons",
3
- "version": "1.59.39",
3
+ "version": "1.60.1",
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",
7
7
  "private": false,
8
8
  "scripts": {
9
- "start": "webpack-dev-server --entry ./devIndex.tsx --open --https",
9
+ "start": "webpack-dev-server --entry ./devIndex.tsx --open",
10
10
  "build": "rm -rf dist && tsc && npm run copy-assets",
11
11
  "copy-assets": "cp -r src/assets/ dist/src/assets/ && cp -r src/style/. dist/src/style/",
12
12
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -50,12 +50,16 @@
50
50
  "react-app"
51
51
  ]
52
52
  },
53
+ "peerDependencies": {
54
+ "libphonenumber-js": "1.9.52"
55
+ },
53
56
  "devDependencies": {
54
57
  "@types/js-cookie": "^3.0.4",
55
58
  "@types/lodash": "^4.17.17",
56
59
  "@types/pdfjs-dist": "^2.10.377",
57
60
  "@types/react-input-mask": "^3.0.5",
58
61
  "html-webpack-plugin": "^5.5.3",
62
+ "libphonenumber-js": "1.9.52",
59
63
  "ts-loader": "^9.4.4",
60
64
  "webpack-cli": "^5.1.4"
61
65
  }
@@ -49,7 +49,11 @@ const DialogForgotPassword: React.FC<{
49
49
  onChange={e => handleInputChange(e)}
50
50
  value={movaAppType === MovaAppType.GARAGE ? form.email.value : form.phoneNumberEmail.value}
51
51
  error={movaAppType === MovaAppType.GARAGE ? !form.email.isValid : !form.phoneNumberEmail.isValid}
52
- helperText={movaAppType === MovaAppType.GARAGE ? form.email.error : form.phoneNumberEmail.error}
52
+ helperText={
53
+ movaAppType === MovaAppType.GARAGE
54
+ ? form.email.error
55
+ : form.phoneNumberEmail.error || "Saisir l’indicatif pour un numéro étranger (ex : +32 …)"
56
+ }
53
57
  />
54
58
  </DialogContent>
55
59
  <DialogActions>
package/src/MovaLogin.tsx CHANGED
@@ -19,6 +19,7 @@ import InputAdornment from '@mui/material/InputAdornment';
19
19
  import Visibility from '@mui/icons-material/Visibility';
20
20
  import VisibilityOff from '@mui/icons-material/VisibilityOff';
21
21
  import DialogForgotPassword from "./DialogForgotPassword";
22
+ import { parsePhoneNumberFromString, isValidPhoneNumber } from 'libphonenumber-js';
22
23
 
23
24
  // Permet de centrer le contenu de l'application
24
25
  const styles: CSSProperties = {
@@ -100,9 +101,30 @@ const MovaLogin: FunctionComponent<MovaLoginProps> = ({ loading, movaAppType, on
100
101
  newForm.email = validateField(form.email, validateEmail, 'Adresse email invalide');
101
102
  }
102
103
 
103
- if(movaAppType === MovaAppType.INDIVIDUAL){
104
+ /* if(movaAppType === MovaAppType.INDIVIDUAL){
104
105
  newForm.phoneNumberEmail = validateField(form.phoneNumberEmail, value => !!value, 'Champ obligatoire');
105
- }
106
+ } */
107
+
108
+ if (movaAppType === MovaAppType.INDIVIDUAL) {
109
+ newForm.phoneNumberEmail = validateField(
110
+ form.phoneNumberEmail,
111
+ (value) => {
112
+ if (!value) return false;
113
+
114
+ // Si c’est un email valide => OK
115
+ if (validateEmail(value)) return true;
116
+
117
+ // Remplace 00 par + si le numéro commence par 00 (pour compatibilité avec libphonenumber-js)
118
+ const normalizedValue = value.startsWith('00') ? value.replace(/^00/, '+') : value;
119
+
120
+ // Si le numéro commence par + ou 00, tentative de parsing direct. Format local, Pays par défaut : FR
121
+ const phoneNumber = parsePhoneNumberFromString(normalizedValue, normalizedValue.startsWith('+') || normalizedValue.startsWith('00') ? undefined : 'FR');
122
+
123
+ return phoneNumber?.isValid() ?? false;
124
+ },
125
+ 'Email ou numéro de téléphone invalide'
126
+ );
127
+ }
106
128
 
107
129
  newForm.password = validateField(form.password, value => !!value, 'Champ obligatoire');
108
130
 
@@ -245,7 +267,10 @@ const MovaLogin: FunctionComponent<MovaLoginProps> = ({ loading, movaAppType, on
245
267
  onChange={e => handleInputChange(e)}
246
268
  value={form.phoneNumberEmail.value}
247
269
  error={!form.phoneNumberEmail.isValid}
248
- helperText={form.phoneNumberEmail.error}
270
+ helperText={
271
+ form.phoneNumberEmail.error ||
272
+ "Saisir l’indicatif pour un numéro étranger (ex : +32 …)"
273
+ }
249
274
  sx={{
250
275
  '& .MuiOutlinedInput-notchedOutline': {
251
276
  borderColor: darkMode ? 'white' : 'default', // Couleur de la bordure
@@ -24,6 +24,7 @@ import isValid from 'date-fns/isValid';
24
24
  import Logger from "./helpers/Logger";
25
25
  import User from "./models/User";
26
26
  import UserService from "./services/UserService";
27
+ import { parsePhoneNumberFromString } from 'libphonenumber-js';
27
28
 
28
29
  // ATTENTION : s'assurer de la présence des documents suivants à la racine du composant porteur (dossier 'public')
29
30
  const CGUPath:string = "https://s3.eu-west-3.amazonaws.com/legal.movalib.com/Movalib_CGU.pdf";
@@ -105,18 +106,29 @@ const MovaSignUp: FunctionComponent<MovaSignUpProps> = ({ loading, movaAppType,
105
106
 
106
107
  // On autorise uniquement les chiffre pour le n° de téléphone
107
108
  if (fieldName == "phoneNumber"){
108
- fieldValue= fieldValue.replace(/[^0-9]/g, '');
109
- // Limiter la longueur à 10 caractères
110
- if (fieldValue.length > 10) {
111
- fieldValue = fieldValue.substring(0, 10);
109
+ // Nettoyage : on autorise chiffres + éventuellement un "+" en début
110
+ let cleaned = fieldValue.trim().replace(/[^\d+]/g, '');
111
+
112
+ // Normalisation : 0033... → +33...
113
+ if (cleaned.startsWith('00')) {
114
+ cleaned = cleaned.replace(/^00/, '+');
112
115
  }
113
- if (fieldValue.length === 10){
114
- UserService.existsByPhoneNumber(fieldValue).then((response) => {
115
- if(response && response.data){
116
- if(response.data.isActive === false){
117
- setUserExist(true);
118
- setUserIsAlreadyActive(false);
119
- } else if (response.data.isActive === true){
116
+
117
+ // Parsing avec FR par défaut si local
118
+ const parsed = parsePhoneNumberFromString(cleaned, cleaned.startsWith('+') ? undefined : 'FR');
119
+
120
+ // Mise à jour du champ
121
+ if (parsed?.isValid()) {
122
+ const e164 = parsed.number; // format +33...
123
+ //fieldValue = e164;
124
+
125
+ // Vérification de l'existence du compte
126
+ UserService.existsByPhoneNumber(e164).then((response) => {
127
+ if (response && response.data) {
128
+ if (response.data.isActive === false) {
129
+ setUserExist(true);
130
+ setUserIsAlreadyActive(false);
131
+ } else if (response.data.isActive === true) {
120
132
  setUserIsAlreadyActive(true);
121
133
  setUserExist(false);
122
134
  } else {
@@ -124,8 +136,9 @@ const MovaSignUp: FunctionComponent<MovaSignUpProps> = ({ loading, movaAppType,
124
136
  setUserIsAlreadyActive(false);
125
137
  }
126
138
  }
127
- })
139
+ });
128
140
  } else {
141
+ // Si numéro invalide ou incomplet, on réinitialise les flags
129
142
  setUserExist(false);
130
143
  setUserIsAlreadyActive(false);
131
144
  }
@@ -313,7 +326,10 @@ const MovaSignUp: FunctionComponent<MovaSignUpProps> = ({ loading, movaAppType,
313
326
  onChange={e => handleInputChange(e)}
314
327
  value={userForm.phoneNumber.value}
315
328
  error={Boolean(userForm.phoneNumber.error)}
316
- helperText={userForm.phoneNumber.error}
329
+ helperText={
330
+ userForm.phoneNumber.error ||
331
+ "Saisir l’indicatif pour un numéro étranger (ex : +32 …)"
332
+ }
317
333
  InputProps={{
318
334
  endAdornment: (
319
335
  <InputAdornment position="end">
@@ -109,7 +109,7 @@ export const QrCodePLVContainer = ({ data }: { data: string }) => {
109
109
  const qrCodeBlob = await qrCode.getRawData("png");
110
110
 
111
111
  // Convertir l'image QR code en un tableau de bytes
112
- const qrImageBytes = await qrCodeBlob?.arrayBuffer();
112
+ const qrImageBytes = await (qrCodeBlob as Blob)?.arrayBuffer();
113
113
  // Intégrer l'image du QR code dans le PDF
114
114
  const qrImage = await pdfDoc.embedPng(qrImageBytes!);
115
115
 
@@ -1,56 +1,92 @@
1
- import Cookies from "js-cookie";
2
- import VehicleTire from "../models/VehicleTire";
3
- import { MovaFormField, MovaInterval } from "./Types";
1
+ import parsePhoneNumberFromString from "libphonenumber-js/max";
4
2
  import { CSSProperties } from "react";
5
- import { DayOfWeek, PartsApplicationType, VehiclePlateFormat } from "./Enums";
6
3
  import Schedule from "../models/Schedule";
4
+ import VehicleTire from "../models/VehicleTire";
5
+ import { DayOfWeek, PartsApplicationType, VehiclePlateFormat } from "./Enums";
6
+ import { MovaFormField, MovaInterval } from "./Types";
7
7
 
8
- export const getApplicationsShortLabels = (applications: PartsApplicationType[] | undefined): string => {
9
- if(!applications) {
10
- return '';
8
+ export const getApplicationsShortLabels = (
9
+ applications: PartsApplicationType[] | undefined
10
+ ): string => {
11
+ if (!applications) {
12
+ return "";
11
13
  }
12
-
13
- return applications.map(getApplicationShortLabel).join(' + ');
14
+
15
+ return applications.map(getApplicationShortLabel).join(" + ");
14
16
  };
15
17
 
16
- export const flexStart:CSSProperties = {
17
- display: 'flex',
18
- justifyContent: 'start',
19
- alignItems: 'center'
20
- }
18
+ export const flexStart: CSSProperties = {
19
+ display: "flex",
20
+ justifyContent: "start",
21
+ alignItems: "center",
22
+ };
21
23
 
22
- export const isSafariOniOS = ():boolean => {
24
+ export const isSafariOniOS = (): boolean => {
23
25
  const userAgent = window.navigator.userAgent;
24
- const iOS = !!userAgent.match(/iPad/i) || !!userAgent.match(/iPhone/i) || !!userAgent.match(/iPod/i);
26
+ const iOS =
27
+ !!userAgent.match(/iPad/i) ||
28
+ !!userAgent.match(/iPhone/i) ||
29
+ !!userAgent.match(/iPod/i);
25
30
  const webkit = !!userAgent.match(/WebKit/i);
26
31
  const criOS = !!userAgent.match(/CriOS/i);
27
-
32
+
28
33
  return iOS && webkit && !criOS;
29
- }
34
+ };
30
35
 
36
+ export const isInvalidMobileNumber = (phoneNumber = "") => {
37
+ if (!phoneNumber || typeof phoneNumber !== "string") return true;
38
+
39
+ // Nettoyage : supprime les espaces et convertit "00..." en "+..."
40
+ const cleaned = phoneNumber.replace(/\s+/g, "").replace(/^00/, "+");
41
+ // Si le numéro ne commence pas par +, on assume que c'est un numéro local français
42
+ const cleanedPhoneNumber = cleaned.startsWith("+")
43
+ ? cleaned
44
+ : `+33${cleaned.replace(/^0/, "")}`;
45
+
46
+ try {
47
+ const parsed = parsePhoneNumberFromString(cleanedPhoneNumber);
48
+ const type = parsed?.getType?.();
49
+ console.log(type);
50
+ console.log(parsed?.isValid());
51
+ console.log(["MOBILE", "MOBILE_OR_FIXED_LINE"].includes(type || ""));
52
+ return !(
53
+ parsed?.isValid() &&
54
+ ["MOBILE", "MOBILE_OR_FIXED_LINE"].includes(type || "")
55
+ );
56
+ } catch {
57
+ return true;
58
+ }
59
+ };
31
60
 
32
- export const FR_WEEK_DAYS: string[] = ['Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche'];
61
+ export const FR_WEEK_DAYS: string[] = [
62
+ "Lundi",
63
+ "Mardi",
64
+ "Mercredi",
65
+ "Jeudi",
66
+ "Vendredi",
67
+ "Samedi",
68
+ "Dimanche",
69
+ ];
33
70
 
34
71
  export const getDayOfWeekLabel = (day: DayOfWeek) => {
35
- if(day){
36
- return FR_WEEK_DAYS[getDayOfWeekIndex(day)]
72
+ if (day) {
73
+ return FR_WEEK_DAYS[getDayOfWeekIndex(day)];
37
74
  }
38
- }
75
+ };
39
76
 
40
77
  export const getDayOfWeekIndex = (day: DayOfWeek) => {
41
- if(day){
78
+ if (day) {
42
79
  // Convertir les valeurs de l'énumération en un tableau
43
80
  const daysArray = Object.values(DayOfWeek);
44
81
  return daysArray.indexOf(day);
45
82
  }
46
83
  return -1;
47
- }
48
-
84
+ };
49
85
 
50
86
  export const formatPhoneNumber = (phoneNumber: string): string => {
51
87
  let formattedNumber = "";
52
88
 
53
- if(phoneNumber){
89
+ if (phoneNumber) {
54
90
  for (let i = 0; i < phoneNumber.length; i++) {
55
91
  if (i > 0 && i % 2 === 0) {
56
92
  formattedNumber += ".";
@@ -62,87 +98,119 @@ export const formatPhoneNumber = (phoneNumber: string): string => {
62
98
  return formattedNumber;
63
99
  };
64
100
 
65
- export const getFormattedSchedule = (schedule: Schedule | null, dayIndex: number) => {
66
- if(schedule){
67
- return `${getFrenchDayLabel(schedule.dayOfWeek)} : ${getFormattedIntervals(schedule.intervals)}`
101
+ export const getFormattedSchedule = (
102
+ schedule: Schedule | null,
103
+ dayIndex: number
104
+ ) => {
105
+ if (schedule) {
106
+ return `${getFrenchDayLabel(
107
+ schedule.dayOfWeek
108
+ )} : ${getFormattedIntervals(schedule.intervals)}`;
68
109
  } else {
69
110
  return `${getFrenchDayLabel(getDayOfWeek(dayIndex))} : fermé`;
70
111
  }
71
- }
112
+ };
72
113
 
73
114
  export const getFormattedIntervals = (intervals: MovaInterval[]) => {
74
- if(intervals){
75
- let times:string = "";
76
- sortMovaIntervals(intervals).map((interval:MovaInterval, index) => {
77
- if(index > 0){
78
- times = `${times} | `;
115
+ if (intervals) {
116
+ let times: string = "";
117
+ sortMovaIntervals(intervals).map((interval: MovaInterval, index) => {
118
+ if (index > 0) {
119
+ times = `${times} | `;
79
120
  }
80
- times = `${times} ${formatTime(interval.startTime)} - ${formatTime(interval.endTime)}`
81
- })
121
+ times = `${times} ${formatTime(interval.startTime)} - ${formatTime(
122
+ interval.endTime
123
+ )}`;
124
+ });
82
125
  return times;
83
126
  }
84
- }
127
+ };
85
128
 
86
129
  export const formatTime = (date: string | Date | null) => {
87
- if(date){
88
- let strDate:string = date.toString();
130
+ if (date) {
131
+ let strDate: string = date.toString();
89
132
  return strDate.substring(0, 5);
90
133
  }
91
134
  };
92
135
 
93
136
  const sortMovaIntervals = (intervals: MovaInterval[]): MovaInterval[] => {
94
- if(intervals){
137
+ if (intervals) {
95
138
  return intervals.sort((a, b) => {
96
139
  // Convertir en Date si nécessaire
97
- const startTimeA = a.startTime instanceof Date ? a.startTime : new Date(a.startTime as string);
98
- const startTimeB = b.startTime instanceof Date ? b.startTime : new Date(b.startTime as string);
99
-
140
+ const startTimeA =
141
+ a.startTime instanceof Date
142
+ ? a.startTime
143
+ : new Date(a.startTime as string);
144
+ const startTimeB =
145
+ b.startTime instanceof Date
146
+ ? b.startTime
147
+ : new Date(b.startTime as string);
148
+
100
149
  // Gérer les valeurs nulles
101
150
  if (startTimeA === null && startTimeB === null) return 0;
102
151
  if (startTimeA === null) return 1;
103
152
  if (startTimeB === null) return -1;
104
-
153
+
105
154
  // Comparer les dates
106
155
  return startTimeA.getTime() - startTimeB.getTime();
107
156
  });
108
157
  }
109
158
  return [];
110
- }
159
+ };
111
160
 
112
- export const findScheduleByDayOfWeek = (schedules: Schedule[], dayIndex: number): Schedule | null => {
113
- const foundSchedule = schedules.find(schedule => schedule.dayOfWeek === getDayOfWeek(dayIndex));
161
+ export const findScheduleByDayOfWeek = (
162
+ schedules: Schedule[],
163
+ dayIndex: number
164
+ ): Schedule | null => {
165
+ const foundSchedule = schedules.find(
166
+ (schedule) => schedule.dayOfWeek === getDayOfWeek(dayIndex)
167
+ );
114
168
  return foundSchedule ? foundSchedule : null;
115
169
  };
116
170
 
117
- export const getDayOfWeek = (index:number) => {
171
+ export const getDayOfWeek = (index: number) => {
118
172
  switch (index) {
119
- case 0 : return DayOfWeek.MONDAY;
120
- case 1 : return DayOfWeek.TUESDAY;
121
- case 2 : return DayOfWeek.WEDNESDAY;
122
- case 3 : return DayOfWeek.THURSDAY;
123
- case 4 : return DayOfWeek.FRIDAY;
124
- case 5 : return DayOfWeek.SATURDAY;
125
- case 6 : return DayOfWeek.SUNDAY;
173
+ case 0:
174
+ return DayOfWeek.MONDAY;
175
+ case 1:
176
+ return DayOfWeek.TUESDAY;
177
+ case 2:
178
+ return DayOfWeek.WEDNESDAY;
179
+ case 3:
180
+ return DayOfWeek.THURSDAY;
181
+ case 4:
182
+ return DayOfWeek.FRIDAY;
183
+ case 5:
184
+ return DayOfWeek.SATURDAY;
185
+ case 6:
186
+ return DayOfWeek.SUNDAY;
126
187
  }
127
- }
188
+ };
128
189
 
129
- export const getFrenchDayLabel = (day:DayOfWeek | undefined) => {
190
+ export const getFrenchDayLabel = (day: DayOfWeek | undefined) => {
130
191
  switch (day) {
131
- case DayOfWeek.MONDAY: return 'Lundi';
132
- case DayOfWeek.TUESDAY: return 'Mardi';
133
- case DayOfWeek.WEDNESDAY: return 'Mercredi';
134
- case DayOfWeek.THURSDAY: return 'Jeudi';
135
- case DayOfWeek.FRIDAY: return 'Vendredi';
136
- case DayOfWeek.SATURDAY: return 'Samedi';
137
- case DayOfWeek.SUNDAY: return 'Dimanche';
192
+ case DayOfWeek.MONDAY:
193
+ return "Lundi";
194
+ case DayOfWeek.TUESDAY:
195
+ return "Mardi";
196
+ case DayOfWeek.WEDNESDAY:
197
+ return "Mercredi";
198
+ case DayOfWeek.THURSDAY:
199
+ return "Jeudi";
200
+ case DayOfWeek.FRIDAY:
201
+ return "Vendredi";
202
+ case DayOfWeek.SATURDAY:
203
+ return "Samedi";
204
+ case DayOfWeek.SUNDAY:
205
+ return "Dimanche";
138
206
  }
139
- }
207
+ };
140
208
 
141
- export const flexLeftRow:CSSProperties = {
142
- display: 'flex',
143
- justifyContent: 'start',
144
- alignItems: 'center'
145
- }
209
+ export const flexLeftRow: CSSProperties = {
210
+ display: "flex",
211
+ justifyContent: "start",
212
+ alignItems: "center",
213
+ };
146
214
 
147
215
  export const capitalizeFirstLetter = (str: string): string => {
148
216
  if (str.length === 0) {
@@ -153,45 +221,56 @@ export const capitalizeFirstLetter = (str: string): string => {
153
221
  const restOfString = str.slice(1);
154
222
 
155
223
  return firstChar + restOfString;
156
- }
157
-
158
- export const getApplicationShortLabel = (application:PartsApplicationType | undefined) => {
159
- if(application){
160
- switch(application){
161
- case PartsApplicationType.FRONT: return "AV";
162
- case PartsApplicationType.REAR: return "AR";
163
- case PartsApplicationType.FRONT_REAR: return "AV + AR";
164
- case PartsApplicationType.LEFT: return "G";
165
- case PartsApplicationType.RIGHT: return "D";
166
- case PartsApplicationType.LEFT_RIGHT: return "G + D";
167
- case PartsApplicationType.FRONT_LEFT: return "AVG";
168
- case PartsApplicationType.FRONT_RIGHT: return "AVD";
169
- case PartsApplicationType.REAR_LEFT: return "ARG";
170
- case PartsApplicationType.REAR_RIGHT: return "ARD";
224
+ };
225
+
226
+ export const getApplicationShortLabel = (
227
+ application: PartsApplicationType | undefined
228
+ ) => {
229
+ if (application) {
230
+ switch (application) {
231
+ case PartsApplicationType.FRONT:
232
+ return "AV";
233
+ case PartsApplicationType.REAR:
234
+ return "AR";
235
+ case PartsApplicationType.FRONT_REAR:
236
+ return "AV + AR";
237
+ case PartsApplicationType.LEFT:
238
+ return "G";
239
+ case PartsApplicationType.RIGHT:
240
+ return "D";
241
+ case PartsApplicationType.LEFT_RIGHT:
242
+ return "G + D";
243
+ case PartsApplicationType.FRONT_LEFT:
244
+ return "AVG";
245
+ case PartsApplicationType.FRONT_RIGHT:
246
+ return "AVD";
247
+ case PartsApplicationType.REAR_LEFT:
248
+ return "ARG";
249
+ case PartsApplicationType.REAR_RIGHT:
250
+ return "ARD";
171
251
  }
172
252
  }
173
253
  return "";
174
- }
254
+ };
175
255
 
176
- export const flexEnd:CSSProperties = {
177
- display: 'flex',
178
- justifyContent: 'end',
179
- alignItems: 'center'
180
- }
256
+ export const flexEnd: CSSProperties = {
257
+ display: "flex",
258
+ justifyContent: "end",
259
+ alignItems: "center",
260
+ };
181
261
 
182
- export const flexCenter:CSSProperties = {
183
- display: 'flex',
184
- justifyContent: 'center',
185
- alignItems: 'center'
186
- }
262
+ export const flexCenter: CSSProperties = {
263
+ display: "flex",
264
+ justifyContent: "center",
265
+ alignItems: "center",
266
+ };
187
267
 
188
268
  export const isEmpty = (data: Object): boolean => {
189
269
  return Object.keys(data).length === 0;
190
- }
270
+ };
191
271
 
192
272
  export const formatFrenchVehiclePlate = (input: string | undefined): string => {
193
- if(input){
194
-
273
+ if (input) {
195
274
  // On commence par détecter s'il s'agit d'un ancien ou nouveau format
196
275
  let plateFormat: VehiclePlateFormat | null = null;
197
276
 
@@ -204,21 +283,24 @@ export const formatFrenchVehiclePlate = (input: string | undefined): string => {
204
283
  }
205
284
 
206
285
  // Supprimer tous les caractères non alphanumériques
207
- let cleanedInput = input.replace(/[^A-Z0-9]/gi, '').toUpperCase();
286
+ let cleanedInput = input.replace(/[^A-Z0-9]/gi, "").toUpperCase();
208
287
 
209
- switch(plateFormat){
210
- case VehiclePlateFormat.FRENCH_NEW : {
288
+ switch (plateFormat) {
289
+ case VehiclePlateFormat.FRENCH_NEW: {
211
290
  // Ajouter des tirets aux positions appropriées
212
291
  if (cleanedInput.length >= 2) {
213
292
  cleanedInput = `${cleanedInput.slice(0, 2)}-${cleanedInput.slice(2)}`;
214
293
  }
215
294
  if (cleanedInput.length >= 6) {
216
- cleanedInput = `${cleanedInput.slice(0, 6)}-${cleanedInput.slice(6, 8)}`;
295
+ cleanedInput = `${cleanedInput.slice(0, 6)}-${cleanedInput.slice(
296
+ 6,
297
+ 8
298
+ )}`;
217
299
  }
218
300
  break;
219
301
  }
220
302
 
221
- case VehiclePlateFormat.FRENCH_OLD : {
303
+ case VehiclePlateFormat.FRENCH_OLD: {
222
304
  // Rien de particulier, pas de tiret sur les anciennes plaques
223
305
  break;
224
306
  }
@@ -231,25 +313,30 @@ export const formatFrenchVehiclePlate = (input: string | undefined): string => {
231
313
  };
232
314
 
233
315
  export const formatVehicleTire = (vehicleTire: VehicleTire) => {
234
- if(vehicleTire){
316
+ if (vehicleTire) {
235
317
  let concatened = `${vehicleTire.width}${vehicleTire.height}${vehicleTire.diameter}${vehicleTire.speedIndex}`;
236
318
  return formatVehicleTireStr(concatened);
237
319
  }
238
- return '';
239
- }
320
+ return "";
321
+ };
240
322
 
241
323
  export const formatVehicleTireStr = (input: string) => {
242
- let formatted = input.toUpperCase().replace(/[^0-9A-QS-Za-qs-z]/g, '').slice(0, 7);
324
+ let formatted = input
325
+ .toUpperCase()
326
+ .replace(/[^0-9A-QS-Za-qs-z]/g, "")
327
+ .slice(0, 7);
243
328
  if (formatted.length > 3) {
244
329
  formatted = `${formatted.substring(0, 3)} / ${formatted.substring(3)}`;
245
330
  }
246
331
  const indexOfRraw = input.indexOf("R");
247
- let toAdd = indexOfRraw !== -1 ? input.substring(indexOfRraw + 3) : '';
248
- if(toAdd.length > 0) {
249
- toAdd = ' ' + toAdd;
332
+ let toAdd = indexOfRraw !== -1 ? input.substring(indexOfRraw + 3) : "";
333
+ if (toAdd.length > 0) {
334
+ toAdd = " " + toAdd;
250
335
  }
251
- if(formatted.length > 8) {
252
- formatted = `${formatted.substring(0, 8)} R${formatted.substring(8)}${toAdd}`;
336
+ if (formatted.length > 8) {
337
+ formatted = `${formatted.substring(0, 8)} R${formatted.substring(
338
+ 8
339
+ )}${toAdd}`;
253
340
  }
254
341
  return formatted;
255
342
  };
@@ -262,13 +349,16 @@ export const formatVehicleTireStr = (input: string) => {
262
349
  * @param {string} errorMsg - Le message d'erreur à associer au champ si la validation échoue.
263
350
  * @returns {MovaFormField} - Le champ de formulaire avec les propriétés `error` et `isValid` mises à jour.
264
351
  */
265
- export const validateField = (field: MovaFormField | undefined, validator: (value: string) => boolean, errorMsg: string): MovaFormField => {
266
- if (field && !validator(field.value)) {
267
- return { value: field.value, error: errorMsg, isValid: false };
268
- } else if (field) {
269
- return { value: field.value, error: '', isValid: true };
270
- } else {
271
- return { value: '', error: '', isValid: true };
272
- }
273
- };
274
-
352
+ export const validateField = (
353
+ field: MovaFormField | undefined,
354
+ validator: (value: string) => boolean,
355
+ errorMsg: string
356
+ ): MovaFormField => {
357
+ if (field && !validator(field.value)) {
358
+ return { value: field.value, error: errorMsg, isValid: false };
359
+ } else if (field) {
360
+ return { value: field.value, error: "", isValid: true };
361
+ } else {
362
+ return { value: "", error: "", isValid: true };
363
+ }
364
+ };
@@ -1,57 +1,59 @@
1
+ import { isInvalidMobileNumber } from "./Tools";
2
+
1
3
  /**
2
4
  * Un email valide
3
5
  */
4
- const emailRegex:RegExp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i;
6
+ const emailRegex: RegExp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i;
5
7
 
6
8
  /**
7
- * Un mot de passe qui contient au moins une majuscule, une minuscule, un chiffre
9
+ * Un mot de passe qui contient au moins une majuscule, une minuscule, un chiffre
8
10
  * et un caractère spécial. La longueur du mot de passe doit être d'au moins 8 caractères.
9
11
  */
10
- const passwordRegex:RegExp = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
12
+ const passwordRegex: RegExp =
13
+ /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
11
14
 
12
15
  /**
13
- * Un numéro de téléphone (10 chiffres)
16
+ * Un numéro de téléphone (10 chiffres)
14
17
  */
15
- const phoneNumberRegex:RegExp = /^\d{0,10}$/;
18
+ const phoneNumberRegex: RegExp = /^\d{0,10}$/;
16
19
 
17
20
  /**
18
21
  * Un code postal (5 chiffres)
19
22
  */
20
- const postalCodeRegex:RegExp = /^\d{5}$/;
23
+ const postalCodeRegex: RegExp = /^\d{5}$/;
21
24
 
22
25
  /**
23
26
  * Une URL valide
24
27
  */
25
- const urlRegex:RegExp =/^(ftp|http|https):\/\/[^ "]+$/;
28
+ const urlRegex: RegExp = /^(ftp|http|https):\/\/[^ "]+$/;
26
29
 
27
30
  /**
28
31
  * Un nom pouvant contenir des lettres, chiffres d'une taille comprise entre 3 et 20 caractères
29
32
  */
30
- const userNameRegex:RegExp = /^[a-z0-9_-]{3,20}$/;
33
+ const userNameRegex: RegExp = /^[a-z0-9_-]{3,20}$/;
31
34
 
32
35
  /**
33
36
  * Un texte pouvant contenir des lettres, chiffres et quelques caractères spéciaux
34
37
  */
35
- const textRegex:RegExp = /^[a-zA-Z0-9\s.,!?'"()+=-_-éèçà]+$/;
36
-
38
+ const textRegex: RegExp = /^[a-zA-Z0-9\s.,!?'"()+=-_-éèçà]+$/;
37
39
 
38
- export function validatePhoneNumber(phoneNumber: string) : boolean {
39
- if (phoneNumber === null || phoneNumber === undefined || phoneNumber === '') {
40
- return false;
41
- }
42
- return phoneNumberRegex.test(phoneNumber);
40
+ export function validatePhoneNumber(phoneNumber: string): boolean {
41
+ if (phoneNumber === null || phoneNumber === undefined || phoneNumber === "") {
42
+ return false;
43
+ }
44
+ return !isInvalidMobileNumber(phoneNumber);
43
45
  }
44
46
 
45
- export function validateText(text: string) : boolean {
46
- if (text === null || text === undefined) {
47
- return false;
48
- }
49
- return textRegex.test(text);
47
+ export function validateText(text: string): boolean {
48
+ if (text === null || text === undefined) {
49
+ return false;
50
+ }
51
+ return textRegex.test(text);
50
52
  }
51
53
 
52
- export function validateEmail(email: string) : boolean {
53
- if (email === null || email === undefined) {
54
- return false;
55
- }
56
- return emailRegex.test(email);
57
- }
54
+ export function validateEmail(email: string): boolean {
55
+ if (email === null || email === undefined) {
56
+ return false;
57
+ }
58
+ return emailRegex.test(email);
59
+ }