This commit is contained in:
2026-01-01 01:05:22 -03:00
parent bad7e15f46
commit e3aff10140
6 changed files with 108 additions and 93 deletions

View File

@@ -6,13 +6,7 @@ import {
Trash2Icon, Trash2Icon,
XIcon XIcon
} from 'lucide-react' } from 'lucide-react'
import { import { useForm, useFieldArray, Controller, useWatch } from 'react-hook-form'
useForm,
useFieldArray,
Controller,
useWatch,
type UseFormSetValue
} from 'react-hook-form'
import { ErrorMessage } from '@hookform/error-message' import { ErrorMessage } from '@hookform/error-message'
import { zodResolver } from '@hookform/resolvers/zod' import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod' import { z } from 'zod'

View File

@@ -3,6 +3,7 @@ import { PatternFormat } from 'react-number-format'
import { ExternalLinkIcon, PencilIcon, SearchIcon } from 'lucide-react' import { ExternalLinkIcon, PencilIcon, SearchIcon } from 'lucide-react'
import { Controller, useForm } from 'react-hook-form' import { Controller, useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod' import { zodResolver } from '@hookform/resolvers/zod'
import { formatCEP } from '@brazilian-utils/brazilian-utils'
import { z } from 'zod' import { z } from 'zod'
import valid from 'card-validator' import valid from 'card-validator'
@@ -41,7 +42,6 @@ import { paymentMethods } from '@repo/ui/routes/orders/data'
import { useWizard } from '@/components/wizard' import { useWizard } from '@/components/wizard'
import { type WizardState } from './store' import { type WizardState } from './store'
import { applyDiscount } from './discount'
import { import {
Field, Field,
FieldDescription, FieldDescription,
@@ -61,7 +61,7 @@ import {
import { useWizardStore } from './store' import { useWizardStore } from './store'
type ReviewProps = { type ReviewProps = {
onSubmit: (value: WizardState) => void | Promise<void> onSubmit: () => void | Promise<void>
} }
export function Review({ onSubmit }: ReviewProps) { export function Review({ onSubmit }: ReviewProps) {
@@ -78,7 +78,7 @@ export function Review({ onSubmit }: ReviewProps) {
onSubmit={async (e) => { onSubmit={async (e) => {
e.preventDefault() e.preventDefault()
set(true) set(true)
// await onSubmit(state) await onSubmit()
}} }}
className="space-y-4" className="space-y-4"
> >
@@ -176,7 +176,7 @@ export function Review({ onSubmit }: ReviewProps) {
} }
export function Summary() { export function Summary() {
const { summary, credit_card, payment_method, installments } = const { summary, credit_card, payment_method, installments, address } =
useWizardStore() useWizardStore()
const { total } = summary() const { total } = summary()
const numberValidation = valid.number(credit_card?.number) const numberValidation = valid.number(credit_card?.number)
@@ -186,15 +186,18 @@ export function Summary() {
<Item variant="outline" className="items-start"> <Item variant="outline" className="items-start">
<ItemContent> <ItemContent>
<ItemTitle>Endereço de cobrança</ItemTitle> <ItemTitle>Endereço de cobrança</ItemTitle>
<ul className="text-muted-foreground text-sm leading-normal font-normal text-balance"> {address && (
Rua Monsenhor Ivo Zanlorenzi, 5190, ap 1802 <ul className="text-muted-foreground text-sm leading-normal font-normal text-balance">
<br /> {address?.address1}
Cidade Industrial {address?.address2 ? <>, {address?.address2}</> : null}
<br /> <br />
Curitiba, Paraná {address?.neighborhood}
<br /> <br />
81280-350 {address?.city}, {address?.state}
</ul> <br />
{formatCEP(address?.postcode)}
</ul>
)}
</ItemContent> </ItemContent>
<ItemActions> <ItemActions>
<AddressDialog /> <AddressDialog />
@@ -236,17 +239,19 @@ const formSchema = z.object({
state: z.string().min(1, 'Digite o estado') state: z.string().min(1, 'Digite o estado')
}) })
type Address = z.infer<typeof formSchema> export type Address = z.infer<typeof formSchema>
export function AddressDialog() { export function AddressDialog() {
const [open, { toggle, set }] = useToggle() const [open, { toggle, set: setOpen }] = useToggle()
const { update, address } = useWizardStore()
const { handleSubmit, control, reset } = useForm({ const { handleSubmit, control, reset } = useForm({
defaultValues: address,
resolver: zodResolver(formSchema) resolver: zodResolver(formSchema)
}) })
const onSubmit = async (data: Address) => { const onSubmit = async (address: Address) => {
set(false) setOpen(false)
console.log(data) update({ address })
} }
return ( return (
@@ -317,69 +322,69 @@ export function AddressDialog() {
</Field> </Field>
)} )}
/> />
</FieldSet>
<FieldSet className="grid grid-cols-3"> <FieldGroup className="grid grid-cols-3">
{/* Neighborhood */} {/* Neighborhood */}
<Controller <Controller
control={control} control={control}
name="neighborhood" name="neighborhood"
defaultValue="" defaultValue=""
render={({ field, fieldState }) => ( render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}> <Field data-invalid={fieldState.invalid}>
<FieldLabel htmlFor={field.name}>Bairro</FieldLabel> <FieldLabel htmlFor={field.name}>Bairro</FieldLabel>
<Input <Input
id={field.name} id={field.name}
aria-invalid={fieldState.invalid} aria-invalid={fieldState.invalid}
{...field} {...field}
/> />
{fieldState.invalid && ( {fieldState.invalid && (
<FieldError errors={[fieldState.error]} /> <FieldError errors={[fieldState.error]} />
)} )}
</Field> </Field>
)} )}
/> />
{/* City */} {/* City */}
<Controller <Controller
control={control} control={control}
name="city" name="city"
defaultValue="" defaultValue=""
render={({ field, fieldState }) => ( render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}> <Field data-invalid={fieldState.invalid}>
<FieldLabel htmlFor={field.name}>Cidade</FieldLabel> <FieldLabel htmlFor={field.name}>Cidade</FieldLabel>
<Input <Input
id={field.name} id={field.name}
aria-invalid={fieldState.invalid} aria-invalid={fieldState.invalid}
{...field} {...field}
/> />
{fieldState.invalid && ( {fieldState.invalid && (
<FieldError errors={[fieldState.error]} /> <FieldError errors={[fieldState.error]} />
)} )}
</Field> </Field>
)} )}
/> />
{/* State */} {/* State */}
<Controller <Controller
control={control} control={control}
name="state" name="state"
defaultValue="" defaultValue=""
render={({ field, fieldState }) => ( render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}> <Field data-invalid={fieldState.invalid}>
<FieldLabel htmlFor={field.name}>Estado</FieldLabel> <FieldLabel htmlFor={field.name}>Estado</FieldLabel>
<Input <Input
id={field.name} id={field.name}
aria-invalid={fieldState.invalid} aria-invalid={fieldState.invalid}
{...field} {...field}
/> />
{fieldState.invalid && ( {fieldState.invalid && (
<FieldError errors={[fieldState.error]} /> <FieldError errors={[fieldState.error]} />
)} )}
</Field> </Field>
)} )}
/> />
</FieldGroup>
</FieldSet> </FieldSet>
</FieldGroup> </FieldGroup>
@@ -414,8 +419,10 @@ function PostcodeForm({ onChange }: PostcodeFormProps) {
type Schema = z.infer<typeof formSchema> type Schema = z.infer<typeof formSchema>
const { address } = useWizardStore()
const { control, handleSubmit, setError, formState } = useForm({ const { control, handleSubmit, setError, formState } = useForm({
resolver: zodResolver(formSchema) resolver: zodResolver(formSchema),
defaultValues: address
}) })
const { runAsync, loading } = useRequest( const { runAsync, loading } = useRequest(

View File

@@ -65,13 +65,14 @@ export default function Route({
}: Route.ComponentProps) { }: Route.ComponentProps) {
const fetcher = useFetcher() const fetcher = useFetcher()
const [mounted, setMounted] = useState(false) const [mounted, setMounted] = useState(false)
const { index, kind, setIndex, setKind } = useWizardStore() const { index, kind, setIndex, setKind, reset, ...state } = useWizardStore()
const onSubmit = async (data: WizardState) => { const onSubmit = async () => {
await fetcher.submit(JSON.stringify(data), { await fetcher.submit(JSON.stringify(state), {
method: 'post', method: 'post',
encType: 'application/json' encType: 'application/json'
}) })
// reset()
} }
useMount(() => { useMount(() => {

View File

@@ -5,6 +5,7 @@ import { calcInterest, type CreditCard } from './payment'
import type { PaymentMethod } from '@repo/ui/routes/orders/data' import type { PaymentMethod } from '@repo/ui/routes/orders/data'
import type { Enrollment } from '../_.$orgid.enrollments.add/data' import type { Enrollment } from '../_.$orgid.enrollments.add/data'
import type { Item } from './bulk' import type { Item } from './bulk'
import type { Address } from './review'
export type WizardState = { export type WizardState = {
index: number index: number
@@ -15,6 +16,7 @@ export type WizardState = {
installments?: number installments?: number
payment_method?: PaymentMethod payment_method?: PaymentMethod
credit_card?: CreditCard credit_card?: CreditCard
address?: Address
} }
type Summary = { type Summary = {
@@ -36,7 +38,12 @@ const emptyWizard: WizardState = {
index: 0, index: 0,
kind: 'bulk', kind: 'bulk',
items: [], items: [],
enrollments: [] enrollments: [],
address: undefined,
coupon: undefined,
installments: undefined,
payment_method: undefined,
credit_card: undefined
} }
export const useWizardStore = create<WizardStore>()( export const useWizardStore = create<WizardStore>()(

View File

@@ -136,8 +136,8 @@ export default function Route({
} }
const scheduled = grouping(filtering(items, undefined)) const scheduled = grouping(filtering(items, undefined))
const executed = grouping(filtering(items, 'EXECUTED')) const executed = sorting(grouping(filtering(items, 'EXECUTED')))
const failed = grouping(filtering(items, 'FAILED')) const failed = sorting(grouping(filtering(items, 'FAILED')))
return ( return (
<div className="space-y-5 lg:max-w-4xl mx-auto"> <div className="space-y-5 lg:max-w-4xl mx-auto">
@@ -330,7 +330,7 @@ function Executed({ items = [] }) {
</Empty> </Empty>
) : null} ) : null}
{items.map(({ course, user, created_at }, index) => ( {sorting(items).map(({ course, user, created_at }, index) => (
<Fragment key={index}> <Fragment key={index}>
<Item className="max-lg:px-0 max-lg:first:pt-0 max-lg:last:pb-0"> <Item className="max-lg:px-0 max-lg:first:pt-0 max-lg:last:pb-0">
<ItemMedia className="hidden lg:block"> <ItemMedia className="hidden lg:block">
@@ -554,3 +554,9 @@ function grouping(items) {
) )
return newItems.sort((x, y) => x[0].localeCompare(y[0])) return newItems.sort((x, y) => x[0].localeCompare(y[0]))
} }
function sorting(items) {
return items.sort((a, b) => {
return new Date(b[0]).getTime() - new Date(a[0]).getTime()
})
}

View File

@@ -34,9 +34,9 @@ import {
} from '@repo/ui/components/ui/form' } from '@repo/ui/components/ui/form'
import { Input } from '@repo/ui/components/ui/input' import { Input } from '@repo/ui/components/ui/input'
import { Spinner } from '@repo/ui/components/ui/spinner' import { Spinner } from '@repo/ui/components/ui/spinner'
import { HttpMethod, request as req } from '@repo/util/request'
import { useWorksapce } from '@/components/workspace-switcher' import { useWorksapce } from '@/components/workspace-switcher'
import { HttpMethod, request as req } from '@repo/util/request'
import { formSchema, type Schema } from './data' import { formSchema, type Schema } from './data'
export function meta({}: Route.MetaArgs) { export function meta({}: Route.MetaArgs) {