@movalib/movalib-commons 1.1.61 → 1.1.63
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 +5 -3
- package/dist/devIndex.js +2 -0
- package/dist/src/AccountValidation.d.ts +1 -0
- package/dist/src/AccountValidation.js +73 -24
- package/dist/src/helpers/Types.d.ts +2 -1
- package/dist/src/services/UserService.d.ts +1 -0
- package/dist/src/services/UserService.js +8 -0
- package/package.json +1 -1
- package/src/AccountValidation.tsx +141 -44
- package/src/helpers/Types.ts +3 -2
- package/src/services/UserService.ts +9 -0
package/devIndex.tsx
CHANGED
|
@@ -195,9 +195,11 @@ const App = () => {
|
|
|
195
195
|
|
|
196
196
|
|
|
197
197
|
{openAccountValidation && <AccountValidation smsValidation={true} movaAppType={MovaAppType.GARAGE}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
198
|
+
onSubmit={function (success: boolean, message: string): void {
|
|
199
|
+
throw new Error('Function not implemented.');
|
|
200
|
+
} } onResendSecurityCode={function (success: boolean, message: string): void {
|
|
201
|
+
throw new Error('Function not implemented.');
|
|
202
|
+
} } /> }
|
|
201
203
|
|
|
202
204
|
</ThemeProvider>
|
|
203
205
|
</LocalizationProvider>
|
package/dist/devIndex.js
CHANGED
|
@@ -157,6 +157,8 @@ var App = function () {
|
|
|
157
157
|
throw new Error('Function not implemented.');
|
|
158
158
|
} })] }))] })), (0, jsx_runtime_1.jsx)(material_1.Box, __assign({ style: Tools_1.flexCenter }, { children: (0, jsx_runtime_1.jsx)(material_1.Button, __assign({ onClick: function () { return setOpenAccountValidation(!openAccountValidation); } }, { children: "Validation de compte" })) })), openAccountValidation && (0, jsx_runtime_1.jsx)(AccountValidation_1.default, { smsValidation: true, movaAppType: Enums_1.MovaAppType.GARAGE, onSubmit: function (success, message) {
|
|
159
159
|
throw new Error('Function not implemented.');
|
|
160
|
+
}, onResendSecurityCode: function (success, message) {
|
|
161
|
+
throw new Error('Function not implemented.');
|
|
160
162
|
} })] })) })) }));
|
|
161
163
|
};
|
|
162
164
|
var root = (0, client_1.createRoot)(document.getElementById('root'));
|
|
@@ -4,6 +4,7 @@ interface AccountValidationProps {
|
|
|
4
4
|
movaAppType: MovaAppType;
|
|
5
5
|
smsValidation: boolean;
|
|
6
6
|
onSubmit: (success: boolean, message: string) => void;
|
|
7
|
+
onResendSecurityCode: (success: boolean, message: string) => void;
|
|
7
8
|
}
|
|
8
9
|
declare const AccountValidation: FunctionComponent<AccountValidationProps>;
|
|
9
10
|
export default AccountValidation;
|
|
@@ -29,28 +29,29 @@ var Tools_1 = require("./helpers/Tools");
|
|
|
29
29
|
var MovaDialog_1 = __importDefault(require("./MovaDialog"));
|
|
30
30
|
var logo_large_png_1 = __importDefault(require("./assets/images/logo/logo_large.png"));
|
|
31
31
|
var logo_pro_large_png_1 = __importDefault(require("./assets/images/logo/logo_pro_large.png"));
|
|
32
|
+
var ConfirmationDialog_1 = __importDefault(require("./ConfirmationDialog"));
|
|
32
33
|
var initialFormState = {
|
|
33
34
|
password: { value: '', isValid: true },
|
|
34
35
|
confirmation: { value: '', isValid: true },
|
|
35
36
|
securityCode: { value: '', isValid: true },
|
|
37
|
+
phoneNumber: { value: '', isValid: true },
|
|
36
38
|
};
|
|
37
39
|
var AccountValidation = function (_a) {
|
|
38
40
|
var _b, _c, _d, _e;
|
|
39
|
-
var movaAppType = _a.movaAppType, smsValidation = _a.smsValidation, onSubmit = _a.onSubmit;
|
|
41
|
+
var movaAppType = _a.movaAppType, smsValidation = _a.smsValidation, onSubmit = _a.onSubmit, onResendSecurityCode = _a.onResendSecurityCode;
|
|
40
42
|
var _f = (0, react_1.useState)(true), loading = _f[0], setLoading = _f[1];
|
|
41
|
-
var _g = (0, react_1.useState)(initialFormState),
|
|
43
|
+
var _g = (0, react_1.useState)(initialFormState), validationForm = _g[0], setValidationForm = _g[1];
|
|
42
44
|
var location = (0, react_router_dom_1.useLocation)();
|
|
43
45
|
var history = (0, react_router_dom_1.useHistory)();
|
|
44
46
|
var theme = (0, material_1.useTheme)();
|
|
45
47
|
var _h = (0, react_1.useState)(false), emptyPwd = _h[0], setEmptyPwd = _h[1];
|
|
46
48
|
var _j = (0, react_1.useState)(false), showPassword = _j[0], setShowPassword = _j[1];
|
|
49
|
+
var _k = (0, react_1.useState)(false), openPhoneNumberInput = _k[0], setOpenPhoneNumberInput = _k[1];
|
|
47
50
|
var isMobile = (0, material_1.useMediaQuery)(theme.breakpoints.down('sm'));
|
|
48
51
|
(0, react_1.useEffect)(function () {
|
|
49
52
|
var params = new URLSearchParams(location.search);
|
|
50
53
|
var token = params.get('token');
|
|
51
54
|
// Si cette variable est transmise, cela signifie que le compte a été créé sans mot de passe
|
|
52
|
-
Logger_1.default.info(params);
|
|
53
|
-
Logger_1.default.info(Boolean(params.get('emptyPwd')));
|
|
54
55
|
var localEmptyPwd = Boolean(params.get('emptyPwd'));
|
|
55
56
|
setEmptyPwd(localEmptyPwd);
|
|
56
57
|
if (token) {
|
|
@@ -92,24 +93,24 @@ var AccountValidation = function (_a) {
|
|
|
92
93
|
var fieldName = e.target.name;
|
|
93
94
|
var fieldValue = e.target.value;
|
|
94
95
|
var newField = (_a = {}, _a[fieldName] = { value: fieldValue, isValid: true }, _a);
|
|
95
|
-
|
|
96
|
+
setValidationForm(__assign(__assign({}, validationForm), newField));
|
|
96
97
|
}
|
|
97
98
|
};
|
|
98
99
|
var validateForm = function () {
|
|
99
|
-
var newForm = __assign({},
|
|
100
|
+
var newForm = __assign({}, validationForm);
|
|
100
101
|
// Validator pour les champs obligatoires
|
|
101
|
-
newForm.password = (0, Tools_1.validateField)(
|
|
102
|
-
newForm.confirmation = (0, Tools_1.validateField)(
|
|
102
|
+
newForm.password = (0, Tools_1.validateField)(validationForm.password, function (value) { return !!value; }, 'Champ obligatoire');
|
|
103
|
+
newForm.confirmation = (0, Tools_1.validateField)(validationForm.confirmation, function (value) { return !!value; }, 'Champ obligatoire');
|
|
103
104
|
if (smsValidation)
|
|
104
|
-
newForm.securityCode = (0, Tools_1.validateField)(
|
|
105
|
+
newForm.securityCode = (0, Tools_1.validateField)(validationForm.securityCode, function (value) { return !!value; }, 'Champ obligatoire');
|
|
105
106
|
// Validator pour le mot de passe
|
|
106
|
-
newForm.password = (0, Tools_1.validateField)(
|
|
107
|
+
newForm.password = (0, Tools_1.validateField)(validationForm.password, function (value) { return value.length >= 10 && /[a-z]/.test(value) && /[A-Z]/.test(value); }, 'Votre mot de passe doit faire au moins 10 caractères et contenir une majuscule et une minuscule minimum');
|
|
107
108
|
// Second validator pour le mot de passe (confirmation)
|
|
108
|
-
newForm.confirmation = (0, Tools_1.validateField)(
|
|
109
|
+
newForm.confirmation = (0, Tools_1.validateField)(validationForm.confirmation, function (value) { return value === validationForm.password.value; }, "Les mots de passe doivent être identiques");
|
|
109
110
|
// Validator pour le code de sécurité
|
|
110
111
|
if (smsValidation)
|
|
111
|
-
newForm.securityCode = (0, Tools_1.validateField)(
|
|
112
|
-
|
|
112
|
+
newForm.securityCode = (0, Tools_1.validateField)(validationForm.securityCode, function (value) { return value.length === 6; }, "Le code doit contenir 6 chiffres");
|
|
113
|
+
setValidationForm(newForm);
|
|
113
114
|
return newForm.password.isValid && newForm.confirmation.isValid && (smsValidation ? newForm.securityCode.isValid : true);
|
|
114
115
|
};
|
|
115
116
|
var handleValidateAccount = function () {
|
|
@@ -118,8 +119,8 @@ var AccountValidation = function (_a) {
|
|
|
118
119
|
var params = new URLSearchParams(location.search);
|
|
119
120
|
var req = {
|
|
120
121
|
token: !smsValidation ? params.get('token') : null,
|
|
121
|
-
securityCode: smsValidation ?
|
|
122
|
-
password:
|
|
122
|
+
securityCode: smsValidation ? validationForm.securityCode.value : null,
|
|
123
|
+
password: validationForm.password.value,
|
|
123
124
|
demoGarage: Boolean(params.get('demoGarage'))
|
|
124
125
|
};
|
|
125
126
|
activateAccount(req);
|
|
@@ -137,25 +138,73 @@ var AccountValidation = function (_a) {
|
|
|
137
138
|
movaAppType === Enums_1.MovaAppType.INDIVIDUAL ? logo_large_png_1.default :
|
|
138
139
|
movaAppType === Enums_1.MovaAppType.ADMIN ? logo_large_png_1.default : logo_large_png_1.default;
|
|
139
140
|
};
|
|
141
|
+
var handleOpenResendCode = function () {
|
|
142
|
+
setOpenPhoneNumberInput(true);
|
|
143
|
+
};
|
|
144
|
+
var validatePhoneNumber = function () {
|
|
145
|
+
var _a, _b, _c, _d, _e;
|
|
146
|
+
var newForm = validationForm;
|
|
147
|
+
var newField;
|
|
148
|
+
// Validator 'phoneNumber'
|
|
149
|
+
if ((_a = newForm.phoneNumber) === null || _a === void 0 ? void 0 : _a.value) {
|
|
150
|
+
if (((_b = newForm.phoneNumber) === null || _b === void 0 ? void 0 : _b.value.length) < 10) {
|
|
151
|
+
newField = { value: (_c = validationForm.phoneNumber) === null || _c === void 0 ? void 0 : _c.value, error: "Le n° de téléphone est invalide." };
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
newField = { value: (_d = validationForm.phoneNumber) === null || _d === void 0 ? void 0 : _d.value, error: '' };
|
|
155
|
+
}
|
|
156
|
+
newForm = __assign(__assign({}, newForm), { phoneNumber: newField });
|
|
157
|
+
}
|
|
158
|
+
setValidationForm(newForm);
|
|
159
|
+
return !Boolean((_e = newForm.phoneNumber) === null || _e === void 0 ? void 0 : _e.error);
|
|
160
|
+
};
|
|
161
|
+
var resendCode = function () {
|
|
162
|
+
var _a;
|
|
163
|
+
if (validatePhoneNumber()) {
|
|
164
|
+
var req = {
|
|
165
|
+
phoneNumber: (_a = validationForm.phoneNumber) === null || _a === void 0 ? void 0 : _a.value
|
|
166
|
+
};
|
|
167
|
+
UserService_1.default.resendSecurityCode(req)
|
|
168
|
+
.then(function (response) {
|
|
169
|
+
var _a, _b;
|
|
170
|
+
Logger_1.default.info(response);
|
|
171
|
+
if (response.success) {
|
|
172
|
+
if (onResendSecurityCode) {
|
|
173
|
+
onResendSecurityCode(response.success, (_a = response.data) !== null && _a !== void 0 ? _a : '');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
if (onResendSecurityCode) {
|
|
178
|
+
onResendSecurityCode(response.success, (_b = response.error) !== null && _b !== void 0 ? _b : '');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}).catch(function (error) {
|
|
182
|
+
Logger_1.default.error(error);
|
|
183
|
+
if (onSubmit) {
|
|
184
|
+
onSubmit(false, error);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
};
|
|
140
189
|
return ((0, jsx_runtime_1.jsxs)("div", { children: [(emptyPwd || smsValidation) &&
|
|
141
|
-
(0, jsx_runtime_1.jsx)(MovaDialog_1.default, __assign({ leafImageColor: 'pink', titleStyle: getTitleStyle(), fullScreen: isMobile, open: emptyPwd, closable: false, onClose: function () {
|
|
190
|
+
(0, jsx_runtime_1.jsx)(MovaDialog_1.default, __assign({ leafImageColor: 'pink', titleStyle: getTitleStyle(), fullScreen: isMobile, open: emptyPwd || smsValidation, closable: false, onClose: function () {
|
|
142
191
|
throw new Error('Function not implemented.');
|
|
143
192
|
}, actions: (0, jsx_runtime_1.jsx)(lab_1.LoadingButton, __assign({ type: "submit", onClick: handleValidateAccount, fullWidth: true, variant: "contained", sx: { mt: 4, mb: 0 } }, { children: (0, jsx_runtime_1.jsx)("span", { children: "Activer mon compte" }) })) }, { children: (0, jsx_runtime_1.jsxs)(material_1.Grid, __assign({ container: true }, { children: [(0, jsx_runtime_1.jsx)(material_1.Grid, __assign({ item: true, xs: 12 }, { children: (0, jsx_runtime_1.jsxs)(material_1.Box, __assign({ sx: {
|
|
144
193
|
display: 'flex',
|
|
145
194
|
flexDirection: 'column',
|
|
146
195
|
alignItems: 'center',
|
|
147
|
-
} }, { children: [(0, jsx_runtime_1.jsx)("img", { src: getMovaLogo(), style: { width: '50%' } }), (0, jsx_runtime_1.jsx)("br", {})] })) })), (0, jsx_runtime_1.jsx)(material_1.Grid, __assign({ item: true, xs: 12 }, { children: (0, jsx_runtime_1.jsx)(material_1.Typography, __assign({ sx: { mt: 2, mb:
|
|
196
|
+
} }, { children: [(0, jsx_runtime_1.jsx)("img", { src: getMovaLogo(), style: { width: '50%' } }), (0, jsx_runtime_1.jsx)("br", {})] })) })), (0, jsx_runtime_1.jsx)(material_1.Grid, __assign({ item: true, xs: 12 }, { children: (0, jsx_runtime_1.jsx)(material_1.Typography, __assign({ sx: { mt: 2, mb: 3 } }, { children: movaAppType === Enums_1.MovaAppType.INDIVIDUAL ?
|
|
148
197
|
"Pour commencer, définis ton mot de passe et active ton compte 😉"
|
|
149
198
|
:
|
|
150
|
-
"Pour commencer, définissez votre mot de passe et activez votre compte 😉" })) })), smsValidation && (0, jsx_runtime_1.jsx)(material_1.Grid, __assign({ item: true, xs: 12 }, { children: (0, jsx_runtime_1.jsx)(material_1.TextField, { label: "Code re\u00E7u par SMS", required: true, fullWidth: true, name: "securityCode", variant: "outlined", value: (_b =
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
199
|
+
"Pour commencer, définissez votre mot de passe et activez votre compte 😉" })) })), smsValidation && (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(material_1.Grid, __assign({ item: true, xs: 12 }, { children: (0, jsx_runtime_1.jsx)(material_1.TextField, { label: "Code re\u00E7u par SMS", required: true, fullWidth: true, name: "securityCode", variant: "outlined", value: (_b = validationForm.securityCode) === null || _b === void 0 ? void 0 : _b.value, error: !((_c = validationForm.securityCode) === null || _c === void 0 ? void 0 : _c.isValid), helperText: Boolean((_d = validationForm.securityCode) === null || _d === void 0 ? void 0 : _d.error) ? (_e = validationForm.securityCode) === null || _e === void 0 ? void 0 : _e.error : null, onChange: function (e) { return handleInputChange(e); }, inputProps: {
|
|
200
|
+
maxLength: 6,
|
|
201
|
+
inputMode: 'numeric',
|
|
202
|
+
pattern: '[0-9]*' // Permet seulement la saisie de chiffres
|
|
203
|
+
} }) })), (0, jsx_runtime_1.jsx)(material_1.Grid, __assign({ item: true, xs: 12 }, { children: (0, jsx_runtime_1.jsx)(material_1.Link, __assign({ component: "button", variant: "body2", onClick: handleOpenResendCode, sx: { cursor: 'pointer', textAlign: 'center', width: '100%' } }, { children: "Renvoyer le code" })) }))] }), (0, jsx_runtime_1.jsx)(material_1.Grid, __assign({ item: true, xs: 12 }, { children: (0, jsx_runtime_1.jsx)(material_1.TextField, { margin: "normal", required: true, fullWidth: true, name: "password", label: "Mot de passe", type: showPassword ? 'text' : 'password', id: "password", autoComplete: "current-password", onChange: function (e) { return handleInputChange(e); }, value: validationForm.password.value, error: !validationForm.password.isValid, helperText: Boolean(validationForm.password.error) ? validationForm.password.error : "10 caractères minimum, 1 majuscule, 1 minuscule", InputProps: {
|
|
155
204
|
endAdornment: ((0, jsx_runtime_1.jsx)(InputAdornment_1.default, __assign({ position: "end" }, { children: (0, jsx_runtime_1.jsx)(material_1.IconButton, __assign({ edge: "end", onClick: function (e) { return setShowPassword(function (prev) { return !prev; }); } }, { children: showPassword ? (0, jsx_runtime_1.jsx)(VisibilityOff_1.default, {}) : (0, jsx_runtime_1.jsx)(Visibility_1.default, {}) })) }))),
|
|
156
|
-
} }) })), (0, jsx_runtime_1.jsx)(material_1.Grid, __assign({ item: true, xs: 12 }, { children: (0, jsx_runtime_1.jsx)(material_1.TextField, { margin: "normal", required: true, fullWidth: true, name: "confirmation", label: "Confirmation", type: showPassword ? 'text' : 'password', id: "confirmation", onChange: function (e) { return handleInputChange(e); }, value:
|
|
205
|
+
} }) })), (0, jsx_runtime_1.jsx)(material_1.Grid, __assign({ item: true, xs: 12 }, { children: (0, jsx_runtime_1.jsx)(material_1.TextField, { margin: "normal", required: true, fullWidth: true, name: "confirmation", label: "Confirmation mot de passe", type: showPassword ? 'text' : 'password', id: "confirmation", onChange: function (e) { return handleInputChange(e); }, value: validationForm.confirmation.value, error: !validationForm.confirmation.isValid, helperText: Boolean(validationForm.confirmation.error) ? validationForm.confirmation.error : "", InputProps: {
|
|
157
206
|
endAdornment: ((0, jsx_runtime_1.jsx)(InputAdornment_1.default, __assign({ position: "end" }, { children: (0, jsx_runtime_1.jsx)(material_1.IconButton, __assign({ edge: "end", onClick: function (e) { return setShowPassword(function (prev) { return !prev; }); } }, { children: showPassword ? (0, jsx_runtime_1.jsx)(VisibilityOff_1.default, {}) : (0, jsx_runtime_1.jsx)(Visibility_1.default, {}) })) }))),
|
|
158
207
|
} }) }))] })) })), loading &&
|
|
159
|
-
(0, jsx_runtime_1.jsx)(material_1.Box, __assign({ display: "flex", justifyContent: "center", alignItems: "center", minHeight: "100vh" }, { children: (0, jsx_runtime_1.jsx)(material_1.CircularProgress, {}) }))] }));
|
|
208
|
+
(0, jsx_runtime_1.jsx)(material_1.Box, __assign({ display: "flex", justifyContent: "center", alignItems: "center", minHeight: "100vh" }, { children: (0, jsx_runtime_1.jsx)(material_1.CircularProgress, {}) })), openPhoneNumberInput && (0, jsx_runtime_1.jsx)(ConfirmationDialog_1.default, { open: openPhoneNumberInput, confirmLabel: "Envoyer", closeLabel: "Annuler", onClose: function () { return setOpenPhoneNumberInput(false); }, onConfirm: resendCode, message: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(material_1.Typography, { children: [(0, jsx_runtime_1.jsx)("b", { children: "Indique nous ton num\u00E9ro de t\u00E9l\u00E9phone" }), (0, jsx_runtime_1.jsx)("br", {})] }), (0, jsx_runtime_1.jsx)(material_1.Grid, __assign({ item: true, xs: 6 }, { children: (0, jsx_runtime_1.jsx)(material_1.TextField, { margin: "normal", fullWidth: true, required: true, id: "phoneNumber", label: "N\u00B0 de t\u00E9l\u00E9phone", name: "phoneNumber", autoComplete: "tel", onChange: function (e) { return handleInputChange(e); }, value: validationForm.phoneNumber.value, error: Boolean(validationForm.phoneNumber.error), helperText: validationForm.phoneNumber.error }) }))] }) })] }));
|
|
160
209
|
};
|
|
161
210
|
exports.default = AccountValidation;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
export type
|
|
1
|
+
export type MovaValidationForm = {
|
|
2
2
|
password: MovaFormField;
|
|
3
3
|
confirmation: MovaFormField;
|
|
4
4
|
securityCode: MovaFormField;
|
|
5
|
+
phoneNumber: MovaFormField;
|
|
5
6
|
};
|
|
6
7
|
export type AddressFieldName = 'streetName' | 'additional' | 'postalCode' | 'cityName';
|
|
7
8
|
export type MovaVehicleForm = {
|
|
@@ -3,6 +3,7 @@ import { MovaAppType } from "../helpers/Enums";
|
|
|
3
3
|
import Garage from "../models/Garage";
|
|
4
4
|
import User from "../models/User";
|
|
5
5
|
export default class UserService {
|
|
6
|
+
static resendSecurityCode(req: any): Promise<APIResponse<string>>;
|
|
6
7
|
static getSalesGarages(salesId: string): Promise<APIResponse<Garage[]>>;
|
|
7
8
|
static validateAccount(req: any): Promise<APIResponse<string>>;
|
|
8
9
|
/**
|
|
@@ -45,6 +45,14 @@ var Logger_1 = __importDefault(require("../helpers/Logger"));
|
|
|
45
45
|
var UserService = /** @class */ (function () {
|
|
46
46
|
function UserService() {
|
|
47
47
|
}
|
|
48
|
+
UserService.resendSecurityCode = function (req) {
|
|
49
|
+
return (0, ApiHelper_1.request)({
|
|
50
|
+
url: "".concat(ApiHelper_1.API_BASE_URL, "/user/resend-security-code"),
|
|
51
|
+
method: Enums_1.APIMethod.POST,
|
|
52
|
+
appType: Enums_1.MovaAppType.INDIVIDUAL,
|
|
53
|
+
body: JSON.stringify(req)
|
|
54
|
+
});
|
|
55
|
+
};
|
|
48
56
|
UserService.getSalesGarages = function (salesId) {
|
|
49
57
|
return (0, ApiHelper_1.request)({
|
|
50
58
|
url: "".concat(ApiHelper_1.API_BASE_URL, "/sales/").concat(salesId, "/garages"),
|
package/package.json
CHANGED
|
@@ -1,41 +1,45 @@
|
|
|
1
1
|
import { CSSProperties, FunctionComponent, useEffect, useState } from 'react';
|
|
2
2
|
import { useHistory, useLocation } from 'react-router-dom';
|
|
3
3
|
import UserService from './services/UserService';
|
|
4
|
-
import { Box, CircularProgress, Grid, IconButton, TextField, Typography, darken, useMediaQuery, useTheme } from '@mui/material';
|
|
4
|
+
import { Box, CircularProgress, Grid, IconButton, Link, TextField, Typography, darken, useMediaQuery, useTheme } from '@mui/material';
|
|
5
5
|
import Logger from './helpers/Logger';
|
|
6
6
|
import InputAdornment from '@mui/material/InputAdornment';
|
|
7
7
|
import Visibility from '@mui/icons-material/Visibility';
|
|
8
8
|
import VisibilityOff from '@mui/icons-material/VisibilityOff';
|
|
9
9
|
import { LoadingButton } from '@mui/lab';
|
|
10
10
|
import { MovaAppType } from './helpers/Enums';
|
|
11
|
-
import { MovaFormField,
|
|
11
|
+
import { MovaFormField, MovaValidationForm } from './helpers/Types';
|
|
12
12
|
import { validateField } from './helpers/Tools';
|
|
13
13
|
import MovaDialog from './MovaDialog';
|
|
14
14
|
|
|
15
15
|
import LogoLarge from './assets/images/logo/logo_large.png';
|
|
16
16
|
import LogoProLarge from './assets/images/logo/logo_pro_large.png';
|
|
17
|
+
import ConfirmationDialog from './ConfirmationDialog';
|
|
17
18
|
|
|
18
19
|
const initialFormState = {
|
|
19
20
|
password: { value: '', isValid: true },
|
|
20
21
|
confirmation: { value: '', isValid: true },
|
|
21
22
|
securityCode: { value: '', isValid: true },
|
|
23
|
+
phoneNumber: { value: '', isValid: true },
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
interface AccountValidationProps {
|
|
25
27
|
movaAppType: MovaAppType,
|
|
26
28
|
smsValidation: boolean,
|
|
27
29
|
onSubmit: (success:boolean, message:string) => void,
|
|
30
|
+
onResendSecurityCode: (success:boolean, message:string) => void,
|
|
28
31
|
}
|
|
29
32
|
|
|
30
|
-
const AccountValidation: FunctionComponent<AccountValidationProps> = ({ movaAppType, smsValidation, onSubmit }) => {
|
|
33
|
+
const AccountValidation: FunctionComponent<AccountValidationProps> = ({ movaAppType, smsValidation, onSubmit, onResendSecurityCode }) => {
|
|
31
34
|
|
|
32
35
|
const [loading, setLoading] = useState(true);
|
|
33
|
-
const [
|
|
36
|
+
const [validationForm, setValidationForm] = useState<MovaValidationForm>(initialFormState);
|
|
34
37
|
const location = useLocation();
|
|
35
38
|
const history = useHistory();
|
|
36
39
|
const theme = useTheme();
|
|
37
40
|
const [emptyPwd, setEmptyPwd] = useState<boolean>(false);
|
|
38
41
|
const [showPassword, setShowPassword] = useState(false);
|
|
42
|
+
const [openPhoneNumberInput, setOpenPhoneNumberInput] = useState<boolean>(false);
|
|
39
43
|
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
|
40
44
|
|
|
41
45
|
useEffect(() => {
|
|
@@ -44,8 +48,6 @@ const AccountValidation: FunctionComponent<AccountValidationProps> = ({ movaAppT
|
|
|
44
48
|
const token = params.get('token');
|
|
45
49
|
|
|
46
50
|
// Si cette variable est transmise, cela signifie que le compte a été créé sans mot de passe
|
|
47
|
-
Logger.info(params);
|
|
48
|
-
Logger.info(Boolean(params.get('emptyPwd')));
|
|
49
51
|
let localEmptyPwd = Boolean(params.get('emptyPwd'));
|
|
50
52
|
setEmptyPwd(localEmptyPwd);
|
|
51
53
|
|
|
@@ -96,33 +98,33 @@ const AccountValidation: FunctionComponent<AccountValidationProps> = ({ movaAppT
|
|
|
96
98
|
const fieldValue: string = e.target.value;
|
|
97
99
|
const newField: MovaFormField = { [fieldName]: { value: fieldValue, isValid: true } };
|
|
98
100
|
|
|
99
|
-
|
|
101
|
+
setValidationForm({ ...validationForm, ...newField});
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
|
|
103
105
|
const validateForm = () => {
|
|
104
|
-
let newForm:
|
|
106
|
+
let newForm: MovaValidationForm = { ...validationForm };
|
|
105
107
|
|
|
106
108
|
// Validator pour les champs obligatoires
|
|
107
|
-
newForm.password = validateField(
|
|
108
|
-
newForm.confirmation = validateField(
|
|
109
|
+
newForm.password = validateField(validationForm.password, value => !!value, 'Champ obligatoire');
|
|
110
|
+
newForm.confirmation = validateField(validationForm.confirmation, value => !!value, 'Champ obligatoire');
|
|
109
111
|
if(smsValidation)
|
|
110
|
-
newForm.securityCode = validateField(
|
|
112
|
+
newForm.securityCode = validateField(validationForm.securityCode, value => !!value, 'Champ obligatoire');
|
|
111
113
|
|
|
112
114
|
// Validator pour le mot de passe
|
|
113
|
-
newForm.password = validateField(
|
|
115
|
+
newForm.password = validateField(validationForm.password,
|
|
114
116
|
value => value.length >= 10 && /[a-z]/.test(value) && /[A-Z]/.test(value),
|
|
115
117
|
'Votre mot de passe doit faire au moins 10 caractères et contenir une majuscule et une minuscule minimum');
|
|
116
118
|
|
|
117
119
|
// Second validator pour le mot de passe (confirmation)
|
|
118
|
-
newForm.confirmation = validateField(
|
|
120
|
+
newForm.confirmation = validateField(validationForm.confirmation, value => value === validationForm.password.value,
|
|
119
121
|
"Les mots de passe doivent être identiques");
|
|
120
122
|
|
|
121
123
|
// Validator pour le code de sécurité
|
|
122
124
|
if(smsValidation)
|
|
123
|
-
newForm.securityCode = validateField(
|
|
125
|
+
newForm.securityCode = validateField(validationForm.securityCode, value => value.length === 6, "Le code doit contenir 6 chiffres");
|
|
124
126
|
|
|
125
|
-
|
|
127
|
+
setValidationForm(newForm);
|
|
126
128
|
|
|
127
129
|
return newForm.password.isValid && newForm.confirmation.isValid && (smsValidation ? newForm.securityCode.isValid : true);
|
|
128
130
|
}
|
|
@@ -135,8 +137,8 @@ const AccountValidation: FunctionComponent<AccountValidationProps> = ({ movaAppT
|
|
|
135
137
|
|
|
136
138
|
let req = {
|
|
137
139
|
token: !smsValidation ? params.get('token') : null,
|
|
138
|
-
securityCode : smsValidation ?
|
|
139
|
-
password:
|
|
140
|
+
securityCode : smsValidation ? validationForm.securityCode.value : null,
|
|
141
|
+
password: validationForm.password.value,
|
|
140
142
|
demoGarage: Boolean(params.get('demoGarage'))
|
|
141
143
|
}
|
|
142
144
|
|
|
@@ -159,6 +161,62 @@ const AccountValidation: FunctionComponent<AccountValidationProps> = ({ movaAppT
|
|
|
159
161
|
movaAppType === MovaAppType.ADMIN ? LogoLarge : LogoLarge;
|
|
160
162
|
}
|
|
161
163
|
|
|
164
|
+
const handleOpenResendCode = () => {
|
|
165
|
+
setOpenPhoneNumberInput(true);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const validatePhoneNumber = ():boolean => {
|
|
169
|
+
|
|
170
|
+
let newForm: MovaValidationForm = validationForm;
|
|
171
|
+
let newField: MovaFormField;
|
|
172
|
+
|
|
173
|
+
// Validator 'phoneNumber'
|
|
174
|
+
if(newForm.phoneNumber?.value){
|
|
175
|
+
if(newForm.phoneNumber?.value.length < 10){
|
|
176
|
+
newField = { value: validationForm.phoneNumber?.value, error: "Le n° de téléphone est invalide."};
|
|
177
|
+
} else {
|
|
178
|
+
newField ={ value: validationForm.phoneNumber?.value, error: ''};
|
|
179
|
+
}
|
|
180
|
+
newForm = { ...newForm, ...{ phoneNumber: newField } };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
setValidationForm(newForm);
|
|
184
|
+
|
|
185
|
+
return !Boolean(newForm.phoneNumber?.error);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const resendCode = () => {
|
|
189
|
+
|
|
190
|
+
if(validatePhoneNumber()){
|
|
191
|
+
|
|
192
|
+
let req = {
|
|
193
|
+
phoneNumber : validationForm.phoneNumber?.value
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
UserService.resendSecurityCode(req)
|
|
197
|
+
.then(response => {
|
|
198
|
+
|
|
199
|
+
Logger.info(response);
|
|
200
|
+
|
|
201
|
+
if(response.success){
|
|
202
|
+
if(onResendSecurityCode){
|
|
203
|
+
onResendSecurityCode(response.success, response.data ?? '');
|
|
204
|
+
}
|
|
205
|
+
}else{
|
|
206
|
+
if(onResendSecurityCode){
|
|
207
|
+
onResendSecurityCode(response.success, response.error ?? '');
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
}).catch(error => {
|
|
212
|
+
Logger.error(error);
|
|
213
|
+
if(onSubmit){
|
|
214
|
+
onSubmit(false, error);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
162
220
|
return (
|
|
163
221
|
<div>
|
|
164
222
|
{(emptyPwd || smsValidation) &&
|
|
@@ -166,7 +224,7 @@ const AccountValidation: FunctionComponent<AccountValidationProps> = ({ movaAppT
|
|
|
166
224
|
leafImageColor='pink'
|
|
167
225
|
titleStyle={getTitleStyle()}
|
|
168
226
|
fullScreen={isMobile}
|
|
169
|
-
open={emptyPwd}
|
|
227
|
+
open={emptyPwd || smsValidation}
|
|
170
228
|
closable={false}
|
|
171
229
|
onClose={function (): void {
|
|
172
230
|
throw new Error('Function not implemented.');
|
|
@@ -195,7 +253,7 @@ const AccountValidation: FunctionComponent<AccountValidationProps> = ({ movaAppT
|
|
|
195
253
|
</Box>
|
|
196
254
|
</Grid>
|
|
197
255
|
<Grid item xs={12}>
|
|
198
|
-
<Typography sx={{ mt: 2, mb:
|
|
256
|
+
<Typography sx={{ mt: 2, mb: 3 }}>
|
|
199
257
|
{movaAppType === MovaAppType.INDIVIDUAL ?
|
|
200
258
|
"Pour commencer, définis ton mot de passe et active ton compte 😉"
|
|
201
259
|
:
|
|
@@ -203,24 +261,37 @@ const AccountValidation: FunctionComponent<AccountValidationProps> = ({ movaAppT
|
|
|
203
261
|
}
|
|
204
262
|
</Typography>
|
|
205
263
|
</Grid>
|
|
206
|
-
{smsValidation &&
|
|
207
|
-
<
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
264
|
+
{smsValidation && <>
|
|
265
|
+
<Grid item xs={12}>
|
|
266
|
+
<TextField
|
|
267
|
+
label="Code reçu par SMS"
|
|
268
|
+
required
|
|
269
|
+
fullWidth
|
|
270
|
+
name="securityCode"
|
|
271
|
+
variant="outlined"
|
|
272
|
+
value={validationForm.securityCode?.value}
|
|
273
|
+
error={!validationForm.securityCode?.isValid}
|
|
274
|
+
helperText={Boolean(validationForm.securityCode?.error) ? validationForm.securityCode?.error : null}
|
|
275
|
+
onChange={e => handleInputChange(e)}
|
|
276
|
+
inputProps={{
|
|
277
|
+
maxLength: 6,
|
|
278
|
+
inputMode: 'numeric', // Affiche un clavier numérique sur les appareils mobiles
|
|
279
|
+
pattern: '[0-9]*' // Permet seulement la saisie de chiffres
|
|
280
|
+
}}
|
|
281
|
+
/>
|
|
282
|
+
</Grid>
|
|
283
|
+
<Grid item xs={12}>
|
|
284
|
+
<Link
|
|
285
|
+
component="button"
|
|
286
|
+
variant="body2"
|
|
287
|
+
onClick={handleOpenResendCode}
|
|
288
|
+
sx={{ cursor: 'pointer', textAlign: 'center', width: '100%' }}
|
|
289
|
+
>
|
|
290
|
+
Renvoyer le code
|
|
291
|
+
</Link>
|
|
292
|
+
</Grid>
|
|
293
|
+
</>
|
|
294
|
+
}
|
|
224
295
|
<Grid item xs={12}>
|
|
225
296
|
<TextField
|
|
226
297
|
margin="normal"
|
|
@@ -232,9 +303,9 @@ const AccountValidation: FunctionComponent<AccountValidationProps> = ({ movaAppT
|
|
|
232
303
|
id="password"
|
|
233
304
|
autoComplete="current-password"
|
|
234
305
|
onChange={e => handleInputChange(e)}
|
|
235
|
-
value={
|
|
236
|
-
error={!
|
|
237
|
-
helperText={Boolean(
|
|
306
|
+
value={validationForm.password.value}
|
|
307
|
+
error={!validationForm.password.isValid}
|
|
308
|
+
helperText={Boolean(validationForm.password.error) ? validationForm.password.error : "10 caractères minimum, 1 majuscule, 1 minuscule"}
|
|
238
309
|
InputProps={{
|
|
239
310
|
endAdornment: (
|
|
240
311
|
<InputAdornment position="end">
|
|
@@ -255,13 +326,13 @@ const AccountValidation: FunctionComponent<AccountValidationProps> = ({ movaAppT
|
|
|
255
326
|
required
|
|
256
327
|
fullWidth
|
|
257
328
|
name="confirmation"
|
|
258
|
-
label="Confirmation"
|
|
329
|
+
label="Confirmation mot de passe"
|
|
259
330
|
type={showPassword ? 'text' : 'password'}
|
|
260
331
|
id="confirmation"
|
|
261
332
|
onChange={e => handleInputChange(e)}
|
|
262
|
-
value={
|
|
263
|
-
error={!
|
|
264
|
-
helperText={Boolean(
|
|
333
|
+
value={validationForm.confirmation.value}
|
|
334
|
+
error={!validationForm.confirmation.isValid}
|
|
335
|
+
helperText={Boolean(validationForm.confirmation.error) ? validationForm.confirmation.error : ""}
|
|
265
336
|
InputProps={{
|
|
266
337
|
endAdornment: (
|
|
267
338
|
<InputAdornment position="end">
|
|
@@ -284,6 +355,32 @@ const AccountValidation: FunctionComponent<AccountValidationProps> = ({ movaAppT
|
|
|
284
355
|
<CircularProgress />
|
|
285
356
|
</Box>
|
|
286
357
|
}
|
|
358
|
+
|
|
359
|
+
{openPhoneNumberInput && <ConfirmationDialog
|
|
360
|
+
open={openPhoneNumberInput}
|
|
361
|
+
confirmLabel="Envoyer"
|
|
362
|
+
closeLabel="Annuler"
|
|
363
|
+
onClose={() => setOpenPhoneNumberInput(false)}
|
|
364
|
+
onConfirm={resendCode}
|
|
365
|
+
message={<>
|
|
366
|
+
<Typography><b>Indique nous ton numéro de téléphone</b><br /></Typography>
|
|
367
|
+
<Grid item xs={6}>
|
|
368
|
+
<TextField
|
|
369
|
+
margin="normal"
|
|
370
|
+
fullWidth
|
|
371
|
+
required
|
|
372
|
+
id="phoneNumber"
|
|
373
|
+
label="N° de téléphone"
|
|
374
|
+
name="phoneNumber"
|
|
375
|
+
autoComplete="tel"
|
|
376
|
+
onChange={e => handleInputChange(e)}
|
|
377
|
+
value={validationForm.phoneNumber.value}
|
|
378
|
+
error={Boolean(validationForm.phoneNumber.error)}
|
|
379
|
+
helperText={validationForm.phoneNumber.error}
|
|
380
|
+
/>
|
|
381
|
+
</Grid>
|
|
382
|
+
</>}
|
|
383
|
+
/> }
|
|
287
384
|
</div>
|
|
288
385
|
);
|
|
289
386
|
};
|
package/src/helpers/Types.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
export type
|
|
2
|
+
export type MovaValidationForm = {
|
|
3
3
|
password: MovaFormField,
|
|
4
4
|
confirmation: MovaFormField,
|
|
5
|
-
securityCode: MovaFormField
|
|
5
|
+
securityCode: MovaFormField,
|
|
6
|
+
phoneNumber: MovaFormField
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
export type AddressFieldName = 'streetName' | 'additional' | 'postalCode' | 'cityName';
|
|
@@ -6,6 +6,15 @@ import User from "../models/User";
|
|
|
6
6
|
|
|
7
7
|
export default class UserService {
|
|
8
8
|
|
|
9
|
+
static resendSecurityCode(req: any): Promise<APIResponse<string>> {
|
|
10
|
+
return request({
|
|
11
|
+
url: `${API_BASE_URL}/user/resend-security-code`,
|
|
12
|
+
method: APIMethod.POST,
|
|
13
|
+
appType: MovaAppType.INDIVIDUAL,
|
|
14
|
+
body: JSON.stringify(req)
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
9
18
|
static getSalesGarages(salesId: string,): Promise<APIResponse<Garage[]>> {
|
|
10
19
|
return request({
|
|
11
20
|
url: `${API_BASE_URL}/sales/${salesId}/garages`,
|