@movalib/movalib-commons 1.0.2 → 1.0.4

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.
@@ -0,0 +1,2 @@
1
+ declare function MovaCopyright(props: any): import("react/jsx-runtime").JSX.Element;
2
+ export default MovaCopyright;
@@ -0,0 +1,17 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ import { Link, Typography } from "@mui/material";
14
+ function MovaCopyright(props) {
15
+ return (_jsxs(Typography, __assign({ variant: "body2", color: "text.secondary", align: "center" }, props, { children: ['Copyright © ', _jsx(Link, __assign({ color: "inherit", href: "https://www.movalib.com" }, { children: "Movalib.com" })), ' ', new Date().getFullYear(), '.'] })));
16
+ }
17
+ export default MovaCopyright;
@@ -0,0 +1,9 @@
1
+ import { FunctionComponent } from "react";
2
+ import { MovaLoginForm } from "./helpers/Types";
3
+ import { MovaAppType } from "./helpers/Enums";
4
+ interface MovaLoginProps {
5
+ movaAppType: MovaAppType;
6
+ onSubmit: (form: MovaLoginForm) => void;
7
+ }
8
+ declare const MovaLogin: FunctionComponent<MovaLoginProps>;
9
+ export default MovaLogin;
@@ -0,0 +1,152 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
13
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
14
+ return new (P || (P = Promise))(function (resolve, reject) {
15
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
16
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
17
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
18
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
19
+ });
20
+ };
21
+ var __generator = (this && this.__generator) || function (thisArg, body) {
22
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
23
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
24
+ function verb(n) { return function (v) { return step([n, v]); }; }
25
+ function step(op) {
26
+ if (f) throw new TypeError("Generator is already executing.");
27
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
28
+ 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;
29
+ if (y = 0, t) op = [op[0] & 2, t.value];
30
+ switch (op[0]) {
31
+ case 0: case 1: t = op; break;
32
+ case 4: _.label++; return { value: op[1], done: false };
33
+ case 5: _.label++; y = op[1]; op = [0]; continue;
34
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
35
+ default:
36
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
37
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
38
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
39
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
40
+ if (t[2]) _.ops.pop();
41
+ _.trys.pop(); continue;
42
+ }
43
+ op = body.call(thisArg, _);
44
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
45
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
46
+ }
47
+ };
48
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
49
+ import { useState } from "react";
50
+ import { LoadingButton } from '@mui/lab';
51
+ import LogoLarge from './assets/images/logo/logo_large.png';
52
+ import LogoProLarge from './assets/images/logo/logo_pro_large.png';
53
+ import GreenLeafImage from './assets/images/logo/leaf_green_large.png';
54
+ import PinkLeafImage from './assets/images/logo/leaf_pink_large.png';
55
+ import { Alert, Box, Checkbox, Container, CssBaseline, FormControlLabel, Grid, Link, TextField } from "@mui/material";
56
+ import MovaCopyright from "./MovaCopyright";
57
+ import { MovaAppType } from "./helpers/Enums";
58
+ import { validateEmail } from "./helpers/Validator";
59
+ // Permet de centrer le contenu de l'application
60
+ var styles = {
61
+ display: 'flex',
62
+ justifyContent: 'center',
63
+ alignItems: 'center',
64
+ height: '100vh', // Ajustez la hauteur en fonction de vos besoins
65
+ };
66
+ var initialFormState = {
67
+ email: { value: '', isValid: true },
68
+ password: { value: '', isValid: true },
69
+ };
70
+ var MovaLogin = function (_a) {
71
+ var movaAppType = _a.movaAppType, onSubmit = _a.onSubmit;
72
+ var _b = useState(initialFormState), form = _b[0], setForm = _b[1];
73
+ var _c = useState(""), message = _c[0], setMessage = _c[1];
74
+ var _d = useState(false), loading = _d[0], setLoading = _d[1];
75
+ var handleInputChange = function (e) {
76
+ var _a;
77
+ var fieldName = e.target.name;
78
+ var fieldValue = e.target.value;
79
+ var newField = (_a = {}, _a[fieldName] = { value: fieldValue, isValid: true }, _a);
80
+ setForm(__assign(__assign({}, form), newField));
81
+ };
82
+ var handleSubmit = function (e) { return __awaiter(void 0, void 0, void 0, function () {
83
+ return __generator(this, function (_a) {
84
+ e.preventDefault();
85
+ setLoading(true);
86
+ try {
87
+ if (validateForm() && onSubmit) {
88
+ // Si le formulaire est valide, on appel la function callback transmise en props
89
+ onSubmit(form);
90
+ }
91
+ }
92
+ catch (error) {
93
+ console.error('Error occurred during submission:', error);
94
+ }
95
+ finally {
96
+ setLoading(false);
97
+ }
98
+ return [2 /*return*/];
99
+ });
100
+ }); };
101
+ var validateForm = function () {
102
+ var newForm = form;
103
+ // Validator email
104
+ if (!validateEmail(form.email.value.length)) {
105
+ var errorMsg = 'Adresse email invalide';
106
+ var newField = { value: form.email.value, error: errorMsg, isValid: false };
107
+ newForm = __assign(__assign({}, newForm), { email: newField });
108
+ }
109
+ else {
110
+ var newField = { value: form.email.value, error: '', isValid: true };
111
+ newForm = __assign(__assign({}, newForm), { email: newField });
112
+ }
113
+ // Validator password
114
+ if (form.password.value.length < 8) {
115
+ var errorMsg = 'Votre mot de passe doit faire au moins 8 caractères de long.';
116
+ var newField = { value: form.password.value, error: errorMsg, isValid: false };
117
+ newForm = __assign(__assign({}, newForm), { password: newField });
118
+ }
119
+ else {
120
+ var newField = { value: form.password.value, error: '', isValid: true };
121
+ newForm = __assign(__assign({}, newForm), { password: newField });
122
+ }
123
+ setForm(newForm);
124
+ return newForm.email.isValid && newForm.password.isValid;
125
+ };
126
+ var getMovaLogo = function () {
127
+ return movaAppType === MovaAppType.GARAGE ? LogoProLarge :
128
+ movaAppType === MovaAppType.USER ? LogoLarge :
129
+ movaAppType === MovaAppType.ADMIN ? LogoLarge : LogoLarge;
130
+ };
131
+ return (_jsxs("div", __assign({ style: styles }, { children: [_jsx("img", { src: GreenLeafImage, style: { position: 'fixed',
132
+ float: 'left',
133
+ width: '250px',
134
+ height: '400px',
135
+ top: '-20%',
136
+ left: '3%',
137
+ opacity: '0.3',
138
+ zIndex: -8 }, alt: 'Feuille Verte Movalib' }), _jsxs(Container, __assign({ component: "main", maxWidth: "xs" }, { children: [_jsx(CssBaseline, {}), _jsxs(Box, __assign({ sx: {
139
+ marginTop: 6,
140
+ display: 'flex',
141
+ flexDirection: 'column',
142
+ alignItems: 'center',
143
+ } }, { children: [_jsx("img", { src: getMovaLogo(), style: { width: '80%' } }), _jsx("br", {})] })), _jsxs(Box, __assign({ component: "form", onSubmit: handleSubmit, noValidate: true, sx: { mt: 1 } }, { children: [_jsx(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: form.email.value, error: !form.email.isValid, helperText: form.email.error }), _jsx(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: form.password.value, error: !form.password.isValid, helperText: form.password.error }), _jsx(FormControlLabel, { control: _jsx(Checkbox, { value: "remember", color: "primary" }), label: "Se souvenir de moi" }), _jsx(LoadingButton, __assign({ loading: loading, type: "submit", fullWidth: true, variant: "contained", sx: { mt: 3, mb: 2 } }, { children: _jsx("span", { children: "Se connecter" }) })), message && _jsx(Alert, __assign({ severity: "error", sx: { mb: 2 } }, { children: message })), _jsxs(Grid, __assign({ container: true }, { children: [_jsx(Grid, __assign({ item: true, xs: true }, { children: _jsx(Link, __assign({ href: "#", variant: "body2", color: "text.secondary" }, { children: "Mot de passe oubli\u00E9 ?" })) })), _jsx(Grid, __assign({ item: true }, { children: _jsx(Link, __assign({ href: "#", variant: "body2", color: "text.secondary" }, { children: "Créer un compte" })) }))] }))] })), _jsx(MovaCopyright, { sx: { mt: 8, mb: 4 } })] })), _jsx("img", { src: PinkLeafImage, style: { position: 'fixed',
144
+ float: 'right',
145
+ width: '250px',
146
+ height: '400px',
147
+ bottom: '-20%',
148
+ right: '3%',
149
+ opacity: '0.3',
150
+ zIndex: '-10' }, alt: 'Feuille Rose Movalib' })] })));
151
+ };
152
+ export default MovaLogin;
@@ -1,12 +1,19 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
4
11
  };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const jsx_runtime_1 = require("react/jsx-runtime");
7
- const material_1 = require("@mui/material");
8
- const CloseRounded_1 = __importDefault(require("@mui/icons-material/CloseRounded"));
9
- const MovaSnackbar = ({ snackbar, setSnackbar }) => {
12
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
13
+ import { Snackbar, Alert, IconButton } from '@mui/material';
14
+ import CloseIcon from '@mui/icons-material/CloseRounded';
15
+ var MovaSnackbar = function (_a) {
16
+ var snackbar = _a.snackbar, setSnackbar = _a.setSnackbar;
10
17
  /**
11
18
  * Gestion de la fermeture de la snackbar. Si la raison de cette fermeture est
12
19
  * un clic en dehors de la zone de contenu on intercepte et annule la fermeture 'clickaway'.
@@ -14,14 +21,14 @@ const MovaSnackbar = ({ snackbar, setSnackbar }) => {
14
21
  * @param reason Origine de l'événnement de fermeture
15
22
  * @returns
16
23
  */
17
- const handleClose = (event, reason) => {
24
+ var handleClose = function (event, reason) {
18
25
  if (reason === 'clickaway')
19
26
  return;
20
27
  setSnackbar({ open: false, message: '', severity: undefined });
21
28
  };
22
- const handleCloseAlert = (event) => {
29
+ var handleCloseAlert = function (event) {
23
30
  setSnackbar({ open: false, message: '', severity: undefined });
24
31
  };
25
- return ((0, jsx_runtime_1.jsx)(material_1.Snackbar, Object.assign({ open: snackbar.open, autoHideDuration: 5000, onClose: handleClose }, { children: (0, jsx_runtime_1.jsx)(material_1.Alert, Object.assign({ severity: snackbar.severity, variant: "filled", sx: { width: '100%' }, action: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ size: "small", "aria-label": "close", color: "inherit", onClick: handleCloseAlert }, { children: (0, jsx_runtime_1.jsx)(CloseRounded_1.default, { fontSize: "small" }) })) }) }, { children: snackbar.message })) })));
32
+ return (_jsx(Snackbar, __assign({ open: snackbar.open, autoHideDuration: 5000, onClose: handleClose }, { children: _jsx(Alert, __assign({ severity: snackbar.severity, variant: "filled", sx: { width: '100%' }, action: _jsx(_Fragment, { children: _jsx(IconButton, __assign({ size: "small", "aria-label": "close", color: "inherit", onClick: handleCloseAlert }, { children: _jsx(CloseIcon, { fontSize: "small" }) })) }) }, { children: snackbar.message })) })));
26
33
  };
27
- exports.default = MovaSnackbar;
34
+ export default MovaSnackbar;
@@ -1,7 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const jsx_runtime_1 = require("react/jsx-runtime");
4
- const TestButton = ({ label }) => {
5
- return (0, jsx_runtime_1.jsx)("button", { children: label });
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ var TestButton = function (_a) {
3
+ var label = _a.label;
4
+ return _jsx("button", { children: label });
6
5
  };
7
- exports.default = TestButton;
6
+ export default TestButton;
@@ -0,0 +1,14 @@
1
+ export declare enum MovaAppType {
2
+ /**
3
+ * Application Garagiste
4
+ */
5
+ GARAGE = "GARAGE",
6
+ /**
7
+ * Application Utilisateur (automobiliste)
8
+ */
9
+ USER = "USER",
10
+ /**
11
+ * Application Administrateur (MovaTeam)
12
+ */
13
+ ADMIN = "ADMIN"
14
+ }
@@ -0,0 +1,15 @@
1
+ export var MovaAppType;
2
+ (function (MovaAppType) {
3
+ /**
4
+ * Application Garagiste
5
+ */
6
+ MovaAppType["GARAGE"] = "GARAGE";
7
+ /**
8
+ * Application Utilisateur (automobiliste)
9
+ */
10
+ MovaAppType["USER"] = "USER";
11
+ /**
12
+ * Application Administrateur (MovaTeam)
13
+ */
14
+ MovaAppType["ADMIN"] = "ADMIN";
15
+ })(MovaAppType || (MovaAppType = {}));
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ export type MovaLoginForm = {
2
+ email: MovaFormField;
3
+ password: MovaFormField;
4
+ };
5
+ export type MovaFormField = {
6
+ value?: any;
7
+ error?: string;
8
+ isValid?: boolean;
9
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ export declare function validatePhoneNumber(phoneNumber: string): boolean;
2
+ export declare function validateText(text: string): boolean;
3
+ export declare function validateEmail(email: string): boolean;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Un email valide
3
+ */
4
+ var emailRegex = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i;
5
+ /**
6
+ * Un mot de passe qui contient au moins une majuscule, une minuscule, un chiffre
7
+ * et un caractère spécial. La longueur du mot de passe doit être d'au moins 8 caractères.
8
+ */
9
+ var passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
10
+ /**
11
+ * Un numéro de téléphone (10 chiffres)
12
+ */
13
+ var phoneNumberRegex = /^\d{0,10}$/;
14
+ /**
15
+ * Un code postal (5 chiffres)
16
+ */
17
+ var postalCodeRegex = /^\d{5}$/;
18
+ /**
19
+ * Une URL valide
20
+ */
21
+ var urlRegex = /^(ftp|http|https):\/\/[^ "]+$/;
22
+ /**
23
+ * Un nom pouvant contenir des lettres, chiffres d'une taille comprise entre 3 et 20 caractères
24
+ */
25
+ var userNameRegex = /^[a-z0-9_-]{3,20}$/;
26
+ /**
27
+ * Un texte pouvant contenir des lettres, chiffres et quelques caractères spéciaux
28
+ */
29
+ var textRegex = /^[a-zA-Z0-9\s.,!?'"()+=-_-éèçà]+$/;
30
+ export function validatePhoneNumber(phoneNumber) {
31
+ if (phoneNumber === null || phoneNumber === undefined) {
32
+ return false;
33
+ }
34
+ return phoneNumberRegex.test(phoneNumber);
35
+ }
36
+ export function validateText(text) {
37
+ if (text === null || text === undefined) {
38
+ return false;
39
+ }
40
+ return textRegex.test(text);
41
+ }
42
+ export function validateEmail(email) {
43
+ if (email === null || email === undefined) {
44
+ return false;
45
+ }
46
+ return emailRegex.test(email);
47
+ }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,6 @@
1
1
  export { default as TestButton } from './TestButton';
2
- export { default as MovaSnackBar } from './MovaSnackbar';
2
+ export { default as MovaSnackbar } from './MovaSnackbar';
3
+ export { default as MovaLogin } from './MovaLogin';
4
+ export { default as MovaCopyright } from './MovaCopyright';
5
+ export type { MovaFormField } from './helpers/Types';
6
+ export type { MovaLoginForm } from './helpers/Types';
package/dist/index.js CHANGED
@@ -1,11 +1,5 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.MovaSnackBar = exports.TestButton = void 0;
7
1
  // src/index.ts
8
- var TestButton_1 = require("./TestButton");
9
- Object.defineProperty(exports, "TestButton", { enumerable: true, get: function () { return __importDefault(TestButton_1).default; } });
10
- var MovaSnackbar_1 = require("./MovaSnackbar");
11
- Object.defineProperty(exports, "MovaSnackBar", { enumerable: true, get: function () { return __importDefault(MovaSnackbar_1).default; } });
2
+ export { default as TestButton } from './TestButton';
3
+ export { default as MovaSnackbar } from './MovaSnackbar';
4
+ export { default as MovaLogin } from './MovaLogin';
5
+ export { default as MovaCopyright } from './MovaCopyright';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@movalib/movalib-commons",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -15,11 +15,20 @@
15
15
  "license": "ISC",
16
16
  "dependencies": {
17
17
  "react": "^18.2.0",
18
- "react-dom": "^18.2.0"
18
+ "react-scripts": "5.0.1",
19
+ "react-dom": "^18.2.0",
20
+ "@types/node": "^16.18.53",
21
+ "@types/react": "^18.2.22"
22
+ },
23
+ "eslintConfig": {
24
+ "extends": [
25
+ "react-app"
26
+ ]
19
27
  },
20
28
  "devDependencies": {
21
29
  "@mui/material": "^5.13.5",
22
30
  "@mui/icons-material": "^5.11.16",
31
+ "@mui/lab": "^5.0.0-alpha.134",
23
32
  "@types/react": "^18.2.22",
24
33
  "@types/react-dom": "^18.2.7",
25
34
  "typescript": "^4.9.5"
@@ -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,198 @@
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/logo/leaf_green_large.png';
6
+ import PinkLeafImage from './assets/images/logo/leaf_pink_large.png';
7
+ import { Alert, 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
+ interface MovaLoginProps {
27
+ movaAppType: MovaAppType,
28
+ onSubmit: (form: MovaLoginForm) => void;
29
+ }
30
+
31
+ const MovaLogin: FunctionComponent<MovaLoginProps> = ({ movaAppType, onSubmit }) => {
32
+
33
+ const [form, setForm] = useState<MovaLoginForm>(initialFormState);
34
+ const [message, setMessage] = useState<string>("");
35
+ const [loading, setLoading] = useState(false);
36
+
37
+ const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>): void => {
38
+ const fieldName: string = e.target.name;
39
+ const fieldValue: string = e.target.value;
40
+ const newField: MovaFormField = { [fieldName]: { value: fieldValue, isValid: true } };
41
+
42
+ setForm({ ...form, ...newField});
43
+ }
44
+
45
+ const handleSubmit = async (e: FormEvent) => {
46
+ e.preventDefault();
47
+ setLoading(true);
48
+
49
+ try {
50
+ if(validateForm() && onSubmit) {
51
+ // Si le formulaire est valide, on appel la function callback transmise en props
52
+ onSubmit(form);
53
+ }
54
+
55
+ }catch (error){
56
+ console.error('Error occurred during submission:', error);
57
+ }finally {
58
+ setLoading(false);
59
+ }
60
+ }
61
+
62
+ const validateForm = () => {
63
+ let newForm: MovaLoginForm = form;
64
+
65
+ // Validator email
66
+ if(!validateEmail(form.email.value.length)) {
67
+ const errorMsg: string = 'Adresse email invalide';
68
+ const newField: MovaFormField = { value: form.email.value, error: errorMsg, isValid: false };
69
+ newForm = { ...newForm, ...{ email: newField } };
70
+ } else {
71
+ const newField: MovaFormField = { value: form.email.value, error: '', isValid: true };
72
+ newForm = { ...newForm, ...{ email: newField } };
73
+ }
74
+
75
+ // Validator password
76
+ if(form.password.value.length < 8) {
77
+ const errorMsg: string = 'Votre mot de passe doit faire au moins 8 caractères de long.';
78
+ const newField: MovaFormField = {value: form.password.value, error: errorMsg, isValid: false};
79
+ newForm = { ...newForm, ...{ password: newField } };
80
+ } else {
81
+ const newField: MovaFormField = { value: form.password.value, error: '', isValid: true };
82
+ newForm = { ...newForm, ...{ password: newField } };
83
+ }
84
+
85
+ setForm(newForm);
86
+
87
+ return newForm.email.isValid && newForm.password.isValid;
88
+ }
89
+
90
+ const getMovaLogo = () => {
91
+
92
+ return movaAppType === MovaAppType.GARAGE ? LogoProLarge :
93
+ movaAppType === MovaAppType.USER ? LogoLarge :
94
+ movaAppType === MovaAppType.ADMIN ? LogoLarge : LogoLarge;
95
+ }
96
+
97
+
98
+ return (
99
+ <div style={styles}>
100
+ <img src={GreenLeafImage} style={{position: 'fixed',
101
+ float:'left',
102
+ width: '250px',
103
+ height: '400px',
104
+ top: '-20%',
105
+ left: '3%',
106
+ opacity: '0.3',
107
+ zIndex: -8}} alt='Feuille Verte Movalib'></img>
108
+
109
+ <Container component="main" maxWidth="xs">
110
+ <CssBaseline />
111
+ <Box
112
+ sx={{
113
+ marginTop: 6,
114
+ display: 'flex',
115
+ flexDirection: 'column',
116
+ alignItems: 'center',
117
+ }}
118
+ >
119
+ <img src={getMovaLogo()} style={{width:'80%'}}/>
120
+ <br />
121
+ </Box>
122
+
123
+ <Box component="form" onSubmit={handleSubmit} noValidate sx={{ mt: 1 }}>
124
+ <TextField
125
+ margin="normal"
126
+ required
127
+ fullWidth
128
+ id="email"
129
+ label="Adresse email"
130
+ name="email"
131
+ autoComplete="email"
132
+ autoFocus
133
+ onChange={e => handleInputChange(e)}
134
+ value={form.email.value}
135
+ error={!form.email.isValid}
136
+ helperText={form.email.error}
137
+ />
138
+ <TextField
139
+ margin="normal"
140
+ required
141
+ fullWidth
142
+ name="password"
143
+ label="Mot de passe"
144
+ type="password"
145
+ id="password"
146
+ autoComplete="current-password"
147
+ onChange={e => handleInputChange(e)}
148
+ value={form.password.value}
149
+ error={!form.password.isValid}
150
+ helperText={form.password.error}
151
+ />
152
+ <FormControlLabel control={<Checkbox value="remember" color="primary" />}
153
+ label="Se souvenir de moi"
154
+ />
155
+ {/* <MyLoadingButton
156
+ type={ButtonType.SUBMIT}
157
+ label="Se connecter" /> */}
158
+
159
+ <LoadingButton
160
+ loading={loading}
161
+ type="submit"
162
+ fullWidth
163
+ variant="contained"
164
+ sx={{ mt: 3, mb: 2 }}>
165
+ <span>Se connecter</span>
166
+ </LoadingButton>
167
+
168
+ {message && <Alert severity="error" sx={{ mb: 2 }}>{message}</Alert>}
169
+
170
+ <Grid container>
171
+ <Grid item xs>
172
+ <Link href="#" variant="body2" color="text.secondary">
173
+ Mot de passe oublié ?
174
+ </Link>
175
+ </Grid>
176
+ <Grid item>
177
+ <Link href="#" variant="body2" color="text.secondary">
178
+ {"Créer un compte"}
179
+ </Link>
180
+ </Grid>
181
+ </Grid>
182
+ </Box>
183
+ <MovaCopyright sx={{ mt: 8, mb: 4 }} />
184
+ </Container>
185
+
186
+ <img src={PinkLeafImage} style={{position: 'fixed',
187
+ float:'right',
188
+ width: '250px',
189
+ height: '400px',
190
+ bottom: '-20%',
191
+ right: '3%',
192
+ opacity: '0.3',
193
+ zIndex: '-10'}} alt='Feuille Rose Movalib'></img>
194
+ </div>
195
+ );
196
+ };
197
+
198
+ export default MovaLogin;
@@ -0,0 +1,15 @@
1
+
2
+ export enum MovaAppType {
3
+ /**
4
+ * Application Garagiste
5
+ */
6
+ GARAGE = "GARAGE",
7
+ /**
8
+ * Application Utilisateur (automobiliste)
9
+ */
10
+ USER = "USER",
11
+ /**
12
+ * Application Administrateur (MovaTeam)
13
+ */
14
+ ADMIN = "ADMIN"
15
+ }
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,11 @@
1
+
2
+ export type MovaLoginForm = {
3
+ email: MovaFormField,
4
+ password: MovaFormField
5
+ }
6
+
7
+ export type MovaFormField = {
8
+ value?: any,
9
+ error?: string,
10
+ isValid?: boolean
11
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Un email valide
3
+ */
4
+ const emailRegex:RegExp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i;
5
+
6
+ /**
7
+ * Un mot de passe qui contient au moins une majuscule, une minuscule, un chiffre
8
+ * et un caractère spécial. La longueur du mot de passe doit être d'au moins 8 caractères.
9
+ */
10
+ const passwordRegex:RegExp = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
11
+
12
+ /**
13
+ * Un numéro de téléphone (10 chiffres)
14
+ */
15
+ const phoneNumberRegex:RegExp = /^\d{0,10}$/;
16
+
17
+ /**
18
+ * Un code postal (5 chiffres)
19
+ */
20
+ const postalCodeRegex:RegExp = /^\d{5}$/;
21
+
22
+ /**
23
+ * Une URL valide
24
+ */
25
+ const urlRegex:RegExp =/^(ftp|http|https):\/\/[^ "]+$/;
26
+
27
+ /**
28
+ * Un nom pouvant contenir des lettres, chiffres d'une taille comprise entre 3 et 20 caractères
29
+ */
30
+ const userNameRegex:RegExp = /^[a-z0-9_-]{3,20}$/;
31
+
32
+ /**
33
+ * Un texte pouvant contenir des lettres, chiffres et quelques caractères spéciaux
34
+ */
35
+ const textRegex:RegExp = /^[a-zA-Z0-9\s.,!?'"()+=-_-éèçà]+$/;
36
+
37
+
38
+ export function validatePhoneNumber(phoneNumber: string) : boolean {
39
+ if (phoneNumber === null || phoneNumber === undefined) {
40
+ return false;
41
+ }
42
+ return phoneNumberRegex.test(phoneNumber);
43
+ }
44
+
45
+ export function validateText(text: string) : boolean {
46
+ if (text === null || text === undefined) {
47
+ return false;
48
+ }
49
+ return textRegex.test(text);
50
+ }
51
+
52
+ export function validateEmail(email: string) : boolean {
53
+ if (email === null || email === undefined) {
54
+ return false;
55
+ }
56
+ return emailRegex.test(email);
57
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,10 @@
1
1
  // src/index.ts
2
+
2
3
  export { default as TestButton } from './TestButton';
3
- export { default as MovaSnackBar } from './MovaSnackbar';
4
+ export { default as MovaSnackbar } from './MovaSnackbar';
5
+ export { default as MovaLogin } from './MovaLogin';
6
+ export { default as MovaCopyright } from './MovaCopyright';
7
+
8
+ // Export des types
9
+ export type { MovaFormField } from './helpers/Types';
10
+ export type { MovaLoginForm } from './helpers/Types';
@@ -0,0 +1 @@
1
+ /// <reference types="react-scripts" />
package/tsconfig.json CHANGED
@@ -11,8 +11,12 @@
11
11
  // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
12
12
 
13
13
  /* Language and Environment */
14
- "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15
- // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
14
+ "target": "es5", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15
+ "lib": [
16
+ "dom",
17
+ "dom.iterable",
18
+ "esnext"
19
+ ], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
16
20
  "jsx": "react-jsx", /* Specify what JSX code is generated. */
17
21
  // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
18
22
  // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
@@ -25,7 +29,7 @@
25
29
  // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
26
30
 
27
31
  /* Modules */
28
- "module": "commonjs", /* Specify what module code is generated. */
32
+ "module": "esnext", /* Specify what module code is generated. */
29
33
  // "rootDir": "./", /* Specify the root folder within your source files. */
30
34
  "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
31
35
  // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
@@ -39,12 +43,12 @@
39
43
  // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
40
44
  // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
41
45
  // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
42
- // "resolveJsonModule": true, /* Enable importing .json files. */
46
+ "resolveJsonModule": true, /* Enable importing .json files. */
43
47
  // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
44
48
  // "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
45
49
 
46
50
  /* JavaScript Support */
47
- // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
51
+ "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
48
52
  // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
49
53
  // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
50
54
 
@@ -57,7 +61,7 @@
57
61
  // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
58
62
  "outDir": "./dist", /* Specify an output folder for all emitted files. */
59
63
  // "removeComments": true, /* Disable emitting comments. */
60
- // "noEmit": true, /* Disable emitting files from a compilation. */
64
+ //"noEmit": true, /* Disable emitting files from a compilation. */
61
65
  // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
62
66
  // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
63
67
  // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
@@ -74,7 +78,7 @@
74
78
  // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
75
79
 
76
80
  /* Interop Constraints */
77
- // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
81
+ "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
78
82
  // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
79
83
  // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
80
84
  "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
@@ -95,7 +99,7 @@
95
99
  // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
96
100
  // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
97
101
  // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
98
- // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
102
+ "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
99
103
  // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
100
104
  // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
101
105
  // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
@@ -106,5 +110,5 @@
106
110
  // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
107
111
  "skipLibCheck": true /* Skip type checking all .d.ts files. */
108
112
  },
109
- "include": ["src/**/*"]
113
+ "include": ["src"]
110
114
  }