Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/components/entities/relationships/EntityRelationshipForm.tsx
T

230 lines
8.9 KiB
TypeScript

import { useNavigation } from "react-router";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import FormGroup from "~/components/ui/forms/FormGroup";
import InputCheckboxWithDescription from "~/components/ui/input/InputCheckboxWithDescription";
import InputRadioGroup from "~/components/ui/input/InputRadioGroup";
import InputSelector from "~/components/ui/input/InputSelector";
import InputText from "~/components/ui/input/InputText";
import { EntityWithDetails } from "~/utils/db/entities/entities.db.server";
import { EntityRelationshipWithDetails } from "~/utils/db/entities/entityRelationships.db.server";
interface Props {
entity: EntityWithDetails;
entities: EntityWithDetails[];
item?: EntityRelationshipWithDetails;
}
export default function EntityRelationshipForm({ entity, entities, item }: Props) {
const { t } = useTranslation();
const navigation = useNavigation();
const [type, setType] = useState<string>(!item ? "child" : item.parentId === entity?.id ? "parent" : "child");
const [parentId, setParentId] = useState<string | undefined>(item?.parentId);
const [childId, setChildId] = useState<string | undefined>(item?.childId);
const [child, setChild] = useState<EntityWithDetails>();
const [parent, setParent] = useState<EntityWithDetails>();
const [title, setTitle] = useState(item?.title ?? "");
const [relationshipType, setRelationshipType] = useState(item?.type ?? "one-to-many");
const [required, setRequired] = useState(item ? item.required : false);
const [cascade, setCascade] = useState(item ? item.cascade : false);
const [readOnly, setReadOnly] = useState(item ? item.readOnly : false);
const [hiddenIfEmpty, setHiddenIfEmpty] = useState(item ? item.hiddenIfEmpty : false);
const [childEntityViewId, setChildEntityViewId] = useState(item?.childEntityViewId ?? undefined);
const [parentEntityViewId, setParentEntityViewId] = useState(item?.parentEntityViewId ?? undefined);
useEffect(() => {
if (type === "parent") {
setParentId(entity?.id);
setChildId(undefined);
} else {
setParentId(undefined);
setChildId(entity?.id);
}
}, [entity, type, entities]);
useEffect(() => {
setChild(entities.find((i) => i.id === childId));
}, [childId, entities]);
useEffect(() => {
setParent(entities.find((i) => i.id === parentId));
}, [parentId, entities]);
return (
<div className="space-y-2">
{/* <h3 className="border-b border-border pb-4 text-lg font-medium leading-3 text-foreground">{t(entity.title)} relationship</h3> */}
<FormGroup
id={item?.id}
editing={true}
state={{
loading: navigation.state === "loading",
submitting: navigation.state === "submitting",
}}
>
<div className="grid grid-cols-2 gap-2">
<InputRadioGroup
className="col-span-2"
name="type"
title={t("models.relationship.form.direction")}
value={type}
disabled={item !== undefined}
setValue={(e) => setType(e?.toString() ?? "")}
options={[
{
name: t("models.relationship.form.entityIsParent", { entity: t(entity.title) }),
value: "parent",
},
{
name: t("models.relationship.form.entityIsChild", { entity: t(entity.title) }),
value: "child",
},
]}
/>
{type === "child" && (
<InputSelector
className="col-span-2"
withSearch={false}
name="parentId"
title={t("models.relationship.form.parentEntity")}
value={parentId}
disabled={item !== undefined}
setValue={(e) => setParentId(e?.toString() ?? "")}
options={entities.map((i) => {
return {
value: i.id,
name: t(i.title),
};
})}
required
/>
)}
{type === "parent" && (
<InputSelector
className="col-span-2"
withSearch={false}
name="childId"
title={t("models.relationship.form.childEntity")}
value={childId}
disabled={item !== undefined}
setValue={(e) => setChildId(e?.toString() ?? "")}
options={entities.map((i) => {
return {
value: i.id,
name: t(i.title),
};
})}
required
/>
)}
<InputSelector
withSearch={false}
className="col-span-2"
name="relationshipType"
title={t("models.relationship.form.relationshipType")}
value={relationshipType}
setValue={(e) => setRelationshipType(e?.toString() ?? "one-to-many")}
options={[
{ name: t("models.relationship.types.oneToMany"), value: "one-to-many" },
{ name: t("models.relationship.types.oneToOne"), value: "one-to-one" },
{ name: t("models.relationship.types.manyToOne"), value: "many-to-one" },
{ name: t("models.relationship.types.manyToMany"), value: "many-to-many" },
]}
required
/>
<InputSelector
disabled={child?.views.filter((f) => f.isSystem).length === 0}
withSearch={false}
className="col-span-2"
name="childEntityViewId"
title={t("models.relationship.form.childrenView")}
value={childEntityViewId}
setValue={(e) => setChildEntityViewId(e?.toString() ?? undefined)}
options={
child?.views
.filter((f) => f.isSystem)
.map((f) => {
return {
value: f.id,
name: `${f.title} (${f.layout})`,
};
}) ?? []
}
hint={
<>
{childEntityViewId !== undefined && (
<button type="button" onClick={() => setChildEntityViewId(undefined)} className="text-muted-foreground hover:text-foreground/80 text-sm">
{t("shared.clear")}
</button>
)}
</>
}
/>
<InputSelector
disabled={parent?.views.filter((f) => f.isSystem).length === 0}
withSearch={false}
className="col-span-2"
name="parentEntityViewId"
title={t("models.relationship.form.parentView")}
value={parentEntityViewId}
setValue={(e) => setParentEntityViewId(e?.toString() ?? undefined)}
options={
parent?.views
.filter((f) => f.isSystem)
.map((f) => {
return {
value: f.id,
name: `${f.title} (${f.layout})`,
};
}) ?? []
}
hint={
<>
{childEntityViewId !== undefined && (
<button type="button" onClick={() => setChildEntityViewId(undefined)} className="text-muted-foreground hover:text-foreground/80 text-sm">
{t("shared.clear")}
</button>
)}
</>
}
/>
<InputCheckboxWithDescription
className="col-span-2"
name="required"
title={t("models.relationship.required")}
description={t("models.relationship.form.descriptions.required")}
value={required}
setValue={(e) => setRequired(Boolean(e))}
/>
<InputCheckboxWithDescription
className="col-span-2"
name="cascade"
title={t("models.relationship.form.cascadeDelete")}
description={t("models.relationship.form.descriptions.cascadeDelete")}
value={cascade}
setValue={(e) => setCascade(Boolean(e))}
/>
<InputCheckboxWithDescription
className="col-span-2"
name="readOnly"
title={t("models.relationship.form.readOnly")}
description={t("models.relationship.form.descriptions.readOnly")}
value={readOnly}
setValue={(e) => setReadOnly(Boolean(e))}
/>
<InputCheckboxWithDescription
className="col-span-2"
name="hiddenIfEmpty"
title={t("models.relationship.form.hiddenIfEmpty")}
description={t("models.relationship.form.descriptions.hiddenIfEmpty")}
value={hiddenIfEmpty}
setValue={(e) => setHiddenIfEmpty(Boolean(e))}
/>
<InputText className="col-span-2" name="title" title={t("models.relationship.form.titleOptional")} value={title} setValue={(e) => setTitle(e)} />
</div>
</FormGroup>
</div>
);
}