Fix some react hook form based prop types

Signed-off-by: Émile Ré <nemile.re@gmail.com>
This commit is contained in:
Émile Ré
2025-12-03 14:20:24 +04:00
parent 21d2246f30
commit f3d45623bd
6 changed files with 56 additions and 59 deletions

View File

@@ -17,28 +17,27 @@ const deleteCustomDomainMutation = graphql`
}
`;
type CustomDomain = {
readonly id: string;
readonly domain: string;
readonly sslStatus: string;
readonly dnsRecords?:
| readonly {
readonly type: string;
readonly name: string;
readonly value: string;
readonly ttl?: number;
readonly purpose: string;
}[]
| null;
readonly createdAt?: string | null;
readonly updatedAt?: string | null;
readonly sslExpiresAt?: string | null;
};
interface CustomDomainManagerProps {
organizationId: string;
customDomain:
| {
readonly id: string;
readonly domain: string;
readonly sslStatus: string;
readonly dnsRecords?:
| readonly {
readonly type: string;
readonly name: string;
readonly value: string;
readonly ttl?: number;
readonly purpose: string;
}[]
| null;
readonly createdAt?: string | null;
readonly updatedAt?: string | null;
readonly sslExpiresAt?: string | null;
}
| null
| undefined;
customDomain: CustomDomain | null | undefined;
}
export function CustomDomainManager({
@@ -58,7 +57,7 @@ export function CustomDomainManager({
const domain = customDomain;
const getStatusBadge = (domain: any) => {
const getStatusBadge = (domain: CustomDomain) => {
if (domain.sslStatus === "ACTIVE") {
return <Badge variant="success">{__("Active")}</Badge>;
}

View File

@@ -1,19 +1,16 @@
import type { ComponentProps, JSX, JSXElementConstructor } from "react";
import type { ComponentProps } from "react";
import { Field } from "@probo/ui";
import { Controller, type Control } from "react-hook-form";
import { Controller, type FieldValues } from "react-hook-form";
import { Select } from "@probo/ui";
type Props<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> =
ComponentProps<T> & {
control: Control<any>;
name: string;
};
type Props<T extends typeof Field | typeof Select, TFieldValues extends FieldValues = FieldValues> =
ComponentProps<T> & Omit<ComponentProps<typeof Controller<TFieldValues>>, "render">;
export function ControlledField({
export function ControlledField<TFieldValues extends FieldValues = FieldValues>({
control,
name,
...props
}: Props<typeof Field>) {
}: Props<typeof Field, TFieldValues>) {
return (
<Controller
control={control}

View File

@@ -1,21 +1,21 @@
import { Button, IconPlusLarge, IconTrashCan, Input, Label } from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { useFieldArray } from "react-hook-form";
import type { Control } from "react-hook-form";
import type { ArrayPath, Control, FieldValue, FieldValues, Path } from "react-hook-form";
import type { UseFormRegister } from "react-hook-form";
type Props = {
control: Control<any>;
register: UseFormRegister<any>;
type Props<TFieldValues extends FieldValues = FieldValues> = {
control: Control<TFieldValues>;
register: UseFormRegister<TFieldValues>;
};
/**
* A field to handle multiple emails
*/
export function EmailsField({ control, register }: Props) {
export function EmailsField<TFieldValues extends FieldValues = FieldValues>({ control, register }: Props<TFieldValues>) {
const { __ } = useTranslate();
const { fields, append, remove } = useFieldArray({
name: "additionalEmailAddresses",
name: "additionalEmailAddresses" as ArrayPath<TFieldValues>,
control,
});
@@ -26,7 +26,7 @@ export function EmailsField({ control, register }: Props) {
<div key={field.id} className="flex items-stretch">
<Input
className="w-full"
{...register(`additionalEmailAddresses.${index}`)}
{...register(`additionalEmailAddresses.${index}` as Path<TFieldValues>)}
type="email"
/>
<Button
@@ -40,7 +40,7 @@ export function EmailsField({ control, register }: Props) {
variant="tertiary"
type="button"
icon={IconPlusLarge}
onClick={() => append("")}
onClick={() => append("" as FieldValue<TFieldValues>)}
>
{__("Add email")}
</Button>

View File

@@ -1,30 +1,30 @@
import { Field, Combobox, ComboboxItem } from "@probo/ui";
import { Suspense, useMemo, useState, type ComponentProps } from "react";
import { useTranslate } from "@probo/i18n";
import { type Control, Controller } from "react-hook-form";
import { type Control, Controller, type FieldPath, type FieldValues } from "react-hook-form";
import { usePaginatedMeasures } from "/hooks/graph/usePaginatedMeasures";
type Props = {
type Props<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>> = {
organizationId: string;
control: Control<any>;
name: string;
control: Control<TFieldValues>;
name: TName;
label?: string;
error?: string;
disabled?: boolean;
} & ComponentProps<typeof Field>;
export function MeasureSelectField({
export function MeasureSelectField<TFieldValues extends FieldValues = FieldValues>({
organizationId,
control,
disabled,
...props
}: Props) {
}: Props<TFieldValues>) {
return (
<Field {...props}>
<Suspense
fallback={<Combobox onSearch={() => {}} placeholder="Loading..." disabled><div /></Combobox>}
>
<MeasureSelectWithQuery
<MeasureSelectWithQuery<TFieldValues>
organizationId={organizationId}
control={control}
name={props.name}
@@ -35,8 +35,8 @@ export function MeasureSelectField({
);
}
function MeasureSelectWithQuery(
props: Pick<Props, "organizationId" | "control" | "name" | "disabled">
function MeasureSelectWithQuery<TFieldValues extends FieldValues = FieldValues>(
props: Pick<Props<TFieldValues>, "organizationId" | "control" | "name" | "disabled">
) {
const { __ } = useTranslate();
const { name, organizationId, control, disabled } = props;

View File

@@ -1,29 +1,29 @@
import { Avatar, Field, Option, Select } from "@probo/ui";
import { Suspense, type ComponentProps } from "react";
import { useTranslate } from "@probo/i18n";
import { type Control, Controller } from "react-hook-form";
import { type Control, Controller, type FieldPath, type FieldValues } from "react-hook-form";
import { usePeople } from "/hooks/graph/PeopleGraph.ts";
type Props = {
type Props<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>> = {
organizationId: string;
control: Control<any>;
name: string;
control: Control<TFieldValues>;
name: TName;
label?: string;
error?: string;
optional?: boolean;
} & ComponentProps<typeof Field>;
export function PeopleSelectField({
export function PeopleSelectField<TFieldValues extends FieldValues = FieldValues>({
organizationId,
control,
...props
}: Props) {
}: Props<TFieldValues>) {
return (
<Field {...props}>
<Suspense
fallback={<Select variant="editor" loading placeholder="Loading..." />}
>
<PeopleSelectWithQuery
<PeopleSelectWithQuery<TFieldValues>
organizationId={organizationId}
control={control}
name={props.name}
@@ -35,9 +35,9 @@ export function PeopleSelectField({
);
}
function PeopleSelectWithQuery(
function PeopleSelectWithQuery<TFieldValues extends FieldValues = FieldValues>(
props: Pick<
Props,
Props<TFieldValues>,
"organizationId" | "control" | "name" | "disabled" | "optional"
>,
) {

View File

@@ -53,9 +53,6 @@ export default function AssetDetailsPage(props: Props) {
const { snapshotId } = useParams<{ snapshotId?: string }>();
const isSnapshotMode = Boolean(snapshotId);
const { isAuthorized } = use(PermissionsContext);
if (!assetEntry || !assetEntry.id) {
return <div>{__("Asset not found")}</div>;
}
validateSnapshotConsistency(assetEntry, snapshotId);
@@ -82,6 +79,10 @@ export default function AssetDetailsPage(props: Props) {
const updateAsset = useUpdateAsset();
if (!assetEntry || !assetEntry.id) {
return <div>{__("Asset not found")}</div>;
}
const onSubmit = handleSubmit(async (formData) => {
await updateAsset({
id: assetEntry.id!,