@pplancq/react-template 2.8.17 → 2.10.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 (180) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/_README.md +57 -52
  3. package/mise.toml +2 -2
  4. package/mocks/browser.ts +1 -1
  5. package/mocks/fixtures/user.ts +14 -14
  6. package/mocks/handlers/userHandlers.ts +3 -3
  7. package/mocks/server.ts +1 -1
  8. package/package.json +30 -30
  9. package/playwright-report/html/index.html +90 -0
  10. package/playwright-report/sonar-results.xml +20 -0
  11. package/playwright.config.ts +3 -3
  12. package/scripts/removeDemo.cjs +105 -66
  13. package/src/README.md +81 -0
  14. package/src/app/App.tsx +18 -0
  15. package/src/{bootstrap.tsx → app/AppHTMLElement.tsx} +5 -5
  16. package/src/app/README.md +69 -0
  17. package/src/app/assets/css/index.ts +2 -0
  18. package/src/{assets → app/assets}/css/reset.css +3 -3
  19. package/src/app/config/queryClientConfig.ts +3 -0
  20. package/src/app/config/serviceContainer.ts +6 -0
  21. package/src/app/providers/Providers/Providers.tsx +18 -0
  22. package/src/app/providers/QueryClientProvider/QueryClientProvider.tsx +16 -0
  23. package/src/app/providers/ServiceProvider/ServiceContext.ts +8 -0
  24. package/src/app/providers/ServiceProvider/ServiceProvider.tsx +14 -0
  25. package/src/app/routing/Router.tsx +14 -0
  26. package/src/app/routing/appRoutes.ts +3 -0
  27. package/src/app/routing/routes.tsx +9 -0
  28. package/src/demo/README.md +149 -0
  29. package/src/demo/application/dtos/ArchitecturePrinciple.ts +5 -0
  30. package/src/{types/profileTypes.ts → demo/application/dtos/ProfileFormValues.ts} +1 -1
  31. package/src/demo/application/use-cases/GetArchitecturePrinciplesUseCase.ts +11 -0
  32. package/src/demo/application/use-cases/GetArchitecturePrinciplesUseCaseInterface.ts +5 -0
  33. package/src/demo/application/use-cases/GetDemoUsersUseCase.ts +11 -0
  34. package/src/demo/application/use-cases/GetDemoUsersUseCaseInterface.ts +5 -0
  35. package/src/demo/domain/entities/DemoUser.ts +7 -0
  36. package/src/demo/domain/repositories/ArchitecturePrincipleRepositoryInterface.d.ts +5 -0
  37. package/src/demo/domain/repositories/DemoUserRepositoryInterface.d.ts +5 -0
  38. package/src/demo/infrastructure/repositories/HttpDemoUserRepository.ts +29 -0
  39. package/src/demo/infrastructure/repositories/StaticArchitecturePrincipleRepository.ts +33 -0
  40. package/src/demo/serviceDemo.ts +40 -0
  41. package/src/demo/serviceIdentifiers.ts +6 -0
  42. package/src/demo/ui/components/DemoFooter/DemoFooter.tsx +17 -0
  43. package/src/demo/ui/components/DemoFooter/index.ts +1 -0
  44. package/src/demo/ui/components/DemoHeader/DemoHeader.tsx +25 -0
  45. package/src/demo/ui/components/DemoHeader/index.ts +1 -0
  46. package/src/{ui/molecules/Navigation/Navigation.tsx → demo/ui/components/DemoNavigation/DemoNavigation.tsx} +6 -6
  47. package/src/demo/ui/components/DemoNavigation/index.ts +1 -0
  48. package/src/{ui/atoms → demo/ui/components}/Input/Input.tsx +3 -3
  49. package/src/demo/ui/components/Input/index.ts +1 -0
  50. package/src/{ui/atoms → demo/ui/components}/Logo/Logo.tsx +2 -2
  51. package/src/demo/ui/components/Logo/index.ts +1 -0
  52. package/src/{ui/atoms → demo/ui/components}/NavLink/NavLink.tsx +3 -3
  53. package/src/demo/ui/components/NavLink/index.ts +1 -0
  54. package/src/{components → demo/ui/components}/TextInput/TextInput.tsx +3 -3
  55. package/src/demo/ui/components/TextInput/index.ts +1 -0
  56. package/src/{forms → demo/ui/forms}/ProfileForm/ProfileForm.tsx +13 -13
  57. package/src/demo/ui/forms/ProfileForm/index.ts +1 -0
  58. package/src/demo/ui/hooks/useDemoUsersQuery/useDemoUsersQuery.ts +13 -0
  59. package/src/demo/ui/layouts/DemoLayout/DemoLayout.tsx +12 -0
  60. package/src/demo/ui/layouts/MainTemplate/MainTemplate.module.css +21 -0
  61. package/src/demo/ui/layouts/MainTemplate/MainTemplate.tsx +26 -0
  62. package/src/demo/ui/layouts/MainTemplate/index.ts +1 -0
  63. package/src/{pages/Demo/Demo.module.scss → demo/ui/pages/DemoHome/DemoHome.module.scss} +5 -5
  64. package/src/demo/ui/pages/DemoHome/DemoHome.tsx +117 -0
  65. package/src/demo/ui/pages/DependencyInjectionDemo/DependencyInjectionDemo.tsx +47 -0
  66. package/src/{pages/Demo → demo/ui/pages}/ReactHookFormDemo/ReactHookFormDemo.tsx +8 -8
  67. package/src/demo/ui/pages/ReactQueryDemo/ReactQueryDemo.module.scss +38 -0
  68. package/src/{pages/Demo → demo/ui/pages}/ReactQueryDemo/ReactQueryDemo.tsx +6 -5
  69. package/src/demo/ui/routing/demoAppRoutes.ts +6 -0
  70. package/src/demo/ui/routing/demoRoutes.tsx +31 -0
  71. package/src/main.ts +5 -5
  72. package/src/react-app-env.d.ts +1 -1
  73. package/src/shared/README.md +53 -0
  74. package/src/shared/application/README.md +49 -0
  75. package/src/shared/domain/README.md +52 -0
  76. package/src/shared/infrastructure/README.md +51 -0
  77. package/src/shared/infrastructure/http/constant.ts +16 -0
  78. package/src/{api → shared/infrastructure/http}/fetchApi.ts +3 -3
  79. package/src/shared/ui/README.md +50 -0
  80. package/src/shared/ui/hooks/useService/useService.ts +13 -0
  81. package/test-results/.last-run.json +4 -0
  82. package/tests/e2e/demo.test.ts +17 -0
  83. package/tests/e2e/fixture/playwright.fixture.ts +15 -0
  84. package/tests/{utils → e2e/utils}/createNetworkFixture.ts +2 -2
  85. package/tests/{utils → e2e/utils}/createTestWithCoverageFixture.ts +8 -8
  86. package/tests/{utils → e2e/utils}/playwright.globalSetup.ts +4 -4
  87. package/tests/{utils → e2e/utils}/playwright.globalTeardown.ts +3 -3
  88. package/{src/__tests__/bootstraps.test.tsx → tests/unit/app/AppHTMLElement.test.tsx} +14 -14
  89. package/tests/unit/demo/ui/components/DemoFooter/Footer.test.tsx +15 -0
  90. package/{src/components/Footer/__tests__ → tests/unit/demo/ui/components/DemoFooter}/__snapshots__/Footer.test.tsx.snap +3 -3
  91. package/tests/unit/demo/ui/components/DemoHeader/Header.test.tsx +15 -0
  92. package/tests/unit/demo/ui/components/DemoHeader/__snapshots__/Header.test.tsx.snap +64 -0
  93. package/tests/unit/demo/ui/components/Logo/Logo.test.tsx +12 -0
  94. package/tsconfig.json +4 -2
  95. package/vitest.config.mts +6 -2
  96. package/postcss.config.mjs +0 -5
  97. package/src/api/README.md +0 -65
  98. package/src/api/constant.ts +0 -16
  99. package/src/api/demoApi.ts +0 -10
  100. package/src/assets/README.md +0 -54
  101. package/src/assets/css/index.ts +0 -2
  102. package/src/components/App/App.tsx +0 -18
  103. package/src/components/App/index.ts +0 -1
  104. package/src/components/Footer/Footer.tsx +0 -16
  105. package/src/components/Footer/__tests__/Footer.test.tsx +0 -15
  106. package/src/components/Footer/index.ts +0 -1
  107. package/src/components/Header/Header.tsx +0 -17
  108. package/src/components/Header/__tests__/Header.test.tsx +0 -15
  109. package/src/components/Header/__tests__/__snapshots__/Header.test.tsx.snap +0 -37
  110. package/src/components/Header/index.ts +0 -1
  111. package/src/components/README.md +0 -33
  112. package/src/components/TextInput/index.ts +0 -1
  113. package/src/config/README.md +0 -63
  114. package/src/config/index.ts +0 -1
  115. package/src/config/queryClientConfig.ts +0 -3
  116. package/src/forms/ProfileForm/index.ts +0 -1
  117. package/src/forms/README.md +0 -142
  118. package/src/hooks/README.md +0 -83
  119. package/src/hooks/api/queryKey.ts +0 -1
  120. package/src/hooks/api/useDemoApi.ts +0 -16
  121. package/src/pages/Demo/Demo.tsx +0 -236
  122. package/src/pages/Demo/ReactHookFormDemo/index.ts +0 -1
  123. package/src/pages/Demo/ReactHookFormDemo/routes.tsx +0 -7
  124. package/src/pages/Demo/ReactQueryDemo/index.ts +0 -1
  125. package/src/pages/Demo/ReactQueryDemo/routes.tsx +0 -7
  126. package/src/pages/Demo/__tests__/Demo.test.tsx +0 -15
  127. package/src/pages/Demo/__tests__/__snapshots__/Demo.test.tsx.snap +0 -557
  128. package/src/pages/Demo/index.ts +0 -1
  129. package/src/pages/Demo/routes.tsx +0 -8
  130. package/src/pages/Layout/Layout.tsx +0 -12
  131. package/src/pages/Layout/index.ts +0 -1
  132. package/src/pages/README.md +0 -91
  133. package/src/pages/UnexpectedError/UnexpectedError.module.css +0 -8
  134. package/src/pages/UnexpectedError/UnexpectedError.tsx +0 -22
  135. package/src/pages/UnexpectedError/index.ts +0 -1
  136. package/src/providers/QueryClientProvider/QueryClientProvider.tsx +0 -16
  137. package/src/providers/QueryClientProvider/index.ts +0 -1
  138. package/src/providers/README.md +0 -112
  139. package/src/providers/index.ts +0 -1
  140. package/src/providers/withProviders/index.ts +0 -1
  141. package/src/providers/withProviders/withProviders.tsx +0 -18
  142. package/src/routing/README.md +0 -76
  143. package/src/routing/appRoutes.ts +0 -5
  144. package/src/routing/routerFactory.ts +0 -12
  145. package/src/routing/routes.tsx +0 -13
  146. package/src/types/README.md +0 -62
  147. package/src/types/demoApi.ts +0 -25
  148. package/src/ui/README.md +0 -144
  149. package/src/ui/atoms/Input/index.ts +0 -1
  150. package/src/ui/atoms/Logo/__tests__/Logo.test.tsx +0 -12
  151. package/src/ui/atoms/Logo/index.ts +0 -1
  152. package/src/ui/atoms/NavLink/index.ts +0 -1
  153. package/src/ui/molecules/Navigation/index.ts +0 -1
  154. package/src/ui/organisms/Footer/Footer.module.css +0 -10
  155. package/src/ui/organisms/Footer/Footer.tsx +0 -10
  156. package/src/ui/organisms/Footer/index.ts +0 -1
  157. package/src/ui/organisms/Header/Header.module.css +0 -17
  158. package/src/ui/organisms/Header/Header.tsx +0 -16
  159. package/src/ui/organisms/Header/index.ts +0 -1
  160. package/src/ui/organisms/MainContent/MainContent.module.css +0 -3
  161. package/src/ui/organisms/MainContent/MainContent.tsx +0 -6
  162. package/src/ui/organisms/MainContent/index.ts +0 -1
  163. package/src/ui/templates/MainTemplate/MainTemplate.module.css +0 -5
  164. package/src/ui/templates/MainTemplate/MainTemplate.tsx +0 -26
  165. package/src/ui/templates/MainTemplate/index.ts +0 -1
  166. package/src/utils/README.md +0 -70
  167. package/tests/demo.test.ts +0 -17
  168. package/tests/fixture/playwright.fixture.ts +0 -15
  169. /package/src/{assets → app/assets}/css/mainBody.css +0 -0
  170. /package/src/{assets → demo/ui/assets}/images/logo.png +0 -0
  171. /package/src/{assets → demo/ui/assets}/images/templatePlugins.png +0 -0
  172. /package/src/{components/Footer/Footer.module.css → demo/ui/components/DemoFooter/DemoFooter.module.css} +0 -0
  173. /package/src/{components/Header/Header.module.css → demo/ui/components/DemoHeader/DemoHeader.module.css} +0 -0
  174. /package/src/{ui/molecules/Navigation/Navigation.module.css → demo/ui/components/DemoNavigation/DemoNavigation.module.css} +0 -0
  175. /package/src/{ui/atoms → demo/ui/components}/Input/Input.module.scss +0 -0
  176. /package/src/{ui/atoms → demo/ui/components}/Logo/Logo.module.css +0 -0
  177. /package/src/{forms → demo/ui/forms}/ProfileForm/ProfileForm.module.scss +0 -0
  178. /package/src/{pages/Demo/ReactQueryDemo/ReactQueryDemo.module.scss → demo/ui/pages/DependencyInjectionDemo/DependencyInjectionDemo.module.scss} +0 -0
  179. /package/src/{pages/Demo/ReactHookFormDemo/ReactHookFormDemo.module.css → demo/ui/pages/ReactHookFormDemo/ReactHookFormDemo.module.scss} +0 -0
  180. /package/src/{types/api.ts → shared/infrastructure/http/fetchApi.type.d.ts} +0 -0
@@ -0,0 +1,50 @@
1
+ # `shared/ui`
2
+
3
+ The `shared/ui` folder contains **UI-layer code that is genuinely reusable across bounded contexts** — hooks,
4
+ utilities, and components that carry no feature identity.
5
+
6
+ ## What the UI layer represents
7
+
8
+ In Clean Architecture, the **UI layer** is the outermost ring. Its job is to:
9
+
10
+ - Present data to the user
11
+ - Translate user actions into application-layer calls (use cases)
12
+ - Never execute business logic or call infrastructure directly
13
+
14
+ The UI layer depends on the application layer (via use cases and DTOs) and occasionally on domain types.
15
+ It must **never** import from `infrastructure`.
16
+
17
+ ## What belongs here
18
+
19
+ ### `hooks/useService`
20
+
21
+ `useService` is the bridge between the Inversify DI container and React components:
22
+
23
+ ```ts
24
+ const myService = useService<MyServiceInterface>(SERVICE_IDENTIFIER);
25
+ ```
26
+
27
+ It reads the container from `ServiceContext` (provided by `ServiceProvider` in `app/providers`) and resolves
28
+ the requested service. This pattern means React components declare _what they need_ without knowing _how it is
29
+ constructed_. Swapping a real implementation for a test double requires only a different container binding —
30
+ zero changes to the component.
31
+
32
+ `useService` lives in `shared/ui` because any bounded context can use it to resolve its own services.
33
+
34
+ ## Dependency rules
35
+
36
+ ```
37
+ shared/ui
38
+ ✅ can import from: shared/domain, shared/application
39
+ ❌ must NOT import from: shared/infrastructure
40
+ ❌ must NOT import from: any bounded context
41
+ ```
42
+
43
+ The UI layer must not call infrastructure directly — if it needs external data it does so through a use case or
44
+ React Query integration, not by importing an HTTP adapter.
45
+
46
+ ## What you should not put here
47
+
48
+ - Demo-specific visual components (buttons, forms, layouts, logos, nav links)
49
+ - Feature-specific React hooks
50
+ - Infrastructure adapters or API calls
@@ -0,0 +1,13 @@
1
+ import { ServiceContext } from "@App/providers/ServiceProvider/ServiceContext";
2
+ import type { ServiceIdentifier } from "inversify";
3
+ import { useContext } from "react";
4
+
5
+ export const useService = <T = unknown>(serviceIdentifier: ServiceIdentifier<T>): T => {
6
+ const context = useContext(ServiceContext);
7
+
8
+ if (!context) {
9
+ throw new Error("useService must be used within a ServiceProvider");
10
+ }
11
+
12
+ return context.container.get<T>(serviceIdentifier);
13
+ };
@@ -0,0 +1,4 @@
1
+ {
2
+ "status": "passed",
3
+ "failedTests": []
4
+ }
@@ -0,0 +1,17 @@
1
+ import { getUsers200 } from "@Mocks/handlers/userHandlers";
2
+ import { expect } from "@playwright/test";
3
+ import { describe, it } from "./fixture/playwright.fixture";
4
+
5
+ describe("Demo Test", () => {
6
+ it("should have a title", async ({ page }) => {
7
+ await page.goto("/");
8
+ const title = page.getByText("WELCOME TO YOUR REACT STARTER KIT");
9
+ await expect(title).toBeVisible();
10
+ });
11
+
12
+ it("should data fetching", async ({ page, network }) => {
13
+ network.use(getUsers200);
14
+ await page.goto("/react-query");
15
+ await expect(page.getByText("Demo user")).toBeVisible();
16
+ });
17
+ });
@@ -0,0 +1,15 @@
1
+ import type { NetworkFixture } from "@msw/playwright";
2
+ import { test as base } from "@playwright/test";
3
+ import { createNetworkFixture } from "../utils/createNetworkFixture";
4
+ import { createTestWithCoverageFixture } from "../utils/createTestWithCoverageFixture";
5
+
6
+ export const test = base.extend<{
7
+ testWithCoverage: string;
8
+ network: NetworkFixture;
9
+ }>({
10
+ testWithCoverage: createTestWithCoverageFixture(),
11
+ network: createNetworkFixture(),
12
+ });
13
+
14
+ export const it = test;
15
+ export const { describe } = test;
@@ -1,5 +1,5 @@
1
- import { defineNetworkFixture, type NetworkFixture } from '@msw/playwright';
2
- import type { PlaywrightTestArgs, PlaywrightWorkerArgs, TestFixture } from '@playwright/test';
1
+ import { defineNetworkFixture, type NetworkFixture } from "@msw/playwright";
2
+ import type { PlaywrightTestArgs, PlaywrightWorkerArgs, TestFixture } from "@playwright/test";
3
3
 
4
4
  export const createNetworkFixture = (): [
5
5
  TestFixture<NetworkFixture, PlaywrightTestArgs & PlaywrightWorkerArgs>,
@@ -1,14 +1,14 @@
1
- import type { PlaywrightTestArgs, PlaywrightWorkerArgs, TestFixture } from '@playwright/test';
2
- import { test } from '@playwright/test';
3
- import { CoverageReport } from 'monocart-coverage-reports';
4
- import { coverageOptions } from '../../mrc.playwright.config';
1
+ import type { PlaywrightTestArgs, PlaywrightWorkerArgs, TestFixture } from "@playwright/test";
2
+ import { test } from "@playwright/test";
3
+ import { CoverageReport } from "monocart-coverage-reports";
4
+ import { coverageOptions } from "../../../mrc.playwright.config";
5
5
 
6
6
  export const createTestWithCoverageFixture = (): [
7
7
  TestFixture<string, PlaywrightTestArgs & PlaywrightWorkerArgs>,
8
- { scope: 'test'; auto: true },
8
+ { scope: "test"; auto: true },
9
9
  ] => [
10
10
  async ({ page }, use) => {
11
- const isChromium = test.info().project.name === 'chromium';
11
+ const isChromium = test.info().project.name === "chromium";
12
12
 
13
13
  if (isChromium && coverageOptions.enabled) {
14
14
  await page.coverage.startJSCoverage({
@@ -16,7 +16,7 @@ export const createTestWithCoverageFixture = (): [
16
16
  });
17
17
  }
18
18
 
19
- await use('testWithCoverage');
19
+ await use("testWithCoverage");
20
20
 
21
21
  if (isChromium && coverageOptions.enabled) {
22
22
  const coverageList = await page.coverage.stopJSCoverage();
@@ -25,7 +25,7 @@ export const createTestWithCoverageFixture = (): [
25
25
  }
26
26
  },
27
27
  {
28
- scope: 'test',
28
+ scope: "test",
29
29
  auto: true,
30
30
  },
31
31
  ];
@@ -1,10 +1,10 @@
1
- import type { FullConfig } from '@playwright/test';
2
- import { CoverageReport } from 'monocart-coverage-reports';
3
- import { coverageOptions } from '../../mrc.playwright.config';
1
+ import type { FullConfig } from "@playwright/test";
2
+ import { CoverageReport } from "monocart-coverage-reports";
3
+ import { coverageOptions } from "../../../mrc.playwright.config";
4
4
 
5
5
  const globalSetup = (config: FullConfig) => {
6
6
  if (config.webServer && coverageOptions.enabled) {
7
- console.info('[playwright] Coverage enabled with monocart');
7
+ console.info("[playwright] Coverage enabled with monocart");
8
8
  const mcr = new CoverageReport(coverageOptions);
9
9
  mcr.cleanCache();
10
10
  }
@@ -1,6 +1,6 @@
1
- import type { FullConfig } from '@playwright/test';
2
- import { CoverageReport } from 'monocart-coverage-reports';
3
- import { coverageOptions } from '../../mrc.playwright.config';
1
+ import type { FullConfig } from "@playwright/test";
2
+ import { CoverageReport } from "monocart-coverage-reports";
3
+ import { coverageOptions } from "../../../mrc.playwright.config";
4
4
 
5
5
  const globalTeardown = async (config: FullConfig) => {
6
6
  if (config.webServer && coverageOptions.enabled) {
@@ -1,19 +1,19 @@
1
- import { App } from '@Front/components/App';
2
- import { waitFor } from '@testing-library/react';
3
- import { StrictMode } from 'react';
4
- import { createRoot } from 'react-dom/client';
5
- import { afterEach, beforeEach, describe, expect, it, type Mock, vi } from 'vitest';
6
- import bootstrap from '../bootstrap';
1
+ import { App } from "@App/App";
2
+ import AppHTMLElement from "@App/AppHTMLElement";
3
+ import { waitFor } from "@testing-library/react";
4
+ import { StrictMode } from "react";
5
+ import { createRoot } from "react-dom/client";
6
+ import { afterEach, beforeEach, describe, expect, it, type Mock, vi } from "vitest";
7
7
 
8
- vi.mock('@Front/components/App', () => ({
8
+ vi.mock("@App/App", () => ({
9
9
  App: () => <div data-testid="app-mock">AppMock</div>,
10
10
  }));
11
11
 
12
- vi.mock('react-dom/client', () => ({
12
+ vi.mock("react-dom/client", () => ({
13
13
  createRoot: vi.fn(),
14
14
  }));
15
15
 
16
- describe('bootstrap', () => {
16
+ describe("AppHTMLElement", () => {
17
17
  let container: HTMLElement;
18
18
  const render = vi.fn();
19
19
  const unmount = vi.fn();
@@ -22,17 +22,17 @@ describe('bootstrap', () => {
22
22
  unmount,
23
23
  }));
24
24
 
25
- customElements.define('bootstrap-html-element', bootstrap);
25
+ customElements.define("bootstrap-html-element", AppHTMLElement);
26
26
 
27
27
  beforeEach(() => {
28
- container = document.createElement('bootstrap-html-element');
28
+ container = document.createElement("bootstrap-html-element");
29
29
  });
30
30
 
31
31
  afterEach(() => {
32
32
  container.remove();
33
33
  });
34
34
 
35
- it('should mount the React component in the custom element', () => {
35
+ it("should mount the React component in the custom element", () => {
36
36
  document.body.appendChild(container);
37
37
 
38
38
  expect(createRoot as Mock).toHaveBeenCalledWith(expect.anything());
@@ -44,7 +44,7 @@ describe('bootstrap', () => {
44
44
  expect(unmount).not.toHaveBeenCalled();
45
45
  });
46
46
 
47
- it('should unmount the React component when removed from the DOM', async () => {
47
+ it("should unmount the React component when removed from the DOM", async () => {
48
48
  document.body.appendChild(container);
49
49
 
50
50
  expect(unmount).not.toHaveBeenCalled();
@@ -56,7 +56,7 @@ describe('bootstrap', () => {
56
56
  });
57
57
  });
58
58
 
59
- it('should not unmount when element is removed and re-added to the DOM', async () => {
59
+ it("should not unmount when element is removed and re-added to the DOM", async () => {
60
60
  document.body.appendChild(container);
61
61
  container.remove();
62
62
  document.body.appendChild(container);
@@ -0,0 +1,15 @@
1
+ import { DemoFooter } from "@Demo/ui/components/DemoFooter";
2
+ import { render } from "@testing-library/react";
3
+ import { BrowserRouter as Router } from "react-router";
4
+
5
+ describe("Footer Component", () => {
6
+ it("should render the Footer component correctly", () => {
7
+ const { container } = render(
8
+ <Router>
9
+ <DemoFooter />
10
+ </Router>,
11
+ );
12
+
13
+ expect(container).toMatchSnapshot();
14
+ });
15
+ });
@@ -3,7 +3,7 @@
3
3
  exports[`Footer Component > should render the Footer component correctly 1`] = `
4
4
  <div>
5
5
  <div
6
- class="_container_acfd2c"
6
+ class="container"
7
7
  >
8
8
  <hr />
9
9
  <a
@@ -12,8 +12,8 @@ exports[`Footer Component > should render the Footer component correctly 1`] = `
12
12
  >
13
13
  <img
14
14
  alt="logo"
15
- class="_logoStyle_9e86a7"
16
- src="/src/assets/images/logo.png"
15
+ class="logoStyle"
16
+ src="/src/demo/ui/assets/images/logo.png"
17
17
  style="width: 50px;"
18
18
  />
19
19
  </a>
@@ -0,0 +1,15 @@
1
+ import { DemoHeader } from "@Demo/ui/components/DemoHeader";
2
+ import { render } from "@testing-library/react";
3
+ import { BrowserRouter as Router } from "react-router";
4
+
5
+ describe("Header Component", () => {
6
+ it("should render the Header component correctly", () => {
7
+ const { container } = render(
8
+ <Router>
9
+ <DemoHeader />
10
+ </Router>,
11
+ );
12
+
13
+ expect(container).toMatchSnapshot();
14
+ });
15
+ });
@@ -0,0 +1,64 @@
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"
7
+ >
8
+ <a
9
+ data-discover="true"
10
+ href="/"
11
+ >
12
+ <img
13
+ alt="logo"
14
+ class="logoStyle"
15
+ src="/src/demo/ui/assets/images/logo.png"
16
+ style="width: 50px;"
17
+ />
18
+ </a>
19
+ <nav>
20
+ <ul
21
+ class="navList"
22
+ >
23
+ <li>
24
+ <a
25
+ aria-current="page"
26
+ class="a active"
27
+ data-discover="true"
28
+ href="/"
29
+ >
30
+ Overview
31
+ </a>
32
+ </li>
33
+ <li>
34
+ <a
35
+ class="a"
36
+ data-discover="true"
37
+ href="/react-query"
38
+ >
39
+ React Query
40
+ </a>
41
+ </li>
42
+ <li>
43
+ <a
44
+ class="a"
45
+ data-discover="true"
46
+ href="/react-hook-form"
47
+ >
48
+ React Hook Form
49
+ </a>
50
+ </li>
51
+ <li>
52
+ <a
53
+ class="a"
54
+ data-discover="true"
55
+ href="/dependency-injection"
56
+ >
57
+ Dependency Injection
58
+ </a>
59
+ </li>
60
+ </ul>
61
+ </nav>
62
+ </div>
63
+ </div>
64
+ `;
@@ -0,0 +1,12 @@
1
+ import { Logo } from "@Demo/ui/components/Logo";
2
+ import { render } from "@testing-library/react";
3
+ import { expect } from "vitest";
4
+ import { axe } from "vitest-axe";
5
+
6
+ describe("<Logo />", () => {
7
+ it("should", async () => {
8
+ const { container } = render(<Logo src="foo" alt="bar" />);
9
+
10
+ expect(await axe(container)).toHaveNoViolations();
11
+ });
12
+ });
package/tsconfig.json CHANGED
@@ -23,10 +23,12 @@
23
23
  "noEmit": true,
24
24
  "jsx": "react-jsx",
25
25
  "paths": {
26
- "@Front/*": ["./src/*"],
26
+ "@App/*": ["./src/app/*"],
27
+ "@Shared/*": ["./src/shared/*"],
28
+ "@Demo/*": ["./src/demo/*"],
27
29
  "@Mocks/*": ["./mocks/*"]
28
30
  }
29
31
  },
30
- "include": ["src", "mocks", "vitest.setup.ts", "rsbuild.config.ts"],
32
+ "include": ["src", "tests", "mocks", "vitest.setup.ts", "rsbuild.config.ts"],
31
33
  "exclude": ["node_modules"]
32
34
  }
package/vitest.config.mts CHANGED
@@ -18,13 +18,17 @@ export default defineConfig(({ mode }) => {
18
18
  environment: 'jsdom',
19
19
  setupFiles: 'vitest.setup.ts',
20
20
  clearMocks: true,
21
- css: false,
21
+ css: {
22
+ modules: {
23
+ classNameStrategy: 'non-scoped',
24
+ },
25
+ },
22
26
  reporters: ['default', 'junit', 'vitest-sonar-reporter'],
23
27
  outputFile: {
24
28
  'vitest-sonar-reporter': 'sonar-report.xml',
25
29
  junit: 'junit-report.xml',
26
30
  },
27
- include: ['src/**/*.(spec|test|steps).[jt]s?(x)'],
31
+ include: ['tests/unit/**/*.(spec|test|steps).[jt]s?(x)'],
28
32
  maxWorkers: env.CI ? 2 : undefined,
29
33
  coverage: {
30
34
  enabled: env.CI === 'true',
@@ -1,5 +0,0 @@
1
- import defaultConfig from '@pplancq/postcss-config';
2
-
3
- export default {
4
- ...defaultConfig,
5
- };
package/src/api/README.md DELETED
@@ -1,65 +0,0 @@
1
- # 📁 api
2
-
3
- The "api" folder is designed to handle calls to native APIs using the fetch function. These calls are essential for retrieving real-time data from external sources, such as remote servers or web services.
4
-
5
- ## 📑 Table of Contents
6
-
7
- - [Folder Organization](#folder-organization)
8
- - [Usage](#usage)
9
- - [Error Handling](#error-handling)
10
- - [Security](#security)
11
- - [Documentation](#documentation)
12
- - [Testing](#testing)
13
- - [Best Practice](#best-practice)
14
-
15
- ## <span id="folder-organization">Folder Organization</span>
16
-
17
- The "api" folder can be organized as follows :
18
-
19
- 1. **API Endpoints** : Create a separate file for each API you are calling. For example, if you have a user management API and a data retrieval API, you can have the files `users.ts` and `data.ts` to handle these respective calls.
20
-
21
- 2. **Call Functions** : Inside each API file, define dedicated functions to make `fetch` requests to the corresponding endpoints. These functions can also include handling responses and errors.
22
-
23
- ## <span id="usage">🧑🏻‍💻 Usage</span>
24
-
25
- When you need to make a call to a native API, import the appropriate function from the "api" folder into your code. For example:
26
-
27
- ```javascript
28
- import { getUsers } from '@Front/api/users';
29
-
30
- const users = getUsers();
31
- ```
32
-
33
- ## <span id="error-handling">Error Handling</span>
34
-
35
- Ensure proper error handling in your API call functions. You can use error handling mechanisms such as promises or `try/catch` to capture and handle potential errors when making API calls.
36
-
37
- ## <span id="security">Security</span>
38
-
39
- Be mindful of security when interacting with external APIs. Avoid storing sensitive information, such as API keys, directly in your source code. Use environment variables or external configuration files to manage this sensitive information securely.
40
-
41
- ## <span id="documentation">Documentation</span>
42
-
43
- Document each API call function, specifying expected parameters, possible responses, and any relevant information about the API itself.
44
-
45
- ## <span id="testing">Testing</span>
46
-
47
- Whenever possible, write unit tests to validate the behavior of API call functions. This will ensure that API calls work correctly and quickly detect potential issues.
48
-
49
- ## <span id="best-practice">🎖️ Best Practice</span>
50
-
51
- It is recommended to implement a custom fetch function that serves as an enhancement or override of the default fetch function. This can be particularly useful for incorporating common configurations, such as adding headers like an API token.
52
-
53
- Consider the following example of a custom fetch function :
54
-
55
- ```javascript
56
- // Custom fetch function with common configurations
57
- export const fetchApi = (uri, options) => {
58
- const headers = new Headers(options.headers ?? []);
59
- headers.append('x-api-key', '<token-api>');
60
-
61
- return fetch(uri, { ...options, headers });
62
- };
63
- ```
64
-
65
- In this example, the fetchApi function extends the default fetch function by automatically including an API token in the request header. This practice helps centralize common configurations and promotes consistency across your application.
@@ -1,16 +0,0 @@
1
- export enum METHODS {
2
- get = 'GET',
3
- post = 'POST',
4
- put = 'PUT',
5
- patch = 'PATCH',
6
- delete = 'DELETE',
7
- }
8
-
9
- export enum HEADERS {
10
- contentType = 'content-type',
11
- }
12
-
13
- export enum MIME_TYPES {
14
- json = 'application/json',
15
- text = 'plain/text',
16
- }
@@ -1,10 +0,0 @@
1
- import { fetchApi } from '@Front/api/fetchApi';
2
- import type { Users } from '@Front/types/demoApi';
3
-
4
- export const fetchDemoApi = async () => {
5
- const users = await fetchApi<Users>({
6
- path: 'https://jsonplaceholder.typicode.com/users',
7
- });
8
-
9
- return users.map(user => ({ ...user, username: user.username.toUpperCase(), email: user.email.toLowerCase() }));
10
- };
@@ -1,54 +0,0 @@
1
- # 📁 assets
2
-
3
- The "assets" folder is a commonly used directory in a React application to store static resources such as images, CSS files, fonts, JSON data files, icons, and other non-JavaScript files used in your application. These resources are typically needed to style and customize the user interface of your application.
4
-
5
- ## 📑 Table of Contents
6
-
7
- - [Why Use an "assets" Folder](#folder-organization)
8
- - [Usage Example](#usage)
9
- - [Best Practice](#best-practice)
10
-
11
- ## <span id="folder-organization">Why Use an "assets" Folder?</span>
12
-
13
- 1. **Organization** : By storing your static resources in a separate folder named "assets," you maintain a cleaner and more organized project structure. This clearly separates static content from JavaScript files.
14
-
15
- 2. **Ease of Access** : Files in the "assets" folder can be easily referenced in your code using relative paths. This simplifies the inclusion of images, CSS, fonts, and other resources in your React components.
16
-
17
- 3. **Performance Optimization** : By storing static resources like images in an "assets" folder, you can optimize these files for better performance, for example, by using image compression tools.
18
-
19
- ## <span id="usage">🧑🏻‍💻 Usage Example </span>
20
-
21
- To use an image stored in the "assets" folder, you can reference its relative path in your JavaScript or JSX code like this:
22
-
23
- ```javascript
24
- import logo from '@Front/assets/images/logo.png';
25
-
26
- export const App = () => {
27
- return (
28
- <div>
29
- <img src={logo} alt="Logo" />
30
- {/* ... other elements of the application */}
31
- </div>
32
- );
33
- };
34
- ```
35
-
36
- ## <span id="best-practice">🎖️ Best Practice</span>
37
-
38
- When it comes to styling and managing assets, adopting the following practices can enhance maintainability and structure in your project:
39
-
40
- ### - Global CSS Rules
41
-
42
- Define all global CSS rules, such as resets, fonts, and general styling, in a centralized stylesheet (in the css folder under the assets ).
43
-
44
- This ensures consistency across your entire application.
45
-
46
- ### - CSS Modules
47
-
48
- For component-specific styles, leverage CSS Modules to encapsulate styles within the component scope.
49
-
50
- This helps prevent unintentional styling conflicts and promotes a modular approach to styling.
51
-
52
- ---
53
-
54
- **_By adhering to these practices, you create a clear separation between global styles and component-specific styles, making your codebase more maintainable and scalable._**
@@ -1,2 +0,0 @@
1
- import './reset.css';
2
- import './mainBody.css';
@@ -1,18 +0,0 @@
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';
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
- };
@@ -1 +0,0 @@
1
- export { App } from './App';
@@ -1,16 +0,0 @@
1
- import logo from '@Front/assets/images/logo.png';
2
- import { Logo } from '@Front/ui/atoms/Logo';
3
- import { Link } from 'react-router';
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
- };
@@ -1,15 +0,0 @@
1
- import { render } from '@testing-library/react';
2
- import { BrowserRouter as Router } from 'react-router';
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
- });
@@ -1 +0,0 @@
1
- export { Footer } from './Footer';
@@ -1,17 +0,0 @@
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';
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
- };