Files
tanami-admin-panel/src/Pages/Fawateer/CreateRequest.jsx
YasinShaikh123 537304f0fb update bug
2024-12-02 12:23:27 +05:30

441 lines
14 KiB
JavaScript

import React, { useState } from "react";
import { OPACITY_ON_LOAD } from "../../Layout/animations";
import {
Box,
Button,
HStack,
Input,
InputGroup,
InputRightAddon,
Textarea,
useDisclosure,
Image,
Icon,
VStack,
Text,
useToast,
} from "@chakra-ui/react";
import { FormControl, FormLabel, FormHelperText } from "@chakra-ui/react";
import { DeleteIcon, Search2Icon } from "@chakra-ui/icons";
import SelectInvestorModal from "./SelectInvestorModal";
import { Controller, useForm } from "react-hook-form"; // Import useForm
import { yupResolver } from "@hookform/resolvers/yup"; // Import resolver for Yup
import * as Yup from "yup"; // Import Yup for validation
import { motion } from "framer-motion"; // Import Framer Motion for animations
import { bytesToMB } from "../../Constants/Constants";
import { useCreateFawateerRequestMutation } from "../../Services/fawateer.maker.service";
import ToastBox from "../../Components/ToastBox";
import { useNavigate } from "react-router-dom";
import CurrencyInput from "../../Components/CurrencyInput";
// Validation schema using Yup
const validationSchema = Yup.object().shape({
investorName: Yup.string().required("Investor name is required"),
clientId: Yup.string().required("Client ID is required"),
transaction_date: Yup.date()
.required("Date is required")
.transform((value, originalValue) => {
return originalValue === "" ? null : value; // Convert empty strings to null
})
.typeError("Please enter a valid date")
.max(new Date(), "Date cannot be in the future"),
transaction_amount: Yup.number()
.required("Transaction amount is required")
.transform((value, originalValue) => (originalValue === "" ? null : value)) // Convert empty strings to null
.typeError("Transaction amount must be a number") // Custom error message if it's not a number
.positive("Transaction amount must be greater than zero"),
spportFile_path: Yup.mixed().required("Support file is required"),
makerComment: Yup.string() .max(200, "Approve Comment cannot be more than 50 characters"),
});
const CreateRequest = () => {
const toast = useToast();
const navigate = useNavigate();
const { isOpen, onOpen, onClose } = useDisclosure();
const [selectedInvestor, setSelectorInvestor] = useState({});
const [filePreview, setFilePreview] = useState(null); // State for previewing the file
const [fileType, setFileType] = useState(null); // State to store file type for conditional rendering
const [isLoading, setIsLoading] = useState(false);
const [id, setId] = useState(null);
// Initialize useForm with the resolver for Yup validation
const {
control,
register,
watch,
handleSubmit,
setValue,
reset,
formState: { errors },
} = useForm({
resolver: yupResolver(validationSchema),
});
const [creatFawaateerRequest] = useCreateFawateerRequestMutation();
const onSubmit = async (data) => {
console.log(data);
setIsLoading(true);
// Convert data to FormData
const formData = new FormData();
// Append each field from the data object to the FormData
Object.keys(data).forEach((key) => {
if (key === "spportFile_path" && data[key] instanceof FileList) {
// Append the first file from FileList (assuming single file input)
formData.append(key, data[key][0]); // Append the file
} else {
formData.append(key, data[key]); // Append other fields
}
});
try {
// Make the API call with formData
const res = await creatFawaateerRequest({ data: formData, id });
if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsLoading(false);
reset();
return;
} else if (res?.data) {
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
setIsLoading(false);
navigate("/fawateer-history");
return;
} else {
toast({
render: () => (
<ToastBox status={"error"} message={"Something went wrong"} />
),
});
setIsLoading(false);
return;
}
} catch (error) {
console.error("Error:", error);
toast({
render: () => (
<ToastBox status={"error"} message={"An error occurred"} />
),
});
setIsLoading(false);
return;
}
};
// Handle file change and preview
const handleFileChange = (e) => {
const file = e.target.files[0];
console.log(file);
setValue("spportFile_path", file); // Set the file value in the form
setFileType(file); // Set the file type
if (file && file.type.startsWith("image/")) {
// If the file is an image, generate a preview
const reader = new FileReader();
reader.onload = () => {
setFilePreview(reader.result); // Set the image preview
};
reader.readAsDataURL(file);
} else {
setFilePreview(null); // Clear preview if the file is not an image
}
};
return (
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={38}>
<Box
display={"flex"}
justifyContent={"space-between"}
flexWrap={"wrap"}
alignItems={"center"}
mt={5}
px={4}
as="form"
onSubmit={handleSubmit(onSubmit)}
>
{/* Investor Name Field */}
<FormControl
isRequired
w={"49%"}
mb={2}
isInvalid={errors.investorName}
>
<FormLabel textAlign={"left"} fontSize={"xs"} color={"gray.600"}>
Investor name
</FormLabel>
<InputGroup size="sm">
<Input
bg={"#F5F8F6"}
focusBorderColor="forestGreen.300"
size={"sm"}
fontSize={"sm"}
rounded={"sm"}
type={"text"}
readOnly={true}
placeholder={"Investor name"}
{...register("investorName")}
_placeholder={{ fontSize: "sm" }}
/>
<InputRightAddon
gap={2}
color={"forestgreen.400"}
onClick={onOpen}
cursor={"pointer"}
fontWeight={600}
fontSize={"xs"}
>
<Search2Icon /> Search
</InputRightAddon>
</InputGroup>
<FormHelperText
fontSize={"xs"}
fontWeight={500}
style={{ color: "red" }}
>
{errors.investorName?.message}
</FormHelperText>
</FormControl>
{/* Client ID Field */}
<FormControl isRequired w={"49%"} mb={2} isInvalid={errors.clientId}>
<FormLabel textAlign={"left"} fontSize={"xs"} color={"gray.600"}>
Client Id
</FormLabel>
<Input
bg={"#F5F8F6"}
focusBorderColor="forestGreen.300"
size={"sm"}
fontSize={"sm"}
rounded={"sm"}
type={"text"}
readOnly={true}
placeholder={"Client ID"}
{...register("clientId")}
/>
<FormHelperText
fontSize={"xs"}
fontWeight={500}
style={{ color: "red" }}
>
{errors.clientId?.message}
</FormHelperText>
</FormControl>
{/* Date Field */}
<FormControl isRequired w={"49%"} mb={2} isInvalid={errors.date}>
<FormLabel textAlign={"left"} fontSize={"xs"} color={"gray.600"}>
Date
</FormLabel>
<Input
bg={"#F5F8F6"}
focusBorderColor="forestGreen.300"
size={"sm"}
fontSize={"sm"}
rounded={"sm"}
type={"date"}
max={new Date().toLocaleDateString("en-CA")} // Ensures max is in local timezone
{...register("transaction_date", {
setValueAs: (value) => {
// Convert date string to local timezone Date object
return value ? new Date(value) : undefined;
},
})}
/>
<FormHelperText
fontSize={"xs"}
fontWeight={500}
style={{ color: "red" }}
>
{errors.transaction_date?.message}
</FormHelperText>
</FormControl>
{/* Amount Field */}
<FormControl isRequired w={"49%"} mb={2} isInvalid={errors.amount}>
<FormLabel textAlign={"left"} fontSize={"xs"} color={"gray.600"}>
Amount (BHD)
</FormLabel>
<Controller
name="transaction_amount"
control={control}
render={({ field }) => (
<CurrencyInput
bg={"#F5F8F6"}
{...field}
textAlign={"right"}
fontSize={"sm"}
type="number"
size={"sm"}
/>
)}
/>
<FormHelperText
fontSize={"xs"}
fontWeight={500}
style={{ color: "red" }}
>
{errors.transaction_amount?.message}
</FormHelperText>
</FormControl>
{/* Support File Field with Preview */}
<FormControl
isRequired
w={"49%"}
mb={2}
isInvalid={errors.spportFile_path}
>
<FormLabel textAlign={"left"} fontSize={"xs"} color={"gray.600"}>
Support file
</FormLabel>
<Input
bg={"#F5F8F6"}
focusBorderColor="forestGreen.300"
size={"sm"}
fontSize={"sm"}
rounded={"sm"}
type={"file"}
className="form-control"
name="spportFile_path"
placeholder={"Support file"}
{...register("spportFile_path")}
// onChange={handleFileChange}
/>
<FormHelperText
fontSize={"xs"}
fontWeight={500}
style={{ color: "red" }}
>
{errors.spportFile_path?.message}
</FormHelperText>
{/* Animated Preview */}
{filePreview && fileType?.type.startsWith("image/") && (
<motion.div
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.5 }}
style={{ marginTop: "10px" }}
>
<Box
position={"relative"}
display={"flex"}
alignContent={"flex-end"}
gap={3}
mt={2}
>
<Image
src={filePreview}
alt="File preview"
maxW={"150px"}
borderRadius="md"
boxShadow="md"
/>
<Icon
onClick={() => setFilePreview(null)}
className="link"
rounded={"md"}
color={"red.700"}
cursor={"pointer"}
p={1.5}
position={"absolute"}
top={0}
right={0}
as={DeleteIcon}
boxSize={7}
/>
<VStack justifyItems={"flex-end"} alignItems={"flex-start"}>
<Text as={"span"} color={"gray.600"} fontSize={"xs"}>
File Name:{" "}
<Text as={"span"} color={"GrayText"}>
{" "}
{fileType?.name}
</Text>
</Text>
<Text as={"span"} color={"gray.600"} fontSize={"xs"}>
File Size:{" "}
<Text as={"span"} color={"GrayText"}>
{" "}
{bytesToMB(fileType?.size)} Mb
</Text>
</Text>
<Text as={"span"} color={"gray.600"} fontSize={"xs"}>
File Type:{" "}
<Text as={"span"} color={"GrayText"}>
{" "}
{fileType?.type}
</Text>
</Text>
</VStack>
</Box>
</motion.div>
)}
</FormControl>
{/* Description Field */}
<FormControl w={"100%"} mb={2} isInvalid={errors.makerComment}>
<FormLabel textAlign={"left"} fontSize={"xs"} color={"gray.600"}>
Description
</FormLabel>
<Textarea
bg={"#F5F8F6"}
focusBorderColor="forestGreen.300"
size={"sm"}
fontSize={"sm"}
rounded={"sm"}
placeholder={"Description"}
{...register("makerComment")}
maxLength={200}
/>
<FormHelperText
fontSize={"xs"}
fontWeight={500}
style={{ color: "red" }}
>
{errors.makerComment?.message}
</FormHelperText>
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>
Maximum length should be 200 characters. You have entered
</Box>
{watch("makerComment")?.length || 0} characters.
</FormHelperText>
</FormControl>
{/* Submit Button */}
<HStack mt={2} w={"100%"} justifyContent={"flex-end"}>
<Button
colorScheme="forestGreen"
size={"sm"}
rounded={"sm"}
fontSize={"xs"}
type="submit"
isLoading={isLoading}
>
Create request
</Button>
</HStack>
</Box>
<SelectInvestorModal
setId={setId}
setValue={setValue}
onClose={onClose}
isOpen={isOpen}
onOpen={onOpen}
/>
</Box>
);
};
export default CreateRequest;