update calebndar
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import type { Route } from './+types/route'
|
||||
|
||||
import { ptBR } from 'react-day-picker/locale'
|
||||
import { useToggle } from 'ahooks'
|
||||
import {
|
||||
CalendarIcon,
|
||||
SearchIcon,
|
||||
@@ -10,7 +10,10 @@ import {
|
||||
PlusIcon
|
||||
} from 'lucide-react'
|
||||
import { Link } from 'react-router'
|
||||
import { useFieldArray, useForm } from 'react-hook-form'
|
||||
import { Controller, useFieldArray, useForm } from 'react-hook-form'
|
||||
import { Fragment, useState } from 'react'
|
||||
import { format } from 'date-fns'
|
||||
import { ptBR } from 'react-day-picker/locale'
|
||||
|
||||
import {
|
||||
Breadcrumb,
|
||||
@@ -20,11 +23,6 @@ import {
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator
|
||||
} from '@repo/ui/components/ui/breadcrumb'
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger
|
||||
} from '@repo/ui/components/ui/tooltip'
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
@@ -49,6 +47,7 @@ import {
|
||||
} from '@repo/ui/components/ui/popover'
|
||||
import { Label } from '@repo/ui/components/ui/label'
|
||||
import { Calendar } from '@repo/ui/components/ui/calendar'
|
||||
import { data } from 'react-router'
|
||||
|
||||
export function meta({}: Route.MetaArgs) {
|
||||
return [{ title: 'Adicionar matrícula' }]
|
||||
@@ -56,12 +55,23 @@ export function meta({}: Route.MetaArgs) {
|
||||
|
||||
export default function Route({}: Route.ComponentProps) {
|
||||
const form = useForm({ defaultValues: { enrollments: [{}] } })
|
||||
const { formState, control } = form
|
||||
const { fields, append, remove } = useFieldArray({
|
||||
const { formState, control, handleSubmit, getValues } = form
|
||||
const { fields, insert, remove, append } = useFieldArray({
|
||||
control,
|
||||
name: 'enrollments'
|
||||
})
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
console.log(data)
|
||||
}
|
||||
|
||||
const duplicateRow = (index: number, times: number = 1) => {
|
||||
const values = getValues(`enrollments.${index}`)
|
||||
Array.from({ length: times }, (_, i) => {
|
||||
insert(index + 1 + i, values)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-2.5">
|
||||
<Breadcrumb>
|
||||
@@ -78,7 +88,10 @@ export default function Route({}: Route.ComponentProps) {
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
|
||||
<div className="lg:max-w-4xl mx-auto space-y-2.5">
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="lg:max-w-4xl mx-auto space-y-2.5"
|
||||
>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-2xl">Adicionar matrícula</CardTitle>
|
||||
@@ -88,137 +101,91 @@ export default function Route({}: Route.ComponentProps) {
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="space-y-4">
|
||||
<table className="table-auto">
|
||||
<thead>
|
||||
<tr>
|
||||
<td className="text-foreground font-medium text-sm w-1/3">
|
||||
Colaborador
|
||||
</td>
|
||||
<td className="text-foreground font-medium text-sm w-1/3 pl-1">
|
||||
Curso
|
||||
</td>
|
||||
<td className="text-foreground font-medium text-sm w-1/3 pl-1">
|
||||
Matricular em
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{fields.map((field, index) => {
|
||||
return (
|
||||
<tr
|
||||
key={field.id}
|
||||
className="*:px-1 *:first:pl-0 *:last:pr-0"
|
||||
>
|
||||
<td className="py-1">
|
||||
<InputGroup>
|
||||
<InputGroupInput placeholder="Search..." />
|
||||
<InputGroupAddon>
|
||||
<SearchIcon />
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</td>
|
||||
<td className="py-1">
|
||||
<InputGroup>
|
||||
<InputGroupInput placeholder="Search..." />
|
||||
<InputGroupAddon>
|
||||
<SearchIcon />
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</td>
|
||||
<td className="py-1">
|
||||
<ScheduledForInput />
|
||||
</td>
|
||||
<td className="flex gap-1.5 py-1">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
tabIndex={-1}
|
||||
variant="outline"
|
||||
className="cursor-pointer"
|
||||
>
|
||||
<CopyIcon />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>Duplicar linha</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<div className="grid lg:grid-cols-[repeat(3,1fr)_auto] w-full gap-1.5">
|
||||
{/* Header */}
|
||||
<>
|
||||
<div className="max-lg:hidden text-foreground font-medium text-sm">
|
||||
Colaborador
|
||||
</div>
|
||||
<div className="max-lg:hidden text-foreground font-medium text-sm">
|
||||
Curso
|
||||
</div>
|
||||
<div className="max-lg:hidden text-foreground font-medium text-sm">
|
||||
Matriculado em
|
||||
</div>
|
||||
<div></div>
|
||||
</>
|
||||
|
||||
<Popover>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
tabIndex={-1}
|
||||
variant="outline"
|
||||
className="cursor-pointer"
|
||||
>
|
||||
<CopyPlusIcon />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>Duplicar várias vezes</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
{/* Rows */}
|
||||
<>
|
||||
{fields.map((field, index) => (
|
||||
<Fragment key={field.id}>
|
||||
{index >= 1 && <div className="h-2.5 lg:hidden"></div>}
|
||||
|
||||
<PopoverContent align="end" className="w-80">
|
||||
<div className="space-y-2.5">
|
||||
<h4 className="leading-none font-medium">
|
||||
Duplicar várias vezes
|
||||
</h4>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
Duplique o curso desta linha na quantidade
|
||||
desejada para agilizar o preenchimento.
|
||||
</p>
|
||||
<InputGroup>
|
||||
<InputGroupInput placeholder="Search..." />
|
||||
<InputGroupAddon>
|
||||
<SearchIcon />
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
|
||||
<div className="grid gap-2">
|
||||
<div className="grid grid-cols-3 items-center gap-4">
|
||||
<Label htmlFor="width">Quantidade</Label>
|
||||
<Input
|
||||
id="width"
|
||||
defaultValue="2"
|
||||
className="col-span-2 h-8"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<InputGroup>
|
||||
<InputGroupInput placeholder="Search..." />
|
||||
<InputGroupAddon>
|
||||
<SearchIcon />
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button>
|
||||
<CopyPlusIcon />
|
||||
Duplicar
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<Controller
|
||||
control={control}
|
||||
name={`enrollments.${index}.scheduled_for`}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<ScheduledForInput value={value} onChange={onChange} />
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button
|
||||
tabIndex={-1}
|
||||
variant="destructive"
|
||||
className="cursor-pointer"
|
||||
disabled={fields.length == 1}
|
||||
onClick={() => remove(index)}
|
||||
>
|
||||
<Trash2Icon />
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
<div>
|
||||
<Button
|
||||
onClick={() => append({})}
|
||||
className="cursor-pointer"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
>
|
||||
<PlusIcon /> Adicionar
|
||||
</Button>
|
||||
{/* Action */}
|
||||
<div className="flex gap-1.5">
|
||||
<Button
|
||||
tabIndex={-1}
|
||||
variant="outline"
|
||||
className="cursor-pointer"
|
||||
onClick={() => duplicateRow(index)}
|
||||
title="Duplicar linha"
|
||||
>
|
||||
<CopyIcon />
|
||||
</Button>
|
||||
|
||||
<DuplicateRowMultipleTimes
|
||||
index={index}
|
||||
duplicateRow={duplicateRow}
|
||||
/>
|
||||
|
||||
<Button
|
||||
tabIndex={-1}
|
||||
variant="destructive"
|
||||
className="cursor-pointer"
|
||||
disabled={fields.length == 1}
|
||||
onClick={() => remove(index)}
|
||||
>
|
||||
<Trash2Icon />
|
||||
</Button>
|
||||
</div>
|
||||
</Fragment>
|
||||
))}
|
||||
</>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => append({})}
|
||||
className="cursor-pointer"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
>
|
||||
<PlusIcon /> Adicionar
|
||||
</Button>
|
||||
|
||||
<Separator />
|
||||
|
||||
<Button
|
||||
@@ -231,17 +198,24 @@ export default function Route({}: Route.ComponentProps) {
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function ScheduledForInput() {
|
||||
function ScheduledForInput({ value, onChange }) {
|
||||
const today = new Date()
|
||||
const [open, { toggle, set }] = useToggle()
|
||||
const [selected, setDate] = useState<Date | undefined>(value)
|
||||
const displayValue = !selected
|
||||
? 'Imediatamente'
|
||||
: format(selected, 'dd/MM/yyyy')
|
||||
|
||||
return (
|
||||
<Popover>
|
||||
<Popover open={open} onOpenChange={toggle}>
|
||||
<PopoverTrigger asChild>
|
||||
<InputGroup>
|
||||
<InputGroupInput placeholder="Imediatamente" />
|
||||
<InputGroupInput readOnly value={displayValue} />
|
||||
<InputGroupAddon>
|
||||
<CalendarIcon />
|
||||
</InputGroupAddon>
|
||||
@@ -250,11 +224,84 @@ function ScheduledForInput() {
|
||||
<PopoverContent className="w-full p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={selected}
|
||||
onSelect={(date: Date) => {
|
||||
setDate(date)
|
||||
onChange?.(date)
|
||||
set(false)
|
||||
}}
|
||||
disabled={{ before: today }}
|
||||
startMonth={new Date(today.getFullYear(), 0)}
|
||||
endMonth={new Date(today.getFullYear() + 3, 11)}
|
||||
captionLayout="dropdown"
|
||||
// startMonth={new Date()}
|
||||
locale={ptBR}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
)
|
||||
}
|
||||
|
||||
function DuplicateRowMultipleTimes({
|
||||
index,
|
||||
duplicateRow
|
||||
}: {
|
||||
index: number
|
||||
duplicateRow: (index: number, times: number) => void
|
||||
}) {
|
||||
const [open, { toggle, set }] = useToggle()
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={toggle}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
tabIndex={-1}
|
||||
variant="outline"
|
||||
className="cursor-pointer"
|
||||
title="Duplicar várias vezes"
|
||||
>
|
||||
<CopyPlusIcon />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
|
||||
<PopoverContent align="end" className="w-80">
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
const formData = new FormData(e.currentTarget)
|
||||
const times = parseInt(formData.get('quantity') as string)
|
||||
duplicateRow(index, times)
|
||||
set(false)
|
||||
}}
|
||||
>
|
||||
<div className="space-y-2.5">
|
||||
<h4 className="leading-none font-medium">Duplicar várias vezes</h4>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
Duplique o curso desta linha na quantidade desejada para agilizar
|
||||
o preenchimento.
|
||||
</p>
|
||||
|
||||
<div className="grid gap-2">
|
||||
<div className="grid grid-cols-3 items-center gap-4">
|
||||
<Label htmlFor="quantity">Quantidade</Label>
|
||||
<Input
|
||||
id="quantity"
|
||||
name="quantity"
|
||||
type="number"
|
||||
defaultValue="2"
|
||||
min="2"
|
||||
max="100"
|
||||
className="col-span-2 "
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">Duplicar</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user