Untitled

 avatar
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