This commit is contained in:
2024-09-27 12:04:23 +05:30
parent 79fd26c6a0
commit f76e413fc9
30 changed files with 1352 additions and 1419 deletions

View File

@@ -15,6 +15,7 @@ import GlobalStateContext from "./Contexts/GlobalStateContext";
import Cookies from "js-cookie";
import NoInternetScreen from "./Pages/NoInternetScreen";
import OnboardingFrame from "./Pages/Onboarding/OnboardingFrame";
import StatusCheck from "./Pages/StatusCheck/StatusCheck";
const App = () => {
// const { isAuthenticate } = useSelector((state) => state?.auth);
@@ -55,6 +56,9 @@ const App = () => {
<Route path="/login" element={<Login />} />
<Route path="/onboarding-frame" element={<OnboardingFrame />} />
<Route path="/status-check" element={<StatusCheck />} />
<Route
path="/*"

View File

@@ -13,10 +13,13 @@ import { MinusIcon } from "@chakra-ui/icons";
const CustomBreadcrumb = () => {
const { pathname } = useLocation();
console.log(pathname);
// Remove leading slash and split path into parts
const pathParts = pathname.replace(/^\//, "").split("/");
console.log(pathParts);
// Find the current menu item based on the provided path
const findMenuItem = (path) => {
let menuItem = null;
@@ -52,6 +55,8 @@ const CustomBreadcrumb = () => {
const breadcrumbs = generateBreadcrumbs(pathParts);
console.log(breadcrumbs);
return (
<Box
fontWeight="medium"
@@ -74,7 +79,7 @@ const CustomBreadcrumb = () => {
size={"xs"}
as={"span"}
>
Dashboard
Home
</Button>
{breadcrumbs.map((item, index) => (
<React.Fragment key={index}>

View File

@@ -36,6 +36,7 @@ const HeaderMain = ({
slideDirecttion,
isDrawerOpen,
toggleDrawer,
blur
}) => {
const navigate = useNavigate();
const { colorMode, toggleColorMode } = useContext(GlobalStateContext);
@@ -52,6 +53,7 @@ const HeaderMain = ({
slideDirecttion ? " ps-2" : ""
} justify-content-between align-items-center`}
zIndex={999}
>
<Box display={"flex"} alignItems={"center"}>
<Box w={"250px"} display={"flex"} alignItems={"center"} justifyContent={"space-between"}>
@@ -66,7 +68,7 @@ const HeaderMain = ({
}}
src={mainLogo}
alt="Logo"
onClick={() => navigate("/")}
onClick={() => !blur && navigate("/")}
cursor={"pointer"}
/>
</Box>
@@ -90,7 +92,7 @@ const HeaderMain = ({
</Button>
</Box>
<InputGroup width={350} size="sm" ml={5}>
{!blur&&<InputGroup width={350} size="sm" ml={5}>
<InputLeftElement pointerEvents="none">
<SearchIcon color="gray.300" />
</InputLeftElement>
@@ -102,9 +104,9 @@ const HeaderMain = ({
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</InputGroup>
</InputGroup>}
</Box>
<Box display={"flex"} justifyContent={"space-between"}>
<Box filter= {blur && "blur(5px)"} display={"flex"} justifyContent={"space-between"}>
<Box display={"flex"} gap={2}>
<Box display={"flex"} gap={2} alignItems={'center'} me={2}>
<Button size={'sm'} bg={"none"} p={0}>
@@ -132,7 +134,11 @@ const HeaderMain = ({
</PopoverFooter>
</PopoverContent>
</Portal>
<PopoverTrigger>
{blur?
<Box>
<Box className="d-flex pointer align-items-center">
<Avatar size="sm" boxSize={37} bg={"#210a33"} />
<Box
@@ -149,7 +155,24 @@ const HeaderMain = ({
</Text>
</Box>
</Box>
</PopoverTrigger>
</Box>:<PopoverTrigger>
<Box className="d-flex pointer align-items-center">
<Avatar size="sm" boxSize={37} bg={"#210a33"} />
<Box
style={{
display: "flex",
}}
className=" overflow-hidden ms-3 flex-column "
>
<Text as={"span"} className="web-text-small">
Hello, Developers
</Text>
<Text as={"span"} className="web-text-xsmall">
mailto:wdi@tanami.com
</Text>
</Box>
</Box>
</PopoverTrigger>}
</Popover>
</Box>
</Box>

View File

@@ -19,6 +19,7 @@ const MiniHeader = ({ title, subTitle, backButton }) => {
bg={"#fff"}
p={1}
rounded={"full"}
/>
)}
<VStack alignItems={"start"} gap={1}>

View File

@@ -125,197 +125,6 @@ const DashboardLayout = ({ isOnline }) => {
navigate("/login");
};
// // Function to get the title based on the route
const getTitle = () => {
switch (true) {
case "/":
return "👋🏻 Hi, Developers";
case path.startsWith("/task"):
return (
<span className="d-flex align-items-center gap-2">
<MdOutlineTaskAlt className="h4 m-0" /> Tasks
</span>
);
case path.startsWith("/notification"):
return (
<span className="d-flex align-items-end gap-2">
<GrNotification className="h5 m-0" /> Notification
</span>
);
case path.startsWith("/exchange-rate"):
return (
<span className="d-flex align-items-end gap-2">
<RiExchangeBoxLine className="h4 m-0 fw-normal" />
Echange rate
</span>
);
case path.startsWith("/create-io"):
if (/^\/create-io\/[A-Za-z0-9_-]+$/.test(path)) {
return (
<span className="d-flex align-items-end gap-2">
<MdOutlineAddChart className="h4 m-0 fw-normal" />
Edit IO
</span>
);
}
return (
<span className="d-flex align-items-end gap-2">
<MdOutlineAddChart className="h4 m-0 fw-normal" />
Create IO
</span>
);
case path.startsWith("/view-io"):
return (
<span className="d-flex align-items-end gap-2">
<HiOutlineChartSquareBar className="h4 m-0 fw-normal" />
View IO
</span>
);
case path.startsWith("/investor-details"):
return (
<span className="d-flex align-items-end gap-2">
<TbListDetails className="h4 m-0 fw-normal" />
Investor Details
</span>
);
case path.startsWith("/investor-transactions"):
return (
<span className="d-flex align-items-end gap-2">
<TbTransactionDollar className="h4 m-0 fw-normal" />
Investor Transactions
</span>
);
case path.startsWith("/deposit-request"):
return (
<span className="d-flex align-items-end gap-2">
<RiMoneyDollarBoxLine className="h4 m-0 fw-normal" />
Deposite pending request
</span>
);
case path.startsWith("/deposit-history"):
return (
<span className="d-flex align-items-end gap-2">
<RiExchangeBoxLine className="h4 m-0 fw-normal" />
Deposite withdrawal request
</span>
);
case path.startsWith("/withdraw-request"):
return (
<span className="d-flex align-items-end gap-2">
<RiMoneyDollarBoxLine className="h4 m-0 fw-normal" />
Withdrawal pending request
</span>
);
case path.startsWith("/withdraw-history"):
return (
<span className="d-flex align-items-end gap-2">
<RiExchangeBoxLine className="h4 m-0 fw-normal" />
Withdrawal request
</span>
);
case path.startsWith("/investor-request"):
return (
<span className="d-flex align-items-end gap-2">
<RiMoneyDollarBoxLine className="h4 m-0 fw-normal" />
Investor pending request
</span>
);
case path.startsWith("/investor-history"):
return (
<span className="d-flex align-items-end gap-2">
<RiExchangeBoxLine className="h4 m-0 fw-normal" />
Investor request
</span>
);
case path.startsWith("/deletion-request"):
return (
<span className="d-flex align-items-end gap-2">
<RiMoneyDollarBoxLine className="h4 m-0 fw-normal" />
Deletion pending request
</span>
);
case path.startsWith("/deletion-history"):
return (
<span className="d-flex align-items-end gap-2">
<RiExchangeBoxLine className="h4 m-0 fw-normal" />
Deletion request
</span>
);
case path.startsWith("/bank-investor"):
return (
<span className="d-flex align-items-end gap-2">
<TbReportMoney className="h4 m-0 fw-normal" />
Ban / Unban Investor
</span>
);
case path.startsWith("/academy"):
return (
<span className="d-flex align-items-end gap-2">
<GrManual className="h4 m-0 fw-normal" />
Academy
</span>
);
case path.startsWith("/notification"):
return (
<span className="d-flex align-items-end gap-2">
<MdNotificationsNone className="h4 m-0 fw-normal" />
Notification
</span>
);
case path.startsWith("/contact"):
return (
<span className="d-flex align-items-end gap-2">
<LuContact className="h4 m-0 fw-normal" />
Contact Details
</span>
);
case path.startsWith("/users"):
return (
<span className="d-flex align-items-end gap-2">
<RiFileUserLine className="h4 m-0 fw-normal" />
Users
</span>
);
case path.startsWith("/bank-details"):
return (
<span className="d-flex align-items-end gap-2">
<RiBankLine className="h4 m-0 fw-normal" />
Bank Details
</span>
);
case path.startsWith("/deletion-request"):
return (
<span className="d-flex align-items-end gap-2">
<RiMoneyDollarBoxLine className="h4 m-0 fw-normal" />
Deletion pending request
</span>
);
case path.startsWith("/deletion-history"):
return (
<span className="d-flex align-items-end gap-2">
<RiExchangeBoxLine className="h4 m-0 fw-normal" />
Deletion request
</span>
);
case path.startsWith("/deletion-request"):
return (
<span className="d-flex align-items-end gap-2">
<RiMoneyDollarBoxLine className="h4 m-0 fw-normal" />
Deletion pending request
</span>
);
case path.startsWith("/deletion-history"):
return (
<span className="d-flex align-items-end gap-2">
<RiExchangeBoxLine className="h4 m-0 fw-normal" />
Deletion request
</span>
);
default:
return <span className="d-flex align-items-end gap-2">Home</span>;
}
};
if (isSplashVisible) {
return <SplashScreen />;
@@ -327,8 +136,6 @@ const DashboardLayout = ({ isOnline }) => {
isDrawerOpen={isDrawerOpen}
logOutHandler={logOutHandler}
toggleDrawer={toggleDrawer}
icon
title={getTitle()}
/>
<Box
h={{ base: "92%", lg: "96%" }}

View File

@@ -18,6 +18,6 @@ export const SLIDE_IN_BOTTOM = {
as: motion.div,
initial: { opacity: 0, scale: 0.9 },
animate: { opacity: 1, scale: 1 },
transition: { duration: 0.5, ease: "easeInOut" }
transition: { duration: 1.5, ease: "easeInOut" }
};

View File

@@ -1,145 +1,260 @@
import React, { useCallback, useState } from 'react';
import { Box, Input, InputGroup, InputLeftElement, Select, Text, VStack, Image, HStack } from '@chakra-ui/react';
import React, { useCallback, useState } from "react";
import {
Box,
Input,
InputGroup,
InputLeftElement,
Select,
Text,
VStack,
Image,
HStack,
FormControl,
FormLabel,
FormErrorMessage,
IconButton,
Button,
} from "@chakra-ui/react";
import PhoneInput from "react-phone-input-2";
import "react-phone-input-2/lib/style.css";
import { IoBagOutline } from "react-icons/io5";
import { SlCloudUpload } from 'react-icons/sl';
import { SlCloudUpload } from "react-icons/sl";
import { useGetPrePopQuery } from "../../Services/on.board.service";
import { useForm } from "react-hook-form";
import * as Yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
import { ArrowBackIcon, ArrowForwardIcon } from "@chakra-ui/icons";
import { OPACITY_ON_LOAD } from "../../Layout/animations";
const OnboardingAboutCompany = () => {
// Validation schema using Yup
const validationSchema = Yup.object().shape({
corporate_name: Yup.string().required("Name is required"),
industry_xid: Yup.string().required("Email is required"),
mobileNumber_corporate: Yup.string()
.matches(/^\d{10}$/, "Phone number must be 10 digits")
.required("Phone number is required"),
});
const [phone, setPhone] = useState("");
const OnboardingAboutCompany = ({
corpData,
setCorpData,
setActiveStep,
activeStep,
steps,
handleNext,
}) => {
const { data, isLoading } = useGetPrePopQuery();
console.log(data?.data?.prepopulateData);
return (
<Box>
<Text color={'#49475A'} fontWeight={500} fontSize={'sm'} mb={1}>
About your company
const [phone, setPhone] = useState("");
// Setup form handling with react-hook-form
const {
register,
handleSubmit,
setValue,
formState: { errors },
} = useForm({
resolver: yupResolver(validationSchema),
});
const handlePhoneChange = (value, country) => {
const countryCode = `+${country.dialCode}`;
let numberWithoutISD = value;
setPhone(numberWithoutISD);
setValue(
"mobileNumber_corporate",
value
.split("")
.splice(countryCode.length - 1, 15)
.join("")
); // Sync phone number
setValue("ISDcode_corporate", countryCode); // Sync ISD code
};
// Handle form submission
const onSubmit = (data) => {
setCorpData({ ...corpData, ...data });
handleNext();
// Handle your submit logic here
};
return (
<Box {...OPACITY_ON_LOAD}>
<Text color={"#49475A"} fontWeight={500} fontSize={"sm"} mb={1}>
About your company
</Text>
<Text color={"#49475A"} fontWeight={500} fontSize={"xs"}>
Lorem ipsum dolor sit amet, adipiscing elit.
</Text>
{/* Form Fields */}
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
{/* Company Name Field */}
<FormControl isRequired mb={3}>
<FormLabel color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Company Name
</FormLabel>
<InputGroup>
<InputLeftElement pointerEvents="none">
<IoBagOutline color="gray.300" />
</InputLeftElement>
<Input
type="text"
border="1px solid #e2e8f0"
borderRadius="8px"
placeholder="Enter company name"
size={"md"}
fontSize={"xs"}
{...register("corporate_name")}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500} as={"span"}>
{errors.corporate_name?.message}
</FormErrorMessage>
</InputGroup>
</FormControl>
{/* Industry Select Field */}
<FormControl isRequired mb={3}>
<Text color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Industry
</Text>
<InputGroup>
<Select
placeholder="Select industry"
fontWeight={500}
size={"md"}
fontSize={"xs"}
{...register("industry_xid")} // Link with react-hook-form
>
{data?.data?.prepopulateData?.map(
({ industry_name, id }, index) => (
<option key={index} value={id}>
{industry_name}
</option>
)
)}
</Select>
<FormErrorMessage fontSize={"xs"} fontWeight={500} as={"span"}>
{errors.industry_xid?.message}
</FormErrorMessage>
</InputGroup>
</FormControl>
{/* Phone Number Field */}
<FormControl isRequired mb={3}>
<FormLabel color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Phone Number
</FormLabel>
<PhoneInput
country={"in"} // Default country
value={phone}
onChange={handlePhoneChange}
inputStyle={{
width: "100%",
borderRadius: "md",
paddingLeft: "8",
border: "1px solid #e2e8f0",
height: "40px",
fontSize: "12px",
}}
buttonStyle={{
border: "none",
borderRadius: "8px 0 0 8px",
backgroundColor: "transparent",
}}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500} as={"span"}>
{errors.mobileNumber_corporate?.message}
</FormErrorMessage>
</FormControl>
{/* Upload Company Logo Field */}
<Box mb={3}>
<Text color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Upload Company Logo
</Text>
<Box
my={2}
position="relative"
onClick={() =>
document.getElementById("company-logo-file-input").click()
}
>
<VStack
border={"1px dashed #D0D5DD"}
boxShadow={"md"}
borderRadius={"md"}
bg={"#faf8fd"}
p={4}
h={"28"}
justifyContent={"center"}
cursor="pointer"
>
<SlCloudUpload color={"#191D23"} size={30} />
<Text
color={"#191D23"}
fontWeight={"500"}
fontSize={"sm"}
mt={"2"}
mb={0}
>
Drag and drop files here or{" "}
<Text as="span" textDecoration="underline">
Choose file
</Text>
</Text>
</VStack>
<input
type="file"
id="company-logo-file-input"
style={{ display: "none" }} // Hide the file input
/>
</Box>
<HStack justifyContent={"space-between"}>
<Text color={"#C3C3C3"} fontSize={"xs"} fontWeight={400} mb={1}>
Supported formats- jpg, png, svg
</Text>
<Text color={'#49475A'} fontWeight={500} fontSize={'xs'}>
Lorem ipsum dolor sit amet, adipiscing elit.
<Text color={"#C3C3C3"} fontSize={"xs"} fontWeight={400} mb={1}>
Maximum size - 20MB
</Text>
</HStack>
{/* Form Fields */}
<Box as="form">
{/* Company Name Field */}
<Box mb={3}>
<Text color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Company Name
</Text>
<InputGroup>
<InputLeftElement pointerEvents='none'>
<IoBagOutline color='gray.300' />
</InputLeftElement>
<Input
type='text'
border="1px solid #e2e8f0"
borderRadius="8px"
placeholder="Enter company name"
size={"md"}
/>
</InputGroup>
</Box>
<HStack mt={6}>
<IconButton
aria-label="Back"
icon={<ArrowBackIcon />}
variant="outline"
size="sm"
px={8}
_hover={{ opacity: 0.8 }}
color={"#d0b8ef"}
border={"1px solid #d0b8ef"}
isDisabled={activeStep === 0}
onClick={() => setActiveStep(activeStep - 1)}
/>
{/* Industry Select Field */}
<Box mb={3}>
<Text color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Industry
</Text>
<InputGroup>
<Select
placeholder='Select industry'
fontSize={"sm"}
fontWeight={500}
size={"md"}
>
<option value="option1">Industry 1</option>
<option value="option2">Industry 2</option>
<option value="option3">Industry 3</option>
</Select>
</InputGroup>
</Box>
{/* Phone Number Field */}
<Box mb={3}>
<Text color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Phone Number
</Text>
<Box>
<PhoneInput
country={"in"} // Default country
value={phone}
onChange={setPhone}
inputStyle={{
width: "100%",
borderRadius: "md",
paddingLeft: "8",
border: "1px solid #e2e8f0",
height:"40px"
}}
buttonStyle={{
border: "none",
borderRadius: "8px 0 0 8px",
backgroundColor: "transparent",
}}
/>
</Box>
</Box>
{/* Upload Company Logo Field */}
<Box mb={3}>
<Text color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Upload Company Logo
</Text>
<Box my={2}
position="relative"
onClick={() => document.getElementById('company-logo-file-input').click()}
>
<VStack
border={"1px dashed #D0D5DD"}
boxShadow={"md"}
borderRadius={"md"}
bg={"#faf8fd"}
p={4}
h={"28"}
justifyContent={"center"}
cursor="pointer"
>
<SlCloudUpload color={"#191D23"} size={30} />
<Text
color={"#191D23"}
fontWeight={"500"}
fontSize={"sm"}
mt={'2'}
mb={0}
>
Drag and drop files here or{' '}
<Text as="span" textDecoration="underline">
Choose file
</Text>
</Text>
</VStack>
<input
type="file"
id="company-logo-file-input"
style={{ display: 'none' }} // Hide the file input
/>
</Box>
<HStack justifyContent={"space-between"}>
<Text color={"#C3C3C3"} fontSize={"xs"} fontWeight={400} mb={1}>
Supported formats- jpg, png, svg
</Text>
<Text color={"#C3C3C3"} fontSize={"xs"} fontWeight={400} mb={1}>
Maximum size - 20MB
</Text>
</HStack>
</Box>
</Box>
<Button
bg={"#6311CB"}
color={"#fff"}
fontSize={"xs"}
fontWeight={500}
size="sm"
_hover={{ opacity: 0.8 }}
rightIcon={<ArrowForwardIcon />}
w={"100%"}
type="submit"
>
{activeStep === steps.length - 1 ? "Next step" : "Next step"}
</Button>
</HStack>
</Box>
);
</Box>
</Box>
);
};
export default OnboardingAboutCompany;

View File

@@ -1,11 +1,40 @@
import React, { useCallback, useState } from 'react';
import { Box, Input, InputGroup, InputLeftElement, Select, Text, VStack, Image, HStack } from '@chakra-ui/react';
import React from 'react';
import { Box, Input, Text, VStack, HStack, FormLabel } from '@chakra-ui/react';
import { SlCloudUpload } from 'react-icons/sl';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
import { OPACITY_ON_LOAD } from '../../Layout/animations';
// Yup validation schema
const schema = yup.object().shape({
cin: yup
.string()
.required('CIN is required')
.matches(/^[A-Za-z0-9]{21}$/, 'CIN must be exactly 21 characters long'),
pan: yup
.string()
.required('Company PAN is required')
.matches(/[A-Z]{5}[0-9]{4}[A-Z]{1}$/, 'Invalid PAN format'),
gst: yup
.string()
.required('GST number is required')
.matches(/\d{2}[A-Z]{5}\d{4}[A-Z]{1}[A-Z\d]{1}[Z]{1}[A-Z\d]{1}/, 'Invalid GST number format'),
// gstFile: yup.mixed().required('GST certificate is required'),
// panFile: yup.mixed().required('PAN card is required'),
});
const OnboardingAddCompanyDetails = () => {
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: yupResolver(schema),
});
const onSubmit = (data) => {
console.log('Form Data:', data);
};
return (
<Box>
<Box {...OPACITY_ON_LOAD}>
<Text color={'#49475A'} fontWeight={500} fontSize={'sm'} mb={1}>
Add company details
</Text>
@@ -13,38 +42,23 @@ const OnboardingAddCompanyDetails = () => {
Lorem ipsum dolor sit amet, adipiscing elit.
</Text>
<Box as="form">
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
{/* CIN Field */}
<Box mb={3}>
<Text color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
<FormLabel color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
CIN
</Text>
</FormLabel>
<Input
type='text'
border="1px solid #e2e8f0"
borderRadius="md"
fontSize={"sm"}
fontWeight={500}
{...register('cin')}
/>
{errors.cin && <Text color="red.500" fontWeight={500} fontSize="xs">{errors.cin.message}</Text>}
</Box>
{/* Industry Select Field */}
<Box mb={3}>
<Text color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Company PAN
</Text>
<InputGroup>
<Select
placeholder='Select company pan'
fontSize={"sm"}
fontWeight={500}
>
<option value="option1">Industry 1</option>
<option value="option2">Industry 2</option>
<option value="option3">Industry 3</option>
</Select>
</InputGroup>
</Box>
{/* Company PAN Field */}
<Box mb={3}>
<Text color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
@@ -56,17 +70,35 @@ const OnboardingAddCompanyDetails = () => {
borderRadius="md"
fontSize={"sm"}
fontWeight={500}
{...register('pan')}
/>
{errors.pan && <Text color="red.500" fontWeight={500} fontSize="xs">{errors.pan.message}</Text>}
</Box>
{/* Company GST Number */}
<Box mb={3}>
<Text color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Company GST number
</Text>
<Input
type='text'
border="1px solid #e2e8f0"
borderRadius="md"
fontSize={"sm"}
fontWeight={500}
{...register('gst')}
/>
{errors.gst && <Text color="red.500" fontWeight={500} fontSize="xs">{errors.gst.message}</Text>}
</Box>
{/* Upload GST Certificate */}
<Box mb={3}>
<Text color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Upload Pan
Upload GST Certificate
</Text>
<Box my={2}
position="relative"
onClick={() => document.getElementById('GST-file-input').click()}
onClick={() => document.getElementById('gst-file-input').click()}
>
<VStack
border={"1px dashed #D0D5DD"}
@@ -94,10 +126,12 @@ const OnboardingAddCompanyDetails = () => {
</VStack>
<input
type="file"
id="GST-file-input"
style={{ display: 'none' }} // Hide the file input
id="gst-file-input"
style={{ display: 'none' }}
{...register('gstFile')}
/>
</Box>
{errors.gstFile && <Text color="red.500" fontSize="xs">{errors.gstFile.message}</Text>}
<HStack justifyContent={"space-between"}>
<Text color={"#C3C3C3"} fontSize={"xs"} fontWeight={400} mb={1}>
@@ -112,7 +146,7 @@ const OnboardingAddCompanyDetails = () => {
{/* Upload PAN Card */}
<Box mb={3}>
<Text color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Upload Pan
Upload PAN Card
</Text>
<Box my={2}
position="relative"
@@ -145,9 +179,11 @@ const OnboardingAddCompanyDetails = () => {
<input
type="file"
id="pan-file-input"
style={{ display: 'none' }} // Hide the file input
style={{ display: 'none' }}
{...register('panFile')}
/>
</Box>
{errors.panFile && <Text color="red.500" fontSize="xs">{errors.panFile.message}</Text>}
<HStack justifyContent={"space-between"}>
<Text color={"#C3C3C3"} fontSize={"xs"} fontWeight={400} mb={1}>
@@ -158,6 +194,22 @@ const OnboardingAddCompanyDetails = () => {
</Text>
</HStack>
</Box>
{/* Submit Button */}
<Box mt={6}>
<Text
as="button"
bg={'#6311CB'}
color={"white"}
fontWeight={600}
fontSize={'sm'}
p={2}
borderRadius={"md"}
type="submit"
>
Submit
</Text>
</Box>
</Box>
</Box>
);

View File

@@ -1,17 +1,15 @@
import React, { useCallback, useState } from 'react';
import { Box, Input, Text, VStack, Image, HStack } from '@chakra-ui/react';
import React, { useState } from 'react';
import { Box, Input, Text, VStack, HStack } from '@chakra-ui/react';
import { SlCloudUpload } from 'react-icons/sl';
import PhoneInput from 'react-phone-input-2';
const OnboardingDirectorDetails = () => {
const [phone, setPhone] = useState("");
// Initial state for director forms
const [directorForms, setDirectorForms] = useState([
{ id: 1, directorName: '', directorEmail: '', directorPhone: '', selectedPanImage: '', selectedAadharImage: '' }
]);
const [directorFormErrors, setDirectorFormErrors] = useState([]);
// Add new director form
const handleAddDirector = () => {
setDirectorForms([
@@ -20,6 +18,67 @@ const OnboardingDirectorDetails = () => {
]);
};
// Update the form field for a particular director
const handleFieldChange = (index, field, value) => {
const updatedForms = [...directorForms];
updatedForms[index][field] = value;
setDirectorForms(updatedForms);
};
// Handle file upload for PAN and Aadhar
const handleFileUpload = (index, field, event) => {
const file = event.target.files[0];
if (file) {
const updatedForms = [...directorForms];
updatedForms[index][field] = file.name; // Store file name (or file object)
setDirectorForms(updatedForms);
}
};
// Basic validation for each field
const validateForm = () => {
const errors = directorForms.map((directorForm) => {
let formErrors = {};
if (!directorForm.directorName) {
formErrors.directorName = "Director Name is required.";
}
if (!directorForm.directorEmail || !/\S+@\S+\.\S+/.test(directorForm.directorEmail)) {
formErrors.directorEmail = "Please enter a valid email address.";
}
if (!directorForm.directorPhone || directorForm.directorPhone.length < 10) {
formErrors.directorPhone = "Phone number is required and should be at least 10 digits.";
}
if (!directorForm.selectedPanImage) {
formErrors.selectedPanImage = "Please upload a PAN file.";
}
if (!directorForm.selectedAadharImage) {
formErrors.selectedAadharImage = "Please upload an Aadhar file.";
}
return formErrors;
});
setDirectorFormErrors(errors);
// Check if all forms are valid (no errors in any form)
const isValid = errors.every((formErrors) => Object.keys(formErrors).length === 0);
return isValid;
};
// Handle form submission
const handleSubmit = () => {
if (validateForm()) {
console.log("Form is valid, proceed with submission.");
} else {
console.log("Form has errors.");
}
};
return (
<Box>
<Text color={'#49475A'} fontWeight={500} fontSize={'sm'} mb={1}>
@@ -53,10 +112,13 @@ const OnboardingDirectorDetails = () => {
fontSize={"sm"}
fontWeight={500}
bg={"#fff"}
placeholder={directorForm.directorNamePlaceholder || " "}
placeholder="Enter director name"
value={directorForm.directorName}
onChange={(e) => directorForm.setDirectorName(e.target.value)}
onChange={(e) => handleFieldChange(index, 'directorName', e.target.value)}
/>
{directorFormErrors[index]?.directorName && (
<Text color="red.500" fontSize="xs">{directorFormErrors[index].directorName}</Text>
)}
</Box>
{/* Director Email Field */}
@@ -71,10 +133,13 @@ const OnboardingDirectorDetails = () => {
fontSize={"sm"}
fontWeight={500}
bg={"#fff"}
placeholder={directorForm.directorEmailPlaceholder || " "}
placeholder="Enter email"
value={directorForm.directorEmail}
onChange={(e) => directorForm.setDirectorEmail(e.target.value)}
onChange={(e) => handleFieldChange(index, 'directorEmail', e.target.value)}
/>
{directorFormErrors[index]?.directorEmail && (
<Text color="red.500" fontSize="xs">{directorFormErrors[index].directorEmail}</Text>
)}
</Box>
{/* Director Phone Number */}
@@ -88,9 +153,9 @@ const OnboardingDirectorDetails = () => {
Phone Number
</Text>
<PhoneInput
country={"in"} // Default country
country={"in"}
value={directorForm.directorPhone}
onChange={(value) => directorForm.setDirectorPhone(value)}
onChange={(value) => handleFieldChange(index, 'directorPhone', value)}
inputStyle={{
width: "100%",
borderRadius: "md",
@@ -104,6 +169,9 @@ const OnboardingDirectorDetails = () => {
backgroundColor: "transparent",
}}
/>
{directorFormErrors[index]?.directorPhone && (
<Text color="red.500" fontSize="xs">{directorFormErrors[index].directorPhone}</Text>
)}
</Box>
{/* Upload Pan */}
@@ -113,7 +181,7 @@ const OnboardingDirectorDetails = () => {
</Text>
<Box my={2}
position="relative"
onClick={() => document.getElementById('pan-file-input').click()}
onClick={() => document.getElementById(`pan-file-input-${index}`).click()}
>
<VStack
border={"1px dashed #D0D5DD"}
@@ -133,37 +201,29 @@ const OnboardingDirectorDetails = () => {
mt={'2'}
mb={0}
>
Drag and drop files here or{' '}
<Text as="span" textDecoration="underline">
Choose file
</Text>
{directorForm.selectedPanImage || "Drag and drop files here or Choose file"}
</Text>
</VStack>
<input
type="file"
id="pan-file-input"
style={{ display: 'none' }} // Hide the file input
id={`pan-file-input-${index}`}
style={{ display: 'none' }}
onChange={(e) => handleFileUpload(index, 'selectedPanImage', e)}
/>
</Box>
<HStack justifyContent={"space-between"}>
<Text color={"#C3C3C3"} fontSize={"xs"} fontWeight={400} mb={1}>
Supported formats- jpg, png, svg
</Text>
<Text color={"#C3C3C3"} fontSize={"xs"} fontWeight={400} mb={1}>
Maximum size - 20MB
</Text>
</HStack>
{directorFormErrors[index]?.selectedPanImage && (
<Text color="red.500" fontSize="xs">{directorFormErrors[index].selectedPanImage}</Text>
)}
</Box>
{/* Upload Aadhar Card */}
{/* Upload Aadhar */}
<Box mb={3}>
<Text color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Upload Aadhar
</Text>
<Box my={2}
position="relative"
onClick={() => document.getElementById('aadhar-file-input').click()}
onClick={() => document.getElementById(`aadhar-file-input-${index}`).click()}
>
<VStack
border={"1px dashed #D0D5DD"}
@@ -183,27 +243,19 @@ const OnboardingDirectorDetails = () => {
mt={'2'}
mb={0}
>
Drag and drop files here or{' '}
<Text as="span" textDecoration="underline">
Choose file
</Text>
{directorForm.selectedAadharImage || "Drag and drop files here or Choose file"}
</Text>
</VStack>
<input
type="file"
id="aadhar-file-input"
style={{ display: 'none' }} // Hide the file input
id={`aadhar-file-input-${index}`}
style={{ display: 'none' }}
onChange={(e) => handleFileUpload(index, 'selectedAadharImage', e)}
/>
</Box>
<HStack justifyContent={"space-between"}>
<Text color={"#C3C3C3"} fontSize={"xs"} fontWeight={400} mb={1}>
Supported formats- jpg, png, svg
</Text>
<Text color={"#C3C3C3"} fontSize={"xs"} fontWeight={400} mb={1}>
Maximum size - 20MB
</Text>
</HStack>
{directorFormErrors[index]?.selectedAadharImage && (
<Text color="red.500" fontSize="xs">{directorFormErrors[index].selectedAadharImage}</Text>
)}
</Box>
</Box>
</Box>
@@ -217,7 +269,22 @@ const OnboardingDirectorDetails = () => {
cursor="pointer"
onClick={() => handleAddDirector()}
>
+ Add director 2
+ Add director {directorForms.length + 1}
</Text>
</Box>
<Box mt={6}>
<Text
as="button"
bg={'#6311CB'}
color={"white"}
fontWeight={600}
fontSize={'sm'}
p={2}
borderRadius={"md"}
onClick={() => handleSubmit()}
>
Submit
</Text>
</Box>
</Box>

View File

@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import {
Box, Text, Stepper, Step, StepIndicator, StepStatus, StepSeparator, useSteps,
StepIcon, StepTitle, Divider, Button, HStack, IconButton, Flex,
@@ -15,8 +15,38 @@ import OnboardingDirectorDetails from './OnboardingDirectorDetails';
import OnboardingSelectPackage from './OnboardingSelectPackage';
import OnboardingSelectPackageModal from './OnboardingSelectPackageModal'; // Import your modal component
import { OPACITY_ON_LOAD } from '../../Layout/animations';
import { useSearchParams } from 'react-router-dom';
// Retrieve the active step from localStorage or set it to 0 if it doesn't exist
const initialStep = parseInt(localStorage.getItem("activeStep")) || 0;
const OnboardingFrame = () => {
// Create a searchParams instance
const [searchParams] = useSearchParams();
const [ corpData, setCorpData ] = useState({})
useEffect(() => {
// Extract specific parameters
if (searchParams) {
const codeCorporate = searchParams.get("code_corporate");
const codeCorporateId = searchParams.get("code_corporateId");
localStorage?.setItem('codeCorporate', codeCorporate)
localStorage?.setItem('codeCorporateId', codeCorporateId)
}
}, [searchParams])
useEffect(() => {
localStorage.setItem("corpData", JSON.stringify(corpData));
console.log(corpData);
}, [corpData])
// Modal state and disclosure hook
const { isOpen, onOpen, onClose } = useDisclosure();
const steps = [
{ title: 'Your details', description: 'Lorem ipsum dolor sit amet dolor', icon: FaUser },
{ title: 'About Company', description: 'Lorem ipsum dolor sit amet dolor', icon: FaBuilding },
@@ -25,34 +55,40 @@ const OnboardingFrame = () => {
{ title: 'Select package', description: 'Lorem ipsum dolor sit amet dolor', icon: FaBoxOpen },
];
// Stepper configuration
const { activeStep, setActiveStep } = useSteps({
index: 0, // Initialize the active step at 0
count: steps.length,
});
// Stepper configuration
const { activeStep, setActiveStep } = useSteps({
index: initialStep, // Initialize the active step from localStorage or 0
count: steps.length,
});
// Function to handle the "Next" button click
const handleNext = () => {
if (activeStep === steps.length - 1) {
// If it's the last step, open the modal
onOpen();
} else {
// Otherwise, go to the next step
const nextStep = activeStep + 1;
setActiveStep(nextStep);
// Store the new active step in localStorage
localStorage.setItem("activeStep", nextStep);
}
};
// Array of components for each step
const stepComponents = [
<OnboardingYourDetails />,
<OnboardingAboutCompany />,
<OnboardingAddCompanyDetails />,
<OnboardingDirectorDetails />,
<OnboardingSelectPackage />
<OnboardingYourDetails corpData={corpData} setCorpData={setCorpData} setActiveStep={setActiveStep} activeStep={activeStep} steps={steps} handleNext={handleNext} />,
<OnboardingAboutCompany corpData={corpData} setCorpData={setCorpData} setActiveStep={setActiveStep} activeStep={activeStep} steps={steps} handleNext={handleNext} />,
<OnboardingAddCompanyDetails corpData={corpData} setCorpData={setCorpData} setActiveStep={setActiveStep} activeStep={activeStep} steps={steps} handleNext={handleNext} />,
<OnboardingDirectorDetails corpData={corpData} setCorpData={setCorpData} setActiveStep={setActiveStep} activeStep={activeStep} steps={steps} handleNext={handleNext} />,
<OnboardingSelectPackage corpData={corpData} setCorpData={setCorpData} setActiveStep={setActiveStep} activeStep={activeStep} steps={steps} handleNext={handleNext} />
];
// Modal state and disclosure hook
const { isOpen, onOpen, onClose } = useDisclosure();
// Function to handle the "Next" button click
const handleNext = () => {
if (activeStep === steps.length - 1) {
// If it's the last step, open the modal
onOpen();
} else {
// Otherwise, go to the next step
setActiveStep(activeStep + 1);
}
};
return (
<Box>
@@ -174,7 +210,7 @@ const OnboardingFrame = () => {
{/* Render the current step component */}
{stepComponents[activeStep]}
<HStack mt={6}>
{/* <HStack mt={6}>
<IconButton
aria-label="Back"
icon={<ArrowBackIcon />}
@@ -201,7 +237,7 @@ const OnboardingFrame = () => {
>
{activeStep === steps.length - 1 ? 'Next step' : 'Next step'}
</Button>
</HStack>
</HStack> */}
</Box>
</Box>
</Box>

View File

@@ -1,9 +1,10 @@
import React from 'react';
import React, { useState } from 'react';
import {
Box, HStack, Text, Modal, ModalOverlay, ModalHeader, ModalCloseButton, ModalBody, ModalContent,Button
} from '@chakra-ui/react';
import { motion } from 'framer-motion';
import PrimaryButton from '../../Components/Buttons/PrimaryButton';
import { useNavigate } from 'react-router-dom';
// Define motion components
const MotionBox = motion(Box);
@@ -12,7 +13,19 @@ const MotionCircle = motion.circle;
const MotionPolyline = motion.polyline;
const OnboardingSelectPackageModalChild = ({isOpen,onClose}) => {
const navigate = useNavigate()
const [ isLoading, setIsLoading ] = useState(false)
const handleCheckMyStatus = () => {
setIsLoading(true); // Set loading state
// 3-second delay before navigating
setTimeout(() => {
navigate('/status-check');
setIsLoading(false); // Reset loading state after navigation
}, 3000);
};
return (
<>
<Modal isOpen={isOpen} onClose={onClose} isCentered>
@@ -88,7 +101,7 @@ const OnboardingSelectPackageModalChild = ({isOpen,onClose}) => {
</Text>
<HStack justifyContent={"center"} mt={6}>
<PrimaryButton title={"Check my status"} />
<PrimaryButton isLoading={isLoading} onClick={handleCheckMyStatus} title={"Check my status"} />
</HStack>
</MotionBox>

View File

@@ -1,103 +1,194 @@
import React, { useState } from 'react';
import { Box, Container, HStack, Image, Input, InputGroup, InputLeftElement, Text } from '@chakra-ui/react';
import React, { useState } from "react";
import {
Box,
Container,
HStack,
Image,
Input,
InputGroup,
InputLeftElement,
Text,
Button,
IconButton,
FormLabel,
FormControl,
FormErrorMessage,
} from "@chakra-ui/react";
import { CiUser, CiMail } from "react-icons/ci";
import optifii_logo from '../../assets/optifii_logo.svg';
import optifii_logo from "../../assets/optifii_logo.svg";
import PhoneInput from "react-phone-input-2";
import "react-phone-input-2/lib/style.css";
import { useForm } from "react-hook-form";
import * as Yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
import { ArrowBackIcon, ArrowForwardIcon } from "@chakra-ui/icons";
import { OPACITY_ON_LOAD } from "../../Layout/animations";
// Validation schema using Yup
const validationSchema = Yup.object().shape({
full_name_principal: Yup.string().required("Name is required"),
emailAddress_principal: Yup.string()
.email("Invalid email format")
.required("Email is required"),
mobileNumber_principal: Yup.string()
.matches(/^\d{10}$/, "Phone number must be 10 digits")
.required("Phone number is required"),
});
const OnboardingYourDetails = () => {
const OnboardingYourDetails = ({
corpData,
setCorpData,
setActiveStep,
activeStep,
steps,
handleNext,
}) => {
const [phone, setPhone] = useState("");
const [phone, setPhone] = useState("");
const handlePhoneChange = (value, country) => {
const countryCode = `+${country.dialCode}`;
let numberWithoutISD = value;
return (
setPhone(numberWithoutISD);
setValue(
"mobileNumber_principal",
value
.split("")
.splice(countryCode.length - 1, 15)
.join("")
); // Sync phone number
setValue("ISDCode_principal", countryCode); // Sync ISD code
};
<Box >
<Box mb={4}>
<Image src={optifii_logo} />
</Box>
<Text fontWeight={600} fontSize={'md'}>
Streamlined Solutions for Seamless Reimbursements!
</Text>
<Text color={'#49475A'} fontWeight={500} fontSize={'sm'} mb={1}>
Add your details
</Text>
<Text color={'#49475A'} fontWeight={500} fontSize={'xs'}>
Lorem ipsum dolor sit amet, adipiscing elit.
</Text>
// Setup form handling with react-hook-form
const {
register,
handleSubmit,
setValue,
formState: { errors },
} = useForm({
resolver: yupResolver(validationSchema),
});
{/* Form Fields */}
<Box as="form">
<Box mb={3}>
<Text
color={"#344054"}
fontSize={"xs"}
fontWeight={500}
mb={1}
>
Name
</Text>
<InputGroup>
<InputLeftElement pointerEvents='none'>
<CiUser color='gray.300' />
</InputLeftElement>
<Input
type='text'
/>
</InputGroup>
</Box>
<Box mb={3}>
<Text
color={"#344054"}
fontSize={"xs"}
fontWeight={500}
mb={1}
>
Email
</Text>
<InputGroup>
<InputLeftElement pointerEvents='none'>
<CiMail color='gray.300' />
</InputLeftElement>
<Input
type='email'
/>
</InputGroup>
</Box>
<Box mb={3}>
<Text
color={"#344054"}
fontSize={"xs"}
fontWeight={500}
mb={1}
>
Phone Number
</Text>
// Handle form submission
const onSubmit = (data) => {
setCorpData({...corpData, ...data})
handleNext()
// Handle your submit logic here
};
<PhoneInput
country={"in"} // Default country
value={phone}
onChange={setPhone}
inputStyle={{
width: "100%",
borderRadius: "md",
paddingLeft: "8",
border: "1px solid #e2e8f0",
height: "40px"
}}
buttonStyle={{
border: "none",
borderRadius: "8px 0 0 8px",
backgroundColor: "transparent",
}}
/>
</Box>
return (
<Box {...OPACITY_ON_LOAD}>
<Box mb={4}>
<Image src={optifii_logo} />
</Box>
<Text fontWeight={600} fontSize={"md"}>
Streamlined Solutions for Seamless Reimbursements!
</Text>
<Text color={"#49475A"} fontWeight={500} fontSize={"sm"} mb={1}>
Add your details
</Text>
<Text color={"#49475A"} fontWeight={500} fontSize={"xs"}>
Lorem ipsum dolor sit amet, adipiscing elit.
</Text>
</Box>
</Box>
{/* Form Fields */}
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<FormControl isRequired mb={3}>
<FormLabel color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Name
</FormLabel>
<InputGroup>
<InputLeftElement pointerEvents="none">
<CiUser color="gray.300" />
</InputLeftElement>
<Input
fontSize={"xs"}
{...register("full_name_principal")}
type="text"
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500} as={"span"}>
{errors.full_name_principal?.message}
</FormErrorMessage>
</InputGroup>
</FormControl>
<FormControl isRequired mb={3}>
<FormLabel color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Email
</FormLabel>
<InputGroup>
<InputLeftElement pointerEvents="none">
<CiMail color="gray.300" />
</InputLeftElement>
<Input
fontSize={"xs"}
{...register("emailAddress_principal")}
type="email"
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500} as={"span"}>
{errors.emailAddress_principal?.message}
</FormErrorMessage>
</InputGroup>
</FormControl>
<FormControl isRequired mb={3}>
<FormLabel color={"#344054"} fontSize={"xs"} fontWeight={500} mb={1}>
Phone Number
</FormLabel>
);
<PhoneInput
country={"in"} // Default country
value={phone}
onChange={handlePhoneChange}
inputStyle={{
width: "100%",
borderRadius: "md",
paddingLeft: "8",
border: "1px solid #e2e8f0",
height: "40px",
}}
buttonStyle={{
border: "none",
borderRadius: "8px 0 0 8px",
backgroundColor: "transparent",
}}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500} as={"span"}>
{errors.mobileNumber_principal?.message}
</FormErrorMessage>
</FormControl>
<HStack mt={6}>
<IconButton
aria-label="Back"
icon={<ArrowBackIcon />}
variant="outline"
size="sm"
px={8}
_hover={{ opacity: 0.8 }}
color={"#d0b8ef"}
border={"1px solid #d0b8ef"}
isDisabled={activeStep === 0}
onClick={() => setActiveStep(activeStep - 1)}
/>
<Button
bg={"#6311CB"}
color={"#fff"}
fontSize={"xs"}
fontWeight={500}
size="sm"
_hover={{ opacity: 0.8 }}
rightIcon={<ArrowForwardIcon />}
w={"100%"}
type="submit"
>
{activeStep === steps.length - 1 ? "Next step" : "Next step"}
</Button>
</HStack>
</Box>
</Box>
);
};
export default OnboardingYourDetails;

View File

@@ -0,0 +1,12 @@
import { Box } from '@chakra-ui/react'
import { OPACITY_ON_LOAD } from '../../Layout/animations'
const GiftDashboard = () => {
return (
<Box {...OPACITY_ON_LOAD} overflowX={"scroll"} p={4}>
GiftDashboard
</Box>
)
}
export default GiftDashboard

View File

@@ -0,0 +1,452 @@
import React, { useContext, useEffect, useState } from "react";
import logo from "../../assets/logo2.png";
import logoDark from "../../assets/logo.png";
import logoMini from "../../assets/logo-min.png";
import logoMiniDark from "../../assets/favicon.png";
import { useDispatch } from "react-redux";
import { loginUser } from "../../Redux/Slice/auth";
// import Button02 from "../Components/Buttons/Button02";
import {
TbArrowBadgeLeftFilled,
TbBriefcase,
TbBuildingBank,
TbListDetails,
TbReportMoney,
TbTransactionDollar,
} from "react-icons/tb";
import { TbArrowBadgeRightFilled } from "react-icons/tb";
import { AddIcon, ArrowBackIcon, ArrowLeftIcon, ArrowRightIcon } from "@chakra-ui/icons";
import {
Link,
Route,
Routes,
useLocation,
useNavigate,
} from "react-router-dom";
import { RouteLink } from "../../Routes/Routes";
import NotFound from "../../Pages/NotFound";
import { nav } from "../../Routes/Nav";
import {
Box,
Text,
Accordion,
AccordionItem,
AccordionButton,
AccordionIcon,
AccordionPanel,
Image,
Alert,
AlertIcon,
VStack,
HStack,
Icon,
} from "@chakra-ui/react";
import GlobalStateContext from "../../Contexts/GlobalStateContext";
import Cookies from "js-cookie"; // Import the Cookies library
import HeaderMain from "../../Components/HeaderMain";
import SplashScreen from "../../Pages/SplashScreen";
import CustomBreadcrumb from "../../Components/CutomBreadcrumb";
import compLogo from "../../assets/complogo.svg";
import { OPACITY_ON_LOAD } from "../../Layout/animations";
import MiniHeader from "../../Components/MiniHeader";
import { RiUser2Line } from "react-icons/ri";
const StatusCheck = ({ isOnline = true }) => {
const navigate = useNavigate();
const location = useLocation();
const [isDrawerOpen, setIsDrawerOpen] = useState(true);
const { setIsAuthenticate } = useContext(GlobalStateContext);
const [isSplashVisible, setSplashVisible] = useState(true);
const [openIndex, setOpenIndex] = useState(null);
useEffect(() => {
const savedIndex = localStorage.getItem("openAccordionIndex");
if (savedIndex !== null) {
setOpenIndex(parseInt(savedIndex));
}
}, []);
const handleAccordionChange = (index) => {
const newIndex = openIndex === index ? null : index;
setOpenIndex(newIndex);
localStorage.setItem("openAccordionIndex", newIndex);
};
useEffect(() => {
// Set a timer to hide the splash screen after 3 seconds
const timer = setTimeout(() => {
setSplashVisible(false);
}, 1000); // 3000ms = 3 seconds
// Cleanup the timer
return () => clearTimeout(timer);
}, []);
const toggleDrawer = () => {
setIsDrawerOpen(!isDrawerOpen);
};
const logOutHandler = () => {
// dispach(loginUser(false));
setIsAuthenticate(false);
Cookies.remove("isAuthenticated");
localStorage.removeItem("refreshToken");
localStorage.removeItem("accessToken");
localStorage.removeItem("refreshTokenExp");
navigate("/login");
};
if (isSplashVisible) {
return <SplashScreen />;
}
return (
<Box {...OPACITY_ON_LOAD} height={"100vh"}>
<HeaderMain
blur={true}
isDrawerOpen={isDrawerOpen}
logOutHandler={logOutHandler}
toggleDrawer={toggleDrawer}
/>
<Box
h={{ base: "92%", lg: "96%" }}
style={{
width: "100%",
position: "relative",
overflow: "hidden",
}}
className="d-flex"
pe={0.5}
>
<Alert
transition={"0.5s"}
h={53}
transform={isOnline ? "translateY(-100px)" : "translateY(0px)"}
position={"absolute"}
zIndex={999}
status="info"
variant="solid"
bgGradient="linear(to-r, red.500, yellow.500, red.500)"
// bgGradient='linear(to-r, #1EBCA3, #22CAB3)'
color={"white"}
fontWeight={600}
fontSize={"md"}
>
<AlertIcon color={"white"} />
No Internet !
</Alert>
<Box
className="h-100 position-relative sideBar"
style={{
width: isDrawerOpen ? 260 : 0,
transition: "width 0.3s ease-in-out, transform 0.3s ease-in-out", // Smooth transition for width and transform
backgroundColor: "#210A33",
position: "relative",
color: "#fff",
transform: isDrawerOpen ? "translateX(-7px)" : "translateX(-260px)", // Move box to the left when closed
}}
filter="blur(5px)" // Apply the blur effect
>
<Box
className="ps-2 scroll-bar pe-1 pt-3"
style={{
height: "100%",
overflowY: "scroll",
overflowX: "hidden",
paddingBottom: "5rem",
}}
>
<Box
display={"flex"}
alignItems={"center"}
bg={" #FFFFFF26"}
p={2}
// m={2}.
mb={2}
rounded="md"
>
<Image me={2} src={compLogo} />
<Text as={"span"} fontSize="10px">
Website Developers India Pvt Ltd
</Text>
</Box>
<Accordion
m={0}
// px={0}
allowToggle
defaultIndex={-1}
index={openIndex}
onChange={handleAccordionChange}
>
{nav.map(
({ title, type, Icon, submenu, path, colorCode }, index) => {
if (type === "accordion") {
return (
<AccordionItem
key={index}
border={"none"}
// style={{ borderRadius: "2px", marginBottom: "8px" }}
>
<AccordionButton
style={{ height: "auto", borderRadius: "2px" }}
_hover={{ bg: "#ced8e6a2" }}
className={`${
true
? "p-2 web-text-medium ps-2 justify-content-between"
: "p-2 ps-1 web-text-xlarge justify-content-center"
} link d-flex align-items-center gap-2 w-100 mb-1`}
>
<Box
display={"flex"}
gap={2}
alignItems={"center"}
style={{ height: "auto", borderRadius: "2px" }}
// _hover={{ bg: "#ced8e6a2" }}
>
{/* {Icon && title === "Admin" ? <Image w={15} src={shield} /> : <Icon className={`web-text-large`} />} */}
{Icon && (
<Icon
fontSize={title === "Admin" ? "18px" : "15px"}
/>
)}
<Text
as={"span"}
display={true ? "flex" : "none"}
alignItems="center"
overflow="hidden"
textAlign={"left"}
>
{title}
</Text>
</Box>
<AccordionIcon />
</AccordionButton>
<AccordionPanel
p={0}
pb={1}
display={"flex"}
flexDirection={"column"}
gap={1}
>
{submenu?.map(
(
{
title: subMenuTitle,
path: link,
icon: SubIcon,
colorCode,
},
i
) => (
<Box
key={i}
style={{
height: "auto",
position: "relative",
}}
className={`${
true
? " web-text-medium ps-4 "
: " web-text-xlarge justify-content-center"
} d-flex align-items-center p-0`}
>
<Link
style={{ borderRadius: "2px" }}
className={`${
true
? "p-2 ps-1 ms-2 web-text-medium "
: "p-2 ps-0 ms-0 zindex-3 ms-4 web-text-xlarge justify-content-center"
} link d-flex align-items-center gap-2 w-100 mx-2`}
>
{SubIcon && (
<SubIcon
fontSize={"8px"}
className="ms-2"
// style={{ zIndex: 111, color:colorCode?colorCode:"" }}
/>
)}
<Text
as={"span"}
display={true ? "flex" : "none"}
alignItems="center"
overflow="hidden"
>
{subMenuTitle}
</Text>
</Link>
</Box>
)
)}
</AccordionPanel>
</AccordionItem>
);
} else if (type === "title") {
return (
<Text
as={"span"}
key={index}
className="web-text-xxsmall fw-600 text-secondary fw-bold"
>
{title}
</Text>
);
} else if (type === "single") {
return (
<Link
key={index}
style={{
height: "auto",
position: "relative",
borderRadius: "2px",
}}
className={`${
true
? "p-2 px-0 web-text-medium"
: "p-2 px-0 ps-0 web-text-xlarge justify-content-start"
} link d-flex align-items-center gap-2 w-100 mb-2`}
>
{Icon && <Icon className="web-text-large ms-2" />}
<Text
as={"span"}
display={true ? "flex" : "none"}
alignItems="center"
overflow="hidden"
>
{title}
</Text>
</Link>
);
} else {
return null;
}
}
)}
</Accordion>
</Box>
</Box>
<Box
style={{
width: `calc(100% - ${isDrawerOpen ? 260 : 0}px)`,
transition: "width 0.3s ease-in-out",
backgroundColor: "#F3F3F9",
display: "flex",
flexDirection: "column",
gap: 0,
}}
>
<Box {...OPACITY_ON_LOAD} p={4} overflowX={"scroll"}>
<Box
rounded={"xl"}
p={4}
// pb={0}
display={"flex"}
flexDirection={"column"}
bg={"#fff"}
shadow={"md"}
h={"88vh"}
>
<MiniHeader title={"Welcome, Sachin!"} />
<VStack overflow={"hidden"} rounded={"lg"} w={"100%"}>
<VStack p={4} w={"100%"} bg={"#F0E8FA"} alignItems={"start"}>
<Text as={"span"} fontWeight={600} fontSize={"md"}>
Youve successfully submitted details
</Text>
<Text
as={"span"}
fontWeight={500}
color={"gray.600"}
fontSize={"xs"}
>
Out team will review your details , wait for the
verification of documents
</Text>
</VStack>
<VStack p={4} px={5} w={"100%"} bg={"#F0E8FA"} alignItems={"start"}>
<Text as={"span"} fontWeight={600} fontSize={"md"}>
Progress Details :
</Text>
<HStack h={"auto"} pb={6} position={"relative"}justifyContent={"space-between"} w={"50%"} px={0} >
<VStack transform={"translateY(19px)"} bg={"#F0E8FA"} zIndex={999} gap={0} >
<Icon mb={2} bgGradient="linear(to-r, #3725EA, #5E0FCD)" as={RiUser2Line} boxSize={9} rounded={'full'} p={2} color={'#fff'} />
<Text as={"span"} fontWeight={600} fontSize={"xs"}>
Bank Details
</Text>
<Text
as={"span"}
fontWeight={500}
color={"gray.600"}
fontSize={"xs"}
>
(Under review)
</Text>
</VStack>
<VStack transform={"translateY(19px)"} bg={"#F0E8FA"} zIndex={999} gap={0} >
<Icon mb={2} bgGradient="linear(to-r, #3725EA, #5E0FCD)" as={TbBuildingBank} boxSize={9} rounded={'full'} p={2} color={'#fff'} />
<Text as={"span"} fontWeight={600} fontSize={"xs"}>
Bank Details
</Text>
<Text
as={"span"}
fontWeight={500}
color={"gray.600"}
fontSize={"xs"}
>
(Under review)
</Text>
</VStack>
<VStack transform={"translateY(19px)"} bg={"#F0E8FA"} zIndex={999} gap={0} >
<Icon mb={2} bgGradient="linear(to-r, #3725EA, #5E0FCD)" as={TbBriefcase} boxSize={9} rounded={'full'} p={2} color={'#fff'} />
<Text as={"span"} fontWeight={600} fontSize={"xs"}>
Business Details
</Text>
<Text
as={"span"}
fontWeight={500}
color={"gray.600"}
fontSize={"xs"}
>
(Under review)
</Text>
</VStack>
<Box position={'absolute'} w={'100%'} as="span" borderTop={"1px dashed purple"}/>
</HStack>
</VStack>
</VStack>
</Box>
</Box>
</Box>
</Box>
</Box>
);
};
export default StatusCheck;
const AppContent = () => {
return (
<Routes>
{RouteLink.map(({ path, Component }, index) => (
<Route key={index} path={path} element={<Component />} />
))}
<Route path="*" element={<NotFound />} />
</Routes>
);
};

View File

@@ -106,7 +106,7 @@ export const nav = [
submenu: [
{
title: "Dashboard",
path: "/optiFii-expense-dashboard",
path: "/optifii-gifts-dashboard",
colorCode:"#70a1ff"
},
{

View File

@@ -18,6 +18,7 @@ import Roles from "../Pages/ManageHumanResource/ManageDepartmentAndRoles/Roles";
import OptiFiiExpenseDashboard from "../Pages/OptiFiiExpense/OptiFiiExpenseDashboard";
import GiftCard from "../Pages/OptiFiiGifsAndVouchers/GiftCard";
import ApplicationStatus from "../Pages/OptiFiiGifsAndVouchers/id/ApplicationStatus";
import GiftDashboard from "../Pages/OptiFiiGifsAndVouchers/GiftDashboard";
export const RouteLink = [
{ path: "/", Component: Dashbaord },
{ path: "/expenses", Component: Expenses },
@@ -39,4 +40,12 @@ export const RouteLink = [
{ path: "/optiFii-expense-dashboard", Component: OptiFiiExpenseDashboard },
{ path: "/gift-card", Component: GiftCard },
{ path: "/application-status", Component: ApplicationStatus },
// =======================[ Gift Voucher ]==============
{ path: "/optifii-gifts-dashboard", Component: GiftDashboard },
];

View File

@@ -1,26 +0,0 @@
// io.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
// import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
// const baseUrl = api?.defaults.baseURL;
export const keyMerits = createApi({
reducerPath: "ioService",
baseQuery: baseQuery,
tagTypes: ["getKeyMerits"],
endpoints: (builder) => ({
// =====[get]
getKeyMerits: builder.query({
query: (id) => `/io/admin/key-merits/${id}`,
providesTags: ["getKeyMerits"],
}),
}),
});
// Export hooks for usage in functional components
export const {
useGetKeyMeritsQuery,
} =
keyMerits;

View File

@@ -1,37 +0,0 @@
// investorDetails.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
// import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
// const baseUrl = api?.defaults.baseURL;
// Define a service using a base URL and expected endpoints
export const bankDetails = createApi({
reducerPath: "bankDetails",
baseQuery: baseQuery,
tagTypes: ["getBank"],
endpoints: (builder) => ({
getBank: builder.query({
query: ({ page, size }) =>
`/bankDetails/admin/?page=${page}&size=${size}`,
providesTags: ["getBank"],
}),
// ========[Update Sponser]========
updateBankDetails: builder.mutation({
query: ({ data, id }) => ({
url: `/bankDetails/admin/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getBank"],
}),
}),
});
// Export hooks for usage in functional components
export const { useGetBankQuery,useUpdateBankDetailsMutation } = bankDetails;

View File

@@ -1,37 +0,0 @@
// investorDetails.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
// import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
// const baseUrl = api?.defaults.baseURL;
// Define a service using a base URL and expected endpoints
export const contact = createApi({
reducerPath: "contact",
baseQuery: baseQuery,
tagTypes: ["getContact"],
endpoints: (builder) => ({
getContact: builder.query({
query: () =>
`/contactDetails/admin`,
providesTags: ["getContact"],
}),
// ========[Update Investment]=======
updateContact: builder.mutation({
query: (data) => ({
url: `/contactDetails/admin/`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getContact"],
}),
}),
});
// Export hooks for usage in functional components
export const { useGetContactQuery, useUpdateContactMutation } = contact;

View File

@@ -1,55 +0,0 @@
// investorDetails.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
// import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
// const baseUrl = api?.defaults.baseURL;
// Define a service using a base URL and expected endpoints
export const depositRequest = createApi({
reducerPath: "depositRequest",
baseQuery: baseQuery,
tagTypes: ["getDepositRequest", "getDepositHistory"],
endpoints: (builder) => ({
getDepositRequest: builder.query({
query: () => `/deposit/admin/pending-requests`,
providesTags: ["getDepositRequest"],
}),
getDepositRequestById: builder.query({
query: (id) => `/deposit/admin/getById/${id}`,
}),
updateDepositRequest: builder.mutation({
query: ({ id, data }) => ({
url: `/deposit/admin/approved/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getDepositRequest", "getDepositHistory"],
}),
depositReject: builder.mutation({
query: ({ id, data }) => ({
url: `/deposit/admin/rejected/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getDepositRequest", "getDepositHistory"],
}),
getDepositHistory: builder.query({
query: () => `/deposit/admin/history`,
providesTags: ["getDepositHistory"],
}),
}),
});
// Export hooks for usage in functional components
export const {
useGetDepositRequestQuery,
useGetDepositRequestByIdQuery,
useUpdateDepositRequestMutation,
useDepositRejectMutation,
useGetDepositHistoryQuery,
} = depositRequest;

View File

@@ -1,51 +0,0 @@
// exchangeRate.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
// import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
// const baseUrl = api?.defaults.baseURL;
// Define a service using a base URL and expected endpoints
export const exchangeRate = createApi({
reducerPath: "exchangeRate",
baseQuery: baseQuery,
tagTypes: ["getAllExchangeRate", "getExchangeById"],
endpoints: (builder) => ({
getAllExchangeRates: builder.query({
query: ({ page, size }) =>
`/currencyExchange/admin?page=${page}&size=${size}`,
providesTags: ["getAllExchangeRate"],
}),
getExchangeRateById: builder.query({
query: (id) => `/currencyExchange/admin/${id}`,
providesTags: ["getAllExchangeRate"],
}),
updateExchangeRate: builder.mutation({
query: ({ data, id }) => ({
url: `/currencyExchange/admin/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getAllExchangeRate"],
}),
getCurrencyHistoryById: builder.query({
query: (id) => `/currencyExchange/admin/history/${id}`,
providesTags: ["getAllExchangeRate"],
}),
}),
});
// Export hooks for usage in functional components
export const {
useGetAllExchangeRatesQuery,
useGetExchangeRateByIdQuery,
useUpdateExchangeRateMutation,
useGetCurrencyHistoryByIdQuery,
} = exchangeRate;

View File

@@ -1,61 +0,0 @@
// io.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
// import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
// const baseUrl = api?.defaults.baseURL;
export const ioService = createApi({
reducerPath: "ioService",
baseQuery: baseQuery,
tagTypes: ["getInvestmentDocuments"],
endpoints: (builder) => ({
// =====[get]
getInvestmentDocuments: builder.query({
query: ({id}) => `/io/admin/document/${id}`,
providesTags: ["getInvestmentDocuments"],
}),
// =====[create]
createInvestmentDocuments: builder.mutation({
query: ({data, id}) => ({
url: `/io/admin/document/${id}`,
method: "POST",
body: data,
}),
invalidatesTags: ["getInvestmentDocuments"],
}),
updateIO: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getInvestmentDocuments"],
}),
}),
});
// Export hooks for usage in functional components
export const {
useCreateInvestmentDocumentsMutation,
} =
ioService;

View File

@@ -1,72 +0,0 @@
// investmentType.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
// import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
// const baseUrl = api?.defaults.baseURL;
// Define a service using a base URL and expected endpoints
export const investmentType = createApi({
reducerPath: "investmentType",
baseQuery: baseQuery,
tagTypes: ["getInvestmentType", "getInvestmentTypeID"],
endpoints: (builder) => ({
// ========[Get All]=========
getInvestmentTypes: builder.query({
query: ({ page, size }) =>
`/investmentType/admin?page=${page}&size=${size}`,
providesTags: ["getInvestmentType"],
}),
// ========[Get ID]=========
getInvestmentTypeById: builder.query({
query: (id) => `/investmentType/admin/${id}`,
providesTags: ["getInvestmentTypeID"],
}),
// ========[Create Investment]========
createInvestmentType: builder.mutation({
query: (data) => ({
url: `/investmentType/admin/`,
method: "POST",
body: data,
}),
invalidatesTags: ["getInvestmentType"],
}),
// ========[Update Investment]=======
updateInvestmentType: builder.mutation({
query: ({ data, id }) => ({
url: `/investmentType/admin/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getInvestmentTypeID", "getInvestmentType"],
}),
// ========[Delete Investment]=======
deleteInvestmentType: builder.mutation({
query: (id) => ({
url: `/investmentType/admin/delete/${id}`,
method: "DELETE",
}),
invalidatesTags: ["getInvestmentType"],
}),
}),
});
// Export hooks for usage in functional components
export const {
useGetInvestmentTypesQuery,
useGetInvestmentTypeByIdQuery,
useCreateInvestmentTypeMutation,
useUpdateInvestmentTypeMutation,
useDeleteInvestmentTypeMutation,
} = investmentType;

View File

@@ -1,33 +0,0 @@
// investorDetails.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
// import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
// const baseUrl = api?.defaults.baseURL;
// Define a service using a base URL and expected endpoints
export const investorDetails = createApi({
reducerPath: "investorDetails",
baseQuery: baseQuery,
tagTypes: [],
endpoints: (builder) => ({
getInvestors: builder.query({
query: ({ page, size }) =>
`/investorDetails/admin?page=${page}&size=${size}`,
providesTags: ["getInvestors"],
}),
// =====[get investment details ]
getInvestorsDetailsById: builder.query({
query: (id) => `/investorDetails/admin/${id}`,
providesTags: ["getInvestors"],
}),
}),
});
// Export hooks for usage in functional components
export const { useGetInvestorsQuery, useGetInvestorsDetailsByIdQuery } = investorDetails;

View File

@@ -1,23 +0,0 @@
// investorTransaction.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { baseQuery } from "./token.serivce";
// const baseUrl = import.meta.env.VITE_API_BASE_URL + "/api";
// Define a service using a base URL and expected endpoints
export const investorTransaction = createApi({
reducerPath: "investorTransaction",
baseQuery: baseQuery,
tagTypes: [],
endpoints: (builder) => ({
getTransactions: builder.query({
query: () => '/getTransactions',
}),
getTransactionById: builder.query({
query: (id) => `/getTransaction/${id}`,
}),
}),
});
// Export hooks for usage in functional components
export const { useGetTransactionsQuery, useGetTransactionByIdQuery } = investorTransaction;

View File

@@ -1,303 +0,0 @@
// io.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
// import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
// const baseUrl = api?.defaults.baseURL;
// Define a service using a base URL and expected endpoints
export const ioService = createApi({
reducerPath: "ioService",
baseQuery: baseQuery,
tagTypes: [
"prePopulate",
"getIO",
"getKeyMerits",
"getArtifactsVideo",
"getInvestmentDocuments",
"getIOById",
],
endpoints: (builder) => ({
// =====[get prepopulate data]
getIOprepopulateData: builder.query({
query: () => `/io/admin/pre-populate`,
providesTags: ["prePopulate"],
}),
// =====[get]
getIOs: builder.query({
query: ({ page, size }) => `/io/admin?page=${page}&size=${size}`,
providesTags: ["getIO"],
}),
getIOById: builder.query({
query: (id) => ({ url: `/io/admin/${id}` }),
providesTags: ["getIOById"],
}),
// =====[create]
createIO: builder.mutation({
query: (data) => ({
url: `/io/admin`,
method: "POST",
body: data,
}),
invalidatesTags: ["getIO"],
}),
updateIO: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getIOById", "getIO"],
}),
// =====[Key Merits]
getKeyMerits: builder.query({
query: (id) => `/io/admin/key-merits/${id}`,
providesTags: ["getKeyMerits"],
}),
createKeyMerits: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/key-merits/${id}`,
method: "POST",
body: data,
// No need to manually set 'Content-Type'
}),
invalidatesTags: ["getIOById"],
}),
deleteKeyMerits: builder.mutation({
query: (id) => ({
url: `/io/admin/key-merits/hard-delete/${id}`,
method: "DELETE",
}),
invalidatesTags: ["getIOById"],
}),
updateKeyMerits: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/key-merits/byId/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
// =====[getIODocument]
createInvestmentDocuments: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/document/${id}`,
method: "POST",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
updateInvestmentDocuments: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/document/byId/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
getInvestmentDocuments: builder.query({
query: (id) => `/io/admin/document/${id}`,
providesTags: ["getInvestmentDocuments"],
}),
deleteIODocs: builder.mutation({
query: (id) => ({
url: `/io/admin/document/hard-delete/${id}`,
method: "DELETE",
}),
invalidatesTags: ["getIOById"],
}),
// =====[Artifacts]
getArtifactsVideo: builder.query({
query: (id) => `/io/artifact/artifactVideo/${id}`,
providesTags: ["getArtifactsVideo"],
}),
// =====[createImageArtifacts]
createImageArtifacts: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/artifact/image/${id}`,
method: "POST",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
updateImageArtifacts: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/artifact/image/byId/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
// =====[createVideoArtifacts]
createVideoArtifacts: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/artifact/video/${id}`,
method: "POST",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
deleteVideoArtifacts: builder.mutation({
query: (id) => ({
url: `/io/admin/artifact/video/byId/${id}`,
method: "DELETE",
}),
invalidatesTags: ["getIOById"],
}),
deleteImageArtifacts: builder.mutation({
query: (id) => ({
url: `/io/admin/artifact/image/byId/${id}`,
method: "DELETE",
}),
invalidatesTags: ["getIOById"],
}),
updateVideoArtifacts: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/artifact/video/byId/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
setDisplayOrder: builder.mutation({
query: ({ data }) => ({
url: `/io/artifact/artifactImage/resetDisplayOrder/`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
updateStatusIo: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/update-status/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getIOById", 'getIO'],
}),
createIoCash: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/io-cash/${id}`,
method: "POST",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
createIoNav: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/io-nav/${id}`,
method: "POST",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
// =====[ Amount Investment ]
amountIvestment : builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/amount-invested/${id}`,
method: "POST",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
}),
});
// Export hooks for usage in functional components
export const {
useGetIOprepopulateDataQuery,
useGetIOsQuery,
useGetIOByIdQuery,
useCreateIOMutation,
useUpdateIOMutation,
useGetKeyMeritsQuery,
useCreateKeyMeritsMutation,
useDeleteKeyMeritsMutation,
useUpdateKeyMeritsMutation,
useGetInvestmentDocumentsQuery,
useCreateInvestmentDocumentsMutation,
useDeleteIODocsMutation,
useUpdateInvestmentDocumentsMutation,
useCreateImageArtifactsMutation,
useUpdateImageArtifactsMutation,
useUpdateVideoArtifactsMutation,
useGetArtifactsVideoQuery,
useCreateVideoArtifactsMutation,
useDeleteVideoArtifactsMutation,
useDeleteImageArtifactsMutation,
useSetDisplayOrderMutation,
useCreateIoCashMutation,
useCreateIoNavMutation,
useUpdateStatusIoMutation,
useAmountIvestmentMutation,
} = ioService;

View File

@@ -0,0 +1,28 @@
// investorDetails.service.js
import { createApi } from "@reduxjs/toolkit/query/react";
// import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
// const baseUrl = api?.defaults.baseURL;
// Define a service using a base URL and expected endpoints
export const onBoarding = createApi({
reducerPath: "onBoarding",
baseQuery: baseQuery,
tagTypes: ["prePop"],
endpoints: (builder) => ({
getPrePop: builder.query({
// query: (searchData) => `/corporate/admin`,
query: () => `/corporate/pre-populate`,
providesTags: ["prePop"],
}),
}),
});
// Export hooks for usage in functional components
export const { useGetPrePopQuery } = onBoarding;

View File

@@ -1,105 +0,0 @@
//sponser.service
// Need to use the React-specific entry point to import createApi
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
// import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
import { ioService } from "./io.service";
// const baseUrl = api?.defaults.baseURL;
// const baseUrl = `${import.meta.env.VITE_API_BASE_URL}/${import.meta.env.VITE_API_VERSION}`
// Define a service using a base URL and expected endpoints
export const sponserMaster = createApi({
reducerPath: "sponserMaster",
baseQuery: baseQuery,
tagTypes: ["getSponser", "prePopulate"],
endpoints: (builder) => ({
// ======[Get All]=====
getSponserMaster: builder.query({
query: ({ page, size }) => `/sponsor/admin?page=${page}&size=${size}`,
providesTags: ["getSponser"],
}),
// ========[Get Active]========
getActiveSponserMaster: builder.query({
query: () => `/sponsor/admin/active`,
}),
getSponserMasterActive: builder.query({
query: () => "/sponsor/admin/active",
}),
// ======[Get ID]=====
getSponserById: builder.query({
query: (id) => `/sponsor/admin/${id}`,
}),
// ========[Toggle Status]========
toggleStatus: builder.mutation({
query: ({ id }) => ({
url: `/sponsor/admin/toggle-status/${id}`,
method: "PATCH",
}),
invalidatesTags: ["getSponser"],
}),
// ========[Create Sponser]========
createSponser: builder.mutation({
query: (data) => ({
url: `/sponsor/admin`,
method: "POST",
body: data,
}),
invalidatesTags: ["getSponser","prePopulate"],
}),
// ========[Update Sponser]========
updateSponser: builder.mutation({
query: ({ data, id }) => ({
url: `/sponsor/admin/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getSponser"],
}),
// ========[Delete Sponser]========
deleteSponser: builder.mutation({
query: (id) => ({
url: `/sponsor/admin/delete/${id}`,
method: "DELETE",
}),
invalidatesTags: ["getSponser"],
}),
}),
});
// Export hooks for usage in functional components
export const {
useGetSponserMasterQuery,
useGetSponserMasterActiveQuery,
useToggleStatusMutation,
useCreateSponserMutation,
useUpdateSponserMutation,
useGetSponserByIdQuery,
useDeleteSponserMutation,
useGetActiveSponserMasterQuery
} = sponserMaster;

View File

@@ -1,28 +1,13 @@
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import Cookies from "js-cookie";
// Define a base query function with RTK Query
// export const baseQuery = fetchBaseQuery({
// baseUrl: 'https://sprint4.tanami.betadelivery.com/api/v1',
// prepareHeaders: (headers) => {
// const token = localStorage.getItem('accessToken');
// if (token) {
// headers.set('x-auth-token', `${token}`);
// }
// return headers;
// },
// });
// Define a base query function with token refresh logic
export const baseQuery = async (args, api, extraOptions) => {
export const baseQuery = async (args, api, extraOptions) => {
let result = await fetchBaseQuery({
baseUrl: 'https://sprint4.tanami.betadelivery.com/api/v1',
baseUrl: import.meta.env.VITE_BASE_URL,
prepareHeaders: (headers) => {
const token = localStorage.getItem('accessToken');
const token = localStorage.getItem("accessToken");
if (token) {
headers.set('x-auth-token', token);
headers.set("x-auth-token", token);
}
return headers;
},
@@ -30,41 +15,55 @@ export const baseQuery = async (args, api, extraOptions) => {
if (result.error && result.error.status === 401) {
// Handle token refresh
const refreshToken = localStorage.getItem('refreshToken');
if (refreshToken) {
try {
const refreshResult = await fetchBaseQuery({
baseUrl: 'https://sprint4.tanami.betadelivery.com/api/v1',
})({
url: '/auth/user/regenerate-token',
method: 'POST',
body: { refreshToken },
}, api, extraOptions);
// const refreshToken = localStorage.getItem("refreshToken");
// if (refreshToken) {
// try {
// const refreshResult = await fetchBaseQuery({
// baseUrl: import.meta.env.VITE_BASE_URL,
// })(
// {
// url: "/regenerate-token",
// method: "POST",
// body: { refreshToken },
// },
// api,
// extraOptions
// );
if (refreshResult.data) {
// Save new tokens
localStorage.setItem('accessToken', refreshResult.data.access.token);
localStorage.setItem('refreshToken', refreshResult.data.refresh.token);
localStorage.setItem('refreshTokenExp', refreshResult.data.refresh.expires);
// if (refreshResult.data) {
// // Save new tokens
// localStorage.setItem("accessToken", refreshResult.data.access.token);
// localStorage.setItem(
// "refreshToken",
// refreshResult.data.refresh.token
// );
// localStorage.setItem(
// "refreshTokenExp",
// refreshResult.data.refresh.expires
// );
// Retry the original request with the new token
result = await fetchBaseQuery({
baseUrl: 'https://sprint4.tanami.betadelivery.com/api/v1',
prepareHeaders: (headers) => {
const token = localStorage.getItem('accessToken');
if (token) {
headers.set('x-auth-token', token);
}
return headers;
},
})(args, api, extraOptions);
}
} catch (err) {
console.error('Failed to refresh token:', err);
// Handle refresh failure (e.g., redirect to login)
}
}
// // Retry the original request with the new token
// result = await fetchBaseQuery({
// baseUrl: import.meta.env.VITE_BASE_URL,
// prepareHeaders: (headers) => {
// const token = localStorage.getItem("accessToken");
// if (token) {
// headers.set("x-auth-token", token);
// }
// return headers;
// },
// })(args, api, extraOptions);
// }
// } catch (err) {
// console.error("Failed to refresh token:", err);
// // Handle refresh failure (e.g., redirect to login)
// }
// }
localStorage.removeItem("accessToken");
localStorage.removeItem("refreshToken");
Cookies.remove("isAuthenticated", { path: '/login' });
}
return result;
@@ -72,36 +71,83 @@ export const baseQuery = async (args, api, extraOptions) => {
// Create an RTK Query API slice
export const apiSlice = createApi({
reducerPath: 'api',
reducerPath: "api",
baseQuery: baseQuery,
endpoints: (builder) => ({
login: builder.mutation({
query: (credentials) => ({
url: '/auth/admin',
method: 'POST',
url: "/auth/admin",
method: "POST",
body: credentials,
}),
async onQueryStarted(arg, { dispatch, queryFulfilled }) {
try {
const { data } = await queryFulfilled;
// Store tokens in local storage
localStorage.setItem('accessToken', data?.data?.access?.token) ;
localStorage.setItem('refreshToken', data?.data?.refresh?.token);
localStorage.setItem("accessToken", data?.data?.access?.token);
localStorage.setItem("refreshToken", data?.data?.refresh?.token);
// localStorage.setItem('refreshTokenExp', data?.data?.refresh?.expires);
localStorage.setItem('accessTokenExp', data?.data?.access?.expires);
localStorage.setItem("accessTokenExp", data?.data?.access?.expires);
} catch (error) {
console.error('Login failed:', error);
console.error("Login failed:", error);
}
},
}),
refreshToken: builder.mutation({
query: (refreshToken) => ({
url: '/auth/user/regenerate-token',
method: 'POST',
url: "/auth/user/regenerate-token",
method: "POST",
body: { refreshToken },
}),
}),
forgotPassword: builder.mutation({
query: (data) => ({
url: "/auth/admin/forget-password",
method: "POST",
body: data ,
}),
}),
resetPassword: builder.mutation({
query: (data) => ({
url: "/auth/admin/reset-password",
method: "POST",
body: data ,
}),
}),
setOtp: builder.mutation({
query: (data) => ({
url: "/auth/admin/verify-otp",
method: "POST",
body: data ,
}),
}),
resendOtp: builder.mutation({
query: (data) => ({
url: "/auth/admin/resend-otp",
method: "POST",
body: data ,
}),
}),
}),
});
export const { useLoginMutation, useRefreshTokenMutation } = apiSlice;
export const { useLoginMutation, useRefreshTokenMutation, useForgotPasswordMutation, useResetPasswordMutation,useResendOtpMutation, useSetOtpMutation } = apiSlice;

View File

@@ -1,30 +1,13 @@
import { configureStore } from "@reduxjs/toolkit";
import { setupListeners } from "@reduxjs/toolkit/query";
import { sponserMaster } from "../Services/sponser.service";
import { investmentType } from "../Services/investment.type.service";
import { exchangeRate } from "../Services/exchange.rate.service";
import { ioService } from "../Services/io.service";
import { investorDetails } from "../Services/investor.details.service";
import { investorTransaction } from "../Services/investor.transaction.service";
// import { api } from "../Services/api.service";
// import { keyMerits } from "../Services/Key.merits.service";
import { bankDetails } from "../Services/bank.details.service";
import { contact } from "../Services/contact.service";
import { depositRequest } from "../Services/deposit.request.service";
import { onBoarding } from "../Services/on.board.service";
import { apiSlice, baseQuery } from "../Services/token.serivce";
import { setupListeners } from "@reduxjs/toolkit/query";
export const store = configureStore({
reducer: {
[apiSlice.reducerPath]: apiSlice.reducer,
[sponserMaster.reducerPath]: sponserMaster.reducer,
[investmentType.reducerPath]: investmentType.reducer,
[exchangeRate.reducerPath]: exchangeRate.reducer,
[ioService.reducerPath]: ioService.reducer,
[investorDetails.reducerPath]: investorDetails.reducer,
[investorTransaction.reducerPath]: investorTransaction.reducer,
[bankDetails.reducerPath]: bankDetails.reducer,
[contact.reducerPath]: contact.reducer,
[depositRequest.reducerPath]: depositRequest.reducer,
[onBoarding.reducerPath]: onBoarding.reducer,
// Add other reducers as needed
},
middleware: (getDefaultMiddleware) =>
@@ -34,15 +17,7 @@ export const store = configureStore({
},
}).concat(
apiSlice.middleware,
sponserMaster.middleware,
investmentType.middleware,
exchangeRate.middleware,
ioService.middleware,
investorDetails.middleware,
investorTransaction.middleware,
bankDetails.middleware,
contact.middleware,
depositRequest.middleware,
onBoarding.middleware,
),
});