"use client"; import { useState } from "react"; import { Button, Group, Stack } from "@mantine/core"; import { zod4Resolver } from "mantine-form-zod-resolver"; import { z } from "zod/v4"; import { objectEntries } from "@homarr/common"; import type { WidgetKind } from "@homarr/definitions"; import { createModal, useModalAction } from "@homarr/modals"; import type { SettingsContextProps } from "@homarr/settings/creator"; import { useI18n } from "@homarr/translation/client"; import { zodErrorMap } from "@homarr/validation/form/i18n"; import { widgetImports } from ".."; import { getInputForType } from "../_inputs"; import { FormProvider, useForm } from "../_inputs/form"; import type { BoardItemAdvancedOptions } from "../../../validation/src/shared"; import type { OptionsBuilderResult } from "../options"; import type { IntegrationSelectOption } from "../widget-integration-select"; import { WidgetIntegrationSelect } from "../widget-integration-select"; import { WidgetAdvancedOptionsModal } from "./widget-advanced-options-modal"; export interface WidgetEditModalState { options: Record; integrationIds: string[]; advancedOptions: BoardItemAdvancedOptions; } interface ModalProps { kind: TSort; value: WidgetEditModalState; onSuccessfulEdit: (value: WidgetEditModalState) => void; integrationData: IntegrationSelectOption[]; integrationSupport: boolean; settings: SettingsContextProps; } export const WidgetEditModal = createModal>(({ actions, innerProps }) => { const t = useI18n(); const [advancedOptions, setAdvancedOptions] = useState(innerProps.value.advancedOptions); // Translate the error messages z.config({ customError: zodErrorMap(t), }); const { definition } = widgetImports[innerProps.kind]; const options = definition.createOptions(innerProps.settings) as Record; const form = useForm({ mode: "controlled", initialValues: innerProps.value, validate: zod4Resolver( z.object({ options: z.object( objectEntries(options).reduce( (acc, [key, value]: [string, { type: string; validate?: z.ZodType }]) => { if (value.validate) { acc[key] = value.type === "multiText" ? z.array(value.validate).optional() : value.validate; } return acc; }, {} as Record>, ), ), integrationIds: z.array(z.string()), advancedOptions: z.object({ customCssClasses: z.array(z.string()), borderColor: z.string(), }), }), ), validateInputOnBlur: true, validateInputOnChange: true, }); const { openModal } = useModalAction(WidgetAdvancedOptionsModal); return (
{ innerProps.onSuccessfulEdit({ ...values, advancedOptions, }); actions.closeModal(); })} > {innerProps.integrationSupport && ( )} {Object.entries(options).map(([key, value]) => { const Input = getInputForType(value.type); if ( // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition !Input || // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition value.shouldHide?.( form.values.options as never, innerProps.integrationData .filter(({ id }) => form.values.integrationIds.includes(id)) .map(({ kind }) => kind), ) ) { return null; } return ( ); })}
); }).withOptions({ keepMounted: true, defaultTitle(t) { return t("item.edit.title"); }, size: "lg", });