Files
saladeaula.digital/apps/admin.saladeaula.digital/app/routes/_.$orgid.enrollments.buy/store.tsx

146 lines
3.4 KiB
TypeScript

import { create } from 'zustand'
import { persist } from 'zustand/middleware'
import type { PaymentMethod } from '@repo/ui/routes/orders/data'
import type { Enrollment } from '../_.$orgid.enrollments.add/data'
import type { Item } from './bulk'
import { applyDiscount, type Coupon } from './discount'
import { calcInterest, type CreditCard } from './payment'
import type { Address } from './review'
export type WizardState = {
index: number
kind: 'bulk' | 'assigned'
items: Item[]
enrollments: Enrollment[]
coupon?: Coupon
installments?: number
payment_method?: PaymentMethod
credit_card?: CreditCard
address?: Address
}
type Summary = {
subtotal: number
discount: number
interest_amount: number
total: number
}
export type WizardStore = WizardState & {
setIndex: (index: number) => void
setKind: (kind: 'bulk' | 'assigned') => void
update: (data: Partial<WizardState>) => void
reset: () => void
summary: () => Summary
}
const emptyWizard: WizardState = {
index: 0,
kind: 'bulk',
items: [],
enrollments: [],
address: undefined,
coupon: undefined,
installments: undefined,
payment_method: undefined,
credit_card: undefined
}
export const useWizardStore = create<WizardStore>()(
persist(
(set, get) => ({
...emptyWizard,
setIndex: (index) => set({ index }),
setKind: (kind) => set({ kind }),
summary: () => {
const { items, coupon, credit_card, installments } = get()
const subtotal = items.reduce(
(acc, { course, quantity }) =>
acc +
(course.unit_price || 0) *
(Number.isFinite(quantity) && quantity > 0 ? quantity : 1),
0
)
const discount = coupon
? applyDiscount(subtotal, coupon.amount, coupon.type) * -1
: 0
const total = subtotal > 0 ? subtotal + discount : 0
const interest_amount =
credit_card && typeof installments === 'number' && installments > 1
? calcInterest(total, installments) - total
: 0
return {
subtotal,
discount,
interest_amount,
total: total + interest_amount
}
},
update: (data) =>
set((state) => {
if (data.enrollments) {
const items = Object.values(
data.enrollments.reduce<Record<string, Item>>(
(acc, { course }) => {
const { id } = course
acc[id] ??= { course, quantity: 0 }
acc[id].quantity++
return acc
},
{}
)
)
return {
...state,
...data,
items
}
}
if (data.items) {
const items = Object.values(
data.items.reduce<Record<string, Item>>((acc, item) => {
const id = item.course.id
if (!acc[id]) {
acc[id] = { ...item }
} else {
acc[id].quantity += item.quantity
}
return acc
}, {})
)
return {
...state,
...data,
items,
enrollments: []
}
}
return {
...state,
...data
}
}),
reset: () => set({ ...emptyWizard })
}),
{
name: 'wizard_cart'
}
)
)