pejay-ui 1.2.2 → 1.3.1

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 (61) hide show
  1. package/README.md +17 -2
  2. package/package.json +2 -2
  3. package/registry.json +33 -1
  4. package/templates/notes/create-pejay.md +222 -0
  5. package/templates/notes/notes-v1.md +516 -0
  6. package/templates/notes/notes-v2.md +764 -0
  7. package/templates/notes/notes-v3.md +574 -0
  8. package/templates/notes/notes-v4.md +811 -0
  9. package/templates/notes/notes-v5.md +579 -0
  10. package/templates/notes/notes-vf+1.md +311 -0
  11. package/templates/notes/notes-vfinal.md +852 -0
  12. package/templates/scaffolds/axios/api/index.ts +40 -0
  13. package/templates/scaffolds/axios/api/one.api.ts +94 -0
  14. package/templates/scaffolds/axios/endpoints.ts +9 -0
  15. package/templates/scaffolds/axios/index.ts +26 -0
  16. package/templates/scaffolds/axios/interceptors.ts +103 -0
  17. package/templates/scaffolds/axios/request.ts +32 -0
  18. package/templates/scaffolds/react-router/hook/useRouterSearch.ts +8 -0
  19. package/templates/scaffolds/react-router/router/guards/private.route.tsx +1 -0
  20. package/templates/scaffolds/react-router/router/index.ts +26 -0
  21. package/templates/scaffolds/react-router/router/layouts/error.layout.tsx +1 -1
  22. package/templates/scaffolds/redux-store/middlewares.ts +0 -0
  23. package/templates/scaffolds/redux-store/reducers.ts +30 -0
  24. package/templates/scaffolds/redux-store/selector/one.selector.ts +43 -0
  25. package/templates/scaffolds/redux-store/selector/two.selector.ts +11 -0
  26. package/templates/scaffolds/redux-store/slices/one.slice.ts +202 -0
  27. package/templates/scaffolds/redux-store/slices/two.slice.ts +21 -0
  28. package/templates/scaffolds/redux-store/store.ts +38 -0
  29. package/templates/scaffolds/rtk-query/baseApi.ts +24 -0
  30. package/templates/scaffolds/rtk-query/baseQuery.ts +12 -0
  31. package/templates/scaffolds/rtk-query/endpoints/api.one.ts +82 -0
  32. package/templates/scaffolds/rtk-query/endpoints/index.ts +1 -0
  33. package/templates/scaffolds/rtk-query/middlewares.ts +11 -0
  34. package/templates/scaffolds/rtk-query/queryTags.ts +13 -0
  35. package/templates/scaffolds/tanstack-query/api-base.ts +68 -68
  36. package/templates/scaffolds/tanstack-query/api-queries.ts +0 -19
  37. package/templates/scaffolds/tanstack-query/client.ts +8 -0
  38. package/templates/scaffolds/tanstack-query/module/index.ts +12 -12
  39. package/templates/scaffolds/tanstack-query/module/keys.ts +17 -17
  40. package/templates/scaffolds/tanstack-query/module/mappers.ts +15 -15
  41. package/templates/scaffolds/tanstack-query/module/mutations.ts +59 -55
  42. package/templates/scaffolds/tanstack-query/module/queries.ts +145 -156
  43. package/templates/scaffolds/tanstack-query/module/services.ts +74 -66
  44. package/templates/scaffolds/tanstack-router/layout/404.layout.tsx +3 -0
  45. package/templates/scaffolds/tanstack-router/layout/app.layout.tsx +10 -0
  46. package/templates/scaffolds/tanstack-router/layout/auth.layout.tsx +10 -0
  47. package/templates/scaffolds/tanstack-router/layout/error.layout.tsx +3 -0
  48. package/templates/scaffolds/tanstack-router/page/auth/login.tsx +3 -0
  49. package/templates/scaffolds/tanstack-router/page/one/index.tsx +3 -0
  50. package/templates/scaffolds/tanstack-router/page/one/one-id.tsx +128 -0
  51. package/templates/scaffolds/tanstack-router/router.ts +90 -0
  52. package/templates/scaffolds/tanstack-router/routes/_404.tsx +0 -0
  53. package/templates/scaffolds/tanstack-router/routes/__root.tsx +9 -0
  54. package/templates/scaffolds/tanstack-router/routes/_app.tsx +6 -0
  55. package/templates/scaffolds/tanstack-router/routes/_auth.tsx +6 -0
  56. package/templates/scaffolds/tanstack-router/routes/_error.tsx +0 -0
  57. package/templates/scaffolds/tanstack-router/routes/auth/login.tsx +6 -0
  58. package/templates/scaffolds/tanstack-router/routes/one/$id.tsx +191 -0
  59. package/templates/scaffolds/tanstack-router/routes/one/index.tsx +6 -0
  60. package/templates/scripts/setup.bat +284 -0
  61. package/templates/scripts/setup.ps1 +318 -0
@@ -0,0 +1,202 @@
1
+ import { createSlice } from "@reduxjs/toolkit";
2
+
3
+ const initialState = {
4
+ /*
5
+ status: "idle" | "loading" | "error" | "success",
6
+ */
7
+ oneData: "",
8
+ error: "",
9
+ status: "idle",
10
+ isLoading: false,
11
+ isError: false,
12
+ meta: {
13
+ requiresAuth: true,
14
+ },
15
+ };
16
+
17
+ /*
18
+
19
+ import { createAsyncThunk } from "@reduxjs/toolkit";
20
+
21
+ # NOTE : it can also have asyncThunks to handle async logic like api calls
22
+
23
+ export const oneAsync = createAsyncThunk(
24
+ "one/oneAsync",
25
+ async (_ ,{rejectWithValue,signal}) => {
26
+ try {
27
+ const response = await axios.get("backend_api_route",{signal});
28
+ return response.data;
29
+ } catch (error:any) {
30
+ return rejectWithValue(error.response.data);
31
+ }
32
+ }
33
+ );
34
+
35
+ ----------------------------------------------------------------
36
+ (method 1)
37
+ # NOTE : and use it
38
+
39
+ const dispatch = useAppDispatch();
40
+
41
+ const [isLoading, setIsLoading] = useState(false);
42
+ const handleClick = async () => {
43
+ try {
44
+ setIsLoading(true);
45
+ const data = await dispatch(oneAsync()).unwrap();
46
+ console.log(data);
47
+ } catch (error) {
48
+ console.log(error);
49
+ }finally{
50
+ setIsLoading(false);
51
+ dispatch(setStatus("idle"));
52
+
53
+ }
54
+ };
55
+
56
+
57
+
58
+ ----------------------------------------------------------------
59
+ (method 2)
60
+ # NOTE : other way to call it by using the slice state variable to store data in that and call from there
61
+
62
+ in this case we call it via useSelector to get the data
63
+
64
+ useEffect(() => {
65
+ dispatch(oneAsync());
66
+ }, [dispatch]);
67
+
68
+
69
+ -----------------------------------------------------------------
70
+ # NOTE :
71
+
72
+ const {status,isloading,isError} = useOne();
73
+
74
+ useEffect(() => {
75
+ if(status === "idle"){
76
+ dispatch(oneAsync());
77
+ }
78
+ }, [dispatch]);
79
+
80
+ in this either i manlually make status idel again to dispatch
81
+
82
+ or
83
+
84
+ useEffect(() => {
85
+ dispatch(fetchUsers(page));
86
+ }, [page, dispatch]);
87
+
88
+ use page for some kind of trigger that keep preventing from unwanted api calls
89
+
90
+ only a page reload or setting the status manually to idle will make the api call again
91
+
92
+ # NOTE : this above can be also done in (method 1) of calling by removing useState or we can make useState for api loading/error/status etc but that is messy and cannot be handel outside comp or doing it inside hook is also not good as each hook call is treated as new instance so best way is to either make inital states and handel via reducers custom ones or use extra reducers which is the best way to handel this. only one thing we can do is spread our manipulation data across 3/4 different steps
93
+ 1. inside fullfill extra reducer (for heavy manipulation)
94
+ 2. inside selector (memoised data can do some manipulation )
95
+ 3. inside hook (optional or for component specifics extraction or manipulation)
96
+ 4. inside component (optional for specific element or ui level requirement)
97
+
98
+ there is another way of data flow
99
+
100
+ 1. call api , do heavy manipulation in fullfilled state, store data in state
101
+ 2. call data in hook (for comp based manipulation further can use useMemo here to avoid unwanted processing of same data)
102
+ 3. call in component (if required do further manipulation )
103
+
104
+ useMemo only preserve manipulated data to save manipulation from rerendering of the component itself not unmount / mount of comp
105
+
106
+ in mounting useMemo / hook will lose instances and cached data is destroyed
107
+
108
+ When createSelector is useful
109
+ When you want to keep raw data in Redux.
110
+ */
111
+
112
+ const oneSlice = createSlice({
113
+ name: "one",
114
+ initialState,
115
+
116
+ // Manually handling async logic via reducers
117
+ reducers: {
118
+ setOne: (state, action) => {
119
+ state.oneData = action.payload;
120
+ },
121
+ setStatus: (state, action) => {
122
+ state.status = action.payload;
123
+ },
124
+ setError: (state, action) => {
125
+ state.isError = true;
126
+ state.error = action.payload;
127
+ state.status = "error";
128
+ },
129
+ setIsLoading: (state, action) => {
130
+ state.isLoading = action.payload;
131
+ state.status = "pending";
132
+ state.isError = false;
133
+ state.error = "";
134
+ },
135
+
136
+ /*
137
+
138
+ there is 2 ways to make a async call in redux
139
+
140
+ 1. Manually handling async logic via reducers
141
+ 2. Using extraReducers
142
+
143
+ usually we use extra reducers because is easy what more we can use is use status state for preventing unwnted api calls
144
+
145
+
146
+
147
+ # NOTE : extraReducers are used to handle async logic like api calls
148
+ extrareducers : {
149
+ builder
150
+ .addCase(oneAsync.pending, (state) => {
151
+ state.isLoading = true;
152
+ })
153
+ .addCase(oneAsync.fulfilled, (state, action) => {
154
+ state.isLoading = false;
155
+ const processedData = action.payload;
156
+ // here manipulates data accordingly and handover to selector.
157
+ state.oneData = processedData;
158
+ state.status = "idle";
159
+ })
160
+ .addCase(oneAsync.rejected, (state, action) => {
161
+ state.isLoading = false;
162
+ state.isError = true;
163
+ state.error = action.payload;
164
+ state.status = "error";
165
+ })
166
+ }
167
+
168
+ */
169
+ },
170
+ });
171
+
172
+ export const { setOne } = oneSlice.actions;
173
+ export default oneSlice.reducer;
174
+
175
+ /*
176
+
177
+ a slice has state, reducers, and actions.
178
+ a state => data
179
+ a reducers => logic on how data changes / basically data manipulation
180
+ a actions => dispatchers to change the data
181
+
182
+ ------------------------------------------------------------
183
+ # NOTE : to dispatch an action
184
+
185
+ import { useDispatch } from "react-redux";
186
+ import { setOne } from "../slices/one.slice";
187
+ const dispatch = useDispatch();
188
+ dispatch(setOne("hello"));
189
+
190
+ its basically calling the function defined in reducers with the data
191
+
192
+ ------------------------------------------------------------
193
+ # NOTE : to call a state to get the data in comp we
194
+
195
+ import { useSelector } from "react-redux";
196
+ import { type RootState } from "../index";
197
+ const one = useSelector((state: RootState) => state.one.oneData);
198
+
199
+ this is basically accessing the value from the store.
200
+
201
+
202
+ */
@@ -0,0 +1,21 @@
1
+ import { createSlice } from "@reduxjs/toolkit";
2
+
3
+ const initialState = {
4
+ twoData: "",
5
+ meta: {
6
+ requiresAuth: true,
7
+ },
8
+ };
9
+
10
+ const twoSlice = createSlice({
11
+ name: "two",
12
+ initialState,
13
+ reducers: {
14
+ setTwo: (state, action) => {
15
+ state.twoData = action.payload;
16
+ },
17
+ },
18
+ });
19
+
20
+ export const { setTwo } = twoSlice.actions;
21
+ export default twoSlice.reducer;
@@ -0,0 +1,38 @@
1
+ import { configureStore } from "@reduxjs/toolkit";
2
+ import {
3
+ persistStore,
4
+ FLUSH,
5
+ REHYDRATE,
6
+ PAUSE,
7
+ PERSIST,
8
+ PURGE,
9
+ REGISTER,
10
+ } from "redux-persist";
11
+ import rootReducer from "./reducers";
12
+
13
+ export const store = configureStore({
14
+ reducer: rootReducer,
15
+ middleware: (getDefaultMiddleware) =>
16
+ getDefaultMiddleware({
17
+ serializableCheck: {
18
+ ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
19
+ },
20
+ }) /* .concat(middleware_name) */,
21
+ });
22
+ export const persistor = persistStore(store);
23
+ export type RootState = ReturnType<typeof store.getState>;
24
+ export type AppDispatch = typeof store.dispatch;
25
+ export default store;
26
+
27
+ /*
28
+
29
+ Example usage:
30
+
31
+ import { Provider } from "react-redux";
32
+ import { store } from "./store";
33
+ <Provider store={store}>
34
+ <App />
35
+ </Provider>
36
+
37
+
38
+ */
@@ -0,0 +1,24 @@
1
+ import { createApi } from "@reduxjs/toolkit/query/react";
2
+ import { baseQuery } from "./baseQuery";
3
+ import { queryTags } from "./queryTags";
4
+ export const baseApi = createApi({
5
+ reducerPath: "baseApi",
6
+ baseQuery: baseQuery,
7
+ tagTypes: queryTags,
8
+ /*
9
+ keepUnusedDataFor: Infinity //data will never be garbage collected
10
+ refetchOnReconnect: true, //refetch on network reconnect
11
+ refetchOnMountOrArgChange: false, //refetch on mount or when args change
12
+ refetchOnFocus: false, //refetch on focus to tab
13
+ */
14
+ endpoints: () => ({}),
15
+ });
16
+
17
+ /*
18
+
19
+ * in reducers.ts of redux store
20
+ const apiReducers = {
21
+ [baseApi.reducerPath]: baseApi.reducer,
22
+ };
23
+
24
+ */
@@ -0,0 +1,12 @@
1
+ import { fetchBaseQuery } from "@reduxjs/toolkit/query";
2
+
3
+ export const baseQuery = fetchBaseQuery({
4
+ baseUrl: "http://localhost:5001",
5
+ prepareHeaders: (headers) => {
6
+ const token = localStorage.getItem("token");
7
+ if (token) {
8
+ headers.set("Authorization", `Bearer ${token}`);
9
+ }
10
+ return headers;
11
+ },
12
+ });
@@ -0,0 +1,82 @@
1
+ import { baseApi } from "../baseApi";
2
+ import { invalidateTagIdOnSuccess } from "../queryTags";
3
+
4
+ export const apiOne = baseApi.injectEndpoints({
5
+ endpoints: (builder) => ({
6
+ // very basic fetch function
7
+ fetchData: builder.query({
8
+ query: () => "/data",
9
+ providesTags: [],
10
+ }),
11
+ // with params method 1
12
+ fetchData2: builder.query({
13
+ query: ({ id }) => `/data/${id}`,
14
+ providesTags: (_result, error, { id }) =>
15
+ error ? [] : [{ type: "Data", id }],
16
+ }),
17
+ // with params method 2
18
+ fetchData3: builder.query({
19
+ query: ({ id, name }) => ({
20
+ url: `/data`,
21
+ method: "GET",
22
+ params: { id, name },
23
+ }),
24
+ // manipulate response before it is sent to the component
25
+ transformResponse: (response) => {
26
+ /* manipulate here */
27
+ return response.data;
28
+ },
29
+ providesTags: [],
30
+ }),
31
+
32
+ /* =================================== */
33
+
34
+ postData: builder.mutation({
35
+ query: (body) => ({
36
+ url: "/data",
37
+ method: "POST",
38
+ body,
39
+ }),
40
+ invalidatesTags: invalidateTagIdOnSuccess("Data"),
41
+ }),
42
+ }),
43
+ });
44
+
45
+ export const {
46
+ useFetchDataQuery,
47
+ useFetchData2Query,
48
+ useFetchData3Query,
49
+ usePostDataMutation,
50
+ } = apiOne;
51
+
52
+ /*
53
+
54
+ ? Query Calls
55
+
56
+ *call in components
57
+ const { data, isLoading, isFetching, isError, error } = useFetchDataQuery();
58
+
59
+ *refetch every 5 seconds
60
+ const { data } = useFetchDataQuery({},{
61
+ pollingInterval: 5000,
62
+ });
63
+
64
+ *get specific data from array of objects
65
+ const { user } = useFetchDataQuery({},{
66
+ selectFromResult: ({ data }) => ({
67
+ user: data?.find((u) => u.id === 2),
68
+ }),
69
+ });
70
+
71
+
72
+ // ==================================== //
73
+
74
+ ? MUTATIONS
75
+
76
+ * call in components
77
+ const [postData] = usePostDataMutation();
78
+ await postData({ name: "John",});
79
+
80
+
81
+
82
+ */
@@ -0,0 +1 @@
1
+ export * from "./api.one";
@@ -0,0 +1,11 @@
1
+ import { baseApi } from "./baseApi";
2
+
3
+ export const apiMiddleware = [baseApi.middleware];
4
+
5
+ /*
6
+
7
+ *in store.ts
8
+ middleware: (getDefaultMiddleware) =>
9
+ getDefaultMiddleware().concat(...apiMiddleware)
10
+
11
+ */
@@ -0,0 +1,13 @@
1
+ export const queryTags = ["Data"] as const;
2
+
3
+ type TagType = (typeof queryTags)[number];
4
+
5
+ /** Invalidate tag ids only when the mutation succeeds (skip on error). */
6
+ export function invalidateTagIdOnSuccess(...types: TagType[]) {
7
+ return (
8
+ _result: unknown,
9
+ error: unknown,
10
+ arg: { id: string | number },
11
+ ) =>
12
+ error ? [] : types.map((type) => ({ type, id: arg.id }));
13
+ }
@@ -1,68 +1,68 @@
1
- /*
2
- #ANCHOR : TYPE:1 VITE PROJECT
3
- const BASE_URL = import.meta.env.VITE_API_URL;
4
-
5
- Environment variables must start with VITE_ to be exposed to client-side code in Vite.
6
-
7
- ---------------------------------------------------------
8
-
9
- #ANCHOR : TYPE:2 NEXT.JS / NON-VITE PROJECTS
10
- const BASE_URL = process.env.NEXT_PUBLIC_API_URL;
11
-
12
- Environment variables must start with NEXT_PUBLIC_ to be available in Next.js browser code.
13
-
14
- ---------------------------------------------------------
15
- #ANCHOR
16
- Vite doesn't automatically provide Node's process.env in browser code.
17
-
18
- | Framework | Access Method | Public Prefix |
19
- | --------------- | ------------------- | ---------------- |
20
- | Next.js | `process.env.X` | `NEXT_PUBLIC_` |
21
- | Vite | `import.meta.env.X` | `VITE_` |
22
- | Node.js Backend | `process.env.X` | No prefix needed |
23
-
24
- */
25
-
26
- export const API_CONFIG = {
27
- // NOTE: Change this BASE_URL to match your actual API endpoint
28
- baseUrl: "http://localhost:5000/api",
29
- timeout: 10000,
30
- headers: {
31
- "Accept": "application/json",
32
- "Content-Type": "application/json",
33
- },
34
- } as const;
35
-
36
- export const QUERY_CLIENT_CONFIG = {
37
- defaultOptions: {
38
- queries: {
39
- // # NOTE: Global TanStack Query configurations
40
- retry: 3, // Automatically retries failed requests 3 times on failure
41
- refetchOnWindowFocus: false, // Refetches stale active queries when the browser tab gets focused
42
- staleTime: 1000 * 60 * 5, // Data is considered fresh for 5 minutes (prevents duplicate requests)
43
- },
44
- },
45
- } as const;
46
-
47
- /*
48
- # NOTE: HOW AND WHERE TO USE QUERY_CLIENT_CONFIG
49
-
50
- This configuration is imported and passed when initializing the QueryClient at the root of your application (e.g., in App.tsx, main.tsx, or layout.tsx):
51
-
52
- ```typescript
53
- import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
54
- import { QUERY_CLIENT_CONFIG } from "./api-base";
55
-
56
- const queryClient = new QueryClient(QUERY_CLIENT_CONFIG);
57
-
58
- export default function Providers({ children }) {
59
- return (
60
- <QueryClientProvider client={queryClient}>
61
- {children}
62
- </QueryClientProvider>
63
- );
64
- }
65
- ```
66
- */
67
-
68
-
1
+ /*
2
+ #ANCHOR : TYPE:1 VITE PROJECT
3
+ const BASE_URL = import.meta.env.VITE_API_URL;
4
+
5
+ Environment variables must start with VITE_ to be exposed to client-side code in Vite.
6
+
7
+ ---------------------------------------------------------
8
+
9
+ #ANCHOR : TYPE:2 NEXT.JS / NON-VITE PROJECTS
10
+ const BASE_URL = process.env.NEXT_PUBLIC_API_URL;
11
+
12
+ Environment variables must start with NEXT_PUBLIC_ to be available in Next.js browser code.
13
+
14
+ ---------------------------------------------------------
15
+ #ANCHOR
16
+ Vite doesn't automatically provide Node's process.env in browser code.
17
+
18
+ | Framework | Access Method | Public Prefix |
19
+ | --------------- | ------------------- | ---------------- |
20
+ | Next.js | `process.env.X` | `NEXT_PUBLIC_` |
21
+ | Vite | `import.meta.env.X` | `VITE_` |
22
+ | Node.js Backend | `process.env.X` | No prefix needed |
23
+
24
+ */
25
+
26
+ export const API_CONFIG = {
27
+ // NOTE: Change this BASE_URL to match your actual API endpoint
28
+ baseUrl: "http://localhost:5000/api",
29
+ timeout: 10000,
30
+ headers: {
31
+ "Accept": "application/json",
32
+ "Content-Type": "application/json",
33
+ },
34
+ } as const;
35
+
36
+ export const QUERY_CLIENT_CONFIG = {
37
+ defaultOptions: {
38
+ queries: {
39
+ // # NOTE: Global TanStack Query configurations
40
+ retry: 3, // Automatically retries failed requests 3 times on failure
41
+ refetchOnWindowFocus: false, // Refetches stale active queries when the browser tab gets focused
42
+ staleTime: 1000 * 60 * 5, // Data is considered fresh for 5 minutes (prevents duplicate requests)
43
+ },
44
+ },
45
+ } as const;
46
+
47
+ /*
48
+ # NOTE: HOW AND WHERE TO USE QUERY_CLIENT_CONFIG
49
+
50
+ This configuration is imported and passed when initializing the QueryClient at the root of your application (e.g., in App.tsx, main.tsx, or layout.tsx):
51
+
52
+ ```typescript
53
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
54
+ import { QUERY_CLIENT_CONFIG } from "./api-base";
55
+
56
+ const queryClient = new QueryClient(QUERY_CLIENT_CONFIG);
57
+
58
+ export default function Providers({ children }) {
59
+ return (
60
+ <QueryClientProvider client={queryClient}>
61
+ {children}
62
+ </QueryClientProvider>
63
+ );
64
+ }
65
+ ```
66
+ */
67
+
68
+
@@ -58,28 +58,9 @@ return <ModuleComponent data={data} />;
58
58
  }
59
59
 
60
60
  # NOTE : Wrapping
61
- <ErrorBoundary fallback={<div>Failed to load Stats</div>}>
62
61
  <Suspense fallback={<FallBackComponent />}>
63
62
  <ModuleComponent />
64
63
  </Suspense>
65
- </ErrorBoundary>
66
-
67
- this is comp level error boundary in case of api fails then suspense bubbeling up will touch this first and stops
68
- in case this is not present then the router level
69
- so in this way we can only show a particaular comp failed to load not entore page
70
-
71
-
72
-
73
-
74
-
75
- Manually (Option A - useQuery):
76
-
77
- Code: if (error) return <ErrorComponent />
78
- Behavior: Bypasses Error Boundaries. Component-level and router-level boundaries never trigger.
79
- Automatically (Option B - useSuspenseQuery or useQuery with throwOnError: true):
80
-
81
- Code: Component throws the error during render.
82
- Behavior: The error bubbles up. It triggers the nearest Error Boundary (either your component-level boundary if you wrapped it, or falls back to the router-level boundary).
83
64
 
84
65
  ---------------------------------------------------------------------------------------------------
85
66
 
@@ -9,6 +9,10 @@ export async function apiRequest<T>(
9
9
  // const token = typeof window !== "undefined" ? localStorage.getItem("token") : null;
10
10
  const token = null;
11
11
 
12
+ /*
13
+ # NOTE: RequestInit options are spread first so each call can pass signal, method, body, or headers.
14
+ The final headers spread lets a specific request override defaults when an endpoint needs it.
15
+ */
12
16
  const response = await fetch(`${API_CONFIG.baseUrl}${endpoint}`, {
13
17
  ...options,
14
18
  headers: {
@@ -18,6 +22,10 @@ export async function apiRequest<T>(
18
22
  },
19
23
  });
20
24
 
25
+ /*
26
+ # NOTE: This template assumes every successful response returns JSON.
27
+ If your API uses 204 No Content or empty delete responses, guard response.status before calling json().
28
+ */
21
29
  if (!response.ok) throw new Error(`Error Code ${response.status}`);
22
30
  return (await response.json()) as T;
23
31
  }
@@ -1,12 +1,12 @@
1
- export { ModuleKeys } from "./keys";
2
- export { ModuleMappers } from "./mappers";
3
- export { ModuleService } from "./services";
4
- export { ModuleQueries } from "./queries";
5
- export { ModuleMutations } from "./mutations";
6
-
7
- /*
8
- # NOTE: here we can export types.ts as well if we defining types seperately in a file
9
- export type * from "./types";
10
- # NOTE : we can also export a mocks.ts file if we using mocks which contains dummy / fall back data
11
- export { ModuleMocks } from "./mocks";
12
- */
1
+ export { ModuleKeys } from "./keys";
2
+ export { ModuleMappers } from "./mappers";
3
+ export { ModuleService } from "./services";
4
+ export { ModuleQueries } from "./queries";
5
+ export { ModuleMutations } from "./mutations";
6
+
7
+ /*
8
+ # NOTE: here we can export types.ts as well if we defining types seperately in a file
9
+ export type * from "./types";
10
+ # NOTE : we can also export a mocks.ts file if we using mocks which contains dummy / fall back data
11
+ export { ModuleMocks } from "./mocks";
12
+ */
@@ -1,17 +1,17 @@
1
- export const ModuleKeys = {
2
- module: () => ["moduleName"] as const,
3
- fetch_query_name_example: () => [...ModuleKeys.module(), "fetch"] as const,
4
- create_query_name_example: () => [...ModuleKeys.module(), "create"] as const,
5
- update_query_name_example: () => [...ModuleKeys.module(), "update"] as const,
6
- delete_query_name_example: () => [...ModuleKeys.module(), "delete"] as const,
7
- fetch_infinite_query_name_example: () => [...ModuleKeys.module(), "fetch-infinite"] as const,
8
- fetch_query_with_params_example: (params: any) => [...ModuleKeys.module(), "fetch-with-params", params] as const,
9
- fetch_query_by_id_example: (id: string) => [...ModuleKeys.module(), "fetch-by-id", id] as const,
10
- fetch_query_combo_example: (id: string, params: any) => [...ModuleKeys.module(), "fetch-combo", id, params] as const,
11
- };
12
-
13
- /*
14
- # NOTE: as const is used at end so that keys are immutable
15
- # NOTE : ans insted of standard object keys usd as function so its easy and clean to use and maintain in larger scale
16
- # NOTE : you can change *_name_example to your own query name
17
- */
1
+ export const ModuleKeys = {
2
+ module: () => ["moduleName"] as const,
3
+ fetch_query_name_example: () => [...ModuleKeys.module(), "fetch"] as const,
4
+ create_query_name_example: () => [...ModuleKeys.module(), "create"] as const,
5
+ update_query_name_example: () => [...ModuleKeys.module(), "update"] as const,
6
+ delete_query_name_example: () => [...ModuleKeys.module(), "delete"] as const,
7
+ fetch_infinite_query_name_example: () => [...ModuleKeys.module(), "fetch-infinite"] as const,
8
+ fetch_query_with_params_example: (params: any) => [...ModuleKeys.module(), "fetch-with-params", params] as const,
9
+ fetch_query_by_id_example: (id: string) => [...ModuleKeys.module(), "fetch-by-id", id] as const,
10
+ fetch_query_combo_example: (id: string, params: any) => [...ModuleKeys.module(), "fetch-combo", id, params] as const,
11
+ };
12
+
13
+ /*
14
+ # NOTE: as const is used at end so that keys are immutable
15
+ # NOTE : ans insted of standard object keys usd as function so its easy and clean to use and maintain in larger scale
16
+ # NOTE : you can change *_name_example to your own query name
17
+ */