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.
- package/package.json +1 -1
- package/registry.json +33 -1
- package/templates/notes/create-pejay.md +222 -0
- package/templates/notes/notes-v1.md +516 -0
- package/templates/notes/notes-v2.md +764 -0
- package/templates/notes/notes-v3.md +574 -0
- package/templates/notes/notes-v4.md +811 -0
- package/templates/notes/notes-v5.md +579 -0
- package/templates/notes/notes-vf+1.md +311 -0
- package/templates/notes/notes-vfinal.md +852 -0
- package/templates/scaffolds/axios/api/index.ts +40 -0
- package/templates/scaffolds/axios/api/one.api.ts +94 -0
- package/templates/scaffolds/axios/endpoints.ts +9 -0
- package/templates/scaffolds/axios/index.ts +26 -0
- package/templates/scaffolds/axios/interceptors.ts +103 -0
- package/templates/scaffolds/axios/request.ts +32 -0
- package/templates/scaffolds/react-router/hook/useRouterSearch.ts +8 -0
- package/templates/scaffolds/react-router/router/guards/private.route.tsx +1 -0
- package/templates/scaffolds/react-router/router/index.ts +26 -0
- package/templates/scaffolds/react-router/router/layouts/error.layout.tsx +1 -1
- package/templates/scaffolds/redux-store/middlewares.ts +0 -0
- package/templates/scaffolds/redux-store/reducers.ts +30 -0
- package/templates/scaffolds/redux-store/selector/one.selector.ts +43 -0
- package/templates/scaffolds/redux-store/selector/two.selector.ts +11 -0
- package/templates/scaffolds/redux-store/slices/one.slice.ts +202 -0
- package/templates/scaffolds/redux-store/slices/two.slice.ts +21 -0
- package/templates/scaffolds/redux-store/store.ts +38 -0
- package/templates/scaffolds/rtk-query/baseApi.ts +24 -0
- package/templates/scaffolds/rtk-query/baseQuery.ts +12 -0
- package/templates/scaffolds/rtk-query/endpoints/api.one.ts +82 -0
- package/templates/scaffolds/rtk-query/endpoints/index.ts +1 -0
- package/templates/scaffolds/rtk-query/middlewares.ts +11 -0
- package/templates/scaffolds/rtk-query/queryTags.ts +13 -0
- package/templates/scaffolds/tanstack-query/api-base.ts +68 -68
- package/templates/scaffolds/tanstack-query/api-queries.ts +0 -19
- package/templates/scaffolds/tanstack-query/client.ts +8 -0
- package/templates/scaffolds/tanstack-query/module/index.ts +12 -12
- package/templates/scaffolds/tanstack-query/module/keys.ts +17 -17
- package/templates/scaffolds/tanstack-query/module/mappers.ts +15 -15
- package/templates/scaffolds/tanstack-query/module/mutations.ts +59 -55
- package/templates/scaffolds/tanstack-query/module/queries.ts +145 -156
- package/templates/scaffolds/tanstack-query/module/services.ts +74 -66
- package/templates/scaffolds/tanstack-router/layout/404.layout.tsx +3 -0
- package/templates/scaffolds/tanstack-router/layout/app.layout.tsx +10 -0
- package/templates/scaffolds/tanstack-router/layout/auth.layout.tsx +10 -0
- package/templates/scaffolds/tanstack-router/layout/error.layout.tsx +3 -0
- package/templates/scaffolds/tanstack-router/page/auth/login.tsx +3 -0
- package/templates/scaffolds/tanstack-router/page/one/index.tsx +3 -0
- package/templates/scaffolds/tanstack-router/page/one/one-id.tsx +128 -0
- package/templates/scaffolds/tanstack-router/router.ts +90 -0
- package/templates/scaffolds/tanstack-router/routes/_404.tsx +0 -0
- package/templates/scaffolds/tanstack-router/routes/__root.tsx +9 -0
- package/templates/scaffolds/tanstack-router/routes/_app.tsx +6 -0
- package/templates/scaffolds/tanstack-router/routes/_auth.tsx +6 -0
- package/templates/scaffolds/tanstack-router/routes/_error.tsx +0 -0
- package/templates/scaffolds/tanstack-router/routes/auth/login.tsx +6 -0
- package/templates/scaffolds/tanstack-router/routes/one/$id.tsx +191 -0
- package/templates/scaffolds/tanstack-router/routes/one/index.tsx +6 -0
- package/templates/scripts/setup.bat +284 -0
- 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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
queryClient.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
} from "
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
-
|
|
138
|
-
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
+
|