@pplancq/react-template 1.0.0

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 (117) hide show
  1. package/.babelrc.js +1 -0
  2. package/.commitlintrc.js +1 -0
  3. package/.editorconfig +4 -0
  4. package/.env +36 -0
  5. package/.eslintrc.js +1 -0
  6. package/.gitattributes +1 -0
  7. package/.husky/commit-msg +1 -0
  8. package/.husky/pre-commit +1 -0
  9. package/.lintstagedrc.js +5 -0
  10. package/.postcssrc.js +1 -0
  11. package/.prettierrc.js +1 -0
  12. package/.stylelintrc.js +1 -0
  13. package/CHANGELOG.md +26 -0
  14. package/LICENSE +21 -0
  15. package/README.md +221 -0
  16. package/_gitignore +26 -0
  17. package/package.json +84 -0
  18. package/public/favicon.ico +0 -0
  19. package/public/index.html +17 -0
  20. package/src/api/README.md +64 -0
  21. package/src/api/demoApi.ts +44 -0
  22. package/src/assets/README.md +51 -0
  23. package/src/assets/css/index.ts +2 -0
  24. package/src/assets/css/mainBody.css +4 -0
  25. package/src/assets/css/reset.css +131 -0
  26. package/src/assets/images/logo.png +0 -0
  27. package/src/assets/images/templatePlugins.png +0 -0
  28. package/src/bootstrap.tsx +26 -0
  29. package/src/components/App/App.tsx +18 -0
  30. package/src/components/App/index.ts +1 -0
  31. package/src/components/Footer/Footer.module.css +4 -0
  32. package/src/components/Footer/Footer.tsx +16 -0
  33. package/src/components/Footer/__tests__/Footer.test.tsx +15 -0
  34. package/src/components/Footer/__tests__/__snapshots__/Footer.test.tsx.snap +21 -0
  35. package/src/components/Footer/index.ts +1 -0
  36. package/src/components/Header/Header.module.css +7 -0
  37. package/src/components/Header/Header.tsx +17 -0
  38. package/src/components/Header/__tests__/Header.test.tsx +15 -0
  39. package/src/components/Header/__tests__/__snapshots__/Header.test.tsx.snap +35 -0
  40. package/src/components/Header/index.ts +1 -0
  41. package/src/components/README.md +34 -0
  42. package/src/components/TextInput/TextInput.tsx +24 -0
  43. package/src/components/TextInput/index.ts +1 -0
  44. package/src/config/README.md +61 -0
  45. package/src/config/index.ts +1 -0
  46. package/src/config/queryClientConfig.ts +3 -0
  47. package/src/forms/ProfileForm/ProfileForm.module.scss +10 -0
  48. package/src/forms/ProfileForm/ProfileForm.tsx +51 -0
  49. package/src/forms/ProfileForm/index.ts +1 -0
  50. package/src/forms/README.md +131 -0
  51. package/src/hooks/README.md +87 -0
  52. package/src/hooks/api/queryKey.ts +1 -0
  53. package/src/hooks/api/useDemoApi.ts +16 -0
  54. package/src/main.ts +3 -0
  55. package/src/pages/Demo/Demo.module.scss +184 -0
  56. package/src/pages/Demo/Demo.tsx +237 -0
  57. package/src/pages/Demo/ReactHookFormDemo/ReactHookFormDemo.module.css +32 -0
  58. package/src/pages/Demo/ReactHookFormDemo/ReactHookFormDemo.tsx +48 -0
  59. package/src/pages/Demo/ReactHookFormDemo/index.ts +1 -0
  60. package/src/pages/Demo/ReactHookFormDemo/routes.tsx +7 -0
  61. package/src/pages/Demo/ReactQueryDemo/ReactQueryDemo.module.scss +38 -0
  62. package/src/pages/Demo/ReactQueryDemo/ReactQueryDemo.tsx +55 -0
  63. package/src/pages/Demo/ReactQueryDemo/index.ts +1 -0
  64. package/src/pages/Demo/ReactQueryDemo/routes.tsx +7 -0
  65. package/src/pages/Demo/__tests__/Demo.test.tsx +15 -0
  66. package/src/pages/Demo/__tests__/__snapshots__/Demo.test.tsx.snap +555 -0
  67. package/src/pages/Demo/index.ts +1 -0
  68. package/src/pages/Demo/routes.tsx +8 -0
  69. package/src/pages/Error/Error.module.css +8 -0
  70. package/src/pages/Error/Error.tsx +22 -0
  71. package/src/pages/Error/index.ts +1 -0
  72. package/src/pages/Layout/Layout.tsx +12 -0
  73. package/src/pages/Layout/index.ts +1 -0
  74. package/src/pages/README.md +88 -0
  75. package/src/providers/QueryClientProvider/QueryClientProvider.tsx +16 -0
  76. package/src/providers/QueryClientProvider/index.ts +1 -0
  77. package/src/providers/README.md +115 -0
  78. package/src/providers/index.ts +1 -0
  79. package/src/providers/withProviders/index.ts +1 -0
  80. package/src/providers/withProviders/withProviders.tsx +18 -0
  81. package/src/react-app-env.d.ts +3 -0
  82. package/src/routing/README.md +80 -0
  83. package/src/routing/appRoutes.ts +5 -0
  84. package/src/routing/routerFactory.ts +10 -0
  85. package/src/routing/routes.tsx +13 -0
  86. package/src/types/README.md +61 -0
  87. package/src/types/demoApi.ts +9 -0
  88. package/src/types/profileTypes.ts +5 -0
  89. package/src/ui/README.md +141 -0
  90. package/src/ui/atoms/Input/Input.module.scss +32 -0
  91. package/src/ui/atoms/Input/Input.tsx +27 -0
  92. package/src/ui/atoms/Input/index.ts +1 -0
  93. package/src/ui/atoms/Logo/Logo.module.css +3 -0
  94. package/src/ui/atoms/Logo/Logo.tsx +11 -0
  95. package/src/ui/atoms/Logo/index.ts +1 -0
  96. package/src/ui/atoms/NavLink/NavLink.tsx +8 -0
  97. package/src/ui/atoms/NavLink/index.ts +1 -0
  98. package/src/ui/molecules/Navigation/Navigation.module.css +22 -0
  99. package/src/ui/molecules/Navigation/Navigation.tsx +25 -0
  100. package/src/ui/molecules/Navigation/index.ts +1 -0
  101. package/src/ui/organisms/Footer/Footer.module.css +10 -0
  102. package/src/ui/organisms/Footer/Footer.tsx +10 -0
  103. package/src/ui/organisms/Footer/index.ts +1 -0
  104. package/src/ui/organisms/Header/Header.module.css +17 -0
  105. package/src/ui/organisms/Header/Header.tsx +16 -0
  106. package/src/ui/organisms/Header/index.ts +1 -0
  107. package/src/ui/organisms/MainContent/MainContent.module.css +3 -0
  108. package/src/ui/organisms/MainContent/MainContent.tsx +6 -0
  109. package/src/ui/organisms/MainContent/index.ts +1 -0
  110. package/src/ui/templates/MainTemplate/MainTemplate.module.css +5 -0
  111. package/src/ui/templates/MainTemplate/MainTemplate.tsx +26 -0
  112. package/src/ui/templates/MainTemplate/index.ts +1 -0
  113. package/src/utils/README.md +68 -0
  114. package/tsconfig.json +32 -0
  115. package/vitest.config.mts +49 -0
  116. package/vitest.setup.ts +1 -0
  117. package/webpack.config.js +22 -0
@@ -0,0 +1,131 @@
1
+ div,
2
+ span,
3
+ applet,
4
+ object,
5
+ iframe,
6
+ h1,
7
+ h2,
8
+ h3,
9
+ h4,
10
+ h5,
11
+ h6,
12
+ p,
13
+ blockquote,
14
+ pre,
15
+ a,
16
+ abbr,
17
+ acronym,
18
+ address,
19
+ big,
20
+ cite,
21
+ code,
22
+ del,
23
+ dfn,
24
+ em,
25
+ img,
26
+ ins,
27
+ kbd,
28
+ q,
29
+ s,
30
+ samp,
31
+ small,
32
+ strike,
33
+ strong,
34
+ sub,
35
+ sup,
36
+ tt,
37
+ var,
38
+ b,
39
+ u,
40
+ i,
41
+ center,
42
+ dl,
43
+ dt,
44
+ dd,
45
+ ol,
46
+ ul,
47
+ li,
48
+ form,
49
+ label,
50
+ table,
51
+ caption,
52
+ tbody,
53
+ tfoot,
54
+ thead,
55
+ tr,
56
+ th,
57
+ td,
58
+ article,
59
+ aside,
60
+ canvas,
61
+ details,
62
+ embed,
63
+ figure,
64
+ figcaption,
65
+ footer,
66
+ header,
67
+ html,
68
+ body,
69
+ hgroup,
70
+ menu,
71
+ nav,
72
+ output,
73
+ ruby,
74
+ section,
75
+ summary,
76
+ time,
77
+ mark,
78
+ audio,
79
+ video {
80
+ margin: 0;
81
+ padding: 0;
82
+ border: 0;
83
+ vertical-align: baseline;
84
+ font: inherit;
85
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans',
86
+ 'Droid Sans', 'Helvetica Neue', sans-serif;
87
+ font-size: 100%;
88
+ -webkit-font-smoothing: antialiased;
89
+ -moz-osx-font-smoothing: grayscale;
90
+ }
91
+
92
+ /* HTML5 display-role reset for older browsers */
93
+ article,
94
+ aside,
95
+ details,
96
+ figcaption,
97
+ figure,
98
+ footer,
99
+ header,
100
+ hgroup,
101
+ menu,
102
+ nav,
103
+ section {
104
+ display: block;
105
+ }
106
+
107
+ ol,
108
+ ul {
109
+ list-style: none;
110
+ }
111
+
112
+ blockquote,
113
+ q {
114
+ quotes: none;
115
+ }
116
+
117
+ blockquote::before,
118
+ blockquote::after,
119
+ q::before,
120
+ q::after {
121
+ content: none;
122
+ }
123
+
124
+ table {
125
+ border-spacing: 0;
126
+ border-collapse: collapse;
127
+ }
128
+
129
+ code {
130
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
131
+ }
Binary file
@@ -0,0 +1,26 @@
1
+ import { App } from '@Front/components/App';
2
+ import { StrictMode } from 'react';
3
+ import { createRoot, type Root } from 'react-dom/client';
4
+
5
+ // eslint-disable-next-line import/no-default-export
6
+ export default class Bootstrap extends HTMLElement {
7
+ private readonly root: Root;
8
+
9
+ constructor() {
10
+ super();
11
+
12
+ this.root = createRoot(this);
13
+ }
14
+
15
+ connectedCallback() {
16
+ this.root.render(
17
+ <StrictMode>
18
+ <App basename={this.getAttribute('basename') ?? ''} />
19
+ </StrictMode>,
20
+ );
21
+ }
22
+
23
+ disconnectedCallback() {
24
+ queueMicrotask(() => this.root.unmount());
25
+ }
26
+ }
@@ -0,0 +1,18 @@
1
+ import { queryClient } from '@Front/config';
2
+ import { withProvider } from '@Front/providers';
3
+ import { createRouter } from '@Front/routing/routerFactory';
4
+ import { RouterProvider } from 'react-router-dom';
5
+
6
+ import '@Front/assets/css';
7
+
8
+ type AppProps = {
9
+ basename?: string;
10
+ };
11
+
12
+ const AppWithProviders = withProvider(RouterProvider);
13
+
14
+ export const App = ({ basename }: AppProps) => {
15
+ const router = createRouter({ basename });
16
+
17
+ return <AppWithProviders queryClient={queryClient} router={router} />;
18
+ };
@@ -0,0 +1 @@
1
+ export { App } from './App';
@@ -0,0 +1,4 @@
1
+ .container {
2
+ width: auto;
3
+ padding: 16px;
4
+ }
@@ -0,0 +1,16 @@
1
+ import logo from '@Front/assets/images/logo.png';
2
+ import { Logo } from '@Front/ui/atoms/Logo';
3
+ import { Link } from 'react-router-dom';
4
+
5
+ import classes from './Footer.module.css';
6
+
7
+ export const Footer = () => {
8
+ return (
9
+ <div className={classes.container}>
10
+ <hr />
11
+ <Link to="/">
12
+ <Logo size="50px" src={logo} alt="logo" />
13
+ </Link>
14
+ </div>
15
+ );
16
+ };
@@ -0,0 +1,15 @@
1
+ import { render } from '@testing-library/react';
2
+ import { BrowserRouter as Router } from 'react-router-dom';
3
+ import { Footer } from '../Footer';
4
+
5
+ describe('Footer Component', () => {
6
+ it('should render the Footer component correctly', () => {
7
+ const { container } = render(
8
+ <Router>
9
+ <Footer />
10
+ </Router>,
11
+ );
12
+
13
+ expect(container).toMatchSnapshot();
14
+ });
15
+ });
@@ -0,0 +1,21 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Footer Component > should render the Footer component correctly 1`] = `
4
+ <div>
5
+ <div
6
+ class="_container_eb428f"
7
+ >
8
+ <hr />
9
+ <a
10
+ href="/"
11
+ >
12
+ <img
13
+ alt="logo"
14
+ class="_logoStyle_a0661f"
15
+ src="/src/assets/images/logo.png"
16
+ style="width: 50px;"
17
+ />
18
+ </a>
19
+ </div>
20
+ </div>
21
+ `;
@@ -0,0 +1 @@
1
+ export { Footer } from './Footer';
@@ -0,0 +1,7 @@
1
+ .container {
2
+ display: flex;
3
+ width: auto;
4
+ padding: 8px;
5
+ flex-direction: row;
6
+ align-items: center;
7
+ }
@@ -0,0 +1,17 @@
1
+ import logo from '@Front/assets/images/logo.png';
2
+ import { Logo } from '@Front/ui/atoms/Logo';
3
+ import { Navigation } from '@Front/ui/molecules/Navigation';
4
+ import { Link } from 'react-router-dom';
5
+
6
+ import classes from './Header.module.css';
7
+
8
+ export const Header = () => {
9
+ return (
10
+ <div className={classes.container}>
11
+ <Link to="/">
12
+ <Logo size="50px" src={logo} alt="logo" />
13
+ </Link>
14
+ <Navigation links={[{ label: 'Demo', url: '/' }]} />
15
+ </div>
16
+ );
17
+ };
@@ -0,0 +1,15 @@
1
+ import { render } from '@testing-library/react';
2
+ import { BrowserRouter as Router } from 'react-router-dom';
3
+ import { Header } from '../Header';
4
+
5
+ describe('Header Component', () => {
6
+ it('should render the Header component correctly', () => {
7
+ const { container } = render(
8
+ <Router>
9
+ <Header />
10
+ </Router>,
11
+ );
12
+
13
+ expect(container).toMatchSnapshot();
14
+ });
15
+ });
@@ -0,0 +1,35 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Header Component > should render the Header component correctly 1`] = `
4
+ <div>
5
+ <div
6
+ class="_container_63c2ea"
7
+ >
8
+ <a
9
+ href="/"
10
+ >
11
+ <img
12
+ alt="logo"
13
+ class="_logoStyle_a0661f"
14
+ src="/src/assets/images/logo.png"
15
+ style="width: 50px;"
16
+ />
17
+ </a>
18
+ <nav>
19
+ <ul
20
+ class="_navList_75d6d6"
21
+ >
22
+ <li>
23
+ <a
24
+ aria-current="page"
25
+ class="_a_75d6d6 active"
26
+ href="/"
27
+ >
28
+ Demo
29
+ </a>
30
+ </li>
31
+ </ul>
32
+ </nav>
33
+ </div>
34
+ </div>
35
+ `;
@@ -0,0 +1 @@
1
+ export { Header } from './Header';
@@ -0,0 +1,34 @@
1
+ # πŸ“ components
2
+
3
+ The "components" folder is a crucial element of any React application. It is used to organize and store reusable components that make up the user interface of your application. React components are self-contained pieces of the user interface, each having its own logic and rendering.
4
+
5
+ ## πŸ“‘ Table of Contents
6
+ - [Why Use a "components" Folder](#folder-organization)
7
+ - [Usage](#usage)
8
+
9
+
10
+ ## <span id="folder-organization">Why Use a "components" Folder?</span>
11
+
12
+ 1. **Modularity** : Components can be reused across different parts of your application. This promotes code modularity and allows you to maintain your application more efficiently.
13
+
14
+ 2. **Clarity** : By grouping all your components in a "components" folder, it is easier to understand the structure of your application. It also facilitates the search and management of components.
15
+
16
+ 3. **Better Organization** : Organizing components in a dedicated folder helps clearly distinguish components from other elements of the application, such as styles, images, or configuration files.
17
+
18
+
19
+ ## <span id="usage">πŸ§‘πŸ»β€πŸ’» Usage Example </span>
20
+
21
+ Suppose you have a "Header.js" component in the "components" folder. You can import and use it in other parts of your application like this:
22
+
23
+ ```javascript
24
+ import Header from '@Front/components/Header';
25
+
26
+ export const App = () => {
27
+ return (
28
+ <div>
29
+ <Header />
30
+ {/* ... other elements of the application */}
31
+ </div>
32
+ );
33
+ }
34
+ ```
@@ -0,0 +1,24 @@
1
+ import { Input } from '@Front/ui/atoms/Input';
2
+ import { InputHTMLAttributes } from 'react';
3
+ import { FieldError, useFormContext } from 'react-hook-form';
4
+
5
+ interface TextInputProps extends InputHTMLAttributes<HTMLInputElement> {
6
+ name: string;
7
+ label: string;
8
+ }
9
+
10
+ export const TextInput = ({ name, label, ...rest }: TextInputProps) => {
11
+ const {
12
+ register,
13
+ formState: { errors },
14
+ } = useFormContext();
15
+ return (
16
+ <Input
17
+ label={label}
18
+ {...register(name)}
19
+ {...rest}
20
+ hasError={!!errors[name]}
21
+ helperText={(errors[name] as FieldError)?.message}
22
+ />
23
+ );
24
+ };
@@ -0,0 +1 @@
1
+ export { TextInput } from './TextInput';
@@ -0,0 +1,61 @@
1
+ # πŸ“ config
2
+
3
+ The "config" folder is intended to store all important configurations and utilities needed for our React project. Bringing together this information in one place makes managing configuration settings easier and ensures better code organization.
4
+
5
+ ## πŸ“‘ Table of Contents
6
+ - [Folder Organization](#folder-organization)
7
+ - [Content Example](#content-example)
8
+ - [Usage](#usage)
9
+ - [Best Practice](#best-practice)
10
+
11
+ ## <span id="folder-organization">Folder Organization</span>
12
+
13
+ Within the "config" folder, you can find the following elements:
14
+
15
+ 1. **Configuration Files** : Files containing variables and configuration parameters, such as `apiConfig.ts` for configurations related to API calls, `appConfig.ts` for general application settings, `queryClientConfig.ts` for react-query-related configuration, etc.
16
+
17
+ 2. **Configuration Scripts** : Scripts or utilities that facilitate dynamic configuration of the application, such as theme configuration, language management, etc.
18
+
19
+ ## <span id="content-example">Content Example</span>
20
+
21
+ Here is an example folder structure for "config":
22
+
23
+ ```
24
+ πŸ“config/
25
+ β”œβ”€β”€ πŸ“„ apiConfig.ts
26
+ β”œβ”€β”€ πŸ“„ appConfig.ts
27
+ β”œβ”€β”€ πŸ“„ queryClientConfig.ts
28
+ β”œβ”€β”€ πŸ“„ translationConfig.ts
29
+ ```
30
+
31
+
32
+ ## <span id="usage">πŸ§‘πŸ»β€πŸ’»Usage in the Project</span>
33
+
34
+ When you need to access a specific configuration in your code, import the appropriate file from the "config" folder. For example:
35
+
36
+
37
+ ```javascript
38
+ // Example of using an API configuration
39
+ import { apiEndpoint } from '@Front/config/apiConfig';
40
+
41
+ // Example of using a react-query configuration
42
+ import { queryClient } from '@Front/config/queryConfig';
43
+
44
+ // Example of using a general application configuration
45
+ import { appName } from '@Front/config/appConfig';
46
+ ```
47
+
48
+ ## <span id="best-practice">πŸŽ–οΈ Best Practice</span>
49
+ Efficient configuration management is crucial for maintaining a clear and organized codebase. Follow these best practices for managing configuration files:
50
+
51
+ #### - Context-Specific Configuration
52
+ Separate configuration files based on different contexts, such as API configurations, QueryClient configurations, translations, etc.
53
+
54
+ This helps in better organization and ease of maintenance.
55
+
56
+ #### - File Naming Convention
57
+ Suffix configuration files with `Config` to enhance visibility and make it easier to identify configuration files at a glance.
58
+
59
+
60
+ ---
61
+ ***By adopting these practices, you create a modular and organized approach to configuration management, making it simpler to locate and manage context-specific settings.***
@@ -0,0 +1 @@
1
+ export { queryClient } from './queryClientConfig';
@@ -0,0 +1,3 @@
1
+ import { QueryClient } from 'react-query';
2
+
3
+ export const queryClient = new QueryClient();
@@ -0,0 +1,10 @@
1
+ .inputStyle {
2
+ margin-top: 16px;
3
+ }
4
+
5
+ .buttonsStyle {
6
+ display: flex;
7
+ padding-right: 8px;
8
+ flex-direction: row;
9
+ justify-content: space-between;
10
+ }
@@ -0,0 +1,51 @@
1
+ import { TextInput } from '@Front/components/TextInput';
2
+ import { ProfileType } from '@Front/types/profileTypes';
3
+ import { yupResolver } from '@hookform/resolvers/yup';
4
+ import { FormProvider, SubmitHandler, useForm } from 'react-hook-form';
5
+ import * as yup from 'yup';
6
+ import classes from './ProfileForm.module.scss';
7
+
8
+ type ProfileFormProps = {
9
+ onSubmit: SubmitHandler<ProfileType>;
10
+ resetForm: () => void;
11
+ };
12
+
13
+ const schema = yup.object().shape({
14
+ mail: yup.string().email('Check the mail pattern').required('This field is required'),
15
+ firstName: yup.string().required('This field is required'),
16
+ lastName: yup.string().required('This field is required'),
17
+ });
18
+
19
+ export const ProfileForm = ({ onSubmit, resetForm }: ProfileFormProps) => {
20
+ const methods = useForm<ProfileType>({
21
+ resolver: yupResolver(schema),
22
+ });
23
+
24
+ return (
25
+ <FormProvider {...methods}>
26
+ <form onSubmit={methods.handleSubmit(onSubmit)}>
27
+ <p>The form is being submited {methods.formState.submitCount} times</p>
28
+ <TextInput label="E-mail" type="email" name="mail" placeholder="Exemple@gmail.com" />
29
+
30
+ <TextInput label="First Name" name="firstName" placeholder="First Name" />
31
+
32
+ <TextInput label="Last Name" name="lastName" placeholder="Last Name" />
33
+
34
+ <div className={classes.buttonsStyle}>
35
+ <input type="submit" className={classes.inputStyle} />
36
+ {methods.formState.isSubmitted && (
37
+ <input
38
+ type="button"
39
+ className={classes.inputStyle}
40
+ value="Reset"
41
+ onClick={() => {
42
+ methods.reset();
43
+ resetForm();
44
+ }}
45
+ />
46
+ )}
47
+ </div>
48
+ </form>
49
+ </FormProvider>
50
+ );
51
+ };
@@ -0,0 +1 @@
1
+ export { ProfileForm } from './ProfileForm';
@@ -0,0 +1,131 @@
1
+ # πŸ“ forms
2
+
3
+ The "forms" folder is designed to organize and manage all the necessary forms in our application. Whether it's for managing vehicle-related risks, contact forms, or any other type of form, this folder is intended to centralize the logic and presentation of forms.
4
+
5
+ ## πŸ“‘ Table of Contents
6
+ - [Why Use a "forms" Folder](#folder-organization)
7
+ - [Typical Structure of a "forms" Folder](#structure)
8
+ - [Usage](#usage)
9
+ - [Using React Hook Form](#react-hook-form)
10
+ - [Best Practice](#best-practice)
11
+
12
+ ## <span id="folder-organization">Why Use a "forms" Folder?</span>
13
+
14
+ 1. **Organization** : By grouping all form components in a dedicated folder, we maintain a clean and clear project structure. This facilitates the search and management of forms.
15
+
16
+ 2. **Reusability** : The form components we develop in this folder can be reused across different parts of the application, promoting code modularity.
17
+
18
+ 3. **Code Clarity** : By separating form components from the application logic, we make our code more readable and easier to maintain.
19
+
20
+ ## <span id="structure">Typical Structure of a "forms" Folder</span>
21
+
22
+ The structure of a "forms" folder can vary based on our project's needs, but here is a typical structure we might adopt:
23
+
24
+ ```
25
+ πŸ“ forms
26
+ β”œβ”€β”€ πŸ“VehicleRiskForm
27
+ β”‚ β”œβ”€β”€ πŸ“„ index.ts
28
+ β”‚ β”œβ”€β”€ πŸ“„ VehicleRiskForm.tsx
29
+ β”‚ β”œβ”€β”€ πŸ“„ VehicleRiskForm.module.css
30
+ β”œβ”€β”€ πŸ“ContactForm
31
+ β”‚ β”œβ”€β”€ πŸ“„ index.ts
32
+ β”‚ β”œβ”€β”€ πŸ“„ ContactForm.tsx
33
+ β”‚ β”œβ”€β”€ πŸ“„ ContactForm.module.css
34
+ ```
35
+ In this structure, each form, such as "VehicleRiskForm" or "ContactForm," has its own sub-folder containing associated TypeScript and CSS files. This helps maintain a clear organization of our code.
36
+
37
+ ## <span id="usage">πŸ§‘πŸ»β€πŸ’»Usage Example</span>
38
+
39
+ Suppose we have a "VehicleRiskForm" form component in the "forms/VehicleRiskForm" folder. We can import and use it in our React components like this:
40
+
41
+ ```javascript
42
+ import { VehicleRiskForm } from '@Front/forms/VehicleRiskForm';
43
+
44
+ export const App = () => {
45
+ return (
46
+ <div>
47
+ <VehicleRiskForm />
48
+ {/* ... other elements of the application */}
49
+ </div>
50
+ );
51
+ };
52
+ ```
53
+ ## <span id="react-hook-form">πŸ’‘ Using React Hook Form</span>
54
+ This project utilizes [React Hook Form](https://react-hook-form.com/) for handling forms. React Hook Form is a powerful library for managing forms in React applications with a simple and intuitive API.
55
+
56
+ ### React Hook Form Overview
57
+
58
+ [React Hook Form](https://react-hook-form.com/) is a library for managing forms in React applications. It offers a declarative approach to handling form state and validation, making it easy to create complex forms with minimal boilerplate.
59
+
60
+ #### Features:
61
+
62
+ - **Declarative Approach:** Define your forms with a declarative syntax, making it easy to understand and maintain.
63
+
64
+ - **Minimal Re-renders:** React Hook Form is designed to minimize re-renders for optimal performance.
65
+
66
+ - **Form Validation:** Easily implement form validation with built-in validation rules or custom validation functions.
67
+
68
+ - **Context API Integration:** Leverage React Hook Form's context API for managing form state across components.
69
+
70
+ ### Implementation using React Hook Form Context
71
+
72
+ In this project, we've taken advantage of React Hook Form's context API to manage the state of our forms across different components. This allows us to access and update form data without prop drilling, making the codebase cleaner and more maintainable.
73
+
74
+ #### Example:
75
+
76
+ ```jsx
77
+ import React from 'react';
78
+ import { useForm } from 'react-hook-form';
79
+
80
+ // Form component using React Hook Form
81
+ const MyForm = () => {
82
+ const { register, handleSubmit, formState } = useForm();
83
+
84
+ const onSubmit = (data) => {
85
+ // Handle form submission
86
+ console.log(data);
87
+ };
88
+
89
+ return (
90
+ <form onSubmit={handleSubmit(onSubmit)}>
91
+ <label>
92
+ Name:
93
+ <input {...register('name', { required: true })} />
94
+ </label>
95
+
96
+ {/* Add more form fields as needed */}
97
+
98
+ <button type="submit" disabled={formState.isSubmitting}>
99
+ Submit
100
+ </button>
101
+ </form>
102
+ );
103
+ };
104
+ ```
105
+ In the above example, we use the useForm hook to initialize the form and get the necessary methods (register, handleSubmit, and formState). The onSubmit function is called when the form is submitted, and you can access the form data from the data parameter.
106
+
107
+ ***By using React Hook Form in this way, we've streamlined the form management process and created a more maintainable and efficient solution for handling forms in our project.***
108
+
109
+ ## <span id="best-practice">πŸŽ–οΈ Best Practice</span>
110
+ When working with `React-hook-form`, consider the following best practices to enhance maintainability and organization:
111
+
112
+ #### - Use FormProvider
113
+
114
+ Always use the `FormProvider` provided by `react-hook-form` to manage the form state.
115
+
116
+ This ensures a centralized state management approach and simplifies form-related operations.
117
+
118
+ #### - Separate Yup Validation Rules
119
+ If validation rules become extensive, consider separating them into a dedicated file for better organization. This enhances readability and simplifies updates to validation logic.
120
+
121
+ #### - Separate useForm Logic
122
+ Separate the logic related to `useForm` into a custom hook file, especially if the form logic is complex or if it is shared across multiple components.
123
+
124
+ #### - Separate onSubmit Function
125
+ If the `onSubmit` function logic is substantial, consider separating it into a dedicated file. This promotes a clean separation of concerns and makes the codebase more modular.
126
+
127
+ #### - Separate Submit Button
128
+ If needed, separate the submit button into its own file to facilitate easy customization or relocation from the main form component.
129
+
130
+ ---
131
+ ***By adhering to these best practices, you create a structured and modular approach to form management, ensuring clarity and maintainability in your codebase.***