@movalib/movalib-commons 1.59.14 → 1.59.15

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.
Files changed (43) hide show
  1. package/devIndex.tsx +1 -1
  2. package/dist/devIndex.js +1 -1
  3. package/dist/index.d.ts +6 -3
  4. package/dist/index.js +14 -4
  5. package/dist/src/components/LinkedDocumentDialog.d.ts +11 -0
  6. package/dist/src/components/LinkedDocumentDialog.js +55 -0
  7. package/dist/src/{VehicleFullCard.d.ts → components/vehicle/VehicleFullCard.d.ts} +5 -2
  8. package/dist/src/{VehicleFullCard.js → components/vehicle/VehicleFullCard.js} +44 -22
  9. package/dist/src/components/vehicle/VehiclePlateField.d.ts +8 -0
  10. package/dist/src/components/vehicle/VehiclePlateField.js +122 -0
  11. package/dist/src/helpers/CookieUtils.js +2 -1
  12. package/dist/src/helpers/Enums.d.ts +6 -1
  13. package/dist/src/helpers/Enums.js +6 -1
  14. package/dist/src/helpers/Tools.d.ts +1 -0
  15. package/dist/src/helpers/Tools.js +10 -1
  16. package/dist/src/services/AuthenticationService.js +2 -0
  17. package/dist/src/services/GarageService.d.ts +2 -0
  18. package/dist/src/services/GarageService.js +18 -3
  19. package/dist/src/services/UserConnected.d.ts +9 -0
  20. package/dist/src/services/UserConnected.js +59 -0
  21. package/dist/src/services/UserService.d.ts +1 -1
  22. package/dist/src/services/VehicleService.d.ts +3 -0
  23. package/dist/src/services/VehicleService.js +22 -0
  24. package/dist/src/style/styled.d.ts +17 -0
  25. package/dist/src/style/styled.js +68 -0
  26. package/dist/src/style/styled.ts +70 -0
  27. package/index.ts +8 -3
  28. package/package.json +3 -2
  29. package/src/VehiclePlateField.tsx +1 -0
  30. package/src/components/LinkedDocumentDialog.tsx +200 -0
  31. package/src/components/vehicle/VehicleFullCard.tsx +549 -0
  32. package/src/components/vehicle/VehiclePlateField.tsx +164 -0
  33. package/src/helpers/CookieUtils.ts +2 -1
  34. package/src/helpers/Enums.ts +8 -1
  35. package/src/helpers/Tools.ts +5 -0
  36. package/src/models/Event.ts +1 -1
  37. package/src/services/AuthenticationService.ts +2 -1
  38. package/src/services/GarageService.ts +42 -36
  39. package/src/services/UserConnected.ts +56 -0
  40. package/src/services/UserService.ts +1 -1
  41. package/src/services/VehicleService.ts +25 -0
  42. package/src/style/styled.ts +70 -0
  43. package/src/VehicleFullCard.tsx +0 -503
@@ -0,0 +1,164 @@
1
+ import React, { FunctionComponent, ReactNode, useEffect, useState } from 'react';
2
+ import TextField from '@mui/material/TextField';
3
+ import { IconButton, InputAdornment } from '@mui/material';
4
+ import SearchIcon from '@mui/icons-material/SearchRounded';
5
+ import { VehiclePlateFormat } from '../../helpers/Enums';
6
+ import Logger from '../../helpers/Logger';
7
+
8
+ interface VehiclePlateFieldProps {
9
+ onValidVehiclePlate: (vehiclePlate: string) => void;
10
+ }
11
+
12
+ // Regex pour une plaque d'immatriculation française (nouveau format SIV)
13
+ export const regexPlate = /^[A-Z]{2}-\d{3}-[A-Z]{2}$/;
14
+ // Regex pour une plaque d'immatriculation française (ancien format FNI)
15
+ export const oldRegexPlate = /^\d{1,4}[ -]?[A-Z]{1,4}[ -]?\d{1,4}$/;
16
+
17
+
18
+ const VehiclePlateField: FunctionComponent<VehiclePlateFieldProps> = ({ onValidVehiclePlate }) => {
19
+
20
+ const [value, setValue] = useState<string>('');
21
+ const [error, setError] = useState<boolean>(false);
22
+ const [lastLength, setLastLength] = useState<number>(0); // Ajout d'un état pour stocker la longueur précédente
23
+ const [helperText, setHelperText] = useState<ReactNode>('');
24
+
25
+ // Hook de validation de la plaque
26
+ useEffect(() => {
27
+ if (!error && value !== '' && value.match(regexPlate)) {
28
+ onValidVehiclePlate(value);
29
+ }
30
+
31
+ }, [error, value, onValidVehiclePlate]);
32
+
33
+ const getPlateFormat = (plate: string): VehiclePlateFormat | undefined => {
34
+ if (plate === '') {
35
+ // Si la saisie est vide, retournez un format par défaut (nouveau format, par exemple)
36
+ return undefined;
37
+ }
38
+
39
+ if (/^[A-Za-z]/.test(plate)) {
40
+ // Commence par une lettre => nouveau format
41
+ return VehiclePlateFormat.FRENCH_NEW;
42
+ } else if (/^\d/.test(plate)) {
43
+ // Commence par un chiffre => ancien format
44
+ return VehiclePlateFormat.FRENCH_OLD;
45
+ } else {
46
+ Logger.error("Format de plaque inconnu");
47
+ // On retourne le nouveau format par défaut
48
+ return VehiclePlateFormat.FRENCH_NEW;
49
+ }
50
+ }
51
+
52
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
53
+
54
+ let inputValue = e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, ''); // Convertir en majuscules et supprimer les caractères non valides
55
+
56
+ // Si la saisie commence par une lettre, on contrôle l'ancien format, sinon le nouveau
57
+ switch(getPlateFormat(inputValue)){
58
+
59
+ case VehiclePlateFormat.FRENCH_NEW :{
60
+ setHelperText(<>Format détecté : <b>AA-111-AA</b></>);
61
+ handleChangeFrenchNew(inputValue);
62
+ break;
63
+ }
64
+
65
+ case VehiclePlateFormat.FRENCH_OLD: {
66
+ setHelperText(
67
+ <>
68
+ Format détecté (ancien) : <b>1111 AAAA 1111</b>
69
+ <br />
70
+ Pour lancer la recherche, cliquez sur <SearchIcon />
71
+ </>
72
+ );
73
+ handleChangeFrenchOld(inputValue);
74
+ break;
75
+ }
76
+
77
+ case undefined: {
78
+ setHelperText('');
79
+ setValue('');
80
+ }
81
+ }
82
+
83
+ };
84
+
85
+ const validatePlate = () => {
86
+
87
+ if(oldRegexPlate.test(value)){
88
+ onValidVehiclePlate(value);
89
+ }
90
+
91
+ setError(!oldRegexPlate.test(value));
92
+ }
93
+
94
+ const handleChangeFrenchOld = (inputValue: string) => {
95
+
96
+ // ON bloque la saisie à 12 caractères max (limite des anciennes plaques)
97
+ if(!(inputValue.length > 12)){
98
+ setValue(inputValue);
99
+ }
100
+
101
+ setLastLength(inputValue.length); // Mettre à jour la longueur précédente
102
+ }
103
+
104
+ const handleChangeFrenchNew = (inputValue: string) => {
105
+
106
+ // Vérifier si l'utilisateur est en train de supprimer un caractère
107
+ const isDeleting = inputValue.length < lastLength;
108
+
109
+ // Supprimer les tirets pour avoir une chaîne propre
110
+ const cleanInput = inputValue.replace(/-/g, '');
111
+
112
+ // Ajouter des tirets aux positions appropriées
113
+ if (cleanInput.length > 1 && !(cleanInput.length == 2 && isDeleting)) {
114
+ inputValue = `${cleanInput.slice(0, 2)}-${cleanInput.slice(2)}`;
115
+ }
116
+
117
+ if (cleanInput.length > 4 && !(cleanInput.length == 5 && isDeleting)) {
118
+ inputValue = `${cleanInput.slice(0, 2)}-${cleanInput.slice(2, 5)}-${cleanInput.slice(5, 7)}`;
119
+ }
120
+
121
+ setValue(inputValue);
122
+
123
+ // On teste la plaque une fois la saisie terminée
124
+ if(inputValue.length == 9){
125
+ setError(!regexPlate.test(inputValue));
126
+ } else {
127
+ setError(false);
128
+ }
129
+
130
+ setLastLength(inputValue.length); // Mettre à jour la longueur précédente
131
+ }
132
+
133
+ return (
134
+ <TextField
135
+ label="Plaque d'immatriculation"
136
+ variant="outlined"
137
+ value={value}
138
+ onChange={handleChange}
139
+ error={error}
140
+ autoFocus
141
+ sx={{
142
+ width: '100%',
143
+ '& input': { textTransform: 'uppercase' } // CSS pour forcer les majuscules dans l'input
144
+ }}
145
+ helperText={lastLength > 0 ? helperText : ''}
146
+ InputProps={{
147
+ endAdornment: (
148
+
149
+ <InputAdornment position="end" sx={{ mr: 1, display: getPlateFormat(value) === VehiclePlateFormat.FRENCH_OLD ? 'inherit' : 'none' }} >
150
+ <IconButton
151
+ edge="end"
152
+ onClick={validatePlate}
153
+ >
154
+ <SearchIcon />
155
+ </IconButton>
156
+ </InputAdornment>
157
+
158
+ ),
159
+ }}
160
+ />
161
+ );
162
+ };
163
+
164
+ export default VehiclePlateField;
@@ -5,8 +5,9 @@ export const COOKIE_INDIVIDUAL_TOKEN: string = 'movalibIndividualToken';
5
5
  export const COOKIE_DEFAULT_EXPIRES: number = 7;
6
6
 
7
7
  export const createCookie = (name:string, value:string) => {
8
+ console.log('from lib', name, value);
8
9
  if(name && value){
9
- Cookies.set(name, value, { expires: COOKIE_DEFAULT_EXPIRES, sameSite: 'None', secure: true });
10
+ Cookies.set(name, value, { expires: COOKIE_DEFAULT_EXPIRES, sameSite: 'Lax' });
10
11
  }
11
12
  }
12
13
 
@@ -235,8 +235,15 @@ export enum DocumentType {
235
235
  USER_BANK_DETAILS = "USER_BANK_DETAILS",
236
236
  USER_APPOINTMENT_QUOTE = "USER_APPOINTMENT_QUOTE",
237
237
  VEHICLE_MAINTENANCE_INVOICE = 'VEHICLE_MAINTENANCE_INVOICE',
238
+ GARAGE_LOGO = "GARAGE_LOGO",
239
+
238
240
  VEHICLE_TIRE_PHOTO = 'VEHICLE_TIRE_PHOTO',
239
- GARAGE_LOGO = "GARAGE_LOGO"
241
+ VEHICLE_INSPECTION = 'VEHICLE_INSPECTION',
242
+ VEHICLE_OTHER = 'VEHICLE_OTHER',
243
+
244
+ EVENT_OTHER = 'EVENT_OTHER',
245
+ EVENT_VISUAL_PROOFS = 'EVENT_VISUAL_PROOFS',
246
+ EVENT_MAINTENANCE = 'EVENT_MAINTENANCE',
240
247
  }
241
248
 
242
249
  export enum MovaAppType {
@@ -4,6 +4,7 @@ import { MovaFormField, MovaInterval } from "./Types";
4
4
  import { CSSProperties } from "react";
5
5
  import { DayOfWeek, PartsApplicationType, VehiclePlateFormat } from "./Enums";
6
6
  import Schedule from "../models/Schedule";
7
+ import UserConnected from "../services/UserConnected";
7
8
 
8
9
  export const getApplicationsShortLabels = (applications: PartsApplicationType[] | undefined): string => {
9
10
  if(!applications) {
@@ -46,6 +47,10 @@ export const getDayOfWeekIndex = (day: DayOfWeek) => {
46
47
  return -1;
47
48
  }
48
49
 
50
+ export const iAmOwner = (ownreId: number): boolean => {
51
+ return ownreId === UserConnected.getInstance().me?.id;
52
+ }
53
+
49
54
  export const formatPhoneNumber = (phoneNumber: string): string => {
50
55
  let formattedNumber = "";
51
56
 
@@ -108,4 +108,4 @@ export default class Event {
108
108
 
109
109
  return [];
110
110
  }
111
- }
111
+ }
@@ -3,6 +3,7 @@ import { COOKIE_PRO_TOKEN, COOKIE_INDIVIDUAL_TOKEN, createCookie } from "../help
3
3
  import { APIMethod, MovaAppType } from "../helpers/Enums";
4
4
  import Logger from "../helpers/Logger";
5
5
  import User from "../models/User";
6
+ import UserConnected from "./UserConnected";
6
7
  import UserService from "./UserService";
7
8
 
8
9
  export default class AuthenticationService {
@@ -68,7 +69,7 @@ export default class AuthenticationService {
68
69
  Logger.error(errorMsg);
69
70
  return { success: false, error: errorMsg };
70
71
  }
71
-
72
+ UserConnected.getInstance().me = userResponse.data;
72
73
  return { success: true, data: userResponse.data };
73
74
 
74
75
  } else {
@@ -78,42 +78,48 @@ export default class GarageService {
78
78
  });
79
79
  }
80
80
 
81
- static updateColorPrestationCategory(
82
- garageId: string,
83
- categoryCode: string,
84
- color: string,
85
- ): Promise<APIResponse<string>> {
86
- return request({
87
- url: `${API_BASE_URL}/garage/${garageId}/prestation-category/${categoryCode}/color`,
88
- method: APIMethod.PATCH,
89
- appType: MovaAppType.GARAGE,
90
- body: JSON.stringify({ color }),
91
- });
92
- }
93
- static updateGarageEventColor(
94
- garageId: string,
95
- eventId: string,
96
- color: string,
97
- ): Promise<APIResponse<string>> {
98
- return request({
99
- url: `${API_BASE_URL}/garage/${garageId}/event/${eventId}/color`,
100
- method: APIMethod.PATCH,
101
- appType: MovaAppType.GARAGE,
102
- body: JSON.stringify({ color }),
103
- });
104
- }
105
- static updateVehicleGarageEvent(
106
- garageId: string,
107
- eventId: string,
108
- req: any,
109
- ): Promise<APIResponse<string>> {
110
- return request({
111
- url: `${API_BASE_URL}/garage/${garageId}/event/${eventId}/vehicle`,
112
- method: APIMethod.PATCH,
113
- appType: MovaAppType.GARAGE,
114
- body: JSON.stringify(req),
115
- });
116
- }
81
+ static updateColorPrestationCategory(garageId: string, categoryCode: string, color: string): Promise<APIResponse<string>> {
82
+ return request({
83
+ url: `${API_BASE_URL}/garage/${garageId}/prestation-category/${categoryCode}/color`,
84
+ method: APIMethod.PATCH,
85
+ appType: MovaAppType.GARAGE,
86
+ body: JSON.stringify({ color })
87
+ });
88
+ }
89
+ static updateGarageEventColor(garageId: string, eventId: string, color: string): Promise<APIResponse<string>> {
90
+ return request({
91
+ url: `${API_BASE_URL}/garage/${garageId}/event/${eventId}/color`,
92
+ method: APIMethod.PATCH,
93
+ appType: MovaAppType.GARAGE,
94
+ body: JSON.stringify({ color })
95
+ });
96
+ }
97
+ static updateVehicleGarageEvent(garageId: string, eventId: string, req: any): Promise<APIResponse<string>> {
98
+
99
+ return request({
100
+ url: `${API_BASE_URL}/garage/${garageId}/event/${eventId}/vehicle`,
101
+ method: APIMethod.PATCH,
102
+ appType: MovaAppType.GARAGE,
103
+ body: JSON.stringify(req)
104
+ });
105
+ }
106
+
107
+ static uploadEventDocument(garageId: string, eventId: string, req: FormData): Promise<APIResponse<string>> {
108
+ return request({
109
+ url: `${API_BASE_URL}/garage/${garageId}/event/${eventId}/documents`,
110
+ method: APIMethod.POST,
111
+ appType: MovaAppType.GARAGE,
112
+ body: req
113
+ });
114
+ }
115
+
116
+ static deleteEventDocument(garageId: string, eventId: string, docId: string): Promise<APIResponse<string>> {
117
+ return request({
118
+ url: `${API_BASE_URL}/garage/${garageId}/event/${eventId}/documents/${docId}`,
119
+ appType: MovaAppType.GARAGE,
120
+ method: APIMethod.DELETE,
121
+ });
122
+ }
117
123
 
118
124
  static sendGarageMandate(garageId: string): Promise<APIResponse<string>> {
119
125
  return request({
@@ -0,0 +1,56 @@
1
+ import User from "../models/User";
2
+ import UserService from "./UserService";
3
+
4
+ export default class UserConnected {
5
+ private static instance: UserConnected;
6
+ private _me: User | null; // Replace 'any' with the appropriate type for the user information
7
+
8
+ private constructor() {
9
+ const storedUser = localStorage.getItem('user');
10
+ this._me = storedUser ? JSON.parse(storedUser) : null;
11
+ }
12
+
13
+ public static getInstance(): UserConnected {
14
+ if (!UserConnected.instance) {
15
+ UserConnected.instance = new UserConnected();
16
+ }
17
+
18
+ return UserConnected.instance;
19
+ }
20
+
21
+ public get me(): any {
22
+ if (!this._me) {
23
+ const storedUser = localStorage.getItem('user');
24
+ if(storedUser === undefined || storedUser === null || storedUser === 'undefined') {
25
+ UserService.getCurrentUser()
26
+ .then((response) => {
27
+ localStorage.setItem('user', JSON.stringify(response.data));
28
+ this._me = response.data as User;
29
+ return this._me;
30
+ })
31
+ } else {
32
+ this._me = JSON.parse(storedUser);
33
+ return this._me;
34
+ }
35
+ } else {
36
+ return this._me;
37
+ }
38
+ }
39
+
40
+
41
+ public set me(user: any) {
42
+ this._me = user;
43
+ if (user) {
44
+ localStorage.setItem('user', JSON.stringify(user));
45
+ } else {
46
+ localStorage.removeItem('user'); // Supprime les données si user est null ou undefined
47
+ }
48
+ }
49
+
50
+ public clearUser() {
51
+ // Méthode pour effacer l'utilisateur
52
+ this._me = null;
53
+ localStorage.removeItem('user');
54
+ }
55
+
56
+ }
@@ -78,7 +78,7 @@ export default class UserService {
78
78
  * @param password
79
79
  * @returns
80
80
  */
81
- static async getCurrentUser(appType: MovaAppType): Promise<APIResponse<User>> {
81
+ static async getCurrentUser(appType?: MovaAppType): Promise<APIResponse<User>> {
82
82
  try {
83
83
  return await request({
84
84
  url: `${API_BASE_URL}/user/me`,
@@ -13,6 +13,31 @@ export default class VehicleService {
13
13
  });
14
14
  }
15
15
 
16
+ static getVehicleDocument(appType: MovaAppType, vehicleId: number): Promise<APIResponse<string>> {
17
+ return request({
18
+ url: `${API_BASE_URL}/vehicle/${vehicleId}/document`,
19
+ method: APIMethod.GET,
20
+ appType: appType,
21
+ });
22
+ }
23
+
24
+ static deleteVehicleDocument(appType: MovaAppType,vehicleId: number, documentId: string): Promise<APIResponse<string>> {
25
+ return request({
26
+ url: `${API_BASE_URL}/vehicle/${vehicleId}/documents/${documentId}`,
27
+ method: APIMethod.DELETE,
28
+ appType: appType,
29
+ });
30
+ }
31
+
32
+ static uploadVehicleDocument(appType: MovaAppType, vehicleId: number, req: FormData): Promise<APIResponse<string>> {
33
+ return request({
34
+ url: `${API_BASE_URL}/vehicle/${vehicleId}/documents`,
35
+ method: APIMethod.POST,
36
+ appType: appType,
37
+ body: req
38
+ });
39
+ }
40
+
16
41
  static editVehicle({vehicleId, appType,...payload}: EditVehicleParams): Promise<APIResponse<string>> {
17
42
  return request({
18
43
  url: `${API_BASE_URL}/vehicle/${vehicleId}`,
@@ -0,0 +1,70 @@
1
+ import { ToggleButtonProps, ToggleButton, styled, ToggleButtonGroup, lighten } from "@mui/material";
2
+
3
+ interface StyledToggleButtonProps extends ToggleButtonProps {
4
+ customSelectedBackgroundColor?: string;
5
+ customBackgroundColor?: string;
6
+ customHoverColor?: string;
7
+ }
8
+
9
+ export const StyledToggleButton = styled(ToggleButton)<StyledToggleButtonProps>(
10
+ ({ theme, customSelectedBackgroundColor, customBackgroundColor, customHoverColor }) => ({
11
+ padding: theme.spacing(1),
12
+ marginBottom: theme.spacing(2),
13
+ borderRadius: theme.shape.borderRadius,
14
+ '&:hover': {
15
+ backgroundColor: customHoverColor || theme.palette.warning.dark,
16
+ },
17
+ '&.Mui-selected': {
18
+ backgroundColor: customSelectedBackgroundColor || theme.palette.warning.main,
19
+ },
20
+ '&.Mui-selected:hover': {
21
+ backgroundColor: customHoverColor || theme.palette.warning.dark,
22
+ },
23
+ '&:not(:first-of-type)': {
24
+ borderRadius: theme.shape.borderRadius,
25
+ border: '1px solid rgba(0, 0, 0, 0.12)',
26
+ },
27
+ '&:first-of-type': {
28
+ borderRadius: theme.shape.borderRadius,
29
+ },
30
+ '&.Mui-disabled': {
31
+ border: 0,
32
+ backgroundColor: theme.palette.grey[100],
33
+ },
34
+ }),
35
+ );
36
+
37
+
38
+ /**
39
+ * Personnalisation du style des Toogle Buttons
40
+ * Note : il n'est posssible de le personnaliser directement au niveau
41
+ * de l'objet "components" du theme.
42
+ */
43
+ export const StyledToggleButtonGroup = styled(ToggleButtonGroup)(({ theme }) => ({
44
+ '& .MuiToggleButtonGroup-grouped': {
45
+ padding: theme.spacing(1),
46
+ marginBottom: theme.spacing(2),
47
+ marginLeft: theme.spacing(1),
48
+ marginRight: theme.spacing(1),
49
+ '&.Mui-disabled': {
50
+ border: 0,
51
+ backgroundColor: theme.palette.grey[100],
52
+ },
53
+ '&.Mui-selected': {
54
+ backgroundColor: theme.palette.primary.light,
55
+ },
56
+ '&:not(:first-of-type)': {
57
+ borderRadius: theme.shape.borderRadius,
58
+ border: '1px solid rgba(0, 0, 0, 0.12)',
59
+ },
60
+ '&:first-of-type': {
61
+ borderRadius: theme.shape.borderRadius,
62
+ },
63
+ '&:hover': {
64
+ backgroundColor: lighten(theme.palette.primary.light, 0.3), // Modifier la couleur de fond au survol
65
+ },
66
+ '&.Mui-selected:hover': {
67
+ backgroundColor: theme.palette.primary.light, // Modifier la couleur de fond au survol
68
+ },
69
+ },
70
+ }));