import { getHotkeyHandler, useHotkeys } from "@mantine/hooks"; import type { FieldApi } from "@tanstack/react-form"; import { ucFirst } from "core/utils"; import type { EntityData, RelationField } from "data"; import { useEffect, useRef, useState } from "react"; import { TbEye } from "react-icons/tb"; import { useEntityQuery } from "ui/client"; import { useBknd } from "ui/client/bknd"; import { Button } from "ui/components/buttons/Button"; import * as Formy from "ui/components/form/Formy"; import { Popover } from "ui/components/overlay/Popover"; import { Link } from "ui/components/wouter/Link"; import { routes } from "ui/lib/routes"; import { useLocation } from "wouter"; import { EntityTable } from "../EntityTable"; // @todo: allow clear if not required export function EntityRelationalFormField({ fieldApi, field, data, disabled, tabIndex }: { fieldApi: FieldApi; field: RelationField; data?: EntityData; disabled?: boolean; tabIndex?: number; }) { const { app } = useBknd(); const entity = app.entity(field.target())!; const [query, setQuery] = useState({ limit: 10, page: 1, perPage: 10 }); const [, navigate] = useLocation(); const ref = useRef(null); const $q = useEntityQuery(field.target(), undefined, { limit: query.limit, offset: (query.page - 1) * query.limit }); const [_value, _setValue] = useState<{ id: number | undefined; [key: string]: any }>(); const referenceField = data?.[field.reference()]; const relationalField = data?.[field.name]; useEffect(() => { const value = data?.[field.reference()]; _setValue(value); }, [referenceField]); useEffect(() => { (async () => { const rel_value = field.target(); if (!rel_value || !relationalField) return; const fetched = await $q.api.readOne(field.target(), relationalField); if (fetched.ok && fetched.data) { _setValue(fetched.data as any); } })(); }, [relationalField]); function handleViewItem(e: React.MouseEvent) { e.preventDefault(); e.stopPropagation(); if (_value) { navigate(routes.data.entity.edit(entity.name, _value.id as any)); } } // fix missing value on fields that are required useEffect(() => { if (field.isRequired() && !fieldApi.state.value) { const firstValue = $q.data?.[0]; if (!firstValue) return; console.warn("setting first value because field is required", field.name, firstValue.id); fieldApi.setValue(firstValue.id); _setValue(firstValue as any); } }, [$q.data]); const fetching = $q.isLoading || $q.isValidating; return ( {field.getLabel({ fallback: false }) ?? entity.label}
( { fieldApi.setValue(row.id); _setValue(row as any); toggle(); }} onClickPage={(page) => { console.log("setting page", page); setQuery((prev) => ({ ...prev, page })); }} /> )} >
{ ref.current?.click(); } ] ])} > {_value ? ( <>
{ucFirst(entity.name)}
{_value && Object.entries(_value).map(([key, value]) => { const field = entity.getField(key)!; if (field.isHidden("table")) return null; const _value = field.getValue(value, "table"); return (
{field.getLabel()}: {" "} {_value !== null && typeof value !== "undefined" ? ( {_value} ) : ( null )}
); })}
) : (
- Select -
)}
); } const PopoverTable = ({ container, entity, query, toggle, onClickRow, onClickPage }) => { function handleNext() { if (query.limit * query.page < container.meta?.count) { onClickPage(query.page + 1); } } function handlePrev() { if (query.page > 1) { onClickPage(query.page - 1); } } useHotkeys([ ["ArrowRight", handleNext], ["ArrowLeft", handlePrev], ["Escape", toggle] ]); return (
); };