pejay-ui 1.2.2 → 1.3.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 (60) hide show
  1. package/package.json +1 -1
  2. package/registry.json +33 -1
  3. package/templates/notes/create-pejay.md +222 -0
  4. package/templates/notes/notes-v1.md +516 -0
  5. package/templates/notes/notes-v2.md +764 -0
  6. package/templates/notes/notes-v3.md +574 -0
  7. package/templates/notes/notes-v4.md +811 -0
  8. package/templates/notes/notes-v5.md +579 -0
  9. package/templates/notes/notes-vf+1.md +311 -0
  10. package/templates/notes/notes-vfinal.md +852 -0
  11. package/templates/scaffolds/axios/api/index.ts +40 -0
  12. package/templates/scaffolds/axios/api/one.api.ts +94 -0
  13. package/templates/scaffolds/axios/endpoints.ts +9 -0
  14. package/templates/scaffolds/axios/index.ts +26 -0
  15. package/templates/scaffolds/axios/interceptors.ts +103 -0
  16. package/templates/scaffolds/axios/request.ts +32 -0
  17. package/templates/scaffolds/react-router/hook/useRouterSearch.ts +8 -0
  18. package/templates/scaffolds/react-router/router/guards/private.route.tsx +1 -0
  19. package/templates/scaffolds/react-router/router/index.ts +26 -0
  20. package/templates/scaffolds/react-router/router/layouts/error.layout.tsx +1 -1
  21. package/templates/scaffolds/redux-store/middlewares.ts +0 -0
  22. package/templates/scaffolds/redux-store/reducers.ts +30 -0
  23. package/templates/scaffolds/redux-store/selector/one.selector.ts +43 -0
  24. package/templates/scaffolds/redux-store/selector/two.selector.ts +11 -0
  25. package/templates/scaffolds/redux-store/slices/one.slice.ts +202 -0
  26. package/templates/scaffolds/redux-store/slices/two.slice.ts +21 -0
  27. package/templates/scaffolds/redux-store/store.ts +38 -0
  28. package/templates/scaffolds/rtk-query/baseApi.ts +24 -0
  29. package/templates/scaffolds/rtk-query/baseQuery.ts +12 -0
  30. package/templates/scaffolds/rtk-query/endpoints/api.one.ts +82 -0
  31. package/templates/scaffolds/rtk-query/endpoints/index.ts +1 -0
  32. package/templates/scaffolds/rtk-query/middlewares.ts +11 -0
  33. package/templates/scaffolds/rtk-query/queryTags.ts +13 -0
  34. package/templates/scaffolds/tanstack-query/api-base.ts +68 -68
  35. package/templates/scaffolds/tanstack-query/api-queries.ts +0 -19
  36. package/templates/scaffolds/tanstack-query/client.ts +8 -0
  37. package/templates/scaffolds/tanstack-query/module/index.ts +12 -12
  38. package/templates/scaffolds/tanstack-query/module/keys.ts +17 -17
  39. package/templates/scaffolds/tanstack-query/module/mappers.ts +15 -15
  40. package/templates/scaffolds/tanstack-query/module/mutations.ts +59 -55
  41. package/templates/scaffolds/tanstack-query/module/queries.ts +145 -156
  42. package/templates/scaffolds/tanstack-query/module/services.ts +74 -66
  43. package/templates/scaffolds/tanstack-router/layout/404.layout.tsx +3 -0
  44. package/templates/scaffolds/tanstack-router/layout/app.layout.tsx +10 -0
  45. package/templates/scaffolds/tanstack-router/layout/auth.layout.tsx +10 -0
  46. package/templates/scaffolds/tanstack-router/layout/error.layout.tsx +3 -0
  47. package/templates/scaffolds/tanstack-router/page/auth/login.tsx +3 -0
  48. package/templates/scaffolds/tanstack-router/page/one/index.tsx +3 -0
  49. package/templates/scaffolds/tanstack-router/page/one/one-id.tsx +128 -0
  50. package/templates/scaffolds/tanstack-router/router.ts +90 -0
  51. package/templates/scaffolds/tanstack-router/routes/_404.tsx +0 -0
  52. package/templates/scaffolds/tanstack-router/routes/__root.tsx +9 -0
  53. package/templates/scaffolds/tanstack-router/routes/_app.tsx +6 -0
  54. package/templates/scaffolds/tanstack-router/routes/_auth.tsx +6 -0
  55. package/templates/scaffolds/tanstack-router/routes/_error.tsx +0 -0
  56. package/templates/scaffolds/tanstack-router/routes/auth/login.tsx +6 -0
  57. package/templates/scaffolds/tanstack-router/routes/one/$id.tsx +191 -0
  58. package/templates/scaffolds/tanstack-router/routes/one/index.tsx +6 -0
  59. package/templates/scripts/setup.bat +284 -0
  60. package/templates/scripts/setup.ps1 +318 -0
@@ -1,15 +1,15 @@
1
- /*
2
- # NOTE : you can change *_name_example to your own query name
3
- # NOTE : you can change raw to your own data after manipulation
4
- */
5
-
6
- export const ModuleMappers = {
7
- fetch_query_name_example(raw: any) {
8
- const data = raw || "manipulate your data here and then return it";
9
- return data;
10
- },
11
- fetch_infinite_query_example(raw: any) {
12
- const data = raw || [];
13
- return data;
14
- },
15
- };
1
+ /*
2
+ # NOTE : you can change *_name_example to your own query name
3
+ # NOTE : you can change raw to your own data after manipulation
4
+ */
5
+
6
+ export const ModuleMappers = {
7
+ fetch_query_name_example(raw: any) {
8
+ const data = raw || "manipulate your data here and then return it";
9
+ return data;
10
+ },
11
+ fetch_infinite_query_example(raw: any) {
12
+ const data = raw || [];
13
+ return data;
14
+ },
15
+ };
@@ -1,55 +1,59 @@
1
- import { mutationOptions, type QueryClient } from "@tanstack/react-query";
2
- import { ModuleKeys } from "./keys";
3
- import { ModuleService } from "./services";
4
-
5
- export const ModuleMutations = {
6
- create_query_name_example: (queryClient: QueryClient) =>
7
- mutationOptions({
8
- mutationFn: (newItem: any) =>
9
- ModuleService.post_query_name_example(newItem),
10
- onMutate: async (newItem: any) => {
11
- /*
12
- # OPTIMISTIC UPDATE TECHNIQUE:
13
- 1. Cancel outgoing refetches so they don't overwrite our optimistic update.
14
- 2. Snapshot the current cache value.
15
- 3. Optimistically insert the new item into the cache.
16
- 4. Return context containing the previous value for error rollbacks.
17
- */
18
- await queryClient.cancelQueries({ queryKey: ModuleKeys.fetch_query_name_example() });
19
-
20
- const previousItems = queryClient.getQueryData(ModuleKeys.fetch_query_name_example());
21
-
22
- queryClient.setQueryData(ModuleKeys.fetch_query_name_example(), (old: any) => {
23
- return old ? [...old, newItem] : [newItem];
24
- });
25
-
26
- return { previousItems };
27
- },
28
- onSuccess: async () => {
29
- /*
30
- # NOTE: In case of mutations, invalidate query keys to refresh with fresh server data.
31
- */
32
- await queryClient.invalidateQueries({
33
- queryKey: ModuleKeys.fetch_query_name_example(),
34
- });
35
- },
36
- onError: (error, newItem, context: any) => {
37
- /*
38
- # ROLLBACK ON FAILURE:
39
- If the mutation fails, rollback the cache to our snapshotted state.
40
- */
41
- if (context?.previousItems) {
42
- queryClient.setQueryData(
43
- ModuleKeys.fetch_query_name_example(),
44
- context.previousItems
45
- );
46
- }
47
- },
48
- onSettled: async () => {
49
- // Always refetch after error or success to keep server in sync
50
- await queryClient.invalidateQueries({
51
- queryKey: ModuleKeys.fetch_query_name_example(),
52
- });
53
- },
54
- }),
55
- };
1
+ import { mutationOptions, type QueryClient } from "@tanstack/react-query";
2
+ import { ModuleKeys } from "./keys";
3
+ import { ModuleService } from "./services";
4
+
5
+ export const ModuleMutations = {
6
+ create_query_name_example: (queryClient: QueryClient) =>
7
+ mutationOptions({
8
+ mutationFn: (newItem: any) =>
9
+ ModuleService.post_query_name_example(newItem),
10
+ onMutate: async (newItem: any) => {
11
+ /*
12
+ # OPTIMISTIC UPDATE TECHNIQUE:
13
+ 1. Cancel outgoing refetches so they don't overwrite our optimistic update.
14
+ 2. Snapshot the current cache value.
15
+ 3. Optimistically insert the new item into the cache.
16
+ 4. Return context containing the previous value for error rollbacks.
17
+
18
+ # EDGE CASE:
19
+ setQueryData updates the raw cached query data, not the value returned by a query select mapper.
20
+ Match this optimistic shape to the actual API response shape stored in the cache.
21
+ */
22
+ await queryClient.cancelQueries({ queryKey: ModuleKeys.fetch_query_name_example() });
23
+
24
+ const previousItems = queryClient.getQueryData(ModuleKeys.fetch_query_name_example());
25
+
26
+ queryClient.setQueryData(ModuleKeys.fetch_query_name_example(), (old: any) => {
27
+ return old ? [...old, newItem] : [newItem];
28
+ });
29
+
30
+ return { previousItems };
31
+ },
32
+ onSuccess: async () => {
33
+ /*
34
+ # NOTE: In case of mutations, invalidate query keys to refresh with fresh server data.
35
+ */
36
+ await queryClient.invalidateQueries({
37
+ queryKey: ModuleKeys.fetch_query_name_example(),
38
+ });
39
+ },
40
+ onError: (error, newItem, context: any) => {
41
+ /*
42
+ # ROLLBACK ON FAILURE:
43
+ If the mutation fails, rollback the cache to our snapshotted state.
44
+ */
45
+ if (context?.previousItems) {
46
+ queryClient.setQueryData(
47
+ ModuleKeys.fetch_query_name_example(),
48
+ context.previousItems
49
+ );
50
+ }
51
+ },
52
+ onSettled: async () => {
53
+ // Always refetch after error or success to keep server state authoritative after optimistic changes.
54
+ await queryClient.invalidateQueries({
55
+ queryKey: ModuleKeys.fetch_query_name_example(),
56
+ });
57
+ },
58
+ }),
59
+ };
@@ -1,156 +1,145 @@
1
- import {
2
- queryOptions,
3
- infiniteQueryOptions,
4
- keepPreviousData,
5
- } from "@tanstack/react-query";
6
-
7
- import { ModuleKeys } from "./keys";
8
- import { ModuleMappers } from "./mappers";
9
- import { ModuleService } from "./services";
10
-
11
- export const ModuleQueries = {
12
- fetch_query_name_example: () =>
13
- queryOptions({
14
- queryKey: ModuleKeys.fetch_query_name_example(),
15
- queryFn: () => {
16
- /*
17
- # NOTE: ModuleService.get_query_name_example() -> hits the api of query fetch or GET
18
- Return the Promise directly to TanStack Query so it can natively handle retries and error states.
19
- */
20
- return ModuleService.get_query_name_example();
21
- },
22
- select: raw => {
23
- /*
24
- # NOTE: ModuleMappers.fetch_query_name_example() -> manipulates the data from api into desird format before returning to ui or page
25
- Using the 'select' property memoizes this transformation (only runs when cached data changes).
26
- */
27
- return ModuleMappers.fetch_query_name_example(raw as any);
28
- },
29
- /*
30
- # NOTE: keeps the last successfully fetched data visible on screen
31
- while fetching new data or if a subsequent fetch fails (preventing layout flickers/empty states).
32
- */
33
- placeholderData: keepPreviousData,
34
- }),
35
-
36
- fetch_infinite_query_example: () =>
37
- infiniteQueryOptions({
38
- queryKey: ModuleKeys.fetch_infinite_query_name_example(),
39
- queryFn: ({ pageParam = 1 }) => {
40
- /*
41
- # NOTE: ModuleService.get_infinite_query_example(pageParam) -> hits the api of query fetch or GET
42
- Return the Promise directly to TanStack Query so it can natively handle retries and error states.
43
- */
44
- return ModuleService.get_infinite_query_example(pageParam as number);
45
- },
46
- getNextPageParam: (raw: any) => {
47
- // --- Option A: Cursor-based Pagination ---
48
- // return raw.nextCursor ?? undefined;
49
-
50
- // --- Option B: Page-number Metadata Pagination (last_page, current_page) ---
51
- // Access metadata from the 'meta' object returned in your API response
52
- const { current_page, last_page } = raw?.meta || {};
53
- const hasMore = current_page < last_page;
54
- return hasMore ? current_page + 1 : undefined;
55
- },
56
- initialPageParam: 1,
57
- select: raw => {
58
- /*
59
- # NOTE: ModuleMappers.fetch_infinite_query_example() -> manipulates the data from api into desird format before returning to ui or page
60
- Using the 'select' property memoizes this transformation (only runs when cached data changes).
61
- */
62
- return {
63
- pages: raw.pages.map((pageData: any) => ({
64
- ...pageData,
65
- data: ModuleMappers.fetch_infinite_query_example(pageData.data),
66
- })),
67
- pageParams: raw.pageParams,
68
- };
69
- },
70
- placeholderData: keepPreviousData,
71
- }),
72
-
73
- fetch_query_with_params_example: (params: Record<string, any>) =>
74
- queryOptions({
75
- queryKey: ModuleKeys.fetch_query_with_params_example(params),
76
- queryFn: ({ signal }) => {
77
- /*
78
- # NOTE: Pass the native 'signal' from the TanStack queryFn context down to the service call.
79
- This enables automatic cancellation if query parameters change or the component unmounts.
80
- */
81
- return ModuleService.get_query_with_params_example(params, signal);
82
- },
83
- select: raw => {
84
- // Reusing the same mapper example for consistency
85
- return ModuleMappers.fetch_query_name_example(raw as any);
86
- },
87
- placeholderData: keepPreviousData,
88
- }),
89
-
90
- fetch_query_by_id_example: (id?: string | null) =>
91
- queryOptions({
92
- queryKey: ModuleKeys.fetch_query_by_id_example(id || ""),
93
- queryFn: ({ signal }) => {
94
- return ModuleService.get_query_by_id_example(id!, signal);
95
- },
96
- select: raw => {
97
- return ModuleMappers.fetch_query_name_example(raw as any);
98
- },
99
- placeholderData: keepPreviousData,
100
- /*
101
- # NOTE: Conditional/Dependent Queries
102
- Setting 'enabled: !!id' stops the query from executing automatically if the ID is missing (undefined, null, or empty).
103
- */
104
- enabled: !!id,
105
- }),
106
-
107
- fetch_query_combo_example: (
108
- id: string | null | undefined,
109
- params: Record<string, any>,
110
- ) =>
111
- queryOptions({
112
- queryKey: ModuleKeys.fetch_query_combo_example(id || "", params),
113
- queryFn: ({ signal }) => {
114
- return ModuleService.get_query_combo_example(id!, params, signal);
115
- },
116
- select: raw => {
117
- return ModuleMappers.fetch_query_name_example(raw as any);
118
- },
119
- placeholderData: keepPreviousData,
120
- enabled: !!id, // Automatically stops API call if ID is null/undefined
121
- }),
122
- };
123
-
124
- /*
125
- # NOTE: RAW DATA VS. MAPPED DATA & MEMOIZATION
126
-
127
- 1. **Where Raw Data Lives:**
128
- - The raw response returned by the API (`queryFn`) is stored unmodified inside the **TanStack Query Cache**.
129
- - This represents the exact payload from your backend database/server.
130
-
131
- 2. **Where Mapped Data Lives:**
132
- - The mapped data is delivered directly to the **UI / React Component** consuming the hook.
133
- - It is calculated on-the-fly by executing the `select` function on the cached raw data.
134
-
135
- 3. **How Memoization Works (Performance Optimization):**
136
- - The `select` function is **automatically memoized** by TanStack Query.
137
- - It will ONLY re-run when the cached raw data changes.
138
- - If the component re-renders for other reasons (e.g., local UI states, parent re-renders, or window focus checks), TanStack Query skips the mapper execution completely and returns the already memoized mapped data instantly.
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
- use this inside queries if you want to show error boundary at component level for perticular query when not using useSuspenseQuery or hook which provides suspense by default. by default it just catches the errror and shows the error in useMutation or useQuery hooks but in case of useSuspenseQuery it throws the error and bubbels up to the nearest error boundary.
151
-
152
- throwOnError: (error) => {
153
- // Throw to boundary for severe errors (like 404 Not Found or 500 Server Crashes)
154
- return error.status === 404 || error.status >= 500;
155
- }
156
- */
1
+ import { queryOptions, infiniteQueryOptions, keepPreviousData } from "@tanstack/react-query";
2
+
3
+ import { ModuleKeys } from "./keys";
4
+ import { ModuleMappers } from "./mappers";
5
+ import { ModuleService } from "./services";
6
+
7
+ export const ModuleQueries = {
8
+ fetch_query_name_example: () =>
9
+ queryOptions({
10
+ queryKey: ModuleKeys.fetch_query_name_example(),
11
+ queryFn: () => {
12
+ /*
13
+ # NOTE: ModuleService.get_query_name_example() -> hits the api of query fetch or GET
14
+ Return the Promise directly to TanStack Query so it can natively handle retries and error states.
15
+ */
16
+ return ModuleService.get_query_name_example();
17
+ },
18
+ select: (raw) => {
19
+ /*
20
+ # NOTE: ModuleMappers.fetch_query_name_example() -> manipulates the data from api into desird format before returning to ui or page
21
+ Using the 'select' property memoizes this transformation (only runs when cached data changes).
22
+ */
23
+ return ModuleMappers.fetch_query_name_example(raw as any);
24
+ },
25
+ /*
26
+ # NOTE: keeps the last successfully fetched data visible on screen
27
+ while fetching new data or if a subsequent fetch fails (preventing layout flickers/empty states).
28
+ */
29
+ placeholderData: keepPreviousData,
30
+ }),
31
+
32
+ fetch_infinite_query_example: () =>
33
+ infiniteQueryOptions({
34
+ queryKey: ModuleKeys.fetch_infinite_query_name_example(),
35
+ queryFn: ({ pageParam = 1 }) => {
36
+ /*
37
+ # NOTE: ModuleService.get_infinite_query_example(pageParam) -> hits the api of query fetch or GET
38
+ Return the Promise directly to TanStack Query so it can natively handle retries and error states.
39
+ */
40
+ return ModuleService.get_infinite_query_example(pageParam as number);
41
+ },
42
+ getNextPageParam: (raw: any) => {
43
+ // --- Option A: Cursor-based Pagination ---
44
+ // return raw.nextCursor ?? undefined;
45
+
46
+ // --- Option B: Page-number Metadata Pagination (last_page, current_page) ---
47
+ // Access metadata from the 'meta' object returned in your API response
48
+ const { current_page, last_page } = raw?.meta || {};
49
+ const hasMore = current_page < last_page;
50
+ return hasMore ? current_page + 1 : undefined;
51
+ },
52
+ initialPageParam: 1,
53
+ select: (raw) => {
54
+ /*
55
+ # NOTE: ModuleMappers.fetch_infinite_query_example() -> manipulates the data from api into desird format before returning to ui or page
56
+ Using the 'select' property memoizes this transformation (only runs when cached data changes).
57
+ */
58
+ return {
59
+ pages: raw.pages.map((pageData: any) => ({
60
+ ...pageData,
61
+ data: ModuleMappers.fetch_infinite_query_example(pageData.data),
62
+ })),
63
+ pageParams: raw.pageParams,
64
+ };
65
+ },
66
+ placeholderData: keepPreviousData,
67
+ }),
68
+
69
+ fetch_query_with_params_example: (params: Record<string, any>) =>
70
+ queryOptions({
71
+ /*
72
+ # NOTE: Include every server-facing filter in the query key.
73
+ TanStack Query uses this key to cache separate results and cancel/refetch when filters change.
74
+ */
75
+ queryKey: ModuleKeys.fetch_query_with_params_example(params),
76
+ queryFn: ({ signal }) => {
77
+ /*
78
+ # NOTE: Pass the native 'signal' from the TanStack queryFn context down to the service call.
79
+ This enables automatic cancellation if query parameters change or the component unmounts.
80
+ */
81
+ return ModuleService.get_query_with_params_example(params, signal);
82
+ },
83
+ select: (raw) => {
84
+ // Reusing the same mapper example for consistency
85
+ return ModuleMappers.fetch_query_name_example(raw as any);
86
+ },
87
+ placeholderData: keepPreviousData,
88
+ }),
89
+
90
+ fetch_query_by_id_example: (id?: string | null) =>
91
+ queryOptions({
92
+ /*
93
+ # NOTE: Keep the query key stable even before the ID exists.
94
+ The enabled flag below prevents the request from running with this fallback value.
95
+ */
96
+ queryKey: ModuleKeys.fetch_query_by_id_example(id || ""),
97
+ queryFn: ({ signal }) => {
98
+ return ModuleService.get_query_by_id_example(id!, signal);
99
+ },
100
+ select: (raw) => {
101
+ return ModuleMappers.fetch_query_name_example(raw as any);
102
+ },
103
+ placeholderData: keepPreviousData,
104
+ /*
105
+ # NOTE: Conditional/Dependent Queries
106
+ Setting 'enabled: !!id' stops the query from executing automatically if the ID is missing (undefined, null, or empty).
107
+ */
108
+ enabled: !!id,
109
+ }),
110
+
111
+ fetch_query_combo_example: (id: string | null | undefined, params: Record<string, any>) =>
112
+ queryOptions({
113
+ /*
114
+ # NOTE: Combo keys should include both route identity and filters.
115
+ This prevents cached data for one ID/filter pair from showing under another pair.
116
+ */
117
+ queryKey: ModuleKeys.fetch_query_combo_example(id || "", params),
118
+ queryFn: ({ signal }) => {
119
+ return ModuleService.get_query_combo_example(id!, params, signal);
120
+ },
121
+ select: (raw) => {
122
+ return ModuleMappers.fetch_query_name_example(raw as any);
123
+ },
124
+ placeholderData: keepPreviousData,
125
+ enabled: !!id, // Automatically stops API call if ID is null/undefined
126
+ }),
127
+ };
128
+
129
+ /*
130
+ # NOTE: RAW DATA VS. MAPPED DATA & MEMOIZATION
131
+
132
+ 1. **Where Raw Data Lives:**
133
+ - The raw response returned by the API (`queryFn`) is stored unmodified inside the **TanStack Query Cache**.
134
+ - This represents the exact payload from your backend database/server.
135
+
136
+ 2. **Where Mapped Data Lives:**
137
+ - The mapped data is delivered directly to the **UI / React Component** consuming the hook.
138
+ - It is calculated on-the-fly by executing the `select` function on the cached raw data.
139
+
140
+ 3. **How Memoization Works (Performance Optimization):**
141
+ - The `select` function is **automatically memoized** by TanStack Query.
142
+ - It will ONLY re-run when the cached raw data changes.
143
+ - If the component re-renders for other reasons (e.g., local UI states, parent re-renders, or window focus checks), TanStack Query skips the mapper execution completely and returns the already memoized mapped data instantly.
144
+ */
145
+
@@ -1,66 +1,74 @@
1
- import { apiClient } from "../client";
2
-
3
- export const ModuleService = {
4
- get_query_name_example: () => apiClient.get("/api_name/get"),
5
- get_infinite_query_example: (page: number) =>
6
- apiClient.get(`/api_name/list?page=${page}`),
7
- get_query_with_params_example: (params: Record<string, any>, signal?: AbortSignal) => {
8
- const queryParams = new URLSearchParams();
9
- Object.entries(params).forEach(([key, value]) => {
10
- if (Array.isArray(value)) {
11
- value.forEach((val) => {
12
- if (val !== undefined && val !== null && val !== "") {
13
- queryParams.append(key, String(val));
14
- }
15
- });
16
- } else if (value !== undefined && value !== null && value !== "") {
17
- queryParams.set(key, String(value));
18
- }
19
- });
20
- return apiClient.get(`/api_name/get-with-params?${queryParams.toString()}`, { signal });
21
- },
22
- get_query_by_id_example: (id: string, signal?: AbortSignal) =>
23
- apiClient.get(`/api_name/get-by-id/${id}`, { signal }),
24
- get_query_combo_example: (id: string, params: Record<string, any>, signal?: AbortSignal) => {
25
- const queryParams = new URLSearchParams();
26
- Object.entries(params).forEach(([key, value]) => {
27
- if (Array.isArray(value)) {
28
- value.forEach((val) => {
29
- if (val !== undefined && val !== null && val !== "") {
30
- queryParams.append(key, String(val));
31
- }
32
- });
33
- } else if (value !== undefined && value !== null && value !== "") {
34
- queryParams.set(key, String(value));
35
- }
36
- });
37
- return apiClient.get(`/api_name/get-combo/${id}?${queryParams.toString()}`, { signal });
38
- },
39
- post_query_name_example: (input: any) =>
40
- apiClient.post("/api_name/post", input),
41
- patch_query_name_example: (input: any) =>
42
- apiClient.patch("/api_name/patch", input),
43
- delete_query_name_example: (id: string) =>
44
- apiClient.delete(`/api_name/${id}`),
45
- };
46
-
47
- /*
48
- # NOTE: you can change *_name_example to your own query name
49
- # NOTE: you can change /api_name to your own api name
50
- # NOTE: you can change input to your own data type
51
- # NOTE: you can change id to your own data type
52
-
53
- -------------------------------------------------------------------------
54
-
55
- # NOTE: WHY WE USE URLSearchParams & THE ROLE OF THE SERVICE LAYER
56
-
57
- 1. **Why we use `URLSearchParams`:**
58
- - **Automatic URL-Encoding:** It automatically sanitizes special characters (like spaces, commas, or quotes) into browser-safe formats (e.g., space becomes `%20`), preventing broken URLs.
59
- - **Dynamic Query String Building:** It generates the final string from a raw object dynamically (calling `.toString()` results in `key1=val1&key2=val2`).
60
-
61
- 2. **Role of this Service Layer (`get_query_with_params_example`):**
62
- - **Decoupled Contracts:** It keeps components "dumb" about network specifics. The component only needs to pass a clean JavaScript object containing the filters.
63
- - **Centralization:** If endpoints change or parameter serialization logic needs to adjust in the future, it is managed in this single file rather than modifying multiple UI files.
64
- */
65
-
66
-
1
+ import { apiClient } from "../client";
2
+
3
+ export const ModuleService = {
4
+ get_query_name_example: () => apiClient.get("/api_name/get"),
5
+ get_infinite_query_example: (page: number) =>
6
+ apiClient.get(`/api_name/list?page=${page}`),
7
+ get_query_with_params_example: (params: Record<string, any>, signal?: AbortSignal) => {
8
+ const queryParams = new URLSearchParams();
9
+ Object.entries(params).forEach(([key, value]) => {
10
+ /*
11
+ # NOTE: Arrays become repeated keys, e.g. brands=samsung&brands=apple.
12
+ Empty values are skipped so default UI state does not create noisy URLs.
13
+ */
14
+ if (Array.isArray(value)) {
15
+ value.forEach((val) => {
16
+ if (val !== undefined && val !== null && val !== "") {
17
+ queryParams.append(key, String(val));
18
+ }
19
+ });
20
+ } else if (value !== undefined && value !== null && value !== "") {
21
+ queryParams.set(key, String(value));
22
+ }
23
+ });
24
+ return apiClient.get(`/api_name/get-with-params?${queryParams.toString()}`, { signal });
25
+ },
26
+ get_query_by_id_example: (id: string, signal?: AbortSignal) =>
27
+ apiClient.get(`/api_name/get-by-id/${id}`, { signal }),
28
+ get_query_combo_example: (id: string, params: Record<string, any>, signal?: AbortSignal) => {
29
+ const queryParams = new URLSearchParams();
30
+ Object.entries(params).forEach(([key, value]) => {
31
+ /*
32
+ # NOTE: Reuse the same serialization rules for route-specific filtered requests.
33
+ Keeping this logic centralized avoids components building query strings by hand.
34
+ */
35
+ if (Array.isArray(value)) {
36
+ value.forEach((val) => {
37
+ if (val !== undefined && val !== null && val !== "") {
38
+ queryParams.append(key, String(val));
39
+ }
40
+ });
41
+ } else if (value !== undefined && value !== null && value !== "") {
42
+ queryParams.set(key, String(value));
43
+ }
44
+ });
45
+ return apiClient.get(`/api_name/get-combo/${id}?${queryParams.toString()}`, { signal });
46
+ },
47
+ post_query_name_example: (input: any) =>
48
+ apiClient.post("/api_name/post", input),
49
+ patch_query_name_example: (input: any) =>
50
+ apiClient.patch("/api_name/patch", input),
51
+ delete_query_name_example: (id: string) =>
52
+ apiClient.delete(`/api_name/${id}`),
53
+ };
54
+
55
+ /*
56
+ # NOTE: you can change *_name_example to your own query name
57
+ # NOTE: you can change /api_name to your own api name
58
+ # NOTE: you can change input to your own data type
59
+ # NOTE: you can change id to your own data type
60
+
61
+ -------------------------------------------------------------------------
62
+
63
+ # NOTE: WHY WE USE URLSearchParams & THE ROLE OF THE SERVICE LAYER
64
+
65
+ 1. **Why we use `URLSearchParams`:**
66
+ - **Automatic URL-Encoding:** It automatically sanitizes special characters (like spaces, commas, or quotes) into browser-safe formats (e.g., space becomes `%20`), preventing broken URLs.
67
+ - **Dynamic Query String Building:** It generates the final string from a raw object dynamically (calling `.toString()` results in `key1=val1&key2=val2`).
68
+
69
+ 2. **Role of this Service Layer (`get_query_with_params_example`):**
70
+ - **Decoupled Contracts:** It keeps components "dumb" about network specifics. The component only needs to pass a clean JavaScript object containing the filters.
71
+ - **Centralization:** If endpoints change or parameter serialization logic needs to adjust in the future, it is managed in this single file rather than modifying multiple UI files.
72
+ */
73
+
74
+
@@ -0,0 +1,3 @@
1
+ export default function PageNotFound () {
2
+ return <div>404 layout</div>;
3
+ }
@@ -0,0 +1,10 @@
1
+ import { Outlet } from "@tanstack/react-router";
2
+
3
+ export default function AppLayout() {
4
+ return (
5
+ <>
6
+ <div>App Section Static</div>
7
+ <Outlet />
8
+ </>
9
+ );
10
+ }
@@ -0,0 +1,10 @@
1
+ import { Outlet } from "@tanstack/react-router";
2
+
3
+ export default function AuthLayout() {
4
+ return (
5
+ <>
6
+ <div>Auth Section Static</div>
7
+ <Outlet />
8
+ </>
9
+ );
10
+ }
@@ -0,0 +1,3 @@
1
+ export default function ErrorLayout() {
2
+ return <div>Something went wrong.</div>;
3
+ }
@@ -0,0 +1,3 @@
1
+ export default function Login() {
2
+ return <>This is login page</>;
3
+ }