First Commit. Duplicate bunext-sqlite preset
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import adminCrudHandler from "../functions/frontend/admin-crud-handler";
|
||||
import _ from "lodash";
|
||||
import { AppData } from "../data/app-data";
|
||||
import useStatus from "@moduletrace/twui/hooks/useStatus";
|
||||
import type { BUN_SQLITE_BSQLITE_ALL_TYPEDEFS } from "@/db/types/db";
|
||||
import type { ApiReqParams, ClientAdminCrudParams, TableType } from "../types";
|
||||
import type { ServerQueryParam } from "@moduletrace/bun-sqlite";
|
||||
import EJSON from "../utils/ejson";
|
||||
|
||||
type Params<T extends {} = BUN_SQLITE_BSQLITE_ALL_TYPEDEFS> = Pick<
|
||||
ClientAdminCrudParams,
|
||||
"id" | "count"
|
||||
> & {
|
||||
table: TableType;
|
||||
sql_query?: ServerQueryParam<T>;
|
||||
debug?: boolean;
|
||||
page?: number;
|
||||
limit?: number;
|
||||
initial_res?: T[];
|
||||
ready?: boolean;
|
||||
request_query?: ApiReqParams<T>;
|
||||
};
|
||||
|
||||
export function useAdminCrudGet<T extends {} = BUN_SQLITE_BSQLITE_ALL_TYPEDEFS>({
|
||||
table,
|
||||
sql_query,
|
||||
count: add_count_param,
|
||||
debug,
|
||||
page: initial_page,
|
||||
limit: initial_limit,
|
||||
initial_res,
|
||||
ready: initial_ready,
|
||||
request_query,
|
||||
...args
|
||||
}: Params<T>) {
|
||||
const [res, setRes] = useState<T[] | undefined>(initial_res);
|
||||
const [count, setCount] = useState<number | undefined>();
|
||||
const [page, setPage] = useState<number>(initial_page || 1);
|
||||
const [limit, setLimit] = useState<number>(
|
||||
initial_limit || AppData["DefaultQueryLimit"],
|
||||
);
|
||||
const [query, setQuery] = useState<ServerQueryParam<T> | undefined>(
|
||||
sql_query,
|
||||
);
|
||||
|
||||
const { ready, setReady } = useStatus();
|
||||
|
||||
const fetching_ref = useRef(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (res) return;
|
||||
if (typeof initial_ready == "boolean" && !initial_ready) return;
|
||||
|
||||
fetching_ref.current = true;
|
||||
|
||||
const final_query = _.merge<ServerQueryParam<T>, ServerQueryParam<T>>(
|
||||
query || {},
|
||||
{ page, limit: query?.limit || limit },
|
||||
);
|
||||
|
||||
if (debug) {
|
||||
console.log("final_query", final_query);
|
||||
}
|
||||
|
||||
adminCrudHandler<T>({
|
||||
action: "get",
|
||||
table,
|
||||
sql_query: final_query,
|
||||
count: add_count_param,
|
||||
request_query,
|
||||
...args,
|
||||
})
|
||||
.then((result) => {
|
||||
if (debug) {
|
||||
console.log("Main result", result);
|
||||
}
|
||||
|
||||
setRes(result.payload || []);
|
||||
setCount(result?.count);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(`Error querying ${table} => ${err.message}`);
|
||||
setRes([]);
|
||||
})
|
||||
.finally(() => {
|
||||
if (!ready) {
|
||||
setTimeout(() => {
|
||||
fetching_ref.current = false;
|
||||
setReady(true);
|
||||
}, 1000);
|
||||
} else {
|
||||
fetching_ref.current = false;
|
||||
}
|
||||
});
|
||||
}, [res, initial_ready]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ready) return;
|
||||
if (fetching_ref.current) return;
|
||||
setRes(undefined);
|
||||
}, [page]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ready) return;
|
||||
if (fetching_ref.current) return;
|
||||
if (query) {
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set("q", EJSON.stringify(query || {}) || "");
|
||||
history.pushState(null, "", url);
|
||||
}
|
||||
setPage(1);
|
||||
setRes(undefined);
|
||||
}, [query]);
|
||||
|
||||
return {
|
||||
res,
|
||||
setRes,
|
||||
count,
|
||||
page,
|
||||
setPage,
|
||||
query,
|
||||
setQuery,
|
||||
limit,
|
||||
setLimit,
|
||||
ready,
|
||||
setReady,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { useContext } from "react";
|
||||
import { AppContext } from "@/src/pages/__root";
|
||||
|
||||
export function useAuthStatus() {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
const user = pageProps?.user;
|
||||
const user_types = pageProps?.user_types;
|
||||
|
||||
return {
|
||||
is_logged_in: !!user?.logged_in_status,
|
||||
user,
|
||||
user_types,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import _ from "lodash";
|
||||
import { AppData } from "../data/app-data";
|
||||
import useStatus from "@moduletrace/twui/hooks/useStatus";
|
||||
import adminFetchHandler from "../functions/frontend/admin-fetch-handler";
|
||||
import type { BUN_SQLITE_BSQLITE_ALL_TYPEDEFS } from "@/db/types/db";
|
||||
import type { AdminFetchParams, ApiReqParams } from "../types";
|
||||
import EJSON from "../utils/ejson";
|
||||
|
||||
type Params<T extends {} = BUN_SQLITE_BSQLITE_ALL_TYPEDEFS> = Omit<
|
||||
AdminFetchParams<T>,
|
||||
"method" | "body"
|
||||
> & {
|
||||
debug?: boolean;
|
||||
initial_res?: T[];
|
||||
count?: boolean;
|
||||
};
|
||||
|
||||
export function useFetchGet<T extends {} = BUN_SQLITE_BSQLITE_ALL_TYPEDEFS>({
|
||||
url,
|
||||
debug,
|
||||
initial_res,
|
||||
query: api_query_params,
|
||||
}: Params<T>) {
|
||||
const [res, setRes] = useState<T[] | undefined>(initial_res);
|
||||
const [count, setCount] = useState<number | undefined>();
|
||||
const [page, setPage] = useState<number>(api_query_params?.page || 1);
|
||||
const [limit, setLimit] = useState<number>(AppData["DefaultQueryLimit"]);
|
||||
const [query, setQuery] = useState<ApiReqParams<T> | undefined>(
|
||||
api_query_params,
|
||||
);
|
||||
|
||||
const { ready, setReady } = useStatus();
|
||||
|
||||
const fetching_ref = useRef(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (res) return;
|
||||
|
||||
fetching_ref.current = true;
|
||||
|
||||
const final_query = _.merge<ApiReqParams<T>, ApiReqParams<T>>(
|
||||
query || {},
|
||||
{ page },
|
||||
);
|
||||
|
||||
if (debug) {
|
||||
console.log("final_query", final_query);
|
||||
}
|
||||
|
||||
adminFetchHandler<T>({
|
||||
url,
|
||||
query: final_query,
|
||||
})
|
||||
.then((result) => {
|
||||
if (debug) {
|
||||
console.log("Main result", result);
|
||||
}
|
||||
|
||||
setRes(result.payload || []);
|
||||
setCount(result?.count);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(`Error => ${err.message}`);
|
||||
setRes([]);
|
||||
})
|
||||
.finally(() => {
|
||||
if (!ready) {
|
||||
setTimeout(() => {
|
||||
fetching_ref.current = false;
|
||||
setReady(true);
|
||||
}, 1000);
|
||||
} else {
|
||||
fetching_ref.current = false;
|
||||
}
|
||||
});
|
||||
}, [res]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ready) return;
|
||||
if (fetching_ref.current) return;
|
||||
setRes(undefined);
|
||||
}, [page]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ready) return;
|
||||
if (fetching_ref.current) return;
|
||||
if (query) {
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set("q", EJSON.stringify(query || {}) || "");
|
||||
history.pushState(null, "", url);
|
||||
}
|
||||
setPage(1);
|
||||
setRes(undefined);
|
||||
}, [query]);
|
||||
|
||||
return {
|
||||
res,
|
||||
setRes,
|
||||
count,
|
||||
page,
|
||||
setPage,
|
||||
query,
|
||||
setQuery,
|
||||
limit,
|
||||
setLimit,
|
||||
ready,
|
||||
setReady,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
import type { BUN_SQLITE_BSQLITE_ALL_TYPEDEFS } from "@/db/types/db";
|
||||
import useStatus from "@moduletrace/twui/hooks/useStatus";
|
||||
import {
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
type Dispatch,
|
||||
type SetStateAction,
|
||||
} from "react";
|
||||
import { AppContext } from "../pages/__root";
|
||||
import type { ImageInputToBase64FunctionReturn } from "@moduletrace/twui/utils/form/imageInputToBase64";
|
||||
import EJSON from "../utils/ejson";
|
||||
import twuiSlugify from "@moduletrace/twui/utils/slugify";
|
||||
import _ from "lodash";
|
||||
import type { AppContextObject } from "../types";
|
||||
|
||||
type Params<T extends {} = BUN_SQLITE_BSQLITE_ALL_TYPEDEFS> = {
|
||||
/**
|
||||
* Existing record for update. All unneccasary fields
|
||||
* like join fields should be excluded.
|
||||
*/
|
||||
existing?: T;
|
||||
/**
|
||||
* Full Existing record with all unneccessary
|
||||
* Fields like join fields.
|
||||
*/
|
||||
existing_full?: T;
|
||||
default?: T;
|
||||
/**
|
||||
* Form title.
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* Object keys to exclude from local storage.
|
||||
* This is useful for image base64 fields
|
||||
*/
|
||||
local_storage_exclude_keys?: (keyof T)[];
|
||||
/**
|
||||
* Async prep to run before the form is marked ready.
|
||||
* Useful for seeding derived fields from the existing record.
|
||||
*/
|
||||
before_ready_function?: (params: {
|
||||
form: T;
|
||||
setForm: Dispatch<SetStateAction<T>>;
|
||||
app_context: AppContextObject;
|
||||
}) => Promise<void>;
|
||||
};
|
||||
|
||||
export default function useFormInit<
|
||||
T extends {} = BUN_SQLITE_BSQLITE_ALL_TYPEDEFS,
|
||||
>(params?: Params<T>) {
|
||||
const appContext = useContext(AppContext);
|
||||
|
||||
const [form, setForm] = useState<T>(
|
||||
params?.existing || params?.default || ({} as T),
|
||||
);
|
||||
const [image, setImage] = useState<ImageInputToBase64FunctionReturn>();
|
||||
|
||||
const { loading, setLoading, status, setStatus, ready, setReady } =
|
||||
useStatus();
|
||||
|
||||
const form_title = params?.title;
|
||||
const local_storage_form_title = form_title
|
||||
? twuiSlugify(
|
||||
`${form_title.replace(/ ?form$/i, "")}_form_local_storage`,
|
||||
)
|
||||
: undefined;
|
||||
|
||||
const runBeforeReadyAndSetReady = () => {
|
||||
if (params?.before_ready_function) {
|
||||
params
|
||||
.before_ready_function({
|
||||
form,
|
||||
setForm,
|
||||
app_context: appContext,
|
||||
})
|
||||
.then(() => {})
|
||||
.catch((e2) => {
|
||||
console.log(`Before ready function error:`, e2.message);
|
||||
})
|
||||
.finally(() => {
|
||||
setReady(true);
|
||||
});
|
||||
} else {
|
||||
setReady(true);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!ready) return;
|
||||
|
||||
if (status) {
|
||||
setStatus(undefined);
|
||||
}
|
||||
|
||||
if (local_storage_form_title) {
|
||||
try {
|
||||
let form_to_store = _.cloneDeep(form);
|
||||
|
||||
if (params?.local_storage_exclude_keys) {
|
||||
params.local_storage_exclude_keys.forEach((k) => {
|
||||
delete form_to_store[k];
|
||||
});
|
||||
}
|
||||
|
||||
localStorage.setItem(
|
||||
local_storage_form_title,
|
||||
EJSON.stringify(form_to_store) || "",
|
||||
);
|
||||
} catch (error) {
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
}, [form, ready]);
|
||||
|
||||
useEffect(() => {
|
||||
if (local_storage_form_title) {
|
||||
try {
|
||||
const existing_form_in_local_storage = localStorage.getItem(
|
||||
local_storage_form_title,
|
||||
);
|
||||
const existing_ls_form_object = EJSON.parse(
|
||||
existing_form_in_local_storage,
|
||||
) as T | undefined;
|
||||
|
||||
if (existing_ls_form_object && !Object.keys(form)?.[0]) {
|
||||
setForm(existing_ls_form_object);
|
||||
}
|
||||
} catch (error) {
|
||||
} finally {
|
||||
runBeforeReadyAndSetReady();
|
||||
}
|
||||
} else {
|
||||
runBeforeReadyAndSetReady();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const clearLocalForm = useCallback(() => {
|
||||
if (local_storage_form_title) {
|
||||
localStorage.removeItem(local_storage_form_title);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return {
|
||||
form,
|
||||
setForm,
|
||||
loading,
|
||||
setLoading,
|
||||
status,
|
||||
setStatus,
|
||||
existing: params?.existing,
|
||||
existing_full: params?.existing_full,
|
||||
app_context: appContext,
|
||||
image,
|
||||
setImage,
|
||||
clearLocalForm,
|
||||
ready,
|
||||
setReady,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
import fetchApi from "@moduletrace/twui/utils/fetch/fetchApi";
|
||||
import type useFormInit from "@/src/hooks/use-form-init";
|
||||
import { AppContext } from "@/src/pages/__root";
|
||||
import type { ApiReqParams, GoogleWindow } from "@/src/types";
|
||||
import type { APIResponseObject } from "@moduletrace/bunext/types";
|
||||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
|
||||
const GoogleScriptSelector =
|
||||
'script[src="https://accounts.google.com/gsi/client"]';
|
||||
|
||||
export type GoogleAuthMode = "login" | "signup";
|
||||
|
||||
type Params = Pick<
|
||||
ReturnType<typeof useFormInit>,
|
||||
"loading" | "setLoading" | "setStatus"
|
||||
> & {
|
||||
mode: GoogleAuthMode;
|
||||
};
|
||||
|
||||
export default function useGoogleAuth({
|
||||
loading,
|
||||
setStatus,
|
||||
setLoading,
|
||||
mode,
|
||||
}: Params) {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
|
||||
const googleButtonRef = useRef<HTMLDivElement>(null);
|
||||
const googleInitializedRef = useRef(false);
|
||||
const [scriptLoaded, setScriptLoaded] = useState(false);
|
||||
const [buttonWidth, setButtonWidth] = useState(0);
|
||||
const [googleReady, setGoogleReady] = useState(false);
|
||||
|
||||
const googleClientId = pageProps?.envs?.GOOGLE_CLIENT_ID;
|
||||
|
||||
const submitGoogleAuth = async (google_token: string) => {
|
||||
setLoading(true);
|
||||
|
||||
const res = await fetchApi<ApiReqParams, APIResponseObject>(
|
||||
`/api/auth/google-login`,
|
||||
{
|
||||
method: "POST",
|
||||
body: {
|
||||
google_token,
|
||||
google_signup: mode == "signup",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (res.success) {
|
||||
window.location.pathname = `/admin`;
|
||||
} else {
|
||||
setStatus({
|
||||
error: true,
|
||||
msg:
|
||||
res.msg ||
|
||||
(mode == "signup"
|
||||
? "Couldn't sign up with Google."
|
||||
: "Couldn't log in with Google."),
|
||||
});
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!googleClientId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const clientWindow = window as GoogleWindow;
|
||||
|
||||
if (clientWindow.google?.accounts?.id) {
|
||||
setScriptLoaded(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const existingScript = document.querySelector(
|
||||
GoogleScriptSelector,
|
||||
) as HTMLScriptElement | null;
|
||||
|
||||
const handleLoad = () => {
|
||||
setScriptLoaded(true);
|
||||
};
|
||||
|
||||
const handleError = () => {
|
||||
setStatus({
|
||||
error: true,
|
||||
msg: "Couldn't load Google sign-in.",
|
||||
});
|
||||
};
|
||||
|
||||
if (existingScript) {
|
||||
existingScript.addEventListener("load", handleLoad);
|
||||
existingScript.addEventListener("error", handleError);
|
||||
|
||||
return () => {
|
||||
existingScript.removeEventListener("load", handleLoad);
|
||||
existingScript.removeEventListener("error", handleError);
|
||||
};
|
||||
}
|
||||
|
||||
const script = document.createElement("script");
|
||||
script.src = "https://accounts.google.com/gsi/client";
|
||||
script.async = true;
|
||||
script.defer = true;
|
||||
script.addEventListener("load", handleLoad);
|
||||
script.addEventListener("error", handleError);
|
||||
|
||||
document.head.appendChild(script);
|
||||
|
||||
return () => {
|
||||
script.removeEventListener("load", handleLoad);
|
||||
script.removeEventListener("error", handleError);
|
||||
};
|
||||
}, [googleClientId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!googleButtonRef.current || typeof ResizeObserver === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
const nextWidth = Math.round(entries[0]?.contentRect.width || 0);
|
||||
|
||||
if (!nextWidth) {
|
||||
return;
|
||||
}
|
||||
|
||||
setButtonWidth((prev) => (prev === nextWidth ? prev : nextWidth));
|
||||
});
|
||||
|
||||
resizeObserver.observe(googleButtonRef.current);
|
||||
|
||||
return () => {
|
||||
resizeObserver.disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
!googleClientId ||
|
||||
!scriptLoaded ||
|
||||
!googleButtonRef.current ||
|
||||
!buttonWidth
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const googleId = (window as GoogleWindow).google?.accounts?.id;
|
||||
|
||||
if (!googleId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!googleInitializedRef.current) {
|
||||
googleId.initialize({
|
||||
client_id: googleClientId,
|
||||
callback: async ({ credential }) => {
|
||||
if (!credential) {
|
||||
setStatus({
|
||||
error: true,
|
||||
msg: "Google didn't return a sign-in token.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await submitGoogleAuth(credential);
|
||||
},
|
||||
});
|
||||
|
||||
googleInitializedRef.current = true;
|
||||
}
|
||||
|
||||
googleButtonRef.current.innerHTML = "";
|
||||
googleId.renderButton(googleButtonRef.current, {
|
||||
theme: "outline",
|
||||
size: "large",
|
||||
text: mode == "signup" ? "signup_with" : "signin_with",
|
||||
shape: "rectangular",
|
||||
width: Math.min(buttonWidth, 400),
|
||||
});
|
||||
setGoogleReady(true);
|
||||
}, [googleClientId, buttonWidth, scriptLoaded]);
|
||||
|
||||
const handleButtonClick = () => {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!googleInitializedRef.current) {
|
||||
setStatus({
|
||||
error: true,
|
||||
msg: "Google sign-in is still loading. Please try again.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
loading,
|
||||
handleButtonClick,
|
||||
googleButtonRef,
|
||||
googleReady,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { User } from "../types";
|
||||
import { useEffect, useState } from "react";
|
||||
import fetchApi from "@moduletrace/twui/utils/fetch/fetchApi";
|
||||
import type { BUN_SQLITE_BSQLITE_USER_TYPES } from "@/db/types/db";
|
||||
import type { APIResponseObject } from "@moduletrace/bunext/types";
|
||||
|
||||
export function useLocalUser() {
|
||||
const [user, setUser] = useState<User>();
|
||||
const [userTypes, setUserTypes] =
|
||||
useState<BUN_SQLITE_BSQLITE_USER_TYPES[]>();
|
||||
|
||||
useEffect(() => {
|
||||
fetchApi<any, APIResponseObject>(`/api/admin/user-auth`).then((res) => {
|
||||
if (res.singleRes) {
|
||||
setUser(res.singleRes as User);
|
||||
}
|
||||
if (res.payload) {
|
||||
setUserTypes(res.payload as BUN_SQLITE_BSQLITE_USER_TYPES[]);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
return {
|
||||
user,
|
||||
user_types: userTypes,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { useContext } from "react";
|
||||
import { AppContext } from "@/src/pages/__root";
|
||||
import type { LoginMethod } from "@/src/types";
|
||||
|
||||
/**
|
||||
* Site-wide login method from `AUTH_LOGIN_METHOD`, passed down by
|
||||
* `__root.server.ts`.
|
||||
*/
|
||||
export default function useLoginMethod(): LoginMethod {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
|
||||
return pageProps?.envs?.AUTH_LOGIN_METHOD == "password" ? "password" : "code";
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import readSSOPendingLogin from "@/src/functions/frontend/read-sso-pending-login";
|
||||
import type { SSOPendingLogin } from "@/src/types";
|
||||
|
||||
export default function useSSOPendingLogin() {
|
||||
const [pending, setPending] = useState<SSOPendingLogin>();
|
||||
|
||||
useEffect(() => {
|
||||
setPending(readSSOPendingLogin());
|
||||
}, []);
|
||||
|
||||
return pending;
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
import _ from "lodash";
|
||||
import useStatus from "@moduletrace/twui/hooks/useStatus";
|
||||
import adminFetchHandler from "../functions/frontend/admin-fetch-handler";
|
||||
import type { ApiReqParams } from "../types";
|
||||
import type { BUN_SQLITE_BSQLITE_USERS_JOIN } from "../types/sql-joins";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import EJSON from "../utils/ejson";
|
||||
|
||||
type Params = {
|
||||
query?: ApiReqParams;
|
||||
debug?: boolean;
|
||||
page?: number;
|
||||
initial_users?: BUN_SQLITE_BSQLITE_USERS_JOIN[];
|
||||
};
|
||||
|
||||
export function useUsersGet({
|
||||
query: req_query,
|
||||
debug,
|
||||
page: initial_page,
|
||||
initial_users,
|
||||
}: Params) {
|
||||
const [users, setUsers] = useState<
|
||||
BUN_SQLITE_BSQLITE_USERS_JOIN[] | undefined
|
||||
>(initial_users);
|
||||
const [count, setCount] = useState<number | undefined>();
|
||||
const [page, setPage] = useState<number>(initial_page || 1);
|
||||
const [usersQuery, setUsersQuery] = useState<ApiReqParams | undefined>(
|
||||
req_query,
|
||||
);
|
||||
|
||||
const { ready, setReady } = useStatus();
|
||||
|
||||
const fetching_ref = useRef(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (users) return;
|
||||
|
||||
fetching_ref.current = true;
|
||||
|
||||
const final_query = _.merge<ApiReqParams, ApiReqParams>(
|
||||
usersQuery || {},
|
||||
{
|
||||
page,
|
||||
count: true,
|
||||
},
|
||||
);
|
||||
|
||||
if (debug) {
|
||||
console.log("final_query", final_query);
|
||||
}
|
||||
|
||||
adminFetchHandler<BUN_SQLITE_BSQLITE_USERS_JOIN>({
|
||||
url: `/api/admin/grab-users`,
|
||||
query: final_query,
|
||||
})
|
||||
.then((result) => {
|
||||
if (debug) {
|
||||
console.log("Main result", result);
|
||||
}
|
||||
|
||||
setUsers(result.payload || []);
|
||||
setCount(result?.count);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(`Error querying users table => ${err.message}`);
|
||||
setUsers([]);
|
||||
})
|
||||
.finally(() => {
|
||||
if (!ready) {
|
||||
setTimeout(() => {
|
||||
fetching_ref.current = false;
|
||||
setReady(true);
|
||||
}, 1000);
|
||||
} else {
|
||||
fetching_ref.current = false;
|
||||
}
|
||||
});
|
||||
}, [users]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ready) return;
|
||||
if (fetching_ref.current) return;
|
||||
setUsers(undefined);
|
||||
}, [page]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ready) return;
|
||||
if (fetching_ref.current) return;
|
||||
if (usersQuery) {
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set("q", EJSON.stringify(usersQuery || {}) || "");
|
||||
history.pushState(null, "", url);
|
||||
}
|
||||
setPage(1);
|
||||
setUsers(undefined);
|
||||
}, [usersQuery]);
|
||||
|
||||
return {
|
||||
users,
|
||||
setUsers,
|
||||
count,
|
||||
page,
|
||||
setPage,
|
||||
usersQuery,
|
||||
setUsersQuery,
|
||||
ready,
|
||||
setReady,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user