@bouko/react 3.1.6 → 3.1.8

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.
@@ -1,3 +1,8 @@
1
1
  export { AuthProvider } from "./provider";
2
- export { useAuth } from "./context";
3
2
  export * from "./redirect";
3
+ export declare function useAuth(): {
4
+ session: import("@supabase/auth-js").Session | null;
5
+ accessToken: string | undefined;
6
+ user: import("@supabase/auth-js").User | null;
7
+ loading: boolean;
8
+ };
@@ -1,3 +1,7 @@
1
+ import { useAuth as useAuthBase } from "./context";
1
2
  export { AuthProvider } from "./provider";
2
- export { useAuth } from "./context";
3
3
  export * from "./redirect";
4
+ export function useAuth() {
5
+ const { session, ...auth } = useAuthBase();
6
+ return { ...auth, session, accessToken: session?.access_token };
7
+ }
@@ -1,19 +1,36 @@
1
1
  type Options<T> = {
2
- fetcher: (query: PaginationQuery) => Promise<T[]>;
2
+ fetcher: (query: PageQuery) => Promise<T[] | {
3
+ items: T[];
4
+ total?: number;
5
+ totalPages?: number;
6
+ }>;
3
7
  pageSize: number;
4
8
  };
5
- type PaginationQuery = {
9
+ export type PageQuery = {
6
10
  page: number;
7
11
  pageSize: number;
8
12
  refresh?: boolean;
9
13
  };
14
+ export type PageState<T> = {
15
+ page: number;
16
+ isLoading: boolean;
17
+ items: T[];
18
+ totalPages: number;
19
+ fetchedAt: Date | null;
20
+ prev: () => void;
21
+ next: () => void;
22
+ jump: (page: number) => void;
23
+ refresh: () => void;
24
+ };
10
25
  export declare const useSearchParam: (key: string) => string | null;
11
26
  export declare function usePagination<T>({ fetcher, pageSize }: Options<T>): {
12
27
  items: T[];
13
- loading: boolean;
28
+ isLoading: boolean;
14
29
  page: number;
30
+ totalPages: number;
15
31
  prev: () => void;
16
32
  next: () => void;
33
+ jump: (target: number) => void;
17
34
  refresh: () => Promise<void>;
18
35
  fetchedAt: Date | null;
19
36
  };
@@ -7,35 +7,77 @@ export const useSearchParam = (key) => {
7
7
  export function usePagination({ fetcher, pageSize }) {
8
8
  const [params, setParams] = useSearchParams();
9
9
  const [items, setItems] = useState([]);
10
+ const [totalPages, setTotalPages] = useState(0);
10
11
  const [loading, setLoading] = useState(false);
11
12
  const [fetchedAt, setFetchedAt] = useState(null);
12
13
  const raw = params.get("page");
13
14
  const page = Math.max(1, Number(raw) || 1);
14
- const setPage = (nextPage) => {
15
- params.set("page", String(Math.max(1, nextPage)));
16
- setParams(params);
17
- };
15
+ const setPage = useCallback((nextPage) => {
16
+ const p = Math.max(1, Math.trunc(nextPage));
17
+ const next = new URLSearchParams(params.toString());
18
+ next.set("page", String(p));
19
+ setParams(next);
20
+ }, [params, setParams]);
21
+ const jump = useCallback((target) => setPage(target), [setPage]);
18
22
  const fetchPage = useCallback(async (refresh = false) => {
19
23
  setLoading(true);
20
- const result = await fetcher({
21
- page,
22
- pageSize,
23
- refresh
24
- });
25
- setItems(result);
26
- setFetchedAt(new Date());
27
- setLoading(false);
24
+ try {
25
+ const result = await fetcher({ page, pageSize, refresh });
26
+ // normalize result to { items, totalPages }
27
+ let resultItems = [];
28
+ let computedTotalPages = 0;
29
+ if (Array.isArray(result)) {
30
+ resultItems = result;
31
+ // can't compute total pages from array alone
32
+ computedTotalPages = 0;
33
+ }
34
+ else {
35
+ resultItems = result?.items ?? [];
36
+ if (typeof result?.totalPages === "number") {
37
+ computedTotalPages = Math.max(0, Math.trunc(result.totalPages));
38
+ }
39
+ else if (typeof result?.total === "number") {
40
+ computedTotalPages = Math.max(0, Math.ceil(result.total / pageSize));
41
+ }
42
+ else {
43
+ computedTotalPages = 0;
44
+ }
45
+ }
46
+ setItems(resultItems);
47
+ setTotalPages(computedTotalPages);
48
+ setFetchedAt(new Date());
49
+ }
50
+ finally {
51
+ setLoading(false);
52
+ }
28
53
  }, [page, pageSize]);
29
54
  useEffect(() => {
30
55
  fetchPage(false);
31
56
  }, [fetchPage]);
57
+ const prev = useCallback(() => {
58
+ if (page > 1)
59
+ setPage(page - 1);
60
+ }, [page, setPage]);
61
+ const next = useCallback(() => {
62
+ // if totalPages is known, don't advance past it
63
+ if (totalPages > 0) {
64
+ if (page < totalPages)
65
+ setPage(page + 1);
66
+ }
67
+ else {
68
+ // unknown total -> allow advancing
69
+ setPage(page + 1);
70
+ }
71
+ }, [page, setPage, totalPages]);
32
72
  return {
33
73
  items,
34
- loading,
74
+ isLoading: loading,
35
75
  page,
36
- prev: () => page > 1 ? setPage(page - 1) : undefined,
37
- next: () => !(page > 1 && items.length === 0) ? setPage(page + 1) : undefined,
76
+ totalPages,
77
+ prev,
78
+ next,
79
+ jump,
38
80
  refresh: () => fetchPage(true),
39
- fetchedAt
81
+ fetchedAt,
40
82
  };
41
83
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
 
3
3
  "name": "@bouko/react",
4
- "version": "3.1.6",
4
+ "version": "3.1.8",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
7
7
  "license": "MIT",