Untitled
unknown
plain_text
10 months ago
14 kB
16
Indexable
"use client"
import { FormDatePicker, FormInput, FormSelect, FormTextarea } from "@/components/form"
import { Button } from "@/components/ui/button"
import { Card } from "@/components/ui/card"
import { Form } from "@/components/ui/form"
import { Switch } from "@/components/ui/switch"
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import type z from "zod"
import {
useCreateCouponMutation,
useGetRetailersQuery,
useGetUtilsQuery,
useUpdateCouponMutation,
} from "@/lib/features/super-admin/coupons/coupons-api"
import { useState, useCallback, useEffect } from "react"
import { CouponCreateSchema } from "../sechema/coupon-create-schema"
import { ContactsList } from "./contacts-list"
import FormMultiSelect from "@/components/form/form-multiselect"
interface CouponData {
id: string
allowedPlans: Array<{ id: string; name: string }>
allowedAddons: Array<{ id: string; name: string }>
allowedRetailers: Array<{ id: string; firstName: string; lastName: string }>
name: string
couponId: string
code: string
description: string
discountType: "percentage" | "fixed"
discountValue: number
startDate: string
expiryDate: string
maxRedemptions: number
perUserUsageLimit: number
status: boolean
createdAt: string
updatedAt: string
}
interface CouponFormProps {
data?: CouponData
}
export default function CouponForm({ data }: CouponFormProps) {
type couponCreateType = z.infer<typeof CouponCreateSchema>
const [searchQuery, setSearchQuery] = useState("")
const [allRetailers, setAllRetailers] = useState<any[]>([])
const [currentPage, setCurrentPage] = useState(1)
const [hasMoreRetailers, setHasMoreRetailers] = useState(true)
useEffect(() => {
console.log(data?.allowedRetailers , "data?.allowedRetailers")
if (data?.allowedRetailers) {
setAllRetailers(data.allowedRetailers)
}
}, [data?.allowedRetailers])
const { data: retailerData, isLoading: isLoadingRetailers } = useGetRetailersQuery(
{ search: searchQuery, page: currentPage },
{ skip: !searchQuery || searchQuery.length < 3 },
)
console.log(retailerData , "retailerData")
const [createCoupon, { isLoading: couponCreateLoading }] = useCreateCouponMutation()
const [updateCoupon, { isLoading: couponUpdateLoading }] = useUpdateCouponMutation()
const { data: utilsData } = useGetUtilsQuery({})
const planOptions =
utilsData?.data?.plans?.map((item: any) => ({
label: item.name,
value: item.id,
})) || []
const addonsOptions =
utilsData?.data?.addonItems?.map((item: any) => ({
label: item.name,
value: item.id,
})) || []
const retailerOption = allRetailers.map((user: any) => ({
value: user.id,
label: `${user.firstName} ${user.lastName}`,
}))
// Extract plan and addon IDs for default values
const defaultPlanIds = data?.allowedPlans?.map((plan) => plan.id) || []
const defaultAddonIds = data?.allowedAddons?.map((addon) => addon.id) || []
const defaultRetailerIds = data?.allowedRetailers?.map((retailer) => retailer.id) || []
const methods = useForm<couponCreateType>({
resolver: zodResolver(CouponCreateSchema),
defaultValues: data
? {
planName: defaultPlanIds,
addOns: defaultAddonIds,
couponName: data.name || "",
couponCode: data.code || "",
description: data.description || "",
discount: data.discountType || "",
flatDiscount: data.discountType === "fixed" ? data.discountValue?.toString() : "",
percentageDiscount: data.discountType === "percentage" ? data.discountValue?.toString() : "",
validityFrom: data.startDate ? new Date(data.startDate) : undefined,
validityTo: data.expiryDate ? new Date(data.expiryDate) : undefined,
maxRedemption: data.maxRedemptions?.toString() || "",
totalUsages: data.perUserUsageLimit?.toString() || "",
allowedRetailers: defaultRetailerIds,
status: data.status || false,
}
: {
planName: [],
addOns: [],
couponName: "",
couponCode: "",
description: "",
discount: "",
flatDiscount: "",
percentageDiscount: "",
validityFrom: undefined,
validityTo: undefined,
maxRedemption: "",
totalUsages: "",
allowedRetailers: [],
status: false,
},
})
const {
handleSubmit,
watch,
setValue,
formState: { errors },
} = methods
const discountType = watch("discount")
const status = watch("status")
const searchUsers = useCallback(
async (query: string, page = 1) => {
if (query && query.length >= 3) {
setSearchQuery(query)
if (page === 1) {
setCurrentPage(1)
setAllRetailers([])
setHasMoreRetailers(true)
}
return {
data:
retailerData?.data?.map((user: any) => ({
value: user.id,
label: `${user.firstName} ${user.lastName}`,
// email:user?.email,
// avatar:user?.image,
// phone:`${user?.phoneNumberPrefix} ${user?.phoneNumber}`
})) || [],
hasMore: retailerData?.hasMore || false,
}
}
return { data: [], hasMore: false }
},
[retailerData],
)
const loadMoreRetailers = useCallback(
async (page: number, query: string) => {
const nextPage = currentPage + 1
setCurrentPage(nextPage)
return new Promise((resolve) => {
setTimeout(() => {
resolve({
data: allRetailers,
hasMore: hasMoreRetailers,
})
}, 100)
})
},
[currentPage, allRetailers, hasMoreRetailers],
)
useEffect(() => {
if (retailerData?.data && searchQuery) {
if (currentPage === 1) {
setAllRetailers(retailerData.data)
} else {
setAllRetailers((prev) => {
const existingIds = new Set(prev.map((r) => r.id))
const newRetailers = retailerData.data.filter((r: any) => !existingIds.has(r.id))
return [...prev, ...newRetailers]
})
}
setHasMoreRetailers(retailerData.hasMore || false)
}
}, [retailerData, currentPage, searchQuery])
const onSubmit = async (formData: couponCreateType) => {
try {
const submissionData = {
name: formData.couponName,
code: formData.couponCode,
description: formData.description,
discountType: formData.discount,
discountValue:
formData.discount === "fixed"
? Number.parseFloat(formData.flatDiscount || "0")
: Number.parseInt(formData.percentageDiscount || "0"),
startDate: formData.validityFrom?.toISOString(),
expiryDate: formData.validityTo?.toISOString(),
maxRedemptions: Number.parseInt(formData.maxRedemption || "0"),
perUserUsageLimit: Number.parseInt(formData.totalUsages || "0"),
allowedPlans: formData.planName, // Already array of IDs
allowedAddons: formData.addOns, // Already array of IDs
allowedRetailers: formData.allowedRetailers, // Already array of IDs
status: formData.status,
}
if (data) {
const res = await updateCoupon({ data: submissionData, id: data.id })
console.log("Update response:", res)
} else {
const res = await createCoupon({ data: submissionData })
console.log("Create response:", res)
}
} catch (error: any) {
console.error("Error submitting form:", error)
}
}
const handleRemoveFromForm = useCallback(
(contactId: string) => {
const currentAllowedRetailers = watch("allowedRetailers") || []
const updatedRetailers = currentAllowedRetailers.filter((id: string) => id !== contactId)
setValue("allowedRetailers", updatedRetailers)
},
[watch, setValue],
)
console.log(allRetailers , "allRetailers")
return (
<div className="py-5">
<Card className="p-5">
<Form {...methods}>
<form onSubmit={handleSubmit(onSubmit)} className="flex w-full flex-col gap-4 sm:gap-5">
<div className="flex justify-between">
<p className="text-3xl font-semibold">{!data ? "Create" : "Edit"} Coupon</p>
<div className="flex gap-1 items-center">
Status*
<Switch
name="status"
onCheckedChange={(value: boolean) => setValue("status", value)}
checked={status}
/>
</div>
</div>
<div className="grid grid-cols-2 w-full gap-5 ">
<FormMultiSelect
methods={methods}
options={planOptions}
label="Select Plan"
name="planName"
placeholder="Select Plan"
required
/>
<FormMultiSelect
methods={methods}
options={addonsOptions}
label="Choose Add-Ons"
name="addOns"
placeholder="Select Add-Ons"
required
/>
</div>
<FormInput
className="w-full"
name="couponName"
label="Coupon Name"
placeholder="Black Friday Special"
required
control={methods.control}
/>
<FormInput
className="w-full"
name="couponCode"
label="Coupon Code"
placeholder="BF2024"
required
control={methods.control}
/>
<FormTextarea
className="w-full"
name="description"
label="Description"
placeholder="About Coupon"
control={methods.control}
/>
<FormSelect
label="Discount Type"
placeholder="Select Discount Type"
name="discount"
control={methods.control}
options={[
{ label: "Flat Discount", value: "fixed" },
{ label: "Percentage Discount", value: "percentage" },
]}
required
/>
{discountType === "fixed" ? (
<FormInput
type="number"
className="w-full"
name="flatDiscount"
label="Flat Discount Amount"
placeholder="10"
required
control={methods.control}
/>
) : discountType === "percentage" ? (
<FormInput
type="number"
className="w-full"
name="percentageDiscount"
label="Percentage Discount"
placeholder="30"
required
control={methods.control}
/>
) : null}
<div className="grid grid-cols-2 w-full gap-5">
<div className="col-span-1 w-full">
<FormDatePicker
useNormalLabel={true}
className="w-full"
name="validityFrom"
label="Start Date"
placeholder="DD/MM/YYYY"
control={methods.control}
/>
</div>
<div className="col-span-1 w-full">
<FormDatePicker
useNormalLabel={true}
className="w-full"
name="validityTo"
label="Expiry Date"
placeholder="DD/MM/YYYY"
control={methods.control}
/>
</div>
</div>
<div className="grid grid-cols-2 w-full gap-5">
<FormInput
type="number"
className="w-full"
name="maxRedemption"
label="Max Redemptions"
placeholder="200"
required
control={methods.control}
/>
<FormInput
type="number"
className="w-full"
name="totalUsages"
label="Usage Limit Per User"
placeholder="2"
required
control={methods.control}
/>
</div>
<FormMultiSelect
methods={methods}
options={retailerOption}
maxSize={5}
required
label="Allowed Retailers"
name="allowedRetailers"
placeholder="Retailer Name"
maxSizeWarnText="sorry you can't select anymore"
searchable={true}
onSearch={searchUsers}
searchPlaceholder="Search users..."
minSearchLength={3}
searchDebounceMs={300}
enablePagination={true}
pageSize={20}
onLoadMore={loadMoreRetailers as any}
loading={isLoadingRetailers}
DrawerRenderContent={
<ContactsList
contacts={allRetailers}
setAllRetailers={setAllRetailers}
onRemoveFromForm={handleRemoveFromForm}
/>
}
cb={(opt:any) => {
console.log("opt", opt)
}}
/>
<Button variant={"stampEzee"} type="submit" disabled={couponCreateLoading || couponUpdateLoading}>
{!data ? "Save" : "Update"}
</Button>
</form>
</Form>
</Card>
</div>
)
}
Editor is loading...
Leave a Comment