add zustard

This commit is contained in:
2025-12-30 14:37:53 -03:00
parent 58068cd463
commit bad7e15f46
15 changed files with 349 additions and 280 deletions

View File

@@ -1,4 +1,4 @@
import { Fragment } from 'react'
import { Fragment, useEffect } from 'react'
import {
Trash2Icon,
PlusIcon,
@@ -10,6 +10,7 @@ import { useParams } from 'react-router'
import { ErrorMessage } from '@hookform/error-message'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import { DateTime } from 'luxon'
import { Form } from '@repo/ui/components/ui/form'
import {
@@ -30,7 +31,6 @@ import {
import {
MAX_ITEMS,
formSchema,
type Enrollment,
type Course,
type User
} from '../_.$orgid.enrollments.add/data'
@@ -41,7 +41,7 @@ import { UserPicker } from '../_.$orgid.enrollments.add/user-picker'
import { Summary } from './bulk'
import { currency } from './utils'
import { useWizard } from '@/components/wizard'
import type { Item } from './bulk'
import { useWizardStore } from './store'
const emptyRow = {
user: undefined,
@@ -49,42 +49,24 @@ const emptyRow = {
scheduled_for: undefined
}
const formSchemaAssigned = formSchema.extend({
coupon: z
.object({
code: z.string(),
type: z.enum(['FIXED', 'PERCENT']),
amount: z.number().positive()
})
.optional()
})
type Schema = z.infer<typeof formSchemaAssigned>
type Schema = z.infer<typeof formSchema>
type AssignedProps = {
onSubmit: (value: any) => void | Promise<void>
courses: Promise<{ hits: Course[] }>
enrollments: Enrollment[]
coupon?: object
}
export function Assigned({
courses,
onSubmit,
enrollments,
coupon: couponInit
}: AssignedProps) {
export function Assigned({ courses }: AssignedProps) {
const wizard = useWizard()
const { orgid } = useParams()
const { update, ...state } = useWizardStore()
const form = useForm({
resolver: zodResolver(formSchemaAssigned),
resolver: zodResolver(formSchema),
defaultValues: {
coupon: couponInit,
enrollments: enrollments.length
? enrollments.map((e: any) => ({
enrollments: state.enrollments.length
? state.enrollments.map((e: any) => ({
...e,
scheduled_for: e.scheduled_for
? new Date(e.scheduled_for)
? DateTime.fromISO(e.scheduled_for, { zone: 'local' }).toJSDate()
: undefined
}))
: [emptyRow]
@@ -96,15 +78,10 @@ export function Assigned({
control,
name: 'enrollments'
})
const items = useWatch({
const enrollments = useWatch({
control,
name: 'enrollments'
})
const coupon = useWatch({ control, name: 'coupon' })
const subtotal = items.reduce(
(acc, { course }) => acc + (course?.unit_price || 0),
0
)
const onSearch = async (search: string) => {
const params = new URLSearchParams({ q: search })
@@ -113,24 +90,22 @@ export function Assigned({
return hits
}
const onSubmit_ = async ({ enrollments, coupon }: Schema) => {
const items = Object.values(
enrollments.reduce<Record<string, Item>>((acc, e) => {
const id = e.course.id
acc[id] ??= { course: e.course, quantity: 0 }
acc[id].quantity++
return acc
}, {})
)
await onSubmit({ enrollments, items, coupon })
const onSubmit = async ({ enrollments }: Schema) => {
update({ enrollments })
wizard('payment')
}
useEffect(() => {
const parsed = formSchema.safeParse({ enrollments })
if (parsed.success) {
update(parsed.data)
}
}, [enrollments])
return (
<Form {...form}>
<form onSubmit={handleSubmit(onSubmit_)} className="space-y-4">
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<div className="grid w-full gap-3 lg:grid-cols-[3fr_3fr_2fr_2fr_auto]">
{/* Header */}
<>
@@ -166,7 +141,9 @@ export function Assigned({
{/* Rows */}
{fields.map((field, index) => {
const { unit_price } = items?.[index]?.course || { unit_price: 0 }
const { unit_price } = enrollments?.[index]?.course || {
unit_price: 0
}
return (
<Fragment key={field.id}>
@@ -281,7 +258,7 @@ export function Assigned({
</div>
{/* Summary */}
<Summary {...{ subtotal, coupon, setValue }} />
<Summary />
</div>
<Separator />