@movalib/movalib-commons 1.59.14 → 1.59.16
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 +1 -1
- package/dist/devIndex.js +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +11 -4
- package/dist/src/components/LinkedDocumentDialog.d.ts +11 -0
- package/dist/src/components/LinkedDocumentDialog.js +55 -0
- package/dist/src/{VehicleFullCard.d.ts → components/vehicle/VehicleFullCard.d.ts} +7 -2
- package/dist/src/{VehicleFullCard.js → components/vehicle/VehicleFullCard.js} +44 -22
- package/dist/src/components/vehicle/VehiclePlateField.d.ts +8 -0
- package/dist/src/components/vehicle/VehiclePlateField.js +122 -0
- package/dist/src/helpers/CookieUtils.js +2 -1
- package/dist/src/helpers/Enums.d.ts +6 -1
- package/dist/src/helpers/Enums.js +6 -1
- package/dist/src/services/GarageService.d.ts +2 -0
- package/dist/src/services/GarageService.js +18 -3
- package/dist/src/services/UserService.d.ts +1 -1
- package/dist/src/services/VehicleService.d.ts +3 -0
- package/dist/src/services/VehicleService.js +22 -0
- package/dist/src/style/styled.d.ts +17 -0
- package/dist/src/style/styled.js +68 -0
- package/dist/src/style/styled.ts +70 -0
- package/index.ts +6 -3
- package/package.json +3 -2
- package/src/VehiclePlateField.tsx +1 -0
- package/src/components/LinkedDocumentDialog.tsx +200 -0
- package/src/components/vehicle/VehicleFullCard.tsx +551 -0
- package/src/components/vehicle/VehiclePlateField.tsx +164 -0
- package/src/helpers/CookieUtils.ts +2 -1
- package/src/helpers/Enums.ts +8 -1
- package/src/helpers/Tools.ts +1 -0
- package/src/models/Event.ts +1 -1
- package/src/services/AuthenticationService.ts +0 -1
- package/src/services/GarageService.ts +42 -36
- package/src/services/UserService.ts +1 -1
- package/src/services/VehicleService.ts +25 -0
- package/src/style/styled.ts +70 -0
- 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: '
|
|
10
|
+
Cookies.set(name, value, { expires: COOKIE_DEFAULT_EXPIRES, sameSite: 'Lax' });
|
|
10
11
|
}
|
|
11
12
|
}
|
|
12
13
|
|
package/src/helpers/Enums.ts
CHANGED
|
@@ -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
|
-
|
|
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 {
|
package/src/helpers/Tools.ts
CHANGED
package/src/models/Event.ts
CHANGED
|
@@ -78,42 +78,48 @@ export default class GarageService {
|
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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({
|
|
@@ -78,7 +78,7 @@ export default class UserService {
|
|
|
78
78
|
* @param password
|
|
79
79
|
* @returns
|
|
80
80
|
*/
|
|
81
|
-
static async getCurrentUser(appType
|
|
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
|
+
}));
|