@movalib/movalib-commons 1.0.13 → 1.0.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 (36) hide show
  1. package/PV_README.md +23 -0
  2. package/dist/GenderSelector.d.ts +12 -0
  3. package/dist/GenderSelector.js +20 -0
  4. package/dist/MovaSignUp.d.ts +21 -0
  5. package/dist/MovaSignUp.js +175 -0
  6. package/dist/assets/images/logo/logo_large.png +0 -0
  7. package/dist/assets/images/logo/logo_pro_large.png +0 -0
  8. package/dist/helpers/Types.d.ts +9 -0
  9. package/dist/index.d.ts +2 -4
  10. package/dist/index.js +1 -2
  11. package/package.json +15 -12
  12. package/src/GenderSelector.tsx +32 -0
  13. package/src/MovaCopyright.tsx +17 -0
  14. package/src/MovaLogin.tsx +202 -0
  15. package/src/MovaSignUp.tsx +274 -0
  16. package/src/MovaSnackbar.tsx +65 -0
  17. package/src/TestButton.tsx +12 -0
  18. package/src/assets/images/logo/header_logo.png +0 -0
  19. package/src/assets/images/logo/header_logo_pro.png +0 -0
  20. package/src/helpers/Enums.ts +38 -0
  21. package/src/helpers/Tools.ts +1 -0
  22. package/src/helpers/Types.ts +20 -0
  23. package/src/helpers/Validator.ts +57 -0
  24. package/src/index.ts +19 -0
  25. package/src/models/Address.ts +28 -0
  26. package/src/models/Role.ts +16 -0
  27. package/src/models/User.ts +59 -0
  28. package/src/react-app-env.d.ts +1 -0
  29. package/tsconfig.json +114 -0
  30. /package/dist/assets/{assets/images → images}/logo/header_logo.png +0 -0
  31. /package/dist/assets/{assets/images → images}/logo/header_logo_pro.png +0 -0
  32. /package/{dist/assets → src}/assets/images/leaf_green_large.png +0 -0
  33. /package/{dist/assets → src}/assets/images/leaf_orange_large.png +0 -0
  34. /package/{dist/assets → src}/assets/images/leaf_pink_large.png +0 -0
  35. /package/{dist/assets → src}/assets/images/logo/logo_large.png +0 -0
  36. /package/{dist/assets → src}/assets/images/logo/logo_pro_large.png +0 -0
package/PV_README.md ADDED
@@ -0,0 +1,23 @@
1
+ # 1. build this movalib commons lib
2
+
3
+ ### `npm build`
4
+
5
+ # 2. publish this movalib commons lib (public)
6
+
7
+ ### `npm login`
8
+ ### `npm publish --access=public`
9
+
10
+ # 3. publish this movalib commons lib (private)
11
+
12
+ Make shure that "private=true" in your package.json
13
+
14
+ ### `npm login`
15
+ ### `npm publish --access=restricted`
16
+
17
+ Pour lier la librairie aux projets qui l'utilise, executer la commande suivnte
18
+
19
+ ### `npm run link`
20
+
21
+ Les commandes exécutées (ci-dessous) permettent de contourner un problème de double référence vers react et react-dom lorsque les deux appli utilisent des Hook
22
+
23
+ "link": "npm link --only=production && npm link \"/home/dimitri/Projets/5 - MOVALIB/02 - Développement/Front-End/movalib-user-app/node_modules/react\" && npm link \"/home/dimitri/Projets/5 - MOVALIB/02 - Développement/Front-End/movalib-user-app/node_modules/react-dom\"",
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { SelectChangeEvent } from '@mui/material';
3
+ import { MovaFormField } from './helpers/Types';
4
+ interface GenderSelectorProps {
5
+ handleSelectChange: (event: SelectChangeEvent<string>) => void;
6
+ form: {
7
+ gender: MovaFormField;
8
+ };
9
+ required?: boolean;
10
+ }
11
+ declare const GenderSelector: React.FC<GenderSelectorProps>;
12
+ export default GenderSelector;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ var jsx_runtime_1 = require("react/jsx-runtime");
15
+ var material_1 = require("@mui/material");
16
+ var GenderSelector = function (_a) {
17
+ var handleSelectChange = _a.handleSelectChange, form = _a.form, required = _a.required;
18
+ return ((0, jsx_runtime_1.jsxs)(material_1.FormControl, __assign({ fullWidth: true, margin: "normal", required: required }, { children: [(0, jsx_runtime_1.jsx)(material_1.InputLabel, __assign({ id: "gender-label" }, { children: "Sexe" })), (0, jsx_runtime_1.jsxs)(material_1.Select, __assign({ labelId: "gender-label", id: "gender", name: "gender", value: form.gender.value, onChange: function (e) { return handleSelectChange(e); } }, { children: [(0, jsx_runtime_1.jsx)(material_1.MenuItem, __assign({ value: "MALE" }, { children: "Homme" })), (0, jsx_runtime_1.jsx)(material_1.MenuItem, __assign({ value: "FEMALE" }, { children: "Femme" })), (0, jsx_runtime_1.jsx)(material_1.MenuItem, __assign({ value: "OTHER" }, { children: "Autre" }))] }))] })));
19
+ };
20
+ exports.default = GenderSelector;
@@ -0,0 +1,21 @@
1
+ import { FunctionComponent } from "react";
2
+ import { AlertColor } from "@mui/material";
3
+ import { MovaLoginForm } from "./helpers/Types";
4
+ import { MovaAppType } from "./helpers/Enums";
5
+ /**
6
+ * Propriétés du composant
7
+ * movaAppType : type d'application Movalib au sein de laquelle le composant est injectée
8
+ * onSubmit : callbakc invoquée en cas de formulaire valide
9
+ * alertMessage : éventuel message à afficher
10
+ * alertSeverity : niveau d'alerte pour le message à afficher
11
+ * loading : permet de mettre éventuellement le bouton de soumission en état de chargement
12
+ */
13
+ interface MovaSignUpProps {
14
+ movaAppType: MovaAppType;
15
+ onSubmit: (form: MovaLoginForm) => void;
16
+ alertMessage?: string;
17
+ alertSeverity?: AlertColor;
18
+ loading?: boolean;
19
+ }
20
+ declare const MovaLogin: FunctionComponent<MovaSignUpProps>;
21
+ export default MovaLogin;
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __importDefault = (this && this.__importDefault) || function (mod) {
50
+ return (mod && mod.__esModule) ? mod : { "default": mod };
51
+ };
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ var jsx_runtime_1 = require("react/jsx-runtime");
54
+ var react_1 = require("react");
55
+ var lab_1 = require("@mui/lab");
56
+ var logo_large_png_1 = __importDefault(require("./assets/images/logo/logo_large.png"));
57
+ var logo_pro_large_png_1 = __importDefault(require("./assets/images/logo/logo_pro_large.png"));
58
+ var leaf_green_large_png_1 = __importDefault(require("./assets/images/leaf_green_large.png"));
59
+ var leaf_pink_large_png_1 = __importDefault(require("./assets/images/leaf_pink_large.png"));
60
+ var material_1 = require("@mui/material");
61
+ var MovaCopyright_1 = __importDefault(require("./MovaCopyright"));
62
+ var Enums_1 = require("./helpers/Enums");
63
+ var Validator_1 = require("./helpers/Validator");
64
+ var GenderSelector_1 = __importDefault(require("./GenderSelector"));
65
+ // Permet de centrer le contenu de l'application
66
+ var styles = {
67
+ display: 'flex',
68
+ justifyContent: 'center',
69
+ alignItems: 'center',
70
+ height: '100vh', // Ajustez la hauteur en fonction de vos besoins
71
+ };
72
+ var initialUserFormState = {
73
+ firstname: { value: '', isValid: true },
74
+ lastname: { value: '', isValid: true },
75
+ email: { value: '', isValid: true },
76
+ password: { value: '', isValid: true },
77
+ gender: { value: '', isValid: true },
78
+ birthDate: { value: '', isValid: true },
79
+ acceptsTerms: { value: false, isValid: true },
80
+ };
81
+ var MovaLogin = function (_a) {
82
+ var loading = _a.loading, movaAppType = _a.movaAppType, onSubmit = _a.onSubmit, alertMessage = _a.alertMessage, alertSeverity = _a.alertSeverity;
83
+ var _b = (0, react_1.useState)(initialUserFormState), userForm = _b[0], setUserForm = _b[1];
84
+ var _c = (0, react_1.useState)(""), message = _c[0], setMessage = _c[1];
85
+ //const [loading, setLoading] = useState(false);
86
+ var handleInputChange = function (e) {
87
+ var _a;
88
+ var fieldName = e.target.name;
89
+ var fieldValue = e.target.value;
90
+ var newField = (_a = {}, _a[fieldName] = { value: fieldValue, isValid: true }, _a);
91
+ setUserForm(__assign(__assign({}, userForm), newField));
92
+ };
93
+ var handleCheckboxChange = function (e, checked) {
94
+ var _a;
95
+ var fieldName = e.target.name;
96
+ var fieldValue = checked;
97
+ var newField = (_a = {}, _a[fieldName] = { value: fieldValue, isValid: true }, _a);
98
+ setUserForm(__assign(__assign({}, userForm), newField));
99
+ };
100
+ var handleSelectChange = function (e) {
101
+ var _a;
102
+ var fieldName = e.target.name;
103
+ var fieldValue = e.target.value;
104
+ var newField = (_a = {}, _a[fieldName] = { value: fieldValue, isValid: true }, _a);
105
+ setUserForm(__assign(__assign({}, userForm), newField));
106
+ };
107
+ var handleSubmit = function (e) { return __awaiter(void 0, void 0, void 0, function () {
108
+ return __generator(this, function (_a) {
109
+ e.preventDefault();
110
+ try {
111
+ if (validateForm() && onSubmit) {
112
+ // Si le formulaire est valide, on appel la function callback transmise en props
113
+ onSubmit(userForm);
114
+ }
115
+ }
116
+ catch (error) {
117
+ console.error('Error occurred during submission:', error);
118
+ }
119
+ return [2 /*return*/];
120
+ });
121
+ }); };
122
+ var validateForm = function () {
123
+ var newForm = userForm;
124
+ // Validator email
125
+ if (!(0, Validator_1.validateEmail)(userForm.email.value)) {
126
+ var errorMsg = 'Adresse email invalide';
127
+ var newField = { value: userForm.email.value, error: errorMsg, isValid: false };
128
+ newForm = __assign(__assign({}, newForm), { email: newField });
129
+ }
130
+ else {
131
+ var newField = { value: userForm.email.value, error: '', isValid: true };
132
+ newForm = __assign(__assign({}, newForm), { email: newField });
133
+ }
134
+ // Validator password
135
+ if (userForm.password.value.length < 8) {
136
+ var errorMsg = 'Votre mot de passe doit faire au moins 8 caractères de long.';
137
+ var newField = { value: userForm.password.value, error: errorMsg, isValid: false };
138
+ newForm = __assign(__assign({}, newForm), { password: newField });
139
+ }
140
+ else {
141
+ var newField = { value: userForm.password.value, error: '', isValid: true };
142
+ newForm = __assign(__assign({}, newForm), { password: newField });
143
+ }
144
+ setUserForm(newForm);
145
+ return newForm.email.isValid && newForm.password.isValid;
146
+ };
147
+ var getMovaLogo = function () {
148
+ return movaAppType === Enums_1.MovaAppType.GARAGE ? logo_pro_large_png_1.default :
149
+ movaAppType === Enums_1.MovaAppType.USER ? logo_large_png_1.default :
150
+ movaAppType === Enums_1.MovaAppType.ADMIN ? logo_large_png_1.default : logo_large_png_1.default;
151
+ };
152
+ 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',
153
+ float: 'left',
154
+ width: '250px',
155
+ height: '400px',
156
+ top: '-20%',
157
+ left: '3%',
158
+ opacity: '0.3',
159
+ zIndex: -8 }, alt: 'Feuille Verte Movalib' }), (0, jsx_runtime_1.jsxs)(material_1.Container, __assign({ component: "main", maxWidth: "sm" }, { children: [(0, jsx_runtime_1.jsx)(material_1.CssBaseline, {}), (0, jsx_runtime_1.jsxs)(material_1.Box, __assign({ sx: {
160
+ marginTop: 6,
161
+ display: 'flex',
162
+ flexDirection: 'column',
163
+ alignItems: 'center',
164
+ } }, { 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.Typography, __assign({ variant: "h2" }, { children: "Nouveau compte utilisateur" }))] })), (0, jsx_runtime_1.jsxs)(material_1.Box, __assign({ component: "form", onSubmit: handleSubmit, noValidate: true, sx: { mt: 1 } }, { children: [(0, jsx_runtime_1.jsx)(material_1.TextField, { margin: "normal", required: true, autoFocus: true, fullWidth: true, id: "firstname", label: "Pr\u00E9nom", name: "firstname", autoComplete: "given-name", onChange: function (e) { return handleInputChange(e); }, value: userForm.firstname.value, error: Boolean(userForm.firstname.error), helperText: userForm.firstname.error }), (0, jsx_runtime_1.jsx)(material_1.TextField, { margin: "normal", required: true, fullWidth: true, id: "lastname", label: "Nom", name: "lastname", autoComplete: "family-name", onChange: function (e) { return handleInputChange(e); }, value: userForm.lastname.value, error: Boolean(userForm.lastname.error), helperText: userForm.lastname.error }), (0, jsx_runtime_1.jsx)(material_1.TextField, { margin: "normal", required: true, fullWidth: true, id: "email", label: "Adresse email", name: "email", autoComplete: "email", autoFocus: true, onChange: function (e) { return handleInputChange(e); }, value: userForm.email.value, error: !userForm.email.isValid, helperText: userForm.email.error }), (0, jsx_runtime_1.jsx)(material_1.TextField, { margin: "normal", required: true, fullWidth: true, name: "password", label: "Mot de passe", type: "password", id: "password", autoComplete: "current-password", onChange: function (e) { return handleInputChange(e); }, value: userForm.password.value, error: !userForm.password.isValid, helperText: userForm.password.error }), (0, jsx_runtime_1.jsx)(GenderSelector_1.default, { handleSelectChange: handleSelectChange, form: userForm, required: true }), (0, jsx_runtime_1.jsx)(material_1.TextField, { margin: "normal", required: true, label: "Date de naissance", type: "date", InputLabelProps: {
165
+ shrink: true,
166
+ }, autoComplete: "bday", value: userForm.password.value, error: !userForm.password.isValid, helperText: userForm.password.error, onChange: function (e) { return handleInputChange(e); } }), (0, jsx_runtime_1.jsxs)(material_1.FormControl, __assign({ error: !userForm.acceptsTerms.isValid }, { children: [(0, jsx_runtime_1.jsx)(material_1.FormControlLabel, { control: (0, jsx_runtime_1.jsx)(material_1.Checkbox, { color: "primary", checked: userForm.acceptsTerms.value, onChange: function (e, checked) { return handleCheckboxChange(e, checked); } }), label: (0, jsx_runtime_1.jsxs)("span", { children: ["J'accepte les", ' ', (0, jsx_runtime_1.jsx)(material_1.Link, __assign({ href: "/terms-and-conditions", target: "_blank" }, { children: "Conditions G\u00E9n\u00E9rales d'Utilisation" }))] }) }), (0, jsx_runtime_1.jsx)(material_1.FormHelperText, { children: userForm.acceptsTerms.error })] })), alertMessage && alertSeverity && (0, jsx_runtime_1.jsx)(material_1.Alert, __assign({ severity: alertSeverity, sx: { mb: 2 } }, { children: alertMessage })), (0, jsx_runtime_1.jsx)(lab_1.LoadingButton, __assign({ loading: loading, type: "submit", fullWidth: true, variant: "contained", sx: { mt: 3, mb: 2 } }, { children: (0, jsx_runtime_1.jsx)("span", { children: "Cr\u00E9er mon compte" }) }))] })), (0, jsx_runtime_1.jsx)(MovaCopyright_1.default, { sx: { mt: 8, mb: 4 } })] })), (0, jsx_runtime_1.jsx)("img", { src: leaf_pink_large_png_1.default, style: { position: 'fixed',
167
+ float: 'right',
168
+ width: '250px',
169
+ height: '400px',
170
+ bottom: '-20%',
171
+ right: '3%',
172
+ opacity: '0.3',
173
+ zIndex: '-10' }, alt: 'Feuille Rose Movalib' })] })));
174
+ };
175
+ exports.default = MovaLogin;
@@ -1,3 +1,12 @@
1
+ export type MovaUserSignUpForm = {
2
+ firstname: MovaFormField;
3
+ lastname: MovaFormField;
4
+ email: MovaFormField;
5
+ password: MovaFormField;
6
+ gender: MovaFormField;
7
+ birthDate: MovaFormField;
8
+ acceptsTerms: MovaFormField;
9
+ };
1
10
  export type MovaLoginForm = {
2
11
  email: MovaFormField;
3
12
  password: MovaFormField;
package/dist/index.d.ts CHANGED
@@ -5,7 +5,5 @@ export { default as MovaCopyright } from './MovaCopyright';
5
5
  export { default as User } from './models/User';
6
6
  export { default as Role } from './models/Role';
7
7
  export { default as Address } from './models/Address';
8
- export type { MovaFormField } from './helpers/Types';
9
- export type { MovaLoginForm } from './helpers/Types';
10
- export { RoleType } from './helpers/Enums';
11
- export { MovaAppType } from './helpers/Enums';
8
+ export type { MovaFormField, MovaLoginForm, MovaUserSignUpForm } from './helpers/Types';
9
+ export { RoleType, MovaAppType } from './helpers/Enums';
package/dist/index.js CHANGED
@@ -24,5 +24,4 @@ Object.defineProperty(exports, "Address", { enumerable: true, get: function () {
24
24
  // Export des enums
25
25
  var Enums_1 = require("./helpers/Enums");
26
26
  Object.defineProperty(exports, "RoleType", { enumerable: true, get: function () { return Enums_1.RoleType; } });
27
- var Enums_2 = require("./helpers/Enums");
28
- Object.defineProperty(exports, "MovaAppType", { enumerable: true, get: function () { return Enums_2.MovaAppType; } });
27
+ Object.defineProperty(exports, "MovaAppType", { enumerable: true, get: function () { return Enums_1.MovaAppType; } });
package/package.json CHANGED
@@ -1,15 +1,12 @@
1
1
  {
2
2
  "name": "@movalib/movalib-commons",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
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
- "files": [
9
- "dist"
10
- ],
11
8
  "scripts": {
12
- "build": "tsc && npm run copy-assets",
9
+ "build": "rm -rf dist && tsc && npm run copy-assets",
13
10
  "copy-assets": "cp -r src/assets/ dist/assets/",
14
11
  "test": "echo \"Error: no test specified\" && exit 1",
15
12
  "clean": "rm -rf dist node_modules package-lock.json"
@@ -18,11 +15,10 @@
18
15
  "author": "",
19
16
  "license": "ISC",
20
17
  "dependencies": {
18
+ "@types/node": "^16.18.53",
21
19
  "react": "^18.2.0",
22
- "react-scripts": "5.0.1",
23
20
  "react-dom": "^18.2.0",
24
- "@types/node": "^16.18.53",
25
- "@types/react": "^18.2.22"
21
+ "react-scripts": "5.0.1"
26
22
  },
27
23
  "eslintConfig": {
28
24
  "extends": [
@@ -30,13 +26,20 @@
30
26
  ]
31
27
  },
32
28
  "devDependencies": {
33
- "@mui/material": "^5.13.5",
34
- "@mui/icons-material": "^5.11.16",
35
- "@mui/lab": "^5.0.0-alpha.134",
36
29
  "@emotion/react": "^11.11.1",
37
30
  "@emotion/styled": "^11.11.0",
31
+ "@mui/icons-material": "^5.11.16",
32
+ "@mui/lab": "^5.0.0-alpha.134",
33
+ "@mui/material": "^5.13.5",
38
34
  "@types/react": "^18.2.22",
39
35
  "@types/react-dom": "^18.2.7",
40
- "typescript": "^4.9.5"
36
+ "babel-plugin-named-exports-order": "^0.0.2",
37
+ "prop-types": "^15.8.1",
38
+ "typescript": "^4.9.5",
39
+ "webpack": "^5.88.2"
40
+ },
41
+ "peerDependencies": {
42
+ "react": "^18.2.0",
43
+ "react-dom": "^18.2.0"
41
44
  }
42
45
  }
@@ -0,0 +1,32 @@
1
+ import React, { ChangeEvent } from 'react';
2
+ import { FormControl, InputLabel, Select, MenuItem, SelectChangeEvent } from '@mui/material';
3
+ import { MovaFormField } from './helpers/Types';
4
+
5
+ interface GenderSelectorProps {
6
+ handleSelectChange: (event: SelectChangeEvent<string>) => void;
7
+ form: {
8
+ gender: MovaFormField
9
+ };
10
+ required?: boolean;
11
+ }
12
+
13
+ const GenderSelector: React.FC<GenderSelectorProps> = ({ handleSelectChange, form, required }) => {
14
+ return (
15
+ <FormControl fullWidth margin="normal" required={required}>
16
+ <InputLabel id="gender-label">Sexe</InputLabel>
17
+ <Select
18
+ labelId="gender-label"
19
+ id="gender"
20
+ name="gender"
21
+ value={form.gender.value}
22
+ onChange={e => handleSelectChange(e)}
23
+ >
24
+ <MenuItem value="MALE">Homme</MenuItem>
25
+ <MenuItem value="FEMALE">Femme</MenuItem>
26
+ <MenuItem value="OTHER">Autre</MenuItem>
27
+ </Select>
28
+ </FormControl>
29
+ );
30
+ };
31
+
32
+ export default GenderSelector;
@@ -0,0 +1,17 @@
1
+ import React, { FunctionComponent } from "react";
2
+ import { Link, Typography } from "@mui/material";
3
+
4
+ function MovaCopyright(props: any) {
5
+ return (
6
+ <Typography variant="body2" color="text.secondary" align="center" {...props}>
7
+ {'Copyright © '}
8
+ <Link color="inherit" href="https://www.movalib.com">
9
+ Movalib.com
10
+ </Link>{' '}
11
+ {new Date().getFullYear()}
12
+ {'.'}
13
+ </Typography>
14
+ );
15
+ }
16
+
17
+ export default MovaCopyright;
@@ -0,0 +1,202 @@
1
+ import { CSSProperties, FormEvent, FunctionComponent, useState } from "react";
2
+ import { LoadingButton } from '@mui/lab';
3
+ import LogoLarge from './assets/images/logo/logo_large.png';
4
+ import LogoProLarge from './assets/images/logo/logo_pro_large.png';
5
+ import GreenLeafImage from "./assets/images/leaf_green_large.png";
6
+ import PinkLeafImage from "./assets/images/leaf_pink_large.png";
7
+ import { Alert, AlertColor, Box, Checkbox, Container, CssBaseline, FormControlLabel, Grid, Link, TextField } from "@mui/material";
8
+ import MovaCopyright from "./MovaCopyright";
9
+ import { MovaLoginForm, MovaFormField } from "./helpers/Types";
10
+ import { MovaAppType } from "./helpers/Enums";
11
+ import { validateEmail } from "./helpers/Validator";
12
+
13
+ // Permet de centrer le contenu de l'application
14
+ const styles: CSSProperties = {
15
+ display: 'flex',
16
+ justifyContent: 'center',
17
+ alignItems: 'center',
18
+ height: '100vh', // Ajustez la hauteur en fonction de vos besoins
19
+ };
20
+
21
+ const initialFormState = {
22
+ email: { value: '', isValid: true },
23
+ password: { value: '', isValid: true },
24
+ };
25
+
26
+ /**
27
+ * Propriétés du composant
28
+ * movaAppType : type d'application Movalib au sein de laquelle le composant est injectée
29
+ * onSubmit : callbakc invoquée en cas de formulaire valide
30
+ * alertMessage : éventuel message à afficher
31
+ * alertSeverity : niveau d'alerte pour le message à afficher
32
+ * loading : permet de mettre éventuellement le bouton de soumission en état de chargement
33
+ */
34
+ interface MovaLoginProps {
35
+ movaAppType: MovaAppType,
36
+ onSubmit: (form: MovaLoginForm) => void,
37
+ alertMessage?: string,
38
+ alertSeverity?: AlertColor,
39
+ loading?: boolean
40
+ }
41
+
42
+ const MovaLogin: FunctionComponent<MovaLoginProps> = ({ loading, movaAppType, onSubmit, alertMessage, alertSeverity }) => {
43
+
44
+ const [form, setForm] = useState<MovaLoginForm>(initialFormState);
45
+ const [message, setMessage] = useState<string>("");
46
+ //const [loading, setLoading] = useState(false);
47
+
48
+ const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>): void => {
49
+ const fieldName: string = e.target.name;
50
+ const fieldValue: string = e.target.value;
51
+ const newField: MovaFormField = { [fieldName]: { value: fieldValue, isValid: true } };
52
+
53
+ setForm({ ...form, ...newField});
54
+ }
55
+
56
+ const handleSubmit = async (e: FormEvent) => {
57
+ e.preventDefault();
58
+ try {
59
+ if(validateForm() && onSubmit) {
60
+ // Si le formulaire est valide, on appel la function callback transmise en props
61
+ onSubmit(form);
62
+ }
63
+
64
+ }catch (error){
65
+ console.error('Error occurred during submission:', error);
66
+ }
67
+ }
68
+
69
+ const validateForm = () => {
70
+ let newForm: MovaLoginForm = form;
71
+
72
+ // Validator email
73
+ if(!validateEmail(form.email.value)) {
74
+ const errorMsg: string = 'Adresse email invalide';
75
+ const newField: MovaFormField = { value: form.email.value, error: errorMsg, isValid: false };
76
+ newForm = { ...newForm, ...{ email: newField } };
77
+ } else {
78
+ const newField: MovaFormField = { value: form.email.value, error: '', isValid: true };
79
+ newForm = { ...newForm, ...{ email: newField } };
80
+ }
81
+
82
+ // Validator password
83
+ if(form.password.value.length < 8) {
84
+ const errorMsg: string = 'Votre mot de passe doit faire au moins 8 caractères de long.';
85
+ const newField: MovaFormField = {value: form.password.value, error: errorMsg, isValid: false};
86
+ newForm = { ...newForm, ...{ password: newField } };
87
+ } else {
88
+ const newField: MovaFormField = { value: form.password.value, error: '', isValid: true };
89
+ newForm = { ...newForm, ...{ password: newField } };
90
+ }
91
+
92
+ setForm(newForm);
93
+
94
+ return newForm.email.isValid && newForm.password.isValid;
95
+ }
96
+
97
+ const getMovaLogo = () => {
98
+
99
+ return movaAppType === MovaAppType.GARAGE ? LogoProLarge :
100
+ movaAppType === MovaAppType.USER ? LogoLarge :
101
+ movaAppType === MovaAppType.ADMIN ? LogoLarge : LogoLarge;
102
+ }
103
+
104
+
105
+ return (
106
+ <div style={styles}>
107
+ <img src={GreenLeafImage} style={{position: 'fixed',
108
+ float:'left',
109
+ width: '250px',
110
+ height: '400px',
111
+ top: '-20%',
112
+ left: '3%',
113
+ opacity: '0.3',
114
+ zIndex: -8}} alt='Feuille Verte Movalib'></img>
115
+
116
+ <Container component="main" maxWidth="xs">
117
+ <CssBaseline />
118
+ <Box
119
+ sx={{
120
+ marginTop: 6,
121
+ display: 'flex',
122
+ flexDirection: 'column',
123
+ alignItems: 'center',
124
+ }}
125
+ >
126
+ <img src={getMovaLogo()} style={{width:'80%'}}/>
127
+ <br />
128
+ </Box>
129
+
130
+ <Box component="form" onSubmit={handleSubmit} noValidate sx={{ mt: 1 }}>
131
+ <TextField
132
+ margin="normal"
133
+ required
134
+ fullWidth
135
+ id="email"
136
+ label="Adresse email"
137
+ name="email"
138
+ autoComplete="email"
139
+ autoFocus
140
+ onChange={e => handleInputChange(e)}
141
+ value={form.email.value}
142
+ error={!form.email.isValid}
143
+ helperText={form.email.error}
144
+ />
145
+ <TextField
146
+ margin="normal"
147
+ required
148
+ fullWidth
149
+ name="password"
150
+ label="Mot de passe"
151
+ type="password"
152
+ id="password"
153
+ autoComplete="current-password"
154
+ onChange={e => handleInputChange(e)}
155
+ value={form.password.value}
156
+ error={!form.password.isValid}
157
+ helperText={form.password.error}
158
+ />
159
+ <FormControlLabel control={<Checkbox value="remember" color="primary" />}
160
+ label="Se souvenir de moi"
161
+ />
162
+
163
+ <LoadingButton
164
+ loading={loading}
165
+ type="submit"
166
+ fullWidth
167
+ variant="contained"
168
+ sx={{ mt: 3, mb: 2 }}>
169
+ <span>Se connecter</span>
170
+ </LoadingButton>
171
+
172
+ {alertMessage && alertSeverity && <Alert severity={alertSeverity} sx={{ mb: 2 }}>{alertMessage}</Alert>}
173
+
174
+ <Grid container>
175
+ <Grid item xs>
176
+ <Link href="#" variant="body2" color="text.secondary">
177
+ Mot de passe oublié ?
178
+ </Link>
179
+ </Grid>
180
+ <Grid item>
181
+ <Link href="#" variant="body2" color="text.secondary">
182
+ {"Créer un compte"}
183
+ </Link>
184
+ </Grid>
185
+ </Grid>
186
+ </Box>
187
+ <MovaCopyright sx={{ mt: 8, mb: 4 }} />
188
+ </Container>
189
+
190
+ <img src={PinkLeafImage} style={{position: 'fixed',
191
+ float:'right',
192
+ width: '250px',
193
+ height: '400px',
194
+ bottom: '-20%',
195
+ right: '3%',
196
+ opacity: '0.3',
197
+ zIndex: '-10'}} alt='Feuille Rose Movalib'></img>
198
+ </div>
199
+ );
200
+ };
201
+
202
+ export default MovaLogin;