This commit is contained in:
2025-12-23 13:42:50 -03:00
parent 22a2046fb1
commit 7ab0eab6bb
4 changed files with 150 additions and 117 deletions

View File

@@ -118,6 +118,7 @@ export function Assigned({ courses }: AssignedProps) {
onChange={onChange}
options={courses}
error={fieldState.error}
readOnly
/>
<ErrorMessage
@@ -142,6 +143,7 @@ export function Assigned({ courses }: AssignedProps) {
<InputGroup>
<InputGroupInput
className="pointer-events-none"
tabIndex={-1}
readOnly
value={currency.format(unit_price)}
/>

View File

@@ -20,8 +20,7 @@ import { CoursePicker } from '../_.$orgid.enrollments.add/course-picker'
import { MAX_ITEMS, type Course } from '../_.$orgid.enrollments.add/data'
const emptyRow = {
course: undefined,
quantity: undefined
course: undefined
}
type BulkProps = {
@@ -54,8 +53,15 @@ export function Bulk({ courses }: BulkProps) {
resolver: zodResolver(formSchema),
defaultValues: { items: [emptyRow] }
})
const { formState, control, handleSubmit, register, setValue, getValues } =
form
const {
formState,
control,
handleSubmit,
register,
setValue,
getValues,
setFocus
} = form
const { fields, remove, append } = useFieldArray({
control,
name: 'items'
@@ -96,15 +102,19 @@ export function Bulk({ courses }: BulkProps) {
control={control}
name={`items.${index}.course`}
render={({
field: { name, value, onChange },
field: { name, value, onChange, ref },
fieldState
}) => (
<div className="grid gap-1">
<CoursePicker
ref={ref}
name={name}
autoFocus={index === 0}
value={value}
onChange={onChange}
options={courses}
error={fieldState.error}
readOnly
/>
<ErrorMessage
@@ -139,6 +149,7 @@ export function Bulk({ courses }: BulkProps) {
<InputGroupAddon align="inline-end">
<InputGroupButton
type="button"
tabIndex={-1}
size="icon-xs"
className="border cursor-pointer"
onClick={() => {
@@ -157,6 +168,7 @@ export function Bulk({ courses }: BulkProps) {
<InputGroupAddon align="inline-end">
<InputGroupButton
type="button"
tabIndex={-1}
size="icon-xs"
className="border cursor-pointer"
onClick={() => {
@@ -172,6 +184,7 @@ export function Bulk({ courses }: BulkProps) {
<InputGroup>
<InputGroupInput
tabIndex={-1}
className="pointer-events-none"
readOnly
value={currency.format(course?.unit_price || 0)}
@@ -180,6 +193,7 @@ export function Bulk({ courses }: BulkProps) {
<InputGroup>
<InputGroupInput
tabIndex={-1}
className="pointer-events-none"
readOnly
value={currency.format(
@@ -207,8 +221,13 @@ export function Bulk({ courses }: BulkProps) {
<Button
type="button"
onClick={() => {
// @ts-ignore
onClick={() => append(emptyRow)}
append(emptyRow, { shouldFocus: false })
queueMicrotask(() => {
setFocus(`items.${fields.length}.course`)
})
}}
className="cursor-pointer"
disabled={fields.length == MAX_ITEMS}
variant="outline"

View File

@@ -1,4 +1,10 @@
import { use, useState, useMemo } from 'react'
import {
use,
useState,
useMemo,
forwardRef,
type InputHTMLAttributes
} from 'react'
import { useToggle } from 'ahooks'
import Fuse from 'fuse.js'
import {
@@ -32,19 +38,18 @@ import {
import { type Course } from './data'
interface CoursePickerProps {
interface CoursePickerProps extends Omit<
InputHTMLAttributes<HTMLInputElement>,
'value' | 'onChange'
> {
value?: Course
options: Promise<{ hits: any[] }>
onChange?: (value: any) => void
error?: any
}
export function CoursePicker({
value,
onChange,
options,
error
}: CoursePickerProps) {
export const CoursePicker = forwardRef<HTMLInputElement, CoursePickerProps>(
({ value, onChange, options, error, ...props }, ref) => {
const { hits } = use(options)
const [search, setSearch] = useState<string>('')
const [open, { set }] = useToggle()
@@ -58,7 +63,9 @@ export function CoursePicker({
}, [hits])
const filtered = useMemo(() => {
const results = !search ? hits : fuse.search(search).map(({ item }) => item)
const results = !search
? hits
: fuse.search(search).map(({ item }) => item)
return results.sort((a, b) => {
const comparison = a.name.localeCompare(b.name)
@@ -71,14 +78,17 @@ export function CoursePicker({
<PopoverTrigger asChild>
<InputGroup>
<InputGroupInput
readOnly
ref={ref}
placeholder="Curso"
value={value?.name || ''}
aria-invalid={!!error}
{...props}
/>
<InputGroupAddon>
<BookIcon />
</InputGroupAddon>
<InputGroupAddon align="inline-end">
<ChevronsUpDownIcon />
</InputGroupAddon>
@@ -152,4 +162,5 @@ export function CoursePicker({
</PopoverContent>
</Popover>
)
}
}
)

View File

@@ -263,6 +263,7 @@ export default function Route({
onChange={onChange}
options={courses}
error={fieldState.error}
readOnly
/>
<ErrorMessage