3
\$\begingroup\$

I've created my own AutoComplete form element based on @nextui-org/autocomplete to be able to use it along with react-hook-form. I am relatively new at TS, at least on generics, so I am not sure if I am overusing generics or have any mistakes really.

// AutoComplete.tsx

import {
  Autocomplete as NUIAutocomplete,
  AutocompleteItem as NUIAutocompleteItem,
  AutocompleteProps as NUIAutocompleteProps,
} from '@nextui-org/autocomplete';
import { CollectionChildren } from '@react-types/shared';
import React from 'react';
import { Control, FieldValues, Path, useController } from 'react-hook-form';

interface IAutoCompleteProps<T extends FieldValues, K extends object>
  extends Omit<NUIAutocompleteProps, 'children' | 'defaultItems'> {
  name: Path<T>;
  control: Control<T>;
  defaultItems?: Iterable<K>;
  children: CollectionChildren<K>;
}

const AutoComplete = <T extends FieldValues, K extends object>({
  name,
  control,
  variant = 'underlined',
  ...otherProps
}: IAutoCompleteProps<T, K>) => {
  const controller = useController({ name, control });

  return (
    <NUIAutocomplete
      aria-label={name}
      onSelectionChange={(value) => {
        console.log('value', value);
        controller.field.onChange(value);
      }}
      onClear={() => controller.field.onChange('')}
      {...controller.field}
      variant={variant}
      {...otherProps}
    >
      {otherProps.children as CollectionChildren<object>}
    </NUIAutocomplete>
  );
};

export default AutoComplete;

export const AutoCompleteItem = NUIAutocompleteItem;

And this is how I use it:

// EditClassroom.jsx

'use client';

import { Classroom, Grade } from '@prisma/client';
import React, { useEffect } from 'react';
import { SubmitHandler, useForm } from 'react-hook-form';

import { trpc } from '@/app/_trpc/client';

import { translateErrors } from '@/lib/translations';

import AutoComplete, {
  AutoCompleteItem,
} from '@/components/ui/form/AutoComplete';

interface IEditClassroomProps {
  onFinish: () => void;
  classroom?: Classroom;
}

const EditClassroom = ({ onFinish, classroom }: IEditClassroomProps) => {

  // ...

  const { data: grades } = trpc.grade.list.useQuery({});

  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
    reset,
    watch,

    setValue,
    control,
  } = useForm<Classroom>();

  // ...
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>

      {/*...*/}

      <AutoComplete
        name={'gradeId'}
        defaultItems={grades.results}
        isRequired={true}
        selectedKey={watch('gradeId')}
        label={t('recordFields.grade')}
        errorMessage={translateErrors(tErrors, 'gradeId', errors.gradeId)}
        control={control}
      >
        {(grade) => {
          return (
            <AutoCompleteItem key={grade.id} textValue={grade.name}>
              {grade.name}
            </AutoCompleteItem>
          );
        }}
      </AutoComplete>

      {/*...*/}

    </form>
  );
};

export default EditClassroom;


\$\endgroup\$

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.