sharpcodes-heroui 1.0.5 → 1.0.7
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/dist/components/index.js +1 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/pagination.d.ts +37 -0
- package/dist/hooks/pagination.js +98 -0
- package/dist/hooks/xlsx.d.ts +22 -0
- package/dist/hooks/xlsx.js +49 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +3 -2
package/dist/components/index.js
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { FieldValues } from "react-hook-form";
|
|
2
|
+
import { DateRangeItem } from "../components";
|
|
3
|
+
type TFilter = {
|
|
4
|
+
key: string;
|
|
5
|
+
values: Array<number | string>;
|
|
6
|
+
};
|
|
7
|
+
type TUsePagination = {
|
|
8
|
+
initial?: Partial<PaginationSchema>;
|
|
9
|
+
url: string;
|
|
10
|
+
name: string;
|
|
11
|
+
filters?: Array<TFilter>;
|
|
12
|
+
isDisabled?: boolean;
|
|
13
|
+
};
|
|
14
|
+
type TUsePaginationLocalCalculator<T extends FieldValues> = {
|
|
15
|
+
pageIndex: number;
|
|
16
|
+
items: Array<T>;
|
|
17
|
+
rowCount: number;
|
|
18
|
+
search?: string;
|
|
19
|
+
};
|
|
20
|
+
export declare const usePagination: <T extends FieldValues, IsPaginated extends boolean = true>({ isDisabled, filters, name, url, initial }: TUsePagination) => {
|
|
21
|
+
query: import("@tanstack/react-query").UseQueryResult<import("@tanstack/query-core").NoInfer<IsPaginated extends true ? PaginatedResponse<T> : Res<T>>, Res<never>>;
|
|
22
|
+
page: number;
|
|
23
|
+
setPage: import("react").Dispatch<import("react").SetStateAction<number>>;
|
|
24
|
+
count: number;
|
|
25
|
+
setCount: import("react").Dispatch<import("react").SetStateAction<number>>;
|
|
26
|
+
search: string;
|
|
27
|
+
setSearch: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
28
|
+
dateRange: DateRangeItem | null;
|
|
29
|
+
setDateRange: import("react").Dispatch<import("react").SetStateAction<DateRangeItem | null>>;
|
|
30
|
+
};
|
|
31
|
+
export declare const usePaginationLocalCalculator: <T extends FieldValues>({ items, pageIndex, rowCount, search }: TUsePaginationLocalCalculator<T>) => {
|
|
32
|
+
canPrev: boolean;
|
|
33
|
+
canNext: boolean;
|
|
34
|
+
currentData: T[];
|
|
35
|
+
totalPages: number;
|
|
36
|
+
};
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/set-state-in-effect */
|
|
2
|
+
import _ from "lodash";
|
|
3
|
+
import { useQuery } from "@tanstack/react-query";
|
|
4
|
+
import { useEffect, useMemo, useState } from "react";
|
|
5
|
+
import { useDebounce } from "react-haiku";
|
|
6
|
+
import { localApi, toMoment } from "../libs";
|
|
7
|
+
// prettier-ignore
|
|
8
|
+
export const usePagination = ({ isDisabled, filters, name, url, initial }) => {
|
|
9
|
+
const [page, setPage] = useState(1);
|
|
10
|
+
const [count, setCount] = useState(10);
|
|
11
|
+
const [search, setSearch] = useState("");
|
|
12
|
+
const [dateRange, setDateRange] = useState({
|
|
13
|
+
from: toMoment().startOf("date").toDate(),
|
|
14
|
+
to: toMoment().endOf("date").toDate()
|
|
15
|
+
});
|
|
16
|
+
const debounced = useDebounce({ search, page, count }, 300);
|
|
17
|
+
const debouncedDateRangeValue = useDebounce(dateRange, 300);
|
|
18
|
+
const serializedFilters = useMemo(() => normalizeFilters(filters), [filters]);
|
|
19
|
+
const serializedDateRange = useMemo(() => normalizeDateRange(debouncedDateRangeValue ?? undefined), [debouncedDateRangeValue]);
|
|
20
|
+
const query = useQuery({
|
|
21
|
+
enabled: !isDisabled,
|
|
22
|
+
queryKey: [name, url, debounced.page, debounced.count, debounced.search, serializedDateRange, serializedFilters],
|
|
23
|
+
queryFn: async ({ signal }) => {
|
|
24
|
+
const params = new URLSearchParams();
|
|
25
|
+
params.set("page", page.toString());
|
|
26
|
+
params.set("count", count.toString());
|
|
27
|
+
if (debounced.search)
|
|
28
|
+
params.set("search", debounced.search);
|
|
29
|
+
if (dateRange) {
|
|
30
|
+
const { from, to } = dateRange;
|
|
31
|
+
params.set("from", toMoment(from).format("YYYY-MM-DD"));
|
|
32
|
+
params.set("to", toMoment(to).format("YYYY-MM-DD"));
|
|
33
|
+
}
|
|
34
|
+
if (filters?.length) {
|
|
35
|
+
for (const { key, values } of filters) {
|
|
36
|
+
params.set(key, values.join(","));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return localApi.get(url, { signal, params })
|
|
40
|
+
.then(({ data }) => data.ok ? data : null);
|
|
41
|
+
},
|
|
42
|
+
placeholderData: (prev) => prev,
|
|
43
|
+
staleTime: 1000 * 30
|
|
44
|
+
});
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
setCount((count) => initial?.count ?? count);
|
|
47
|
+
setPage((page) => initial?.page ?? page);
|
|
48
|
+
setSearch((search) => initial?.search ?? search);
|
|
49
|
+
setDateRange((range) => initial?.range ?? range);
|
|
50
|
+
}, [initial]);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
setPage(1);
|
|
53
|
+
}, [debounced.count, debounced.search, serializedFilters, serializedDateRange]);
|
|
54
|
+
return {
|
|
55
|
+
query,
|
|
56
|
+
page, setPage,
|
|
57
|
+
count, setCount,
|
|
58
|
+
search, setSearch,
|
|
59
|
+
dateRange, setDateRange
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
// prettier-ignore
|
|
63
|
+
const normalizeFilters = (filters) => _(filters).map((f) => ({
|
|
64
|
+
key: f.key,
|
|
65
|
+
values: _.sortBy(f.values)
|
|
66
|
+
}))
|
|
67
|
+
.sortBy("key")
|
|
68
|
+
.value();
|
|
69
|
+
// prettier-ignore
|
|
70
|
+
const normalizeDateRange = (range) => {
|
|
71
|
+
if (!range?.from || !range?.to)
|
|
72
|
+
return "";
|
|
73
|
+
const from = toMoment(range.from).format("YYYY-MM-DD");
|
|
74
|
+
const to = toMoment(range.to).format("YYYY-MM-DD");
|
|
75
|
+
return [from, to].join("_");
|
|
76
|
+
};
|
|
77
|
+
// prettier-ignore
|
|
78
|
+
export const usePaginationLocalCalculator = ({ items, pageIndex, rowCount, search }) => {
|
|
79
|
+
const [canPrev, setCanPrev] = useState(false);
|
|
80
|
+
const [canNext, setCanNext] = useState(false);
|
|
81
|
+
const [currentData, setCurrentData] = useState(items);
|
|
82
|
+
const [totalPages, setTotalPages] = useState(1);
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
const filteredItems = search
|
|
85
|
+
? items.filter((item) => JSON.stringify(item).toLowerCase().includes(search.toLowerCase()))
|
|
86
|
+
: items;
|
|
87
|
+
const totalPages = Math.ceil(filteredItems.length / rowCount) || 1;
|
|
88
|
+
const canPrev = (pageIndex + 1) > 1;
|
|
89
|
+
const canNext = (pageIndex + 1) < totalPages;
|
|
90
|
+
const startIndex = pageIndex * rowCount;
|
|
91
|
+
const data = filteredItems.slice(startIndex, startIndex + rowCount);
|
|
92
|
+
setCurrentData(data);
|
|
93
|
+
setCanNext(canNext);
|
|
94
|
+
setCanPrev(canPrev);
|
|
95
|
+
setTotalPages(totalPages);
|
|
96
|
+
}, [items, pageIndex, search, rowCount]);
|
|
97
|
+
return { canPrev, canNext, currentData, totalPages };
|
|
98
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as xlsx from "xlsx";
|
|
2
|
+
import { FieldValues, Path } from "react-hook-form";
|
|
3
|
+
export type TExcelToJsonResult<T extends FieldValues> = {
|
|
4
|
+
headers: Array<{
|
|
5
|
+
normalized: Path<T>;
|
|
6
|
+
original: string;
|
|
7
|
+
}>;
|
|
8
|
+
data: Array<T>;
|
|
9
|
+
metadata: xlsx.FullProperties | undefined;
|
|
10
|
+
};
|
|
11
|
+
type TUseExcelReader<T extends FieldValues> = {
|
|
12
|
+
headerRowIndex?: number;
|
|
13
|
+
rowStartIndex: number;
|
|
14
|
+
normalizeKeys: Partial<Record<string, Path<T>>>;
|
|
15
|
+
dateKeys?: Array<Path<T>>;
|
|
16
|
+
};
|
|
17
|
+
export declare const useExcelReader: <T extends FieldValues>({ normalizeKeys, dateKeys, rowStartIndex, headerRowIndex }: TUseExcelReader<T>) => {
|
|
18
|
+
readWithId: (buffer: Buffer) => Record<string, TExcelToJsonResult<T & {
|
|
19
|
+
_id: string;
|
|
20
|
+
}>>;
|
|
21
|
+
};
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import _ from "lodash";
|
|
2
|
+
import * as xlsx from "xlsx";
|
|
3
|
+
// prettier-ignore
|
|
4
|
+
export const useExcelReader = ({ normalizeKeys, dateKeys, rowStartIndex, headerRowIndex = 0 }) => {
|
|
5
|
+
const readWithId = (buffer) => {
|
|
6
|
+
const result = {};
|
|
7
|
+
const workbook = xlsx.read(buffer, { type: "buffer" });
|
|
8
|
+
for (const sheetName of workbook.SheetNames) {
|
|
9
|
+
const sheet = workbook.Sheets[sheetName];
|
|
10
|
+
const rows = xlsx.utils.sheet_to_json(sheet, {
|
|
11
|
+
header: 1,
|
|
12
|
+
defval: null,
|
|
13
|
+
raw: true,
|
|
14
|
+
});
|
|
15
|
+
const excelHeaders = rows[headerRowIndex];
|
|
16
|
+
const headers = excelHeaders.map((header) => normalizeKeys[header] || header);
|
|
17
|
+
const data = rows.slice(rowStartIndex).map((row) => {
|
|
18
|
+
const o = {};
|
|
19
|
+
headers.forEach((key, index) => {
|
|
20
|
+
let value = row[index];
|
|
21
|
+
const isDate = dateKeys?.includes(key) && typeof value === "number";
|
|
22
|
+
if (isDate) {
|
|
23
|
+
const parsed = xlsx.SSF.parse_date_code(value);
|
|
24
|
+
if (parsed)
|
|
25
|
+
value = new Date(parsed.y, parsed.m - 1, parsed.d);
|
|
26
|
+
}
|
|
27
|
+
o[key] = value;
|
|
28
|
+
});
|
|
29
|
+
return {
|
|
30
|
+
...o,
|
|
31
|
+
_id: crypto.randomUUID()
|
|
32
|
+
};
|
|
33
|
+
})
|
|
34
|
+
.filter((row) => Object.values(row).some((v) => !_.isNil(v)));
|
|
35
|
+
result[sheetName] = {
|
|
36
|
+
// @ts-expect-error data
|
|
37
|
+
data,
|
|
38
|
+
// @ts-expect-error Path<T>
|
|
39
|
+
headers: headers.map((normalized, index) => ({
|
|
40
|
+
normalized,
|
|
41
|
+
original: excelHeaders[index]
|
|
42
|
+
})),
|
|
43
|
+
metadata: workbook.Props
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
return { readWithId };
|
|
49
|
+
};
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sharpcodes-heroui",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.7",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.js",
|
|
@@ -35,12 +35,13 @@
|
|
|
35
35
|
"react-haiku": "^2.4.1",
|
|
36
36
|
"react-hook-form": "^7.72.1",
|
|
37
37
|
"use-local-storage-state": "^19.5.0",
|
|
38
|
+
"xlsx": "^0.18.5",
|
|
38
39
|
"zod": "^4.3.6"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|
|
41
42
|
"@eslint/js": "^9.39.4",
|
|
42
43
|
"@types/lodash": "^4.17.24",
|
|
43
|
-
"@types/node": "^
|
|
44
|
+
"@types/node": "^25.6.0",
|
|
44
45
|
"@types/react": "^19.2.14",
|
|
45
46
|
"@types/react-dom": "^19.2.3",
|
|
46
47
|
"@vitejs/plugin-react": "^6.0.1",
|