CreateUpdateModel (Subscription Unlimited Design)

 avatar
unknown
javascript
6 months ago
14 kB
2
Indexable
'use client';

import Button from '@/components/Formik/Button';
import DragAndDropUpload from '@/components/Formik/DragAndDropUpload';
import InputField from '@/components/Formik/InputField';
import { SerializedError } from '@/features/api/apiSlice';
import { useUpdateSubscriptionMutation } from '@/features/super-admin/subscription/subscriptionApi';
import getSubDetailsObject from '@/utils/get-subscription-details-object';
import objectToFormData from '@/utils/objectToFormData';
import { FieldArray, Form, Formik } from 'formik';
import { useEffect, useState } from 'react';
import toast from 'react-hot-toast';
import { BsCheck2Circle, BsPatchCheck } from 'react-icons/bs';
import { IoCloseOutline, IoStorefrontOutline } from 'react-icons/io5';
import { LuCalendarDays, LuCircleDollarSign } from 'react-icons/lu';
import { RiTeamLine } from 'react-icons/ri';
import { TbInfinity, TbInfinityOff } from 'react-icons/tb';
import { ActionIcon, Modal, Title } from 'rizzui';
import * as Yup from 'yup';

export default function CreateUpdateModel({
  setFormData,
  formData,
  modalState,
  setModalState,
}: {
  formData: any;
  modalState: boolean;
  setFormData: (data: any) => void;
  setModalState: (state: boolean) => void;
}) {
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [updateSubscription, { isSuccess: updateSuccess, error: updateError }] = useUpdateSubscriptionMutation();

  const initialValues = {
    title: formData?.title || '',
    price: formData?.price || 0,
    image: formData?.image || null,
    allowTotalBranch: formData?.allowTotalBranch || null,
    allowTotalTeamMember: formData?.allowTotalTeamMember || null,
    allowTotalStamp: formData?.allowTotalStamp || null,
    limit: formData?.limit || null,
    descriptions: formData?.descriptions || getSubDetailsObject(false),
    type: formData?.type || 'subscription',
    slug: formData?.slug || '',
    duration: formData?.duration || 0,
  };

  const validationSchema = Yup.object({
    title: Yup.string().trim().required('Required!'),
    price: Yup.mixed().required('Required!'),
    slug: Yup.string().trim().required('Required!'),
    type: Yup.mixed().oneOf(['subscription', 'addon']).required('Required!'),
    allowTotalBranch: Yup.string().when('type', {
      is: 'subscription',
      then: () => Yup.string().required('Required!').notOneOf(['0'], 'The value 0 is not allowed!'),
      otherwise: () => Yup.number().nullable(),
    }),
    allowTotalTeamMember: Yup.string().when('type', {
      is: 'subscription',
      then: () => Yup.string().required('Required!').notOneOf(['0'], 'The value 0 is not allowed!'),
      otherwise: () => Yup.number().nullable(),
    }),
    allowTotalStamp: Yup.string().when('type', {
      is: 'subscription',
      then: () => Yup.string().required('Required!').notOneOf(['0'], 'The value 0 is not allowed!'),
      otherwise: () => Yup.number().nullable(),
    }),
    limit: Yup.string().when('type', {
      is: 'addon',
      then: () => Yup.number().required('Required!'),
      otherwise: () => Yup.number().nullable(),
    }),
    descriptions: Yup.string().when('type', {
      is: 'subscription',
      then: () =>
        Yup.array()
          .of(Yup.string().required('Array must contain a string'))
          .min(1, 'Array must contain at least one string')
          .required('Required!'),
      otherwise: () => Yup.array().nullable(),
    }),
  });

  // Submit Handler
  const submitHandler = async (values: any) => {
    setIsSubmitting(true);
    const isFile = (obj: any): obj is File => obj instanceof File;

    let objToFormData: FormData;
    console.log({ values });

    if (formData?._id) {
      const ignoreList = [];
      if (values?.type === 'subscription') {
        ignoreList.push('limit');
      } else {
        ignoreList.push('allowTotalBranch', 'allowTotalTeamMember', 'allowTotalStamp');
      }
      if (!isFile(values?.image)) ignoreList.push('image');

      objToFormData = objectToFormData(values, ignoreList);

      updateSubscription({ id: formData._id, data: objToFormData });
    }
  };

  // Handle Update Response
  useEffect(() => {
    if (updateError) {
      const myError = updateError as SerializedError;
      toast.error(myError?.data?.message || 'Something went wrong. Please try again!.');
      setIsSubmitting(false);
    }
    if (updateSuccess) {
      toast.success('Subscription updated successfully!');
      setFormData({});
      setIsSubmitting(false);
      setModalState(false);
    }
  }, [setFormData, setModalState, updateError, updateSuccess]);

  return (
    <Modal isOpen={modalState} onClose={() => setModalState(true)} customSize="650px">
      <div className="m-auto px-7 pb-8 pt-6">
        <div className="mb-7 flex items-center justify-between">
          {formData?._id ? <Title as="h4">Update A Subscription</Title> : <Title as="h4">Add New Subscription</Title>}

          <ActionIcon
            size="sm"
            variant="text"
            onClick={() => {
              setModalState(false);
              setFormData({});
            }}
          >
            <IoCloseOutline className="text-2xl text-danger" />
          </ActionIcon>
        </div>
        <div>
          <Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={submitHandler}>
            {({ values, setFieldValue }) => {
              return (
                <Form className="mt-5">
                  {formData?._id && formData?.type === 'subscription' && (
                    <div className="my-5 flex justify-center">
                      <DragAndDropUpload
                        value={{ name: 'image', image: values.image }}
                        onChange={(image: any) => setFieldValue('image', image)}
                        className="mt-2"
                        size={1024 * 1000}
                        sizeText="1MB"
                        isRounded={true}
                        uploadText="Upload Image"
                      />
                    </div>
                  )}

                  <div className="flex gap-3">
                    <InputField name="title" label="Title" placeholder="Title" />
                    <InputField
                      name="price"
                      disabled={formData?.slug === 'trial' ? true : false}
                      label="Price (CAD)"
                      type="number"
                      placeholder="9.99"
                      prefix={<LuCircleDollarSign className="text-xl" />}
                    />
                    {formData?.slug === 'trial' && (
                      <InputField
                        name="duration"
                        label="Duration (Days)"
                        type="number"
                        placeholder="7"
                        prefix={<LuCalendarDays className="text-xl" />}
                      />
                    )}
                  </div>
                  <div className="my-3 flex gap-3">
                    {formData?.type === 'subscription' && (
                      <InputField
                        name="allowTotalBranch"
                        label="Total Branch"
                        type="number"
                        placeholder="1"
                        prefix={<IoStorefrontOutline className="text-xl" />}
                        suffix={
                          values.allowTotalBranch < 0 ? (
                            <TbInfinity
                              className="cursor-pointer text-xl"
                              title="Infinite"
                              onClick={() => setFieldValue('allowTotalBranch', '')}
                            />
                          ) : (
                            <TbInfinityOff
                              className="cursor-pointer text-xl"
                              title="Non-Infinite"
                              onClick={() => setFieldValue('allowTotalBranch', '-1')}
                            />
                          )
                        }
                        disabled={values.allowTotalBranch < 0}
                      />
                    )}

                    {formData?.type === 'subscription' && (
                      <InputField
                        name="allowTotalTeamMember"
                        label="Total Team Member"
                        type="number"
                        placeholder="1"
                        prefix={<RiTeamLine className="text-xl" />}
                        suffix={
                          values.allowTotalTeamMember < 0 ? (
                            <TbInfinity
                              className="cursor-pointer text-xl"
                              title="Infinite"
                              onClick={() => setFieldValue('allowTotalTeamMember', '')}
                            />
                          ) : (
                            <TbInfinityOff
                              className="cursor-pointer text-xl"
                              title="Non-Infinite"
                              onClick={() => setFieldValue('allowTotalTeamMember', '-1')}
                            />
                          )
                        }
                        disabled={values.allowTotalTeamMember < 0}
                      />
                    )}

                    {formData?.type === 'subscription' && (
                      <InputField
                        name="allowTotalStamp"
                        label="Total Stamp"
                        type="number"
                        placeholder="1"
                        prefix={<BsPatchCheck className="text-xl" />}
                        suffix={
                          values.allowTotalStamp < 0 ? (
                            <TbInfinity
                              className="cursor-pointer text-xl"
                              title="Infinite"
                              onClick={() => setFieldValue('allowTotalStamp', '')}
                            />
                          ) : (
                            <TbInfinityOff
                              className="cursor-pointer text-xl"
                              title="Non-Infinite"
                              onClick={() => setFieldValue('allowTotalStamp', '-1')}
                            />
                          )
                        }
                        disabled={values.allowTotalStamp < 0}
                      />
                    )}

                    {formData?.type !== 'subscription' && <InputField name="limit" type="number" label="Limit" placeholder="0" />}
                  </div>

                  <div className="relative mt-4 grid grid-cols-1 gap-4">
                    <FieldArray
                      name="descriptions"
                      render={(arrayHelpers) => (
                        <div>
                          {values?.descriptions?.map((des: any, index: number) => (
                            <div key={des.id} className="z-1 relative mb-4 flex items-center gap-2">
                              {index !== 0 && (
                                <div
                                  className="absolute right-0 top-0 flex h-4 w-4 cursor-pointer items-center justify-center rounded-full bg-red-500 text-white"
                                  onClick={() => arrayHelpers.remove(index)}
                                >
                                  -
                                </div>
                              )}
                              <div className="flex-grow">
                                <div className="flex flex-col">
                                  <InputField
                                    label={`Description (${index + 1})`}
                                    name={`descriptions[${index}]`}
                                    placeholder="Write here..."
                                    required={true}
                                  />
                                </div>
                              </div>
                            </div>
                          ))}

                          <button
                            type="button"
                            className="flex cursor-pointer items-center justify-center rounded-lg bg-danger px-3 py-1 text-white"
                            onClick={() => arrayHelpers.push('')}
                          >
                            + Add
                          </button>
                        </div>
                      )}
                    />
                  </div>

                  <p className="mt-3 text-end text-xs font-semibold">
                    Fields marked with <span className="text-danger">*</span> are mandatory!
                  </p>
                  <p className="mt-1 text-end text-xs font-semibold">
                    <span className="text-danger">-1</span> indicates an <span className="text-danger">infinite</span>!
                  </p>
                  <p className="mt-1 flex items-center justify-end gap-x-1 text-xs font-semibold">
                    <TbInfinity className="text-base text-danger" />
                    <span>indicates an </span>
                    <span className="text-danger"> infinite sign!</span>
                  </p>
                  <p className="mt-1 flex items-center justify-end gap-x-1 text-xs font-semibold">
                    <TbInfinityOff className="text-base text-danger" />
                    <span>indicates a </span>
                    <span className="text-danger"> non-infinite sign!</span>
                  </p>
                  <div className="mt-6 flex justify-end">
                    <Button
                      color="danger"
                      type="submit"
                      text={formData?._id ? 'Update' : 'Submit'}
                      postIcon={<BsCheck2Circle className="text-base" />}
                      isSubmitting={isSubmitting}
                    />
                  </div>
                </Form>
              );
            }}
          </Formik>
        </div>
      </div>
    </Modal>
  );
}
Editor is loading...
Leave a Comment