@void-snippets/react 0.2.2 → 0.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/README.md +106 -92
- package/dist/index.d.mts +177 -43
- package/dist/index.d.ts +177 -43
- package/dist/index.js +182 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +176 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
2
|
-
import {
|
|
2
|
+
import { VSAdapters, VSQueryParams, VSPagination, VSListResult } from '@void-snippets/core';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
3
4
|
|
|
4
|
-
type CapitalizeStr<S extends string> = S extends `${infer F}${infer Rest}` ? `${Uppercase<F>}${Rest}` : S;
|
|
5
5
|
interface WithResourceTypes {
|
|
6
6
|
readonly __types: {
|
|
7
7
|
id: unknown;
|
|
@@ -20,21 +20,23 @@ type Create<S extends WithResourceTypes> = S["__types"]["create"];
|
|
|
20
20
|
type Update<S extends WithResourceTypes> = S["__types"]["update"];
|
|
21
21
|
type ListRaw<S extends WithResourceTypes> = S["__types"]["listRaw"];
|
|
22
22
|
type SingleRaw<S extends WithResourceTypes> = S["__types"]["singleRaw"];
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
23
|
+
interface VSUseListReturn<TBase> {
|
|
24
|
+
list: TBase[];
|
|
25
|
+
pagination: VSPagination;
|
|
26
|
+
isLoading: boolean;
|
|
27
|
+
error: Error | null;
|
|
28
|
+
invalidate: () => void;
|
|
29
|
+
}
|
|
30
|
+
interface VSUseGetReturn<TDetail> {
|
|
31
|
+
item: TDetail | undefined;
|
|
32
|
+
isLoading: boolean;
|
|
33
|
+
error: Error | null;
|
|
34
|
+
refetch: () => void;
|
|
35
|
+
}
|
|
36
|
+
interface VSResourceHooksOptions<TListRaw, TBase, TSingleRaw, TDetail> {
|
|
35
37
|
/**
|
|
36
|
-
* Adapters map your API's raw response
|
|
37
|
-
*
|
|
38
|
+
* Adapters map your API's raw response to the library's internal format.
|
|
39
|
+
* Omit if your API matches the default shape:
|
|
38
40
|
* List: { data: { items, page, limit, totalPages, totalDocuments } }
|
|
39
41
|
* Single: { data: <item> }
|
|
40
42
|
*
|
|
@@ -54,54 +56,186 @@ interface CreateResourceHooksOptions<TListRaw, TBase, TSingleRaw, TDetail> {
|
|
|
54
56
|
* },
|
|
55
57
|
* })
|
|
56
58
|
*/
|
|
57
|
-
adapters?:
|
|
59
|
+
adapters?: VSAdapters<TListRaw, TBase, TSingleRaw, TDetail>;
|
|
58
60
|
/**
|
|
59
61
|
* Default params passed to useList and useInfinite when none are provided.
|
|
60
62
|
* @default { page: 1, limit: 10 }
|
|
61
63
|
*/
|
|
62
|
-
defaultParams?:
|
|
64
|
+
defaultParams?: VSQueryParams;
|
|
63
65
|
}
|
|
64
66
|
/**
|
|
65
67
|
* Creates a set of TanStack Query hooks for a resource.
|
|
66
|
-
* All types are fully inferred from the `apiService` instance — no generics
|
|
67
|
-
* need to be passed manually.
|
|
68
|
+
* All types are fully inferred from the `apiService` instance — no generics needed.
|
|
68
69
|
*
|
|
69
|
-
* @param queryKeyPrefix - TanStack Query cache key
|
|
70
|
-
* for
|
|
71
|
-
* e.g. "contacts" → { contacts, isContactsLoading, ... }
|
|
70
|
+
* @param queryKeyPrefix - TanStack Query cache key. Used to scope the cache
|
|
71
|
+
* and for auto-invalidation. e.g. "contacts"
|
|
72
72
|
* @param apiService - An instance of ResourceService (or a subclass).
|
|
73
73
|
* @param options - Optional adapters and default params.
|
|
74
74
|
*
|
|
75
75
|
* @example
|
|
76
|
-
* // contacts.hooks.ts
|
|
77
|
-
* import { createResourceHooks } from '@void-snippets/react';
|
|
78
|
-
* import { ContactsApis } from './contacts.api';
|
|
79
|
-
*
|
|
80
|
-
* // No generics needed — all types are inferred from ContactsApis
|
|
81
76
|
* export const contactHooks = createResourceHooks('contacts', ContactsApis);
|
|
82
77
|
*
|
|
83
|
-
* //
|
|
84
|
-
* const {
|
|
85
|
-
*
|
|
86
|
-
*
|
|
78
|
+
* // useList — generic fixed shape
|
|
79
|
+
* const { list, isLoading, pagination, error, invalidate } = contactHooks.useList();
|
|
80
|
+
* // list is typed as Contact.Base[] ✅
|
|
81
|
+
*
|
|
82
|
+
* // useGet
|
|
83
|
+
* const { item, isLoading, error, refetch } = contactHooks.useGet(id);
|
|
84
|
+
* // item is typed as Contact.WithCreatedBy ✅
|
|
85
|
+
*
|
|
86
|
+
* // useMutations
|
|
87
|
+
* const { create, update, remove } = contactHooks.useMutations();
|
|
87
88
|
*/
|
|
88
|
-
declare function createResourceHooks<K extends string, S extends WithResourceTypes>(queryKeyPrefix: K, apiService: S, options?:
|
|
89
|
-
useList: (params?:
|
|
90
|
-
useGet: (id: Id<S>, staleTime?: number) =>
|
|
91
|
-
data: _tanstack_react_query.NoInfer<Detail<S>> | undefined;
|
|
92
|
-
isLoading: boolean;
|
|
93
|
-
error: Error | null;
|
|
94
|
-
refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<_tanstack_react_query.NoInfer<Detail<S>>, Error>>;
|
|
95
|
-
};
|
|
89
|
+
declare function createResourceHooks<K extends string, S extends WithResourceTypes>(queryKeyPrefix: K, apiService: S, options?: VSResourceHooksOptions<ListRaw<S>, Base<S>, SingleRaw<S>, Detail<S>>): {
|
|
90
|
+
useList: (params?: VSQueryParams) => VSUseListReturn<Base<S>>;
|
|
91
|
+
useGet: (id: Id<S>, staleTime?: number) => VSUseGetReturn<Detail<S>>;
|
|
96
92
|
useMutations: () => {
|
|
97
93
|
create: _tanstack_react_query.UseMutationResult<Detail<S>, Error, Create<S>, unknown>;
|
|
98
94
|
update: _tanstack_react_query.UseMutationResult<Detail<S>, Error, {
|
|
99
95
|
_id: Id<S>;
|
|
100
96
|
payload: Update<S>;
|
|
101
97
|
}, unknown>;
|
|
102
|
-
|
|
98
|
+
remove: _tanstack_react_query.UseMutationResult<Detail<S>, Error, Id<S>, unknown>;
|
|
103
99
|
};
|
|
104
|
-
useInfinite: (params?:
|
|
100
|
+
useInfinite: (params?: VSQueryParams) => _tanstack_react_query.UseInfiniteQueryResult<_tanstack_react_query.InfiniteData<VSListResult<Base<S>>, unknown>, Error>;
|
|
105
101
|
};
|
|
106
102
|
|
|
107
|
-
|
|
103
|
+
type VSAlertVariant = "success" | "info" | "error";
|
|
104
|
+
interface VSAlertState {
|
|
105
|
+
message: ReactNode | string;
|
|
106
|
+
type: VSAlertVariant;
|
|
107
|
+
isVisible: boolean;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Manages alert/toast message state with optional auto-hide.
|
|
111
|
+
*
|
|
112
|
+
* @param autoHideDuration - ms before alert hides automatically. Pass 0 to disable. Default: 3000
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* const { alert, showAlert, hideAlert } = useAlertMessage();
|
|
116
|
+
* showAlert('Saved successfully!', 'success');
|
|
117
|
+
* showAlert(<b>Something went wrong</b>, 'error');
|
|
118
|
+
*/
|
|
119
|
+
declare function useAlertMessage(autoHideDuration?: number): {
|
|
120
|
+
alert: VSAlertState;
|
|
121
|
+
showAlert: (message: ReactNode | string, type?: VSAlertVariant) => void;
|
|
122
|
+
hideAlert: () => void;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
type VSAsyncStatus = "idle" | "pending" | "success" | "error";
|
|
126
|
+
interface VSAsyncState<T> {
|
|
127
|
+
data: T | null;
|
|
128
|
+
status: VSAsyncStatus;
|
|
129
|
+
error: Error | null;
|
|
130
|
+
}
|
|
131
|
+
interface VSUseAsyncStateReturn<T> extends VSAsyncState<T> {
|
|
132
|
+
isLoading: boolean;
|
|
133
|
+
isSuccess: boolean;
|
|
134
|
+
isError: boolean;
|
|
135
|
+
setData: (data: T | null) => void;
|
|
136
|
+
setError: (error: Error | null) => void;
|
|
137
|
+
reset: () => void;
|
|
138
|
+
/**
|
|
139
|
+
* Executes an async function, updates state, and returns a [err, data] tuple.
|
|
140
|
+
* Allows immediate result handling without try/catch.
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* const [err, data] = await execute(() => ContactsApis.create(payload));
|
|
144
|
+
* if (err) return showAlert(err.message, 'error');
|
|
145
|
+
* showAlert('Created!', 'success');
|
|
146
|
+
*/
|
|
147
|
+
execute: (asyncFn: () => Promise<T>, options?: {
|
|
148
|
+
onSuccess?: (data: T) => void;
|
|
149
|
+
onError?: (error: Error) => void;
|
|
150
|
+
}) => Promise<[Error, null] | [null, T]>;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Generic async state machine — tracks data, status, and error for any async operation.
|
|
154
|
+
* Pair with any async function: API calls, file reads, timers, etc.
|
|
155
|
+
*
|
|
156
|
+
* @param initialData - Optional initial data value. Default: null
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* const { data, isLoading, isError, execute } = useAsyncState<User>();
|
|
160
|
+
*
|
|
161
|
+
* const handleSubmit = async () => {
|
|
162
|
+
* const [err, user] = await execute(() => fetchUser(id));
|
|
163
|
+
* if (err) return;
|
|
164
|
+
* console.log(user.name);
|
|
165
|
+
* };
|
|
166
|
+
*/
|
|
167
|
+
declare function useAsyncState<T>(initialData?: T | null): VSUseAsyncStateReturn<T>;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Tracks elapsed time from a given start timestamp — useful for call durations,
|
|
171
|
+
* countdowns, or any elapsed-time display.
|
|
172
|
+
*
|
|
173
|
+
* @param startedAt - Unix timestamp in ms (e.g. Date.now()). Pass null/undefined to reset.
|
|
174
|
+
* @returns Formatted duration string "MM:SS"
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* const duration = useCallTimer(call.startedAt);
|
|
178
|
+
* // duration → "02:45"
|
|
179
|
+
*
|
|
180
|
+
* // Reset when no active call
|
|
181
|
+
* const duration = useCallTimer(activeCall ? activeCall.startedAt : null);
|
|
182
|
+
*/
|
|
183
|
+
declare function useCallTimer(startedAt?: number | null): string;
|
|
184
|
+
|
|
185
|
+
interface VSModalReturn<T> {
|
|
186
|
+
isOpen: boolean;
|
|
187
|
+
data: T | null;
|
|
188
|
+
isLoading: boolean;
|
|
189
|
+
openCreateModal: () => void;
|
|
190
|
+
openEditModal: (editData: T) => void;
|
|
191
|
+
setLoading: (loading: boolean) => void;
|
|
192
|
+
closeModal: () => void;
|
|
193
|
+
setModal: (open: boolean, editData?: T | null) => void;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Manages modal open/close state with optional data payload and loading state.
|
|
197
|
+
* Works for both create and edit modals — pass data to distinguish the mode.
|
|
198
|
+
*
|
|
199
|
+
* @typeParam T - The type of data the modal operates on (e.g. a Contact, User, etc.)
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* const modal = useModal<Contact.Base>();
|
|
203
|
+
*
|
|
204
|
+
* modal.openCreateModal(); // data → null (create mode)
|
|
205
|
+
* modal.openEditModal(contact); // data → contact (edit mode)
|
|
206
|
+
*
|
|
207
|
+
* if (modal.data) {
|
|
208
|
+
* // Edit mode — modal.data is Contact.Base
|
|
209
|
+
* } else {
|
|
210
|
+
* // Create mode
|
|
211
|
+
* }
|
|
212
|
+
*/
|
|
213
|
+
declare function useModal<T = unknown>(): VSModalReturn<T>;
|
|
214
|
+
|
|
215
|
+
interface VSPaginationReturn {
|
|
216
|
+
page: number;
|
|
217
|
+
limit: number;
|
|
218
|
+
onPaginationChange: (newPage: number, newLimit: number) => void;
|
|
219
|
+
resetPagination: () => void;
|
|
220
|
+
setPage: (page: number) => void;
|
|
221
|
+
setLimit: (limit: number) => void;
|
|
222
|
+
/** Ready-to-use query params object — pass directly to useList() */
|
|
223
|
+
queryParams: VSQueryParams;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Manages pagination state and produces a ready-to-use queryParams object
|
|
227
|
+
* compatible with createResourceHooks' useList() and useInfinite().
|
|
228
|
+
*
|
|
229
|
+
* @param initialPage - Starting page. Default: 1
|
|
230
|
+
* @param initialLimit - Items per page. Default: 10
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* const { queryParams, onPaginationChange } = usePagination(1, 20);
|
|
234
|
+
*
|
|
235
|
+
* const { list, isLoading } = contactHooks.useList(queryParams);
|
|
236
|
+
*
|
|
237
|
+
* <Pagination onChange={onPaginationChange} total={pagination.totalDocuments} />
|
|
238
|
+
*/
|
|
239
|
+
declare function usePagination(initialPage?: number, initialLimit?: number): VSPaginationReturn;
|
|
240
|
+
|
|
241
|
+
export { type VSAlertState, type VSAlertVariant, type VSAsyncStatus, type VSModalReturn, type VSPaginationReturn, type VSResourceHooksOptions, type VSUseAsyncStateReturn, type VSUseGetReturn, type VSUseListReturn, createResourceHooks, useAlertMessage, useAsyncState, useCallTimer, useModal, usePagination };
|
package/dist/index.js
CHANGED
|
@@ -20,7 +20,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
createResourceHooks: () => createResourceHooks
|
|
23
|
+
createResourceHooks: () => createResourceHooks,
|
|
24
|
+
useAlertMessage: () => useAlertMessage,
|
|
25
|
+
useAsyncState: () => useAsyncState,
|
|
26
|
+
useCallTimer: () => useCallTimer,
|
|
27
|
+
useModal: () => useModal,
|
|
28
|
+
usePagination: () => usePagination
|
|
24
29
|
});
|
|
25
30
|
module.exports = __toCommonJS(index_exports);
|
|
26
31
|
|
|
@@ -37,40 +42,35 @@ function createResourceHooks(queryKeyPrefix, apiService, options = {}) {
|
|
|
37
42
|
adapters = (0, import_core.createDefaultAdapters)(),
|
|
38
43
|
defaultParams = DEFAULT_PAGINATION
|
|
39
44
|
} = options;
|
|
40
|
-
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
41
|
-
const capPrefix = capitalize(queryKeyPrefix);
|
|
42
45
|
return {
|
|
43
46
|
// -------------------------------------------------------------------------
|
|
44
|
-
// useList —
|
|
47
|
+
// useList — fixed generic shape: { list, isLoading, pagination, error, invalidate }
|
|
45
48
|
// -------------------------------------------------------------------------
|
|
46
49
|
useList: (params = defaultParams) => {
|
|
47
50
|
var _a, _b, _c, _d, _e;
|
|
48
51
|
const queryClient = (0, import_react_query.useQueryClient)();
|
|
49
|
-
const queryKey = [queryKeyPrefix, params];
|
|
50
52
|
const query = (0, import_react_query.useQuery)({
|
|
51
|
-
queryKey,
|
|
53
|
+
queryKey: [queryKeyPrefix, params],
|
|
52
54
|
queryFn: async () => {
|
|
53
55
|
const raw = await service.list(params);
|
|
54
56
|
return adapters.fromList(raw);
|
|
55
57
|
}
|
|
56
58
|
});
|
|
57
|
-
const items = (_b = (_a = query.data) == null ? void 0 : _a.items) != null ? _b : [];
|
|
58
|
-
const pagination = (_e = (_c = query.data) == null ? void 0 : _c.pagination) != null ? _e : {
|
|
59
|
-
page: 1,
|
|
60
|
-
limit: (_d = defaultParams.limit) != null ? _d : 10,
|
|
61
|
-
totalPages: 0,
|
|
62
|
-
totalDocuments: 0
|
|
63
|
-
};
|
|
64
59
|
return {
|
|
65
|
-
|
|
66
|
-
pagination
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
list: (_b = (_a = query.data) == null ? void 0 : _a.items) != null ? _b : [],
|
|
61
|
+
pagination: (_e = (_c = query.data) == null ? void 0 : _c.pagination) != null ? _e : {
|
|
62
|
+
page: 1,
|
|
63
|
+
limit: (_d = defaultParams.limit) != null ? _d : 10,
|
|
64
|
+
totalPages: 0,
|
|
65
|
+
totalDocuments: 0
|
|
66
|
+
},
|
|
67
|
+
isLoading: query.isLoading || query.isFetching,
|
|
68
|
+
error: query.error,
|
|
69
|
+
invalidate: () => queryClient.invalidateQueries({ queryKey: [queryKeyPrefix] })
|
|
70
70
|
};
|
|
71
71
|
},
|
|
72
72
|
// -------------------------------------------------------------------------
|
|
73
|
-
// useGet —
|
|
73
|
+
// useGet — { item, isLoading, error, refetch }
|
|
74
74
|
// -------------------------------------------------------------------------
|
|
75
75
|
useGet: (id, staleTime = 3e4) => {
|
|
76
76
|
const query = (0, import_react_query.useQuery)({
|
|
@@ -83,14 +83,14 @@ function createResourceHooks(queryKeyPrefix, apiService, options = {}) {
|
|
|
83
83
|
staleTime
|
|
84
84
|
});
|
|
85
85
|
return {
|
|
86
|
-
|
|
86
|
+
item: query.data,
|
|
87
87
|
isLoading: query.isLoading || query.isFetching,
|
|
88
88
|
error: query.error,
|
|
89
89
|
refetch: query.refetch
|
|
90
90
|
};
|
|
91
91
|
},
|
|
92
92
|
// -------------------------------------------------------------------------
|
|
93
|
-
// useMutations — create / update / delete
|
|
93
|
+
// useMutations — create / update / remove (not delete — reserved keyword)
|
|
94
94
|
// -------------------------------------------------------------------------
|
|
95
95
|
useMutations: () => {
|
|
96
96
|
const queryClient = (0, import_react_query.useQueryClient)();
|
|
@@ -109,7 +109,7 @@ function createResourceHooks(queryKeyPrefix, apiService, options = {}) {
|
|
|
109
109
|
},
|
|
110
110
|
onSuccess: invalidate
|
|
111
111
|
});
|
|
112
|
-
const
|
|
112
|
+
const removeMutation = (0, import_react_query.useMutation)({
|
|
113
113
|
mutationFn: async (_id) => {
|
|
114
114
|
const raw = await service.delete(_id);
|
|
115
115
|
return adapters.fromSingle(raw);
|
|
@@ -119,7 +119,7 @@ function createResourceHooks(queryKeyPrefix, apiService, options = {}) {
|
|
|
119
119
|
return {
|
|
120
120
|
create: createMutation,
|
|
121
121
|
update: updateMutation,
|
|
122
|
-
|
|
122
|
+
remove: removeMutation
|
|
123
123
|
};
|
|
124
124
|
},
|
|
125
125
|
// -------------------------------------------------------------------------
|
|
@@ -146,8 +146,166 @@ function createResourceHooks(queryKeyPrefix, apiService, options = {}) {
|
|
|
146
146
|
}
|
|
147
147
|
};
|
|
148
148
|
}
|
|
149
|
+
|
|
150
|
+
// src/hooks/useAlertMessage.ts
|
|
151
|
+
var import_react = require("react");
|
|
152
|
+
function useAlertMessage(autoHideDuration = 3e3) {
|
|
153
|
+
const [alert, setAlert] = (0, import_react.useState)({
|
|
154
|
+
message: null,
|
|
155
|
+
type: "info",
|
|
156
|
+
isVisible: false
|
|
157
|
+
});
|
|
158
|
+
const showAlert = (0, import_react.useCallback)(
|
|
159
|
+
(message, type = "info") => {
|
|
160
|
+
setAlert({ message, type, isVisible: true });
|
|
161
|
+
if (autoHideDuration) {
|
|
162
|
+
setTimeout(() => {
|
|
163
|
+
setAlert((prev) => ({ ...prev, isVisible: false }));
|
|
164
|
+
}, autoHideDuration);
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
[autoHideDuration]
|
|
168
|
+
);
|
|
169
|
+
const hideAlert = (0, import_react.useCallback)(() => {
|
|
170
|
+
setAlert((prev) => ({ ...prev, isVisible: false }));
|
|
171
|
+
}, []);
|
|
172
|
+
return { alert, showAlert, hideAlert };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/hooks/useAsyncState.ts
|
|
176
|
+
var import_react2 = require("react");
|
|
177
|
+
var import_core2 = require("@void-snippets/core");
|
|
178
|
+
function useAsyncState(initialData = null) {
|
|
179
|
+
const [state, setState] = (0, import_react2.useState)({
|
|
180
|
+
data: initialData,
|
|
181
|
+
status: "idle",
|
|
182
|
+
error: null
|
|
183
|
+
});
|
|
184
|
+
const setData = (0, import_react2.useCallback)((data) => {
|
|
185
|
+
setState({ data, status: "success", error: null });
|
|
186
|
+
}, []);
|
|
187
|
+
const setError = (0, import_react2.useCallback)((error) => {
|
|
188
|
+
setState((prev) => ({ ...prev, error, status: "error" }));
|
|
189
|
+
}, []);
|
|
190
|
+
const reset = (0, import_react2.useCallback)(() => {
|
|
191
|
+
setState({ data: initialData, status: "idle", error: null });
|
|
192
|
+
}, [initialData]);
|
|
193
|
+
const execute = (0, import_react2.useCallback)(
|
|
194
|
+
async (asyncFn, options) => {
|
|
195
|
+
var _a, _b;
|
|
196
|
+
setState((prev) => ({ ...prev, status: "pending", error: null }));
|
|
197
|
+
const [err, res] = await (0, import_core2.catchError)(asyncFn());
|
|
198
|
+
if (err) {
|
|
199
|
+
setState((prev) => ({ ...prev, status: "error", error: err }));
|
|
200
|
+
(_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, err);
|
|
201
|
+
return [err, null];
|
|
202
|
+
}
|
|
203
|
+
setState({ data: res, status: "success", error: null });
|
|
204
|
+
(_b = options == null ? void 0 : options.onSuccess) == null ? void 0 : _b.call(options, res);
|
|
205
|
+
return [null, res];
|
|
206
|
+
},
|
|
207
|
+
[]
|
|
208
|
+
);
|
|
209
|
+
const flags = (0, import_react2.useMemo)(
|
|
210
|
+
() => ({
|
|
211
|
+
isLoading: state.status === "pending",
|
|
212
|
+
isSuccess: state.status === "success",
|
|
213
|
+
isError: state.status === "error"
|
|
214
|
+
}),
|
|
215
|
+
[state.status]
|
|
216
|
+
);
|
|
217
|
+
return { ...state, ...flags, setData, setError, reset, execute };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// src/hooks/useCallTimer.ts
|
|
221
|
+
var import_react3 = require("react");
|
|
222
|
+
function useCallTimer(startedAt) {
|
|
223
|
+
const [duration, setDuration] = (0, import_react3.useState)("00:00");
|
|
224
|
+
(0, import_react3.useEffect)(() => {
|
|
225
|
+
if (!startedAt) {
|
|
226
|
+
setDuration("00:00");
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const interval = setInterval(() => {
|
|
230
|
+
const diffInSeconds = Math.floor((Date.now() - startedAt) / 1e3);
|
|
231
|
+
const minutes = Math.floor(diffInSeconds / 60).toString().padStart(2, "0");
|
|
232
|
+
const seconds = (diffInSeconds % 60).toString().padStart(2, "0");
|
|
233
|
+
setDuration(`${minutes}:${seconds}`);
|
|
234
|
+
}, 1e3);
|
|
235
|
+
return () => clearInterval(interval);
|
|
236
|
+
}, [startedAt]);
|
|
237
|
+
return duration;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// src/hooks/useModal.ts
|
|
241
|
+
var import_react4 = require("react");
|
|
242
|
+
function useModal() {
|
|
243
|
+
const [isOpen, setIsOpen] = (0, import_react4.useState)(false);
|
|
244
|
+
const [data, setData] = (0, import_react4.useState)(null);
|
|
245
|
+
const [isLoading, setIsLoading] = (0, import_react4.useState)(false);
|
|
246
|
+
const openCreateModal = (0, import_react4.useCallback)(() => {
|
|
247
|
+
setIsOpen(true);
|
|
248
|
+
setData(null);
|
|
249
|
+
}, []);
|
|
250
|
+
const openEditModal = (0, import_react4.useCallback)((editData) => {
|
|
251
|
+
setIsOpen(true);
|
|
252
|
+
setData(editData);
|
|
253
|
+
}, []);
|
|
254
|
+
const setLoading = (0, import_react4.useCallback)((loading) => {
|
|
255
|
+
setIsLoading(loading);
|
|
256
|
+
}, []);
|
|
257
|
+
const closeModal = (0, import_react4.useCallback)(() => {
|
|
258
|
+
setIsOpen(false);
|
|
259
|
+
setData(null);
|
|
260
|
+
}, []);
|
|
261
|
+
const setModal = (0, import_react4.useCallback)((open, editData) => {
|
|
262
|
+
setIsOpen(open);
|
|
263
|
+
setData(editData != null ? editData : null);
|
|
264
|
+
}, []);
|
|
265
|
+
return {
|
|
266
|
+
isOpen,
|
|
267
|
+
data,
|
|
268
|
+
isLoading,
|
|
269
|
+
openCreateModal,
|
|
270
|
+
openEditModal,
|
|
271
|
+
setLoading,
|
|
272
|
+
closeModal,
|
|
273
|
+
setModal
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// src/hooks/usePagination.ts
|
|
278
|
+
var import_react5 = require("react");
|
|
279
|
+
function usePagination(initialPage = 1, initialLimit = 10) {
|
|
280
|
+
const [page, setPage] = (0, import_react5.useState)(initialPage);
|
|
281
|
+
const [limit, setLimit] = (0, import_react5.useState)(initialLimit);
|
|
282
|
+
const onPaginationChange = (0, import_react5.useCallback)(
|
|
283
|
+
(newPage, newLimit) => {
|
|
284
|
+
setPage(newPage);
|
|
285
|
+
setLimit(newLimit);
|
|
286
|
+
},
|
|
287
|
+
[]
|
|
288
|
+
);
|
|
289
|
+
const resetPagination = (0, import_react5.useCallback)(() => {
|
|
290
|
+
setPage(1);
|
|
291
|
+
}, []);
|
|
292
|
+
return {
|
|
293
|
+
page,
|
|
294
|
+
limit,
|
|
295
|
+
onPaginationChange,
|
|
296
|
+
resetPagination,
|
|
297
|
+
setPage,
|
|
298
|
+
setLimit,
|
|
299
|
+
queryParams: { page, limit }
|
|
300
|
+
};
|
|
301
|
+
}
|
|
149
302
|
// Annotate the CommonJS export names for ESM import in node:
|
|
150
303
|
0 && (module.exports = {
|
|
151
|
-
createResourceHooks
|
|
304
|
+
createResourceHooks,
|
|
305
|
+
useAlertMessage,
|
|
306
|
+
useAsyncState,
|
|
307
|
+
useCallTimer,
|
|
308
|
+
useModal,
|
|
309
|
+
usePagination
|
|
152
310
|
});
|
|
153
311
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/hooks/createResourceHooks.ts"],"sourcesContent":["export { createResourceHooks } from \"./hooks/createResourceHooks\";\nexport type {\n UseListReturn,\n CreateResourceHooksOptions,\n} from \"./hooks/createResourceHooks\";\n","import {\n useInfiniteQuery,\n useMutation,\n useQuery,\n useQueryClient,\n} from \"@tanstack/react-query\";\nimport type { ResourceService } from \"@void-snippets/client\";\nimport type {\n ResourceAdapters,\n ResourceListResult,\n TPagination,\n TQueryParams,\n TDefaultPaginatedResponse,\n TDefaultSingleResponse,\n} from \"@void-snippets/core\";\nimport { createDefaultAdapters } from \"@void-snippets/core\";\n\n// ============================================================================\n// TYPE HELPERS\n// ============================================================================\n\ntype CapitalizeStr<S extends string> = S extends `${infer F}${infer Rest}`\n ? `${Uppercase<F>}${Rest}`\n : S;\n\nconst DEFAULT_PAGINATION: TQueryParams = {\n page: 1,\n limit: 10,\n};\n\n// ============================================================================\n// PHANTOM TYPE CONSTRAINT\n//\n// We constrain S only on the __types phantom property (which is readonly,\n// i.e. covariant) so that ResourceService<string, ...> is assignable to\n// WithResourceTypes. This avoids the variance issue that arises when\n// constraining against method parameter types (contravariant positions).\n//\n// Inside the function we cast apiService once to a fully-typed ResourceService\n// using the phantom generics — this is safe because S IS a ResourceService.\n// ============================================================================\n\ninterface WithResourceTypes {\n readonly __types: {\n id: unknown;\n base: unknown;\n detail: unknown;\n create: unknown;\n update: unknown;\n listRaw: unknown;\n singleRaw: unknown;\n };\n}\n\n// Aliases for reading phantom types from S — keeps the function body readable\ntype Id<S extends WithResourceTypes> = S[\"__types\"][\"id\"];\ntype Base<S extends WithResourceTypes> = S[\"__types\"][\"base\"];\ntype Detail<S extends WithResourceTypes> = S[\"__types\"][\"detail\"];\ntype Create<S extends WithResourceTypes> = S[\"__types\"][\"create\"];\ntype Update<S extends WithResourceTypes> = S[\"__types\"][\"update\"];\ntype ListRaw<S extends WithResourceTypes> = S[\"__types\"][\"listRaw\"];\ntype SingleRaw<S extends WithResourceTypes> = S[\"__types\"][\"singleRaw\"];\n\n// ============================================================================\n// RETURN TYPE — useList\n// Dynamically named keys based on the queryKeyPrefix (e.g. \"contacts\"):\n// { contacts: TBase[], isContactsLoading: boolean, contactsError: Error | null, invalidateContacts: () => void }\n// ============================================================================\n\nexport type UseListReturn<K extends string, TBase> = {\n [P in K]: TBase[];\n} & {\n pagination: TPagination;\n} & {\n [P in `is${CapitalizeStr<K>}Loading`]: boolean;\n} & {\n [P in `${K}Error`]: Error | null;\n} & {\n [P in `invalidate${CapitalizeStr<K>}`]: () => void;\n};\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport interface CreateResourceHooksOptions<\n TListRaw,\n TBase,\n TSingleRaw,\n TDetail,\n> {\n /**\n * Adapters map your API's raw response shapes to the library's internal\n * format. Omit this entirely if your API matches the default shape:\n * List: { data: { items, page, limit, totalPages, totalDocuments } }\n * Single: { data: <item> }\n *\n * @example\n * createResourceHooks(\"contacts\", ContactsApis, {\n * adapters: {\n * fromList: (raw) => ({\n * items: raw.results,\n * pagination: {\n * page: raw.meta.page,\n * limit: raw.meta.perPage,\n * totalPages: raw.meta.lastPage,\n * totalDocuments: raw.meta.total,\n * },\n * }),\n * fromSingle: (raw) => raw.payload,\n * },\n * })\n */\n adapters?: ResourceAdapters<TListRaw, TBase, TSingleRaw, TDetail>;\n\n /**\n * Default params passed to useList and useInfinite when none are provided.\n * @default { page: 1, limit: 10 }\n */\n defaultParams?: TQueryParams;\n}\n\n// ============================================================================\n// FACTORY\n// ============================================================================\n\n/**\n * Creates a set of TanStack Query hooks for a resource.\n * All types are fully inferred from the `apiService` instance — no generics\n * need to be passed manually.\n *\n * @param queryKeyPrefix - TanStack Query cache key prefix and the base name\n * for the returned hook properties.\n * e.g. \"contacts\" → { contacts, isContactsLoading, ... }\n * @param apiService - An instance of ResourceService (or a subclass).\n * @param options - Optional adapters and default params.\n *\n * @example\n * // contacts.hooks.ts\n * import { createResourceHooks } from '@void-snippets/react';\n * import { ContactsApis } from './contacts.api';\n *\n * // No generics needed — all types are inferred from ContactsApis\n * export const contactHooks = createResourceHooks('contacts', ContactsApis);\n *\n * // In a component:\n * const { contacts, isContactsLoading } = contactHooks.useList();\n * const { data } = contactHooks.useGet(id); // data: Contact.WithCreatedBy\n * const { create, update, delete: remove } = contactHooks.useMutations();\n */\nexport function createResourceHooks<\n K extends string,\n S extends WithResourceTypes,\n>(\n queryKeyPrefix: K,\n apiService: S,\n options: CreateResourceHooksOptions<\n ListRaw<S>,\n Base<S>,\n SingleRaw<S>,\n Detail<S>\n > = {},\n) {\n // One safe cast: S is guaranteed to be a ResourceService subclass because\n // __types is only present on ResourceService. Casting here lets us call\n // the service methods with the correct types extracted from the phantom.\n const service = apiService as unknown as ResourceService<\n Id<S>,\n Base<S>,\n Detail<S>,\n Create<S>,\n Update<S>,\n ListRaw<S>,\n SingleRaw<S>\n >;\n\n const {\n adapters = createDefaultAdapters<Base<S>, Detail<S>>() as ResourceAdapters<\n TDefaultPaginatedResponse<Base<S>>,\n Base<S>,\n TDefaultSingleResponse<Detail<S>>,\n Detail<S>\n > as ResourceAdapters<ListRaw<S>, Base<S>, SingleRaw<S>, Detail<S>>,\n defaultParams = DEFAULT_PAGINATION,\n } = options;\n\n const capitalize = (str: string) =>\n str.charAt(0).toUpperCase() + str.slice(1);\n const capPrefix = capitalize(queryKeyPrefix);\n\n return {\n // -------------------------------------------------------------------------\n // useList — paginated list with invalidation helper\n // -------------------------------------------------------------------------\n useList: (\n params: TQueryParams = defaultParams,\n ): UseListReturn<K, Base<S>> => {\n const queryClient = useQueryClient();\n const queryKey = [queryKeyPrefix, params];\n\n const query = useQuery<ResourceListResult<Base<S>>, Error>({\n queryKey,\n queryFn: async () => {\n const raw = await service.list(params);\n return adapters.fromList(raw as ListRaw<S>);\n },\n });\n\n const items = query.data?.items ?? [];\n const pagination: TPagination = query.data?.pagination ?? {\n page: 1,\n limit: defaultParams.limit ?? 10,\n totalPages: 0,\n totalDocuments: 0,\n };\n\n return {\n [queryKeyPrefix]: items,\n pagination,\n [`is${capPrefix}Loading`]: query.isLoading || query.isFetching,\n [`${queryKeyPrefix}Error`]: query.error,\n [`invalidate${capPrefix}`]: () =>\n queryClient.invalidateQueries({ queryKey: [queryKeyPrefix] }),\n } as UseListReturn<K, Base<S>>;\n },\n\n // -------------------------------------------------------------------------\n // useGet — single item by id\n // -------------------------------------------------------------------------\n useGet: (id: Id<S>, staleTime = 30_000) => {\n const query = useQuery<Detail<S>, Error>({\n queryKey: [queryKeyPrefix, id],\n queryFn: async () => {\n const raw = await service.get(id);\n return adapters.fromSingle(raw as SingleRaw<S>);\n },\n enabled: id !== undefined && id !== null && id !== \"\",\n staleTime,\n });\n\n return {\n data: query.data,\n isLoading: query.isLoading || query.isFetching,\n error: query.error,\n refetch: query.refetch,\n };\n },\n\n // -------------------------------------------------------------------------\n // useMutations — create / update / delete with auto-invalidation\n // -------------------------------------------------------------------------\n useMutations: () => {\n const queryClient = useQueryClient();\n const invalidate = () =>\n queryClient.invalidateQueries({ queryKey: [queryKeyPrefix] });\n\n const createMutation = useMutation<Detail<S>, Error, Create<S>>({\n mutationFn: async (payload) => {\n const raw = await service.create(payload);\n return adapters.fromSingle(raw as SingleRaw<S>);\n },\n onSuccess: invalidate,\n });\n\n const updateMutation = useMutation<\n Detail<S>,\n Error,\n { _id: Id<S>; payload: Update<S> }\n >({\n mutationFn: async ({ _id, payload }) => {\n const raw = await service.update(_id, payload);\n return adapters.fromSingle(raw as SingleRaw<S>);\n },\n onSuccess: invalidate,\n });\n\n const deleteMutation = useMutation<Detail<S>, Error, Id<S>>({\n mutationFn: async (_id) => {\n const raw = await service.delete(_id);\n return adapters.fromSingle(raw as SingleRaw<S>);\n },\n onSuccess: invalidate,\n });\n\n return {\n create: createMutation,\n update: updateMutation,\n delete: deleteMutation,\n };\n },\n\n // -------------------------------------------------------------------------\n // useInfinite — infinite scroll / load more\n // -------------------------------------------------------------------------\n useInfinite: (params: TQueryParams = defaultParams) => {\n return useInfiniteQuery<ResourceListResult<Base<S>>, Error>({\n queryKey: [queryKeyPrefix, \"INFINITE\", params],\n queryFn: async ({ pageParam }) => {\n const raw = await service.list({\n ...params,\n page: pageParam as number,\n limit: params.limit ?? 20,\n });\n return adapters.fromList(raw as ListRaw<S>);\n },\n getNextPageParam: (lastPage) => {\n const { page, totalPages } = lastPage.pagination;\n return page < totalPages ? page + 1 : undefined;\n },\n initialPageParam: 1,\n });\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/hooks/createResourceHooks.ts","../src/hooks/useAlertMessage.ts","../src/hooks/useAsyncState.ts","../src/hooks/useCallTimer.ts","../src/hooks/useModal.ts","../src/hooks/usePagination.ts"],"sourcesContent":["// Resource hooks factory\nexport { createResourceHooks } from \"./hooks/createResourceHooks\";\nexport type {\n VSUseListReturn,\n VSUseGetReturn,\n VSResourceHooksOptions,\n} from \"./hooks/createResourceHooks\";\n\n// General-purpose React hooks\nexport { useAlertMessage } from \"./hooks/useAlertMessage\";\nexport type { VSAlertVariant, VSAlertState } from \"./hooks/useAlertMessage\";\n\nexport { useAsyncState } from \"./hooks/useAsyncState\";\nexport type {\n VSAsyncStatus,\n VSUseAsyncStateReturn,\n} from \"./hooks/useAsyncState\";\n\nexport { useCallTimer } from \"./hooks/useCallTimer\";\n\nexport { useModal } from \"./hooks/useModal\";\nexport type { VSModalReturn } from \"./hooks/useModal\";\n\nexport { usePagination } from \"./hooks/usePagination\";\nexport type { VSPaginationReturn } from \"./hooks/usePagination\";\n","import {\n useInfiniteQuery,\n useMutation,\n useQuery,\n useQueryClient,\n} from \"@tanstack/react-query\";\nimport type { ResourceService } from \"@void-snippets/client\";\nimport type {\n VSAdapters,\n VSListResult,\n VSPagination,\n VSQueryParams,\n VSDefaultPaginatedResponse,\n VSDefaultSingleResponse,\n} from \"@void-snippets/core\";\nimport { createDefaultAdapters } from \"@void-snippets/core\";\n\n// ============================================================================\n// TYPE HELPERS\n// ============================================================================\n\nconst DEFAULT_PAGINATION: VSQueryParams = {\n page: 1,\n limit: 10,\n};\n\n// ============================================================================\n// PHANTOM TYPE CONSTRAINT\n//\n// We constrain S only on the __types phantom property (readonly = covariant)\n// so ResourceService<string, ...> is always assignable to WithResourceTypes.\n// This avoids the variance issue from constraining method parameter types.\n// ============================================================================\n\ninterface WithResourceTypes {\n readonly __types: {\n id: unknown;\n base: unknown;\n detail: unknown;\n create: unknown;\n update: unknown;\n listRaw: unknown;\n singleRaw: unknown;\n };\n}\n\ntype Id<S extends WithResourceTypes> = S[\"__types\"][\"id\"];\ntype Base<S extends WithResourceTypes> = S[\"__types\"][\"base\"];\ntype Detail<S extends WithResourceTypes> = S[\"__types\"][\"detail\"];\ntype Create<S extends WithResourceTypes> = S[\"__types\"][\"create\"];\ntype Update<S extends WithResourceTypes> = S[\"__types\"][\"update\"];\ntype ListRaw<S extends WithResourceTypes> = S[\"__types\"][\"listRaw\"];\ntype SingleRaw<S extends WithResourceTypes> = S[\"__types\"][\"singleRaw\"];\n\n// ============================================================================\n// RETURN TYPES\n// ============================================================================\n\nexport interface VSUseListReturn<TBase> {\n list: TBase[];\n pagination: VSPagination;\n isLoading: boolean;\n error: Error | null;\n invalidate: () => void;\n}\n\nexport interface VSUseGetReturn<TDetail> {\n item: TDetail | undefined;\n isLoading: boolean;\n error: Error | null;\n refetch: () => void;\n}\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport interface VSResourceHooksOptions<TListRaw, TBase, TSingleRaw, TDetail> {\n /**\n * Adapters map your API's raw response to the library's internal format.\n * Omit if your API matches the default shape:\n * List: { data: { items, page, limit, totalPages, totalDocuments } }\n * Single: { data: <item> }\n *\n * @example\n * createResourceHooks(\"contacts\", ContactsApis, {\n * adapters: {\n * fromList: (raw) => ({\n * items: raw.results,\n * pagination: {\n * page: raw.meta.page,\n * limit: raw.meta.perPage,\n * totalPages: raw.meta.lastPage,\n * totalDocuments: raw.meta.total,\n * },\n * }),\n * fromSingle: (raw) => raw.payload,\n * },\n * })\n */\n adapters?: VSAdapters<TListRaw, TBase, TSingleRaw, TDetail>;\n\n /**\n * Default params passed to useList and useInfinite when none are provided.\n * @default { page: 1, limit: 10 }\n */\n defaultParams?: VSQueryParams;\n}\n\n// ============================================================================\n// FACTORY\n// ============================================================================\n\n/**\n * Creates a set of TanStack Query hooks for a resource.\n * All types are fully inferred from the `apiService` instance — no generics needed.\n *\n * @param queryKeyPrefix - TanStack Query cache key. Used to scope the cache\n * and for auto-invalidation. e.g. \"contacts\"\n * @param apiService - An instance of ResourceService (or a subclass).\n * @param options - Optional adapters and default params.\n *\n * @example\n * export const contactHooks = createResourceHooks('contacts', ContactsApis);\n *\n * // useList — generic fixed shape\n * const { list, isLoading, pagination, error, invalidate } = contactHooks.useList();\n * // list is typed as Contact.Base[] ✅\n *\n * // useGet\n * const { item, isLoading, error, refetch } = contactHooks.useGet(id);\n * // item is typed as Contact.WithCreatedBy ✅\n *\n * // useMutations\n * const { create, update, remove } = contactHooks.useMutations();\n */\nexport function createResourceHooks<\n K extends string,\n S extends WithResourceTypes,\n>(\n queryKeyPrefix: K,\n apiService: S,\n options: VSResourceHooksOptions<\n ListRaw<S>,\n Base<S>,\n SingleRaw<S>,\n Detail<S>\n > = {},\n) {\n const service = apiService as unknown as ResourceService<\n Id<S>, Base<S>, Detail<S>, Create<S>, Update<S>, ListRaw<S>, SingleRaw<S>\n >;\n\n const {\n adapters = createDefaultAdapters<Base<S>, Detail<S>>() as VSAdapters<\n VSDefaultPaginatedResponse<Base<S>>,\n Base<S>,\n VSDefaultSingleResponse<Detail<S>>,\n Detail<S>\n > as VSAdapters<ListRaw<S>, Base<S>, SingleRaw<S>, Detail<S>>,\n defaultParams = DEFAULT_PAGINATION,\n } = options;\n\n return {\n // -------------------------------------------------------------------------\n // useList — fixed generic shape: { list, isLoading, pagination, error, invalidate }\n // -------------------------------------------------------------------------\n useList: (\n params: VSQueryParams = defaultParams,\n ): VSUseListReturn<Base<S>> => {\n const queryClient = useQueryClient();\n\n const query = useQuery<VSListResult<Base<S>>, Error>({\n queryKey: [queryKeyPrefix, params],\n queryFn: async () => {\n const raw = await service.list(params);\n return adapters.fromList(raw as ListRaw<S>);\n },\n });\n\n return {\n list: query.data?.items ?? [],\n pagination: query.data?.pagination ?? {\n page: 1,\n limit: defaultParams.limit ?? 10,\n totalPages: 0,\n totalDocuments: 0,\n },\n isLoading: query.isLoading || query.isFetching,\n error: query.error,\n invalidate: () =>\n queryClient.invalidateQueries({ queryKey: [queryKeyPrefix] }),\n };\n },\n\n // -------------------------------------------------------------------------\n // useGet — { item, isLoading, error, refetch }\n // -------------------------------------------------------------------------\n useGet: (id: Id<S>, staleTime = 30_000): VSUseGetReturn<Detail<S>> => {\n const query = useQuery<Detail<S>, Error>({\n queryKey: [queryKeyPrefix, id],\n queryFn: async () => {\n const raw = await service.get(id);\n return adapters.fromSingle(raw as SingleRaw<S>);\n },\n enabled: id !== undefined && id !== null && id !== \"\",\n staleTime,\n });\n\n return {\n item: query.data,\n isLoading: query.isLoading || query.isFetching,\n error: query.error,\n refetch: query.refetch,\n };\n },\n\n // -------------------------------------------------------------------------\n // useMutations — create / update / remove (not delete — reserved keyword)\n // -------------------------------------------------------------------------\n useMutations: () => {\n const queryClient = useQueryClient();\n const invalidate = () =>\n queryClient.invalidateQueries({ queryKey: [queryKeyPrefix] });\n\n const createMutation = useMutation<Detail<S>, Error, Create<S>>({\n mutationFn: async (payload) => {\n const raw = await service.create(payload);\n return adapters.fromSingle(raw as SingleRaw<S>);\n },\n onSuccess: invalidate,\n });\n\n const updateMutation = useMutation<\n Detail<S>,\n Error,\n { _id: Id<S>; payload: Update<S> }\n >({\n mutationFn: async ({ _id, payload }) => {\n const raw = await service.update(_id, payload);\n return adapters.fromSingle(raw as SingleRaw<S>);\n },\n onSuccess: invalidate,\n });\n\n const removeMutation = useMutation<Detail<S>, Error, Id<S>>({\n mutationFn: async (_id) => {\n const raw = await service.delete(_id);\n return adapters.fromSingle(raw as SingleRaw<S>);\n },\n onSuccess: invalidate,\n });\n\n return {\n create: createMutation,\n update: updateMutation,\n remove: removeMutation,\n };\n },\n\n // -------------------------------------------------------------------------\n // useInfinite — infinite scroll / load more\n // -------------------------------------------------------------------------\n useInfinite: (params: VSQueryParams = defaultParams) => {\n return useInfiniteQuery<VSListResult<Base<S>>, Error>({\n queryKey: [queryKeyPrefix, \"INFINITE\", params],\n queryFn: async ({ pageParam }) => {\n const raw = await service.list({\n ...params,\n page: pageParam as number,\n limit: params.limit ?? 20,\n });\n return adapters.fromList(raw as ListRaw<S>);\n },\n getNextPageParam: (lastPage) => {\n const { page, totalPages } = lastPage.pagination;\n return page < totalPages ? page + 1 : undefined;\n },\n initialPageParam: 1,\n });\n },\n };\n}\n","import { type ReactNode, useCallback, useState } from \"react\";\n\nexport type VSAlertVariant = \"success\" | \"info\" | \"error\";\n\nexport interface VSAlertState {\n message: ReactNode | string;\n type: VSAlertVariant;\n isVisible: boolean;\n}\n\n/**\n * Manages alert/toast message state with optional auto-hide.\n *\n * @param autoHideDuration - ms before alert hides automatically. Pass 0 to disable. Default: 3000\n *\n * @example\n * const { alert, showAlert, hideAlert } = useAlertMessage();\n * showAlert('Saved successfully!', 'success');\n * showAlert(<b>Something went wrong</b>, 'error');\n */\nexport function useAlertMessage(autoHideDuration = 3000) {\n const [alert, setAlert] = useState<VSAlertState>({\n message: null,\n type: \"info\",\n isVisible: false,\n });\n\n const showAlert = useCallback(\n (message: ReactNode | string, type: VSAlertVariant = \"info\") => {\n setAlert({ message, type, isVisible: true });\n if (autoHideDuration) {\n setTimeout(() => {\n setAlert((prev) => ({ ...prev, isVisible: false }));\n }, autoHideDuration);\n }\n },\n [autoHideDuration]\n );\n\n const hideAlert = useCallback(() => {\n setAlert((prev) => ({ ...prev, isVisible: false }));\n }, []);\n\n return { alert, showAlert, hideAlert };\n}\n","import { useCallback, useMemo, useState } from \"react\";\nimport { catchError } from \"@void-snippets/core\";\n\nexport type VSAsyncStatus = \"idle\" | \"pending\" | \"success\" | \"error\";\n\ninterface VSAsyncState<T> {\n data: T | null;\n status: VSAsyncStatus;\n error: Error | null;\n}\n\nexport interface VSUseAsyncStateReturn<T> extends VSAsyncState<T> {\n isLoading: boolean;\n isSuccess: boolean;\n isError: boolean;\n\n setData: (data: T | null) => void;\n setError: (error: Error | null) => void;\n reset: () => void;\n\n /**\n * Executes an async function, updates state, and returns a [err, data] tuple.\n * Allows immediate result handling without try/catch.\n *\n * @example\n * const [err, data] = await execute(() => ContactsApis.create(payload));\n * if (err) return showAlert(err.message, 'error');\n * showAlert('Created!', 'success');\n */\n execute: (\n asyncFn: () => Promise<T>,\n options?: {\n onSuccess?: (data: T) => void;\n onError?: (error: Error) => void;\n }\n ) => Promise<[Error, null] | [null, T]>;\n}\n\n/**\n * Generic async state machine — tracks data, status, and error for any async operation.\n * Pair with any async function: API calls, file reads, timers, etc.\n *\n * @param initialData - Optional initial data value. Default: null\n *\n * @example\n * const { data, isLoading, isError, execute } = useAsyncState<User>();\n *\n * const handleSubmit = async () => {\n * const [err, user] = await execute(() => fetchUser(id));\n * if (err) return;\n * console.log(user.name);\n * };\n */\nexport function useAsyncState<T>(\n initialData: T | null = null\n): VSUseAsyncStateReturn<T> {\n const [state, setState] = useState<VSAsyncState<T>>({\n data: initialData,\n status: \"idle\",\n error: null,\n });\n\n const setData = useCallback((data: T | null) => {\n setState({ data, status: \"success\", error: null });\n }, []);\n\n const setError = useCallback((error: Error | null) => {\n setState((prev) => ({ ...prev, error, status: \"error\" }));\n }, []);\n\n const reset = useCallback(() => {\n setState({ data: initialData, status: \"idle\", error: null });\n }, [initialData]);\n\n const execute = useCallback(\n async (\n asyncFn: () => Promise<T>,\n options?: {\n onSuccess?: (data: T) => void;\n onError?: (error: Error) => void;\n }\n ): Promise<[Error, null] | [null, T]> => {\n setState((prev) => ({ ...prev, status: \"pending\", error: null }));\n\n const [err, res] = await catchError(asyncFn());\n\n if (err) {\n setState((prev) => ({ ...prev, status: \"error\", error: err }));\n options?.onError?.(err);\n return [err, null];\n }\n\n setState({ data: res as T, status: \"success\", error: null });\n options?.onSuccess?.(res as T);\n return [null, res as T];\n },\n []\n );\n\n const flags = useMemo(\n () => ({\n isLoading: state.status === \"pending\",\n isSuccess: state.status === \"success\",\n isError: state.status === \"error\",\n }),\n [state.status]\n );\n\n return { ...state, ...flags, setData, setError, reset, execute };\n}\n","import { useEffect, useState } from \"react\";\n\n/**\n * Tracks elapsed time from a given start timestamp — useful for call durations,\n * countdowns, or any elapsed-time display.\n *\n * @param startedAt - Unix timestamp in ms (e.g. Date.now()). Pass null/undefined to reset.\n * @returns Formatted duration string \"MM:SS\"\n *\n * @example\n * const duration = useCallTimer(call.startedAt);\n * // duration → \"02:45\"\n *\n * // Reset when no active call\n * const duration = useCallTimer(activeCall ? activeCall.startedAt : null);\n */\nexport function useCallTimer(startedAt?: number | null): string {\n const [duration, setDuration] = useState(\"00:00\");\n\n useEffect(() => {\n if (!startedAt) {\n setDuration(\"00:00\");\n return;\n }\n\n const interval = setInterval(() => {\n const diffInSeconds = Math.floor((Date.now() - startedAt) / 1000);\n const minutes = Math.floor(diffInSeconds / 60).toString().padStart(2, \"0\");\n const seconds = (diffInSeconds % 60).toString().padStart(2, \"0\");\n setDuration(`${minutes}:${seconds}`);\n }, 1000);\n\n return () => clearInterval(interval);\n }, [startedAt]);\n\n return duration;\n}\n","import { useCallback, useState } from \"react\";\n\nexport interface VSModalReturn<T> {\n isOpen: boolean;\n data: T | null;\n isLoading: boolean;\n openCreateModal: () => void;\n openEditModal: (editData: T) => void;\n setLoading: (loading: boolean) => void;\n closeModal: () => void;\n setModal: (open: boolean, editData?: T | null) => void;\n}\n\n/**\n * Manages modal open/close state with optional data payload and loading state.\n * Works for both create and edit modals — pass data to distinguish the mode.\n *\n * @typeParam T - The type of data the modal operates on (e.g. a Contact, User, etc.)\n *\n * @example\n * const modal = useModal<Contact.Base>();\n *\n * modal.openCreateModal(); // data → null (create mode)\n * modal.openEditModal(contact); // data → contact (edit mode)\n *\n * if (modal.data) {\n * // Edit mode — modal.data is Contact.Base\n * } else {\n * // Create mode\n * }\n */\nexport function useModal<T = unknown>(): VSModalReturn<T> {\n const [isOpen, setIsOpen] = useState(false);\n const [data, setData] = useState<T | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n\n const openCreateModal = useCallback(() => {\n setIsOpen(true);\n setData(null);\n }, []);\n\n const openEditModal = useCallback((editData: T) => {\n setIsOpen(true);\n setData(editData);\n }, []);\n\n const setLoading = useCallback((loading: boolean) => {\n setIsLoading(loading);\n }, []);\n\n const closeModal = useCallback(() => {\n setIsOpen(false);\n setData(null);\n }, []);\n\n const setModal = useCallback((open: boolean, editData?: T | null) => {\n setIsOpen(open);\n setData(editData ?? null);\n }, []);\n\n return {\n isOpen,\n data,\n isLoading,\n openCreateModal,\n openEditModal,\n setLoading,\n closeModal,\n setModal,\n };\n}\n","import { useCallback, useState } from \"react\";\nimport type { VSQueryParams } from \"@void-snippets/core\";\n\nexport interface VSPaginationReturn {\n page: number;\n limit: number;\n onPaginationChange: (newPage: number, newLimit: number) => void;\n resetPagination: () => void;\n setPage: (page: number) => void;\n setLimit: (limit: number) => void;\n /** Ready-to-use query params object — pass directly to useList() */\n queryParams: VSQueryParams;\n}\n\n/**\n * Manages pagination state and produces a ready-to-use queryParams object\n * compatible with createResourceHooks' useList() and useInfinite().\n *\n * @param initialPage - Starting page. Default: 1\n * @param initialLimit - Items per page. Default: 10\n *\n * @example\n * const { queryParams, onPaginationChange } = usePagination(1, 20);\n *\n * const { list, isLoading } = contactHooks.useList(queryParams);\n *\n * <Pagination onChange={onPaginationChange} total={pagination.totalDocuments} />\n */\nexport function usePagination(\n initialPage = 1,\n initialLimit = 10\n): VSPaginationReturn {\n const [page, setPage] = useState(initialPage);\n const [limit, setLimit] = useState(initialLimit);\n\n const onPaginationChange = useCallback(\n (newPage: number, newLimit: number) => {\n setPage(newPage);\n setLimit(newLimit);\n },\n []\n );\n\n const resetPagination = useCallback(() => {\n setPage(1);\n }, []);\n\n return {\n page,\n limit,\n onPaginationChange,\n resetPagination,\n setPage,\n setLimit,\n queryParams: { page, limit },\n };\n}\n"],"mappings":"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","names":["import_react","import_core","import_react","import_react","import_react"]}
|