extra fee edit and cancel modal

 avatar
Yash
javascript
2 months ago
15 kB
3
Indexable
import React, { useEffect, useState } from "react";
import {
  Box,
  Button,
  Flex,
  FormControl,
  FormLabel,
  HStack,
  Input,
  Tag,
  Table,
  Thead,
  Tbody,
  Tr,
  Th,
  Td,
  Spinner,
  Text,
  Drawer,
  DrawerOverlay,
  DrawerContent,
  DrawerHeader,
  DrawerBody,
  DrawerFooter,
  useDisclosure,
  IconButton,
  Select,
  Badge,
  Menu,
  MenuButton,
  MenuList,
  MenuItem,
  Modal,
  ModalOverlay,
  ModalContent,
  ModalHeader,
  ModalCloseButton,
  ModalBody,
  ModalFooter,
  Grid,
  GridItem,
  FormErrorMessage,
} from "@chakra-ui/react";
import { useForm } from "react-hook-form";
import {
  useGetAllExtraFeeUser,
  useUpdateExtraFeeUser,
} from "../../../services/extraFeeUser.service";
import { ErrorAlert, SuccessAlert } from "../../../utils/Helper";
import { ExtraFeeAssignStudent } from "./ExtraFeeAssignStudent";
import { EditIcon, SmallCloseIcon } from "@chakra-ui/icons";
import { PaymentModal } from "./PaymentForExtraFees";
import { last } from "lodash";
import { useRouter } from "next/router";
import moment from "moment";
import { BsThreeDotsVertical } from "react-icons/bs";

export const ExtraFeeData = ({ userId, userCourseId }) => {

  const { query } = useRouter();

  const [isDrawerOpen, setDrawerOpen] = useState(false);

  const { isOpen: isModalOpen, onOpen: openModal, onClose: closeModal } = useDisclosure();

  const { isOpen: isPayModalOpen, onOpen: openPayModal, onClose: closePayModal } = useDisclosure();

  const [currentFee, setCurrentFee] = useState(null);

  const { isOpen: cancelFeeIsOpen, onOpen: cancelFeeOnOpen, onClose: cancelFeeOnClose } = useDisclosure()


  const { data, isPending, refetch } = useGetAllExtraFeeUser({
    userId,
    userCourseId: userCourseId,
    nonPaginated: true,
    enabled: !!userId
  });

  const { mutate, isPending: updatePending } = useUpdateExtraFeeUser({
    onSuccess: () => {
      SuccessAlert("Extra fee user has been successfully updated");
      refetch()
      setDrawerOpen(false);
    },
    onError: (e) => {
      ErrorAlert(e.message);
    },
  });

  const handleEditClick = (fee) => {
    setCurrentFee(fee);
    setDrawerOpen(true);
  };

  const handleCancelClick = (fee) => {
    setCurrentFee(fee);
    cancelFeeOnOpen(true);
  };

  const handlePayClick = (fee) => {
    setCurrentFee(fee);
    openPayModal();
  };

  const handleSave = async (values) => {
    try {
      if (values.initialAmount < currentFee.paidAmount) {
        ErrorAlert("Intital amount can not be less paid amount")
      } else {
        mutate({ ...values, id: currentFee._id });
      }
    } catch (error) {
      console.error(error);
    }
  };
  return (
    <>
      {userId !== null ? <>
        <HStack justify="space-between">
          <Box>
            <Tag
              px={4}
              variant="subtle"
              fontWeight="bold"
              py={2}
              colorScheme="blue"
            >
              Total Records {data?.length || 0}
            </Tag>
          </Box>
          <Button onClick={openModal} colorScheme="blue" size="sm">
            Add Extra Fee
          </Button>
        </HStack>

        {isPending ? (
          <Flex justify="center" mt={4}>
            <Spinner />
          </Flex>
        ) : (
          <>
            <FeeTable data={data} onEdit={handleEditClick} onCancel={handleCancelClick} onPay={handlePayClick} cancelFeeOnOpen={cancelFeeOnOpen} />
            {!data?.length && (
              <Text mt={4} textAlign="center" color="gray.500">
                No records found.
              </Text>
            )}
          </>
        )}
        <FeeCancelModal isOpen={cancelFeeIsOpen} onClose={cancelFeeOnClose} onSave={handleSave} pending={updatePending} fee={currentFee} />

        <FeeModal
          isOpen={isDrawerOpen}
          onClose={() => setDrawerOpen(false)}
          onSave={handleSave}
          fee={currentFee}
          pending={updatePending}
        />
        {isModalOpen && <ExtraFeeAssignStudent
          closeModal={closeModal}
          studentDetails={userId}
          isOpen={isModalOpen}
          refetch={refetch}
          userCourseId={query.userCourseId}
        />}
        {isPayModalOpen && <PaymentModal
          closeModal={closePayModal}
          studentDetails={currentFee}
          userId={currentFee.userId}
          courseId={currentFee.courseId}
          isOpen={isPayModalOpen}
          extraFeeUserId={currentFee._id}
          refetch={refetch}
        />}
      </> : <Flex flexDirection={"row"} justifyContent={"center"}>
        <Text fontSize={"2xl"} color={"red.500"} fontWeight={"bold"}>Admission Fees Not Paid</Text>
      </Flex>}
    </>
  );
};

export const FeeTable = ({ data, onEdit, onCancel, onPay, cancelFeeOnOpen }) => {
  const statusColor = {
    pending: "orange",
    paid: "green",
    cancel: "red",
    PartialPayment: "purple",
  };
  return (
    <Box overflowX="auto">
      <Table size="sm" mt={4}>
        <Thead bg={"gray.100"}>
          <Tr>
            <Th>sr. no.</Th>
            <Th>Fee Name</Th>
            <Th>Fees Type</Th>
            <Th>Due Date</Th>
            <Th>Initial Amount</Th>
            <Th>Due Amount</Th>
            <Th>Paid Amount</Th>
            <Th>Status</Th>
            <Th>Actions</Th>
          </Tr>
        </Thead>
        <Tbody>
          {data?.map((fee, i) => (
            <Tr key={fee._id}>
              <Td>{i + 1}</Td>
              <Td>{fee.extraFeesId?.name}</Td>
              <Td>{fee.extraFeesId?.applicableOn}</Td>
              <Td>{moment(fee.dueDate).format("DD-MMM-YYYY") ?? "-"}</Td>
              <Td>{fee?.initialAmount}</Td>
              <Td>{fee?.initialAmount - fee.paidAmount}</Td>
              <Td>{fee.paidAmount}</Td>
              <Td>
                <Badge colorScheme={statusColor[fee.status] || "gray"} variant={"outline"}>
                  {fee.status}
                </Badge>
              </Td>
              <Td>
                <HStack>
                  <Button size="xs" colorScheme="blue" onClick={() => onPay(fee)}>
                    Collect
                  </Button>
                  <Menu>
                    <MenuButton
                      as={IconButton}
                      aria-label='Options'
                      icon={<BsThreeDotsVertical />}
                      // variant='outline'
                      bgColor={"white"}
                      size={"xs"}
                    />
                    <MenuList>
                      <MenuItem icon={<EditIcon />} onClick={() => onEdit(fee)}>
                        Edit Fee
                      </MenuItem>
                      <MenuItem icon={<SmallCloseIcon />} onClick={() => onCancel(fee)}>
                        Cancel Fee
                      </MenuItem>
                    </MenuList>
                  </Menu>
                  {/* <IconButton
                    size="xs"
                    onClick={() => onEdit(fee)}
                    icon={<BsThreeDotsVertical />}
                  /> */}
                </HStack>
              </Td>
            </Tr>
          ))}
        </Tbody>
      </Table>
    </Box>
  );
};

// export const FeeDrawer = ({ isOpen, onClose, onSave, fee, pending, updatePending }) => {

//   const { register, handleSubmit, reset, setValue } = useForm({
//     defaultValues: {
//       initialAmount: "",
//       remark: "",
//       status: ""
//     },
//   });

//   useEffect(() => {
//     if (fee) {
//       const lastHistory = last(fee.initialAmountHistory) || {};
//       reset({
//         initialAmount: fee.initialAmount || "",
//         remark: lastHistory.remark || "",
//         status: ""
//       });
//     }
//   }, [fee, reset]);

//   const handleClose = () => {
//     reset();
//     onClose();
//   };

//   const onSubmit = (values) => {
//     onSave(values);
//     handleClose();
//   };

//   const handleCancel = () => {
//     setValue("status", "cancel");
//     handleSubmit(onSubmit)();
//   };

//   return (
//     <Drawer isOpen={isOpen} onClose={handleClose} size="sm">
//       <DrawerOverlay />
//       <DrawerContent>
//         <DrawerHeader>{fee ? "Edit Extra Fee" : "Add Extra Fee"}</DrawerHeader>
//         <DrawerBody>
//           <form onSubmit={handleSubmit(onSubmit)}>
//             <FormControl>
//               <FormLabel>Initial Amount</FormLabel>
//               <Input
//                 type="number"
//                 {...register("initialAmount", { required: true })}
//               />
//             </FormControl>
//             <FormControl mt={4}>
//               <FormLabel>Remark</FormLabel>
//               <Input type="text" {...register("remark")} />
//             </FormControl>

//             <input type="hidden" {...register("status")} />

//             <DrawerFooter px={0}>
//               {/* <Button
//                 variant="solid"
//                 colorScheme="red"
//                 mr="auto"
//                 onClick={handleCancel}
//                 isPending={pending || updatePending}
//               >
//                 Cancel Fee
//               </Button> */}

//               <Button variant="outline" mr={3} onClick={handleClose}>
//                 Close
//               </Button>

//               <Button type="submit" colorScheme="blue" isPending={pending || updatePending}>
//                 Save
//               </Button>
//             </DrawerFooter>
//           </form>
//         </DrawerBody>
//       </DrawerContent>
//     </Drawer>
//   );
// };


export const FeeModal = ({ isOpen, onClose, onSave, fee, pending, updatePending }) => {
  const { register, handleSubmit, reset, setValue, watch, formState: { errors } } = useForm({
    defaultValues: {
      initialAmount: "",
      confirmAmount: "",
      remark: "",
      status: ""
    },
  });

  const initialAmount = watch("initialAmount");
  const confirmAmount = watch("confirmAmount");

  useEffect(() => {
    if (fee) {
      const lastHistory = fee.initialAmountHistory?.slice(-1)[0] || {};
      reset({
        initialAmount: fee?.initialAmount || "",
        confirmAmount: fee?.initialAmount || "",
        remark: lastHistory.remark || "",
        status: ""
      });
    }
  }, [fee, reset]);

  const handleClose = () => {
    reset();
    onClose();
  };

  const onSubmit = (values) => {
    if (Number(values.initialAmount) !== Number(values.confirmAmount)) {
      ErrorAlert("Amount and Confirm Amount must match");
      return;
    }

    const dataToSubmit = {
      initialAmount: values.initialAmount,
      remark: values.remark,
      status: values.status
    };

    onSave(dataToSubmit);
    handleClose();
  };

  const handleCancel = () => {
    setValue("status", "cancel");
    handleSubmit(onSubmit)();
  };

  return (
    <Modal isOpen={isOpen} onClose={handleClose} size="md">
      <ModalOverlay />
      <ModalContent>
        <ModalHeader>{fee ? "Edit Extra Fee" : "Add Extra Fee"}</ModalHeader>
        <ModalCloseButton />
        <ModalBody>
          <form onSubmit={handleSubmit(onSubmit)}>
            <Flex justifyContent={"center"} mb={4}>
              <Text fontSize={"lg"} fontWeight={"semibold"}>Initial Amount: {fee?.initialAmount}</Text>
            </Flex>
            <Grid templateColumns="repeat(2, 1fr)" gap={4}>
              <GridItem>
                <FormControl isRequired isInvalid={errors.initialAmount}>
                  <FormLabel>Amount</FormLabel>
                  <Input
                    type="number"
                    {...register("initialAmount", { required: true })}
                  />
                </FormControl>
              </GridItem>
              <GridItem>
                <FormControl isRequired isInvalid={initialAmount !== confirmAmount}>
                  <FormLabel>Confirm Amount</FormLabel>
                  <Input
                    type="number"
                    {...register("confirmAmount", { required: true })}
                  />
                  {initialAmount !== confirmAmount && initialAmount && confirmAmount && (
                    <FormErrorMessage>Amounts must be same</FormErrorMessage>
                  )}
                </FormControl>
              </GridItem>
            </Grid>
            <FormControl isRequired mt={4}>
              <FormLabel>Remark</FormLabel>
              <Input type="text" {...register("remark", { required: true })} />
            </FormControl>

            <input type="hidden" {...register("status")} />
          </form>
        </ModalBody>

        <ModalFooter>
          <Button variant="outline" mr={3} onClick={handleClose}>
            Close
          </Button>
          <Button
            type="submit"
            colorScheme="blue"
            onClick={handleSubmit(onSubmit)}
            isLoading={pending || updatePending}
            isDisabled={initialAmount !== confirmAmount}
          >
            Save
          </Button>
        </ModalFooter>
      </ModalContent>
    </Modal>
  );
};


export const FeeCancelModal = ({ isOpen, onClose, onSave, pending, updatePending, fee }) => {

  const { register, handleSubmit, reset, setValue } = useForm({
    defaultValues: {
      initialAmount: "",
      remark: "",
      status: "",
    },
  });

  useEffect(() => {
    if (fee) {
      const lastHistory = last(fee.initialAmountHistory) || {};
      reset({
        initialAmount: fee?.initialAmount || "",
        remark: lastHistory.remark || "",
        status: ""
      });
    }
  }, [fee, reset]);


  const handleClose = () => {
    reset();
    onClose();
  };

  const onSubmit = (values) => {
    onSave(values);
    handleClose();
  };

  const handleCancel = () => {
    setValue("status", "cancel");
    handleSubmit(onSubmit)();
  };

  return (
    <Modal isOpen={isOpen} onClose={onClose}>
      <ModalOverlay />
      <ModalContent>
        <ModalHeader>Cancel Fee</ModalHeader>
        <ModalCloseButton />
        <ModalBody>
          Are you sure you want to cancel the Fee?
        </ModalBody>
        <ModalFooter>
          <Button variant="ghost" mr={3} onClick={onClose}>
            Close
          </Button>
          <Button
            variant="solid"
            colorScheme="red"
            onClick={handleCancel}
            isLoading={pending}
          >
            Confirm
          </Button>
        </ModalFooter>
      </ModalContent>
    </Modal>
  );
};

Editor is loading...
Leave a Comment