mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-15 20:17:22 +00:00
admin: fix useSearch
This commit is contained in:
@@ -104,15 +104,17 @@ export function DataTable<Data extends Record<string, any> = Record<string, any>
|
||||
<button
|
||||
type="button"
|
||||
className={twMerge(
|
||||
"link hover:bg-primary/5 py-1.5 rounded-md inline-flex flex-row justify-start items-center gap-1",
|
||||
onClickSort ? "pl-2.5 pr-1" : "px-2.5",
|
||||
"py-1.5 rounded-md inline-flex flex-row justify-start items-center gap-1",
|
||||
onClickSort
|
||||
? "link hover:bg-primary/5 pl-2.5 pr-1"
|
||||
: "px-2.5",
|
||||
)}
|
||||
onClick={() => onClickSort?.(property)}
|
||||
>
|
||||
<span className="text-left text-nowrap whitespace-nowrap">
|
||||
{label}
|
||||
</span>
|
||||
{onClickSort && (
|
||||
{(onClickSort || (sort && sort.by === property)) && (
|
||||
<SortIndicator sort={sort} field={property} />
|
||||
)}
|
||||
</button>
|
||||
|
||||
@@ -1,32 +1,41 @@
|
||||
import { decodeSearch, encodeSearch, mergeObject, parseDecode } from "core/utils";
|
||||
import { decodeSearch, encodeSearch, mergeObject } from "core/utils";
|
||||
import { isEqual, transform } from "lodash-es";
|
||||
import { useLocation, useSearch as useWouterSearch } from "wouter";
|
||||
import { type s, parse, cloneSchema } from "core/object/schema";
|
||||
import { type s, parse } from "core/object/schema";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export type UseSearchOptions<Schema extends s.TAnySchema = s.TAnySchema> = {
|
||||
defaultValue?: Partial<s.StaticCoerced<Schema>>;
|
||||
beforeEncode?: (search: Partial<s.StaticCoerced<Schema>>) => object;
|
||||
};
|
||||
|
||||
// @todo: migrate to Typebox
|
||||
export function useSearch<Schema extends s.TAnySchema = s.TAnySchema>(
|
||||
_schema: Schema,
|
||||
defaultValue?: Partial<s.StaticCoerced<Schema>>,
|
||||
schema: Schema,
|
||||
options?: UseSearchOptions<Schema>,
|
||||
) {
|
||||
const schema = cloneSchema(_schema as any) as s.TSchema;
|
||||
const searchString = useWouterSearch();
|
||||
const [location, navigate] = useLocation();
|
||||
const initial = searchString.length > 0 ? decodeSearch(searchString) : (defaultValue ?? {});
|
||||
const value = parse(schema, initial, {
|
||||
withDefaults: true,
|
||||
clone: true,
|
||||
}) as s.StaticCoerced<Schema>;
|
||||
const [value, setValue] = useState<s.StaticCoerced<Schema>>(
|
||||
options?.defaultValue ?? ({} as any),
|
||||
);
|
||||
const _defaults = mergeObject(
|
||||
// @ts-ignore
|
||||
schema.template({ withOptional: true }),
|
||||
options?.defaultValue ?? {},
|
||||
);
|
||||
|
||||
// @ts-ignore
|
||||
const _defaults = mergeObject(schema.template({ withOptional: true }), defaultValue ?? {});
|
||||
useEffect(() => {
|
||||
const initial =
|
||||
searchString.length > 0 ? decodeSearch(searchString) : (options?.defaultValue ?? {});
|
||||
const v = parse(schema, Object.assign({}, _defaults, initial)) as any;
|
||||
setValue(v);
|
||||
}, [searchString, JSON.stringify(options?.defaultValue), location]);
|
||||
|
||||
function set<Update extends Partial<s.StaticCoerced<Schema>>>(update: Update): void {
|
||||
// @ts-ignore
|
||||
if (schema.validate(update).valid) {
|
||||
const search = getWithoutDefaults(mergeObject(value, update), _defaults);
|
||||
const encoded = encodeSearch(search, { encode: false });
|
||||
navigate(location + (encoded.length > 0 ? "?" + encoded : ""));
|
||||
}
|
||||
const search = getWithoutDefaults(Object.assign({}, value, update), _defaults);
|
||||
const prepared = options?.beforeEncode?.(search) ?? search;
|
||||
const encoded = encodeSearch(prepared, { encode: false });
|
||||
navigate(location + (encoded.length > 0 ? "?" + encoded : ""));
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -257,15 +257,20 @@ function EntityDetailInner({
|
||||
}) {
|
||||
const other = relation.other(entity);
|
||||
const [navigate] = useNavigate();
|
||||
|
||||
const search = {
|
||||
const [search, setSearch] = useState({
|
||||
select: other.entity.getSelect(undefined, "table"),
|
||||
sort: other.entity.getDefaultSort(),
|
||||
limit: 10,
|
||||
offset: 0,
|
||||
};
|
||||
});
|
||||
|
||||
// @todo: add custom key for invalidation
|
||||
const $q = useApiQuery((api) =>
|
||||
api.data.readManyByReference(entity.name, id, other.reference, search),
|
||||
const $q = useApiQuery(
|
||||
(api) => api.data.readManyByReference(entity.name, id, other.reference, search),
|
||||
{
|
||||
keepPreviousData: true,
|
||||
revalidateOnFocus: true,
|
||||
},
|
||||
);
|
||||
|
||||
function handleClickRow(row: Record<string, any>) {
|
||||
@@ -300,11 +305,17 @@ function EntityDetailInner({
|
||||
select={search.select}
|
||||
data={$q.data ?? null}
|
||||
entity={other.entity}
|
||||
sort={search.sort}
|
||||
onClickRow={handleClickRow}
|
||||
onClickNew={handleClickNew}
|
||||
page={1}
|
||||
page={Math.floor(search.offset / search.limit) + 1}
|
||||
total={$q.data?.body?.meta?.count ?? 1}
|
||||
/*onClickPage={handleClickPage}*/
|
||||
onClickPage={(page) => {
|
||||
setSearch((s) => ({
|
||||
...s,
|
||||
offset: (page - 1) * s.limit,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -35,8 +35,19 @@ export function DataEntityList({ params }) {
|
||||
useBrowserTitle(["Data", entity?.label ?? params.entity]);
|
||||
const [navigate] = useNavigate();
|
||||
const search = useSearch(searchSchema, {
|
||||
select: entity.getSelect(undefined, "table"),
|
||||
sort: entity.getDefaultSort(),
|
||||
defaultValue: {
|
||||
select: entity.getSelect(undefined, "table"),
|
||||
sort: entity.getDefaultSort(),
|
||||
},
|
||||
beforeEncode: (v) => {
|
||||
if ("sort" in v && v.sort) {
|
||||
return {
|
||||
...v,
|
||||
sort: `${v.sort.dir === "asc" ? "" : "-"}${v.sort.by}`,
|
||||
};
|
||||
}
|
||||
return v;
|
||||
},
|
||||
});
|
||||
|
||||
const $q = useApiQuery(
|
||||
|
||||
Reference in New Issue
Block a user