@m5kdev/frontend 0.1.4 → 0.1.5

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/dist/src/modules/auth/auth.lib.d.ts +0 -1
  2. package/dist/src/modules/auth/components/AuthProvider.d.ts +0 -1
  3. package/dist/src/modules/auth/hooks/useAuth.d.ts +0 -1
  4. package/dist/src/modules/auth/hooks/useAuthAdmin.d.ts +0 -1
  5. package/dist/src/modules/auth/hooks/useSession.d.ts +0 -1
  6. package/dist/src/modules/billing/components/BillingProvider.d.ts +0 -1
  7. package/dist/src/modules/billing/hooks/useSubscription.d.ts +0 -1
  8. package/dist/src/modules/file/hooks/useS3DownloadUrl.d.ts +0 -1
  9. package/dist/src/modules/file/hooks/useS3Upload.d.ts +0 -1
  10. package/dist/src/modules/file/hooks/useUpload.d.ts +0 -1
  11. package/dist/src/modules/table/hooks/useDateRangeFilter.d.ts +0 -1
  12. package/dist/src/modules/table/hooks/useNuqsQueryParams.d.ts +0 -1
  13. package/dist/src/modules/table/hooks/useNuqsTable.d.ts +0 -1
  14. package/dist/src/modules/table/hooks/useQueryWithParams.d.ts +0 -1
  15. package/dist/src/types.d.ts +0 -1
  16. package/dist/src/utils/date.d.ts +0 -1
  17. package/dist/src/utils/query.d.ts +0 -1
  18. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  19. package/package.json +7 -4
  20. package/.cursor/rules/frontend.mdc +0 -49
  21. package/.turbo/turbo-build.log +0 -5
  22. package/.turbo/turbo-check-types.log +0 -5
  23. package/.turbo/turbo-lint$colon$fix.log +0 -101
  24. package/.turbo/turbo-lint.log +0 -162
  25. package/CHANGELOG.md +0 -33
  26. package/dist/src/modules/auth/auth.lib.d.ts.map +0 -1
  27. package/dist/src/modules/auth/components/AuthProvider.d.ts.map +0 -1
  28. package/dist/src/modules/auth/hooks/useAuth.d.ts.map +0 -1
  29. package/dist/src/modules/auth/hooks/useAuthAdmin.d.ts.map +0 -1
  30. package/dist/src/modules/auth/hooks/useSession.d.ts.map +0 -1
  31. package/dist/src/modules/billing/components/BillingProvider.d.ts.map +0 -1
  32. package/dist/src/modules/billing/hooks/useSubscription.d.ts.map +0 -1
  33. package/dist/src/modules/file/hooks/useS3DownloadUrl.d.ts.map +0 -1
  34. package/dist/src/modules/file/hooks/useS3Upload.d.ts.map +0 -1
  35. package/dist/src/modules/file/hooks/useUpload.d.ts.map +0 -1
  36. package/dist/src/modules/table/hooks/useDateRangeFilter.d.ts.map +0 -1
  37. package/dist/src/modules/table/hooks/useNuqsQueryParams.d.ts.map +0 -1
  38. package/dist/src/modules/table/hooks/useNuqsTable.d.ts.map +0 -1
  39. package/dist/src/modules/table/hooks/useQueryWithParams.d.ts.map +0 -1
  40. package/dist/src/types.d.ts.map +0 -1
  41. package/dist/src/utils/date.d.ts.map +0 -1
  42. package/dist/src/utils/query.d.ts.map +0 -1
  43. package/src/modules/auth/auth.lib.ts +0 -49
  44. package/src/modules/auth/components/AuthProvider.tsx +0 -105
  45. package/src/modules/auth/hooks/useAuth.ts +0 -20
  46. package/src/modules/auth/hooks/useAuthAdmin.ts +0 -188
  47. package/src/modules/auth/hooks/useSession.ts +0 -6
  48. package/src/modules/billing/components/BillingProvider.tsx +0 -58
  49. package/src/modules/billing/hooks/useSubscription.ts +0 -6
  50. package/src/modules/file/hooks/useS3DownloadUrl.ts +0 -18
  51. package/src/modules/file/hooks/useS3Upload.ts +0 -89
  52. package/src/modules/file/hooks/useUpload.ts +0 -220
  53. package/src/modules/table/hooks/useDateRangeFilter.ts +0 -55
  54. package/src/modules/table/hooks/useNuqsQueryParams.ts +0 -134
  55. package/src/modules/table/hooks/useNuqsTable.ts +0 -83
  56. package/src/modules/table/hooks/useQueryWithParams.ts +0 -62
  57. package/src/types.ts +0 -4
  58. package/src/utils/date.ts +0 -88
  59. package/src/utils/query.ts +0 -72
  60. package/src/vite-env.d.ts +0 -1
  61. package/tsconfig.json +0 -29
@@ -1,220 +0,0 @@
1
- import { useCallback, useState } from "react";
2
-
3
- export type UploadStatus = "pending" | "uploading" | "completed" | "error";
4
-
5
- export interface UploadFileTask {
6
- id: string;
7
- file: File;
8
- progress: number;
9
- status: UploadStatus;
10
- errorMessage?: string;
11
- bytesUploaded: number;
12
- totalBytes: number;
13
- }
14
-
15
- interface UploadCallbacks {
16
- onProgress: (progress: number, bytesUploaded: number) => void;
17
- onComplete: () => void;
18
- onError: (error: string) => void;
19
- }
20
-
21
- // Shared utility function to create upload promise
22
- const createUploadPromise = <T>(
23
- type: string,
24
- file: File,
25
- callbacks: UploadCallbacks
26
- ): Promise<T> => {
27
- return new Promise((resolve, reject) => {
28
- const xhr = new XMLHttpRequest();
29
-
30
- xhr.upload.onprogress = (event: ProgressEvent<EventTarget>) => {
31
- if (event.lengthComputable) {
32
- const progress = Math.round((event.loaded * 100) / event.total);
33
- callbacks.onProgress(progress, event.loaded);
34
- }
35
- };
36
-
37
- xhr.onload = () => {
38
- if (xhr.status === 200) {
39
- callbacks.onComplete();
40
- // if response has json header, parse it
41
- if (xhr.getResponseHeader("Content-Type")?.includes("application/json")) {
42
- resolve(JSON.parse(xhr.response) as T);
43
- } else {
44
- resolve(xhr.response as T);
45
- }
46
- } else {
47
- const errorMessage = `Upload failed with status ${xhr.status}`;
48
- callbacks.onError(errorMessage);
49
- reject(new Error(errorMessage));
50
- }
51
- };
52
-
53
- xhr.onerror = () => {
54
- const errorMessage = "Network error during upload";
55
- callbacks.onError(errorMessage);
56
- reject(new Error(errorMessage));
57
- };
58
-
59
- xhr.open("POST", `${import.meta.env.VITE_SERVER_URL}/upload/file/${type}`);
60
- const formData = new FormData();
61
- formData.append("file", file);
62
- xhr.send(formData);
63
- });
64
- };
65
-
66
- // Shared utility to create a task
67
- const createUploadTask = (file: File): UploadFileTask => ({
68
- id:
69
- typeof crypto !== "undefined" && crypto.randomUUID
70
- ? crypto.randomUUID()
71
- : Math.random().toString(36).substr(2, 9),
72
- file,
73
- progress: 0,
74
- status: "pending",
75
- bytesUploaded: 0,
76
- totalBytes: file.size,
77
- });
78
-
79
- // Hook for single file upload
80
- export function useFileUpload() {
81
- const [uploadTask, setUploadTask] = useState<UploadFileTask | null>(null);
82
-
83
- const upload = useCallback(async <T>(type: string, file: File): Promise<T> => {
84
- const task = createUploadTask(file);
85
- setUploadTask(task);
86
-
87
- const callbacks: UploadCallbacks = {
88
- onProgress: (progress, bytesUploaded) => {
89
- setUploadTask((prev) =>
90
- prev
91
- ? {
92
- ...prev,
93
- progress,
94
- bytesUploaded,
95
- status: "uploading",
96
- }
97
- : null
98
- );
99
- },
100
- onComplete: () => {
101
- setUploadTask((prev) => (prev ? { ...prev, status: "completed", progress: 100 } : null));
102
- },
103
- onError: (errorMessage) => {
104
- setUploadTask((prev) =>
105
- prev
106
- ? {
107
- ...prev,
108
- status: "error",
109
- errorMessage,
110
- progress: 0,
111
- }
112
- : null
113
- );
114
- },
115
- };
116
-
117
- return createUploadPromise<T>(type, file, callbacks);
118
- }, []);
119
-
120
- const reset = useCallback(() => {
121
- setUploadTask(null);
122
- }, []);
123
-
124
- return {
125
- ...uploadTask,
126
- upload,
127
- reset,
128
- };
129
- }
130
-
131
- // Hook for multiple file uploads
132
- export function useMultipartUpload() {
133
- const [uploadQueue, setUploadQueue] = useState<UploadFileTask[]>([]);
134
- const [overallProgress, setOverallProgress] = useState<number>(0);
135
-
136
- const updateTask = useCallback((id: string, changes: Partial<UploadFileTask>) => {
137
- setUploadQueue((prev) => prev.map((task) => (task.id === id ? { ...task, ...changes } : task)));
138
- }, []);
139
-
140
- const updateOverallProgress = useCallback((queue: UploadFileTask[]) => {
141
- if (queue.length === 0) {
142
- setOverallProgress(100);
143
- return;
144
- }
145
- const totalBytes = queue.reduce((sum, task) => sum + task.file.size, 0);
146
- const uploadedBytes = queue.reduce((sum, task) => {
147
- if (task.status === "completed") {
148
- return sum + task.file.size;
149
- }
150
- if (task.status === "uploading") {
151
- return sum + (task.progress / 100) * task.file.size;
152
- }
153
- return sum;
154
- }, 0);
155
- setOverallProgress(Math.floor((uploadedBytes / totalBytes) * 100));
156
- }, []);
157
-
158
- const uploadSingleFile = useCallback(
159
- async <T>(type: string, task: UploadFileTask): Promise<T> => {
160
- const callbacks: UploadCallbacks = {
161
- onProgress: (progress, bytesUploaded) => {
162
- updateTask(task.id, {
163
- progress,
164
- bytesUploaded,
165
- status: "uploading",
166
- });
167
- setUploadQueue((currentQueue) => {
168
- const updatedQueue = currentQueue.map((q) =>
169
- q.id === task.id ? { ...q, progress, bytesUploaded } : q
170
- );
171
- updateOverallProgress(updatedQueue);
172
- return updatedQueue;
173
- });
174
- },
175
- onComplete: () => {
176
- updateTask(task.id, { status: "completed", progress: 100 });
177
- },
178
- onError: (errorMessage) => {
179
- updateTask(task.id, {
180
- status: "error",
181
- errorMessage,
182
- progress: 0,
183
- });
184
- },
185
- };
186
-
187
- return createUploadPromise<T>(type, task.file, callbacks);
188
- },
189
- [updateTask, updateOverallProgress]
190
- );
191
-
192
- const uploadFiles = useCallback(
193
- async (type: string, files: File[]) => {
194
- const initialQueue = files.map(createUploadTask);
195
- setUploadQueue(initialQueue);
196
- updateOverallProgress(initialQueue);
197
-
198
- for (const task of initialQueue) {
199
- try {
200
- await uploadSingleFile(type, task);
201
- } catch (_error) {}
202
- }
203
- },
204
- [uploadSingleFile, updateOverallProgress]
205
- );
206
-
207
- const reset = useCallback(() => {
208
- setUploadQueue([]);
209
- setOverallProgress(0);
210
- }, []);
211
-
212
- return {
213
- uploadQueue,
214
- overallProgress,
215
- uploadFiles,
216
- reset,
217
- getTotalBytes: () => uploadQueue.reduce((sum, task) => sum + task.totalBytes, 0),
218
- getTotalBytesUploaded: () => uploadQueue.reduce((sum, task) => sum + task.bytesUploaded, 0),
219
- };
220
- }
@@ -1,55 +0,0 @@
1
- import type { UseQueryOptions, UseQueryResult } from "@tanstack/react-query";
2
- import { useNuqsQueryParams, type NuqsQueryParams } from "./useNuqsQueryParams";
3
- import { useQueryWithParams } from "./useQueryWithParams";
4
-
5
- export interface DateRangeFilterReturn<TData> {
6
- params: NuqsQueryParams;
7
- query: UseQueryResult<TData>;
8
- }
9
-
10
- /**
11
- * Flexible query options type that accepts both standard TanStack Query options
12
- * and tRPC's queryOptions function return type.
13
- * Uses permissive generics to handle type differences between TanStack Query and tRPC.
14
- */
15
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
- type QueryOptionsLike<TData> = UseQueryOptions<TData, any, TData, any>;
17
-
18
- /**
19
- * Function type that accepts both standard query options functions and tRPC's queryOptions.
20
- * tRPC's queryOptions accepts (input, opts?) while standard functions may only accept (input).
21
- */
22
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
- type GetQueryOptionsFn<TInput, TData> = (input: TInput, ...args: any[]) => QueryOptionsLike<TData>;
24
-
25
- export interface DateRangeFilterOptions<TInput, TData> {
26
- getQueryOptions: GetQueryOptionsFn<TInput, TData>;
27
- queryParams?: TInput;
28
- }
29
-
30
- /**
31
- * Hook for charts with URL-synced query parameters and data fetching
32
- * Similar to useNuqsTable but without rowSelection (not needed for charts)
33
- */
34
- export const useDateRangeFilter = <TInput, TData>({
35
- getQueryOptions,
36
- queryParams = {} as TInput,
37
- }: DateRangeFilterOptions<TInput, TData>): DateRangeFilterReturn<TData> => {
38
- // Get only filters from URL query state
39
- const { filters, setFilters, granularity, setGranularity } = useNuqsQueryParams();
40
-
41
-
42
- // Get query result
43
- const queryResult = useQueryWithParams({
44
- getQueryOptions,
45
- queryParams,
46
- queryState: { filters },
47
- });
48
-
49
- return {
50
- params: { filters, setFilters, granularity, setGranularity },
51
- query: queryResult,
52
- };
53
- };
54
-
55
-
@@ -1,134 +0,0 @@
1
- import type { QueryFilters } from "@m5kdev/commons/modules/schemas/query.schema";
2
- import { filtersSchema } from "@m5kdev/commons/modules/schemas/query.schema";
3
- import type { PaginationState, SortingState, Updater } from "@tanstack/react-table";
4
- import {
5
- parseAsInteger,
6
- parseAsJson,
7
- parseAsString,
8
- parseAsStringLiteral,
9
- useQueryState,
10
- } from "nuqs";
11
- import { useCallback, useEffect, useMemo } from "react";
12
-
13
- const parseAsFilters = parseAsJson<QueryFilters>((value) => filtersSchema.parse(value)).withDefault(
14
- []
15
- );
16
-
17
- export type Order = "asc" | "desc";
18
-
19
- export type Granularity = "daily" | "weekly" | "monthly" | "yearly";
20
-
21
- export interface NuqsQueryParams {
22
- filters?: QueryFilters;
23
- setFilters?: (filters: QueryFilters) => void;
24
- granularity?: Granularity;
25
- setGranularity?: (value: Granularity) => void;
26
- sort?: string;
27
- order?: Order | null;
28
- setSorting?: (updater: Updater<SortingState>) => void;
29
- sorting?: SortingState;
30
- page?: number;
31
- limit?: number;
32
- setPagination?: (updater: Updater<PaginationState>) => void;
33
- pagination?: PaginationState;
34
- }
35
-
36
- /**
37
- * Hook to manage all query parameters via nuqs (URL query parameters)
38
- * Manages: filters, sort, order, page, limit
39
- * Reusable for any paginated/sorted/filtered lists
40
- */
41
- export const useNuqsQueryParams = (): NuqsQueryParams => {
42
- const [sort, setSort] = useQueryState<string>("sort", parseAsString.withDefault(""));
43
- const [order, setOrder] = useQueryState<Order>("order", parseAsStringLiteral(["asc", "desc"]));
44
- const [page, setPage] = useQueryState<number>("page", parseAsInteger.withDefault(1));
45
- const [limit, setLimit] = useQueryState<number>("limit", parseAsInteger.withDefault(10));
46
- const [filters, setFilters] = useQueryState<QueryFilters>("filters", parseAsFilters);
47
- const [granularity, setGranularity] = useQueryState<Granularity>(
48
- "granularity",
49
- parseAsStringLiteral(["daily", "weekly", "monthly", "yearly"]).withDefault("daily")
50
- );
51
-
52
- const sorting = useMemo(() => {
53
- if (!sort) {
54
- return [];
55
- }
56
- const effectiveOrder = order ?? "asc";
57
- return [{ id: sort, desc: effectiveOrder === "desc" }];
58
- }, [sort, order]);
59
-
60
- const pagination = useMemo(() => ({ pageIndex: page - 1, pageSize: limit }), [page, limit]);
61
-
62
- const setSorting = useCallback(
63
- (updater: Updater<SortingState>) => {
64
- // Build current sorting state from current values
65
- const currentSorting: SortingState = sort
66
- ? [{ id: sort, desc: (order ?? "asc") === "desc" }]
67
- : [];
68
-
69
- const next = typeof updater === "function" ? updater(currentSorting) : updater;
70
- const first = next[0];
71
-
72
- if (!first || !first.id) {
73
- setSort("");
74
- setOrder(null);
75
- return;
76
- }
77
-
78
- setSort(first.id);
79
- setOrder(first.desc ? "desc" : "asc");
80
- },
81
- [sort, order, setSort, setOrder]
82
- );
83
-
84
- // Sync order to "asc" if sort is set but order is null (handles URL state inconsistencies)
85
- useEffect(() => {
86
- if (sort && !order) {
87
- setOrder("asc");
88
- }
89
- }, [sort, order, setOrder]);
90
-
91
- // biome-ignore lint/correctness/useExhaustiveDependencies: dependent on page and limit only
92
- const setPagination = useCallback(
93
- (updater: Updater<PaginationState>) => {
94
- // TanStack Table uses 0-based indexing, but URL uses 1-based
95
- const currentState = { pageIndex: page - 1, pageSize: limit };
96
- const next = typeof updater === "function" ? updater(currentState) : updater;
97
- // Convert back to 1-based for URL
98
- setPage((next.pageIndex ?? 0) + 1);
99
- setLimit(next.pageSize ?? 10);
100
- },
101
- [page, limit]
102
- );
103
-
104
- return useMemo(
105
- () => ({
106
- filters,
107
- setFilters,
108
- granularity,
109
- setGranularity,
110
- sort,
111
- order,
112
- setSorting,
113
- sorting,
114
- page,
115
- limit,
116
- setPagination,
117
- pagination,
118
- }),
119
- [
120
- filters,
121
- setFilters,
122
- granularity,
123
- setGranularity,
124
- sort,
125
- order,
126
- setSorting,
127
- sorting,
128
- page,
129
- limit,
130
- setPagination,
131
- pagination,
132
- ]
133
- );
134
- };
@@ -1,83 +0,0 @@
1
- import type { UseQueryOptions, UseQueryResult } from "@tanstack/react-query";
2
- import type { RowSelectionState, Updater } from "@tanstack/react-table";
3
- import { useCallback, useMemo, useState } from "react";
4
- import { type NuqsQueryParams, useNuqsQueryParams } from "./useNuqsQueryParams";
5
- import { useQueryWithParams } from "./useQueryWithParams";
6
-
7
- export interface TableParams extends NuqsQueryParams {
8
- rowSelection: RowSelectionState;
9
- setRowSelection: (updater: Updater<RowSelectionState>) => void;
10
- }
11
-
12
- /**
13
- * Alias for TableParams - used by TablePagination and other table components
14
- */
15
- export type TableProps = TableParams;
16
-
17
- export interface NuqsTableReturn<TData> {
18
- params: TableParams;
19
- query: UseQueryResult<TData>;
20
- }
21
-
22
- /**
23
- * Flexible query options type that accepts both standard TanStack Query options
24
- * and tRPC's queryOptions function return type.
25
- * Uses permissive generics to handle type differences between TanStack Query and tRPC.
26
- */
27
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
- type QueryOptionsLike<TData> = UseQueryOptions<TData, any, TData, any>;
29
-
30
- /**
31
- * Function type that accepts both standard query options functions and tRPC's queryOptions.
32
- * tRPC's queryOptions accepts (input, opts?) while standard functions may only accept (input).
33
- */
34
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
- type GetQueryOptionsFn<TInput, TData> = (input: TInput, ...args: any[]) => QueryOptionsLike<TData>;
36
-
37
- export interface NuqsTableOptions<TInput, TData> {
38
- getQueryOptions: GetQueryOptionsFn<TInput, TData>;
39
- queryParams?: TInput;
40
- }
41
-
42
- const useNuqsTable = <TInput, TData>({
43
- getQueryOptions,
44
- queryParams = {} as TInput,
45
- }: NuqsTableOptions<TInput, TData>): NuqsTableReturn<TData> => {
46
- // Get all URL query state
47
- const queryState = useNuqsQueryParams();
48
-
49
- // Get query result
50
- const queryResult = useQueryWithParams({
51
- getQueryOptions,
52
- queryParams,
53
- queryState,
54
- });
55
-
56
- // Table-specific row selection state
57
- const [rowSelection, setRowSelectionRaw] = useState<RowSelectionState>({});
58
-
59
- console.log("rowSelection", rowSelection);
60
-
61
- const setRowSelection = useCallback((updater: Updater<RowSelectionState>) => {
62
- setRowSelectionRaw((prev: RowSelectionState) => {
63
- const next = typeof updater === "function" ? updater(prev) : updater;
64
- return next;
65
- });
66
- }, []);
67
-
68
- const params = useMemo(
69
- () => ({
70
- ...queryState,
71
- rowSelection,
72
- setRowSelection,
73
- }),
74
- [queryState, rowSelection, setRowSelection]
75
- );
76
-
77
- return {
78
- params,
79
- query: queryResult,
80
- };
81
- };
82
-
83
- export default useNuqsTable;
@@ -1,62 +0,0 @@
1
- import { type UseQueryOptions, type UseQueryResult, useQuery } from "@tanstack/react-query";
2
- import { useMemo } from "react";
3
- import type { NuqsQueryParams } from "./useNuqsQueryParams";
4
-
5
- /**
6
- * Flexible query options type that accepts both standard TanStack Query options
7
- * and tRPC's queryOptions function return type.
8
- * Uses permissive generics to handle type differences between TanStack Query and tRPC.
9
- */
10
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
- type QueryOptionsLike<TData> = UseQueryOptions<TData, any, TData, any>;
12
-
13
- /**
14
- * Function type that accepts both standard query options functions and tRPC's queryOptions.
15
- * tRPC's queryOptions accepts (input, opts?) while standard functions may only accept (input).
16
- */
17
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
- type GetQueryOptionsFn<TInput, TData> = (input: TInput, ...args: any[]) => QueryOptionsLike<TData>;
19
-
20
- export interface QueryWithParamsOptions<TInput, TData> {
21
- getQueryOptions: GetQueryOptionsFn<TInput, TData>;
22
- queryParams?: TInput;
23
- queryState: Pick<NuqsQueryParams, "filters" | "sort" | "order" | "page" | "limit">;
24
- enabled?: boolean;
25
- }
26
-
27
- /**
28
- * Hook to integrate query state with React Query
29
- * Combines queryParams with queryState and manages data fetching
30
- */
31
- export const useQueryWithParams = <TInput, TData>({
32
- getQueryOptions,
33
- queryParams = {} as TInput,
34
- queryState,
35
- enabled = true,
36
- }: QueryWithParamsOptions<TInput, TData>): UseQueryResult<TData> => {
37
- const { filters, sort, order, page, limit } = queryState;
38
-
39
- const input = useMemo(
40
- () => ({
41
- ...queryParams,
42
- page,
43
- limit,
44
- sort,
45
- order: order ?? undefined,
46
- filters,
47
- }),
48
- [queryParams, page, limit, sort, order, filters]
49
- );
50
-
51
- const queryOptions = useMemo(
52
- () => ({
53
- ...getQueryOptions(input),
54
- placeholderData: (previousData: TData | undefined) => previousData,
55
- enabled,
56
- }),
57
- [getQueryOptions, input, enabled]
58
- );
59
-
60
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
- return useQuery(queryOptions as any) as UseQueryResult<TData>;
62
- };
package/src/types.ts DELETED
@@ -1,4 +0,0 @@
1
- import type { BackendTRPCRouter } from "@m5kdev/backend/types";
2
- import type { createTRPCContext } from "@trpc/tanstack-react-query";
3
-
4
- export type UseBackendTRPC = ReturnType<typeof createTRPCContext<BackendTRPCRouter>>["useTRPC"];
package/src/utils/date.ts DELETED
@@ -1,88 +0,0 @@
1
- import type { DateValue, RangeValue } from "@heroui/react";
2
- import { CalendarDate, getLocalTimeZone, parseAbsolute } from "@internationalized/date";
3
- import type { QueryFilter } from "@m5kdev/commons/modules/schemas/query.schema";
4
- import { DateTime } from "luxon";
5
-
6
- /**
7
- * Convert CalendarDate to UTC ISO string at midnight UTC
8
- */
9
- export const calendarDateToUTC = (date: CalendarDate): string => {
10
- return DateTime.utc(date.year, date.month, date.day).toISO() ?? "";
11
- };
12
-
13
- /**
14
- * Convert CalendarDate to UTC ISO string at end of day UTC
15
- */
16
- export const calendarDateToUTCEndOfDay = (date: CalendarDate): string => {
17
- return DateTime.utc(date.year, date.month, date.day).endOf("day").toISO() ?? "";
18
- };
19
-
20
- /**
21
- * Convert RangeValue<DateValue> to URL string format "startISO,endISO"
22
- */
23
- export const rangeToUrlString = (range: RangeValue<DateValue> | null): string | null => {
24
- if (!range || !range.start || !range.end) return null;
25
-
26
- const start = range.start as unknown as CalendarDate;
27
- const end = range.end as unknown as CalendarDate;
28
-
29
- if (!start?.year || !end?.year) return null;
30
-
31
- // Format as ISO date strings (YYYY-MM-DD)
32
- const startISO = `${start.year}-${String(start.month).padStart(2, "0")}-${String(start.day).padStart(2, "0")}`;
33
- const endISO = `${end.year}-${String(end.month).padStart(2, "0")}-${String(end.day).padStart(2, "0")}`;
34
-
35
- return `${startISO},${endISO}`;
36
- };
37
-
38
- /**
39
- * Convert URL string "startISO,endISO" to RangeValue<DateValue>
40
- */
41
- export const urlStringToRange = (value: string | null): RangeValue<DateValue> | null => {
42
- if (!value) return null;
43
-
44
- const [startISO, endISO] = value.split(",");
45
- if (!startISO || !endISO) return null;
46
-
47
- const tz = getLocalTimeZone();
48
-
49
- // Parse ISO date strings using parseAbsolute for proper timezone handling
50
- const startZoned = parseAbsolute(`${startISO}T00:00:00Z`, tz);
51
- const endZoned = parseAbsolute(`${endISO}T00:00:00Z`, tz);
52
-
53
- if (!startZoned || !endZoned) return null;
54
-
55
- const startDate = new CalendarDate(startZoned.year, startZoned.month, startZoned.day);
56
- const endDate = new CalendarDate(endZoned.year, endZoned.month, endZoned.day);
57
-
58
- return {
59
- start: startDate as unknown as DateValue,
60
- end: endDate as unknown as DateValue,
61
- } as RangeValue<DateValue>;
62
- };
63
-
64
- /**
65
- * Convert date range to QueryFilter format
66
- */
67
- export const dateRangeToFilter = (
68
- dateRange: RangeValue<DateValue> | null,
69
- columnId = "startedAt"
70
- ): QueryFilter | null => {
71
- if (!dateRange || !dateRange.start || !dateRange.end) return null;
72
-
73
- const start = dateRange.start as unknown as CalendarDate;
74
- const end = dateRange.end as unknown as CalendarDate;
75
-
76
- if (!start?.year || !end?.year) return null;
77
-
78
- const startISO = calendarDateToUTC(start);
79
- const endISO = calendarDateToUTCEndOfDay(end);
80
-
81
- return {
82
- columnId,
83
- type: "date",
84
- method: "between",
85
- value: startISO,
86
- valueTo: endISO,
87
- };
88
- };