API implementation for CMS and Master module

This commit is contained in:
rockyeverlast
2025-03-06 13:16:38 +05:30
parent a673ea69d4
commit 346af173b2
62 changed files with 1615 additions and 449 deletions

View File

@@ -4,12 +4,15 @@ import GlobalStateContext from "./Contexts/GlobalStateContext";
import DefaultLayout from "./Layouts/DefaultLayout";
import Login from "./Pages/Login";
import { RouteLink } from "./Routes/Routes";
import ForgotPassword from "./Pages/ForgotPassword";
import VerifyEnterOTP from "./Pages/VerifyEnterOTP";
import SetNewPassword from "./Pages/SetNewPassword";
function App() {
const context = useContext(GlobalStateContext);
if (!context) throw new Error("App must be used within a GlobalStateProvider");
const { isAuthenticate, setIsAuthenticate } = context;
const { isAuthenticate, setIsAuthenticate } = context;
useEffect(() => {
const token = localStorage.getItem("token");
@@ -23,6 +26,9 @@ function App() {
<Routes>
{/* Redirect logged-in users away from login */}
<Route path="/login" element={isAuthenticate && localStorage.getItem("token") ? <Navigate to="/" /> : <Login />} />
<Route path="/forgot-password" element={<ForgotPassword />} />
<Route path="/forgot-password/verify-otp" element={<VerifyEnterOTP />} />
<Route path="/forgot-password/reset-password" element={<SetNewPassword />} />
{/* Protected Routes */}
<Route

View File

@@ -0,0 +1,155 @@
import {
Box,
Center,
HStack,
Image,
Input,
Text,
VStack,
} from "@chakra-ui/react";
import axios from "axios";
import { useState } from "react";
import { useForm } from "react-hook-form";
// import { useDispatch } from "react-redux";
import logo from "../assets/logo.svg";
import { Button } from "../components/ui/button";
import { Field } from "../components/ui/field";
import { toaster, Toaster } from "../components/ui/toaster";
import { useNavigate } from "react-router-dom";
interface FormValues {
mobileNumber: number;
}
const ForgotPassword = () => {
const navigate = useNavigate();
const [isLoading, setIsLoading] = useState<boolean>(false);
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormValues>();
const onSubmit = handleSubmit(async (data) => {
setIsLoading(true);
try {
const res = await axios.post(
`${import.meta.env.VITE_API_URL}/send-otp`,
{
mobile_number: Number(data.mobileNumber),
},
);
if (res.status === 200) {
navigate(`/forgot-password/verify?phone=${data.mobileNumber}`)
} else {
alert(res.data.message || "Something went wrong");
}
console.log("============", res);
} catch (error) {
console.log('error', error);
if (error) {
toaster.create({
// title: error?.response?.data?.message,
title: "Something Went Wrong",
type: "info",
})
// console.log("Login failed", error?.response?.data?.message);
setIsLoading(false);
}
}
});
return (
<VStack appearance={'light'} w={"100%"} h={"100vh"} bg={"#ffffff"}>
<HStack
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
w={"100%"}
ps={8}
h={"7%"}
justifyContent={"flex-start"}
>
<Image w={50} src={logo} />
</HStack>
<HStack w={"100%"} h={"93%"} p={8} gap={8}>
<Center
display={{ base: "none", md: "flex" }}
bg={"#02A0A033"}
w={"50%"}
h={"100%"}
rounded={"3xl"}
>
<Image w={250} src={logo} />
</Center>
<Box
as={"form"}
onSubmit={onSubmit}
p={{ base: 4, md: 16 }}
w={{ base: "100%", md: "50%" }}
h={"100%"}
>
<VStack gap={2} w={"100%"}>
<Text
w={"100%"}
textAlign={"center"}
fontSize={"24px"}
fontWeight={"normal"}
color={"#313039"}
>
Forgot Password
</Text>
<Box mt={6} gap={4} w={"full"}>
<Field
color={"#313039"}
label={"Enter Mobile Number"}
w={"100%"}
invalid={!!errors.mobileNumber}
errorText={errors.mobileNumber?.message}
mb={4}
>
<Input
type="number"
ps={3}
maxLength={10}
{...register("mobileNumber", {
required: "Please enter a 10 digit mobile number",
pattern: {
value: /^[0-9]{10}$/,
message: "Mobile number must be exactly 10 digits"
}
})}
placeholder="Enter Mobile Number"
onInput={(e) => {
const target = e.target as HTMLInputElement;
target.value = target.value.replace(/\D/g, "").slice(0, 10);
}}
/>
</Field>
<Button
loading={isLoading}
mt={4}
size={"sm"}
bg={"#02A0A0"}
rounded={"md"}
w={"100%"}
color={"#ffffff"}
type="submit"
>
Send OTP
</Button>
</Box>
</VStack>
</Box>
<Toaster />
</HStack>
</VStack>
);
};
export default ForgotPassword;

View File

@@ -5,7 +5,6 @@ import {
Image,
Input,
Text,
Theme,
VStack,
} from "@chakra-ui/react";
import axios from "axios";
@@ -19,8 +18,8 @@ import { Button } from "../components/ui/button";
import { Field } from "../components/ui/field";
import { toaster, Toaster } from "../components/ui/toaster";
import { PasswordInput } from "../components/ui/password-input";
import { useNavigate } from "react-router-dom";
import ForgetPassword from "./ForgetPassword";
import { Link, useNavigate } from "react-router-dom";
// import ForgetPassword from "./ForgetPassword";
interface FormValues {
mobileNumber: number;
@@ -63,8 +62,8 @@ const Login = () => {
},
}
);
console.log("============",res);
console.log("============", res);
if (res.data) {
setIsAuthenticate(true);
@@ -80,7 +79,7 @@ const Login = () => {
}
} catch (error) {
console.log('error', error);
if (error) {
toaster.create({
// title: error?.response?.data?.message,
@@ -182,7 +181,15 @@ const Login = () => {
Login
</Button>
<ForgetPassword />
{/* <ForgetPassword /> */}
<Box textAlign={"right"}>
<Link
to={'/forgot-password'}
style={{ color: "black", fontSize: "18px" }}
>
Forgot Password
</Link>
</Box>
</Box>
</VStack>
</Box>

View File

@@ -21,7 +21,7 @@ function AboutUsAddModel({ aboutUsData }: { aboutUsData: any }) {
const [isOpen, setIsOpen] = useState(false);
// RTK Query Mutation Hook
const [updateAboutUs, { isLoading }] = useUpdateAboutUsMutation();
const [updateAboutUs] = useUpdateAboutUsMutation();
// React Hook Form
const {

View File

@@ -91,7 +91,7 @@ import {
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import { Field, Input, Span, Stack, Textarea } from "@chakra-ui/react";
import { Field, Input, Stack, Textarea } from "@chakra-ui/react";
import Edit from "../../../components/ActionIcons/Edit";
interface RowData {

View File

@@ -30,7 +30,7 @@ const managepost: any[] = [
<Switch colorPalette={'teal'} size={"xs"} />
</Box>
{/* <EditDetails /> */}
<EditDetails />
<EditDetails id={(i + 1).toString()} question="Lorem Ipsum" answer="Lorem Ipsum" />
<AlertDailog
AltertTiggerIcon={() => <Delete />}

View File

@@ -8,7 +8,10 @@ import { useContext, useEffect } from "react";
const PrivacyPolicy = () => {
const { data, isLoading, isFetching } = useGetPrivacyPolicyQuery();
const { data, isLoading, isFetching, refetch } = useGetPrivacyPolicyQuery();
console.log('PRIVACY', data?.data);
const context = useContext(GlobalStateContext);
if (!context) throw new Error('App must be used within a GlobalStateProvider');
@@ -35,16 +38,15 @@ const PrivacyPolicy = () => {
Privacy Policy <Badge variant={'surface'} colorPalette="cyan" ms={2} size={'sm'} fontSize={'xs'} px={2}>🎓 {privacy_language?.language_name}</Badge>
</Text>
<PrivacyPolicyAddModel />
<PrivacyPolicyAddModel policyData={data?.data} refetch={refetch} />
</HStack>
<Text
as="p"
fontSize="sm"
fontWeight={400}
color="#1D1D1D"
>
{content}
</Text>
dangerouslySetInnerHTML={{ __html: content }}
/>
</VStack>)}
</VStack>

View File

@@ -9,27 +9,77 @@ import {
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import { Field, Stack, Text, Textarea } from "@chakra-ui/react";
import { Field, Stack, Text } from "@chakra-ui/react";
import { Button } from "../../../components/ui/button";
import { useUpdatePrivacyPolicyMutation } from "../../../Redux/Service/privacy.policy.service";
import { Controller, useForm } from "react-hook-form";
import { useState } from "react";
import ReactQuill from "react-quill";
function PrivacyPolicyAddModel({ policyData, refetch }: { policyData: any, refetch: VoidFunction }) {
const [isOpen, setIsOpen] = useState(false);
const [selectedId, setSelectedId] = useState(null);
const [updatePrivacyPolicy] = useUpdatePrivacyPolicyMutation()
const {
control,
handleSubmit,
reset,
setValue,
} = useForm({
defaultValues: {
content: "",
languageCode: "",
},
});
console.log('POLICY', policyData);
const handleEditClick = (data: any) => {
setSelectedId(data?.id)
setValue("content", data.content); // Pre-fill the content field
setValue("languageCode", data.privacy_language.language_code); // Pre-fill the language code
setIsOpen(true); // Open dialog
};
const onSubmit = async (formData: any) => {
if (!formData.content.trim()) return; // Prevent empty updates
try {
await updatePrivacyPolicy({
id: selectedId,
content: formData.content,
language_code: formData.languageCode,
}).unwrap();
setIsOpen(false); // Close dialog on success
reset(); // Reset the form
refetch()
} catch (error) {
console.error("Update failed:", error);
}
};
function PrivacyPolicyAddModel() {
return (
<DialogRoot placement="center">
<DialogTrigger asChild>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Button bgColor={"#EEEEEE"} pl={3} pr={3} size={"xs"} color={"#000"}>
{" "}
<FaRegEdit
color="#000"
style={{ height: "14px", width: "14px" }}
/>{" "}
<Text color={"#000"} mt={1}>
Edit
</Text>
</Button>
</DialogTrigger>
<DialogRoot placement="center" open={isOpen}>
{policyData?.map((item: any) => (
<DialogTrigger asChild>
<Button
bgColor={"#EEEEEE"}
pl={3} pr={3}
size={"xs"}
color={"#000"}
onClick={() => handleEditClick(item)}
>
{" "}
<FaRegEdit
color="#000"
style={{ height: "14px", width: "14px" }}
/>{" "}
<Text color={"#000"} mt={1}>
Edit
</Text>
</Button>
</DialogTrigger>
))}
<DialogContent
bg={"#fff"}
@@ -51,7 +101,7 @@ function PrivacyPolicyAddModel() {
<Field.Label color="black" pt={1} fontSize="12px">
PrivacyPolicy
</Field.Label>
<Textarea
{/* <Textarea
placeholder=""
bgColor="#EEEEEE"
color="black"
@@ -59,19 +109,46 @@ function PrivacyPolicyAddModel() {
p={2}
fontSize="12px"
height={'140px'}
_focusVisible={{outline:'none'}}
_focusVisible={{ outline: 'none' }}
resize={'none'}
/> */}
<Controller
name="content"
control={control}
render={({ field }) => (
<ReactQuill
value={field.value}
onChange={field.onChange}
placeholder="Enter About Us content"
modules={{
toolbar: [
[{ 'header': [1, 2, false] }],
['bold', 'italic', 'underline', 'strike'],
['link', 'image'],
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
['clean']
],
}}
formats={[
'header',
'bold', 'italic', 'underline', 'strike',
'list', 'bullet',
'link', 'image'
]}
style={{ color: "black", border: "none", fontSize: "12px", height: "170px", width: "100%" }}
/>
)}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} mt={'4'} onClick={handleSubmit(onSubmit)}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
</DialogRoot>
);

View File

@@ -2,9 +2,13 @@ import { Box, HStack, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame"
import { p } from "framer-motion/client";
import TermsAndConditionsAddModel from "./TermsAndConditionsAddModel";
import { useGetTermsQuery } from "../../../Redux/Service/terms.and.condition.service";
const TermsAndConditions = () => {
const { data, refetch } = useGetTermsQuery()
const termsData = data?.data
return (
<MainFrame>
@@ -17,22 +21,29 @@ const TermsAndConditions = () => {
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
Terms And Conditions
Terms And Conditions
</Text>
<HStack >
<TermsAndConditionsAddModel />
<TermsAndConditionsAddModel termsData={termsData} refetch={refetch}/>
</HStack>
</HStack>
<Text as={p} fontSize={"sm"} fontWeight={400} color={"#1D1D1D"} px={3} w={"85%"} mb={"15px"} >
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Numquam soluta doloremque quibusdam facilis quas, unde hic eaque doloribus sed perferendis atque, eos dolores eius consectetur iure sint adipisci itaque tempora fugit quidem culpa provident possimus. Ullam, vitae in voluptatum dignissimos, quos blanditiis sequi aut repellat error eaque veritatis unde quam temporibus adipisci consectetur neque vero exercitationem dolor cum numquam maiores alias, totam minima quas. Possimus, ratione harum. Alias laboriosam nesciunt esse fugit deserunt pariatur corporis tempora quia veniam laborum aliquid enim voluptatibus asperiores minima tempore repudiandae vero quo porro, doloribus explicabo sit beatae et hic natus. Non earum nisi reiciendis?
{data?.data.map((item) => (
<Text
as={p}
fontSize={"sm"}
fontWeight={400}
color={"#1D1D1D"}
px={3} w={"85%"} mb={"15px"}
dangerouslySetInnerHTML={{ __html: item.content }}
/>
))}
<Text as={p} fontSize={"sm"} fontWeight={400} color={"#1D1D1D"} px={3} w={"85%"} >
</Text>
<Text as={p} fontSize={"sm"} fontWeight={400} color={"#1D1D1D"} px={3} w={"85%"} >
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Numquam soluta doloremque quibusdam facilis quas, unde hic eaque doloribus sed perferendis atque, eos dolores eius consectetur iure sint adipisci itaque tempora fugit quidem culpa provident possimus. Ullam, vitae in voluptatum dignissimos, quos blanditiis sequi aut repellat error eaque veritatis unde quam temporibus adipisci consectetur neque vero exercitationem dolor cum numquam maiores alias, totam minima quas. Possimus, ratione harum. Alias laboriosam nesciunt esse fugit deserunt pariatur corporis tempora quia veniam laborum aliquid enim voluptatibus asperiores minima tempore repudiandae vero quo porro, doloribus explicabo sit beatae et hic natus. Non earum nisi reiciendis?
</Text>
</Box>
</MainFrame>
</Box>
</MainFrame >
)
}
export default TermsAndConditions

View File

@@ -9,24 +9,75 @@ import {
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import { Field, Stack, Text, Textarea } from "@chakra-ui/react";
import { Field, Stack, Text } from "@chakra-ui/react";
import { Button } from "../../../components/ui/button";
import { Controller, useForm } from "react-hook-form";
import ReactQuill from "react-quill";
import { useState } from "react";
import { useUpdateTermsMutation } from "../../../Redux/Service/terms.and.condition.service";
function TermsAndConditionsAddModel({ termsData, refetch }: { termsData: any, refetch: VoidFunction}) {
const [isOpen, setIsOpen] = useState(false);
const [selectedId, setSelectedId] = useState(null);
const [updateTerms] = useUpdateTermsMutation()
const {
control,
handleSubmit,
reset,
setValue,
} = useForm({
defaultValues: {
content: "",
languageCode: "",
},
});
const handleEditClick = (data: any) => {
setSelectedId(data?.id)
setValue("content", data.content); // Pre-fill the content field
setValue("languageCode", data.terms_cond_language.language_code); // Pre-fill the language code
setIsOpen(true); // Open dialog
};
const onSubmit = async (formData: any) => {
if (!formData.content.trim()) return; // Prevent empty updates
try {
await updateTerms({
id: selectedId,
content: formData.content,
language_code: formData.languageCode,
}).unwrap();
setIsOpen(false); // Close dialog on success
reset(); // Reset the form
refetch()
} catch (error) {
console.error("Update failed:", error);
}
};
function TermsAndConditionsAddModel() {
return (
<DialogRoot placement="center">
<DialogTrigger asChild>
<Button bgColor={"#EEEEEE"} pl={3} pr={3} size={"xs"} color={"#000"}>
{" "}
<FaRegEdit
color="#000"
style={{ height: "14px", width: "14px" }}
/>{" "}
<Text color={"#000"} mt={1}>
Edit
</Text>
</Button>
</DialogTrigger>
<DialogRoot placement="center" open={isOpen}>
{termsData?.map((item: any) => (
<DialogTrigger asChild>
<Button
bgColor={"#EEEEEE"}
pl={3} pr={3}
size={"xs"}
color={"#000"}
onClick={() => handleEditClick(item)}
>
{" "}
<FaRegEdit
color="#000"
style={{ height: "14px", width: "14px" }}
/>{" "}
<Text color={"#000"} mt={1}>
Edit
</Text>
</Button>
</DialogTrigger>
))}
<DialogContent
bg={"#fff"}
@@ -43,12 +94,12 @@ function TermsAndConditionsAddModel() {
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Stack py={3} mb={8}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
TermsAndConditions
</Field.Label>
<Textarea
{/* <Textarea
placeholder=""
bgColor="#EEEEEE"
color="black"
@@ -58,17 +109,44 @@ function TermsAndConditionsAddModel() {
height={'140px'}
_focusVisible={{outline:'none'}}
resize={'none'}
/> */}
<Controller
name="content"
control={control}
render={({ field }) => (
<ReactQuill
value={field.value}
onChange={field.onChange}
placeholder="Enter About Us content"
modules={{
toolbar: [
[{ 'header': [1, 2, false] }],
['bold', 'italic', 'underline', 'strike'],
['link', 'image'],
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
['clean']
],
}}
formats={[
'header',
'bold', 'italic', 'underline', 'strike',
'list', 'bullet',
'link', 'image'
]}
style={{ color: "black", border: "none", fontSize: "12px", height: "170px", width: "100%" }}
/>
)}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} mt={'4'} onClick={handleSubmit(onSubmit)}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
</DialogRoot>
);

View File

@@ -1,6 +1,6 @@
import { Button } from "../../components/ui/button"
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
import { Avatar, Box, Field, Heading, Input, Stack, Text } from "@chakra-ui/react"
import { Field, Heading, Input, Stack, Text } from "@chakra-ui/react"
import { Switch } from "../../components/ui/switch";
import { IoMdAdd } from "react-icons/io";
function AddGroup() {

View File

@@ -4,7 +4,7 @@ import { InputGroup } from "../../components/ui/input-group";
import { LuSearch } from "react-icons/lu";
import DataTable from "../../components/DataTable";
import AlertDailog from "../../components/AlertDailog";
import { RiDeleteBin5Line } from "react-icons/ri";
// import { RiDeleteBin5Line } from "react-icons/ri";
import ViewManageGroup from "./ViewManageGroup";
import EditDetailGroups from "./EditDetailGroup";
import AddGroup from "./AddGroup";

View File

@@ -1,6 +1,6 @@
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
import { LuSearch } from "react-icons/lu";
import { RiDeleteBin5Line } from "react-icons/ri";
// import { RiDeleteBin5Line } from "react-icons/ri";
import AlertDailog from "../../components/AlertDailog";
import DataTable from "../../components/DataTable";
import MainFrame from "../../components/MainFrame";

View File

@@ -1,6 +1,5 @@
import {
Field,
Icon,
Input,
SelectValueText,
Span,
@@ -19,7 +18,7 @@ import {
DialogTrigger,
} from "../../components/ui/dialog";
import { TbEdit } from "react-icons/tb";
// import { TbEdit } from "react-icons/tb";
import {
SelectContent,
SelectItem,

View File

@@ -1,6 +1,5 @@
import {
Field,
Icon,
Input,
SelectValueText,
Span,
@@ -19,7 +18,7 @@ import {
DialogTrigger,
} from "../../components/ui/dialog";
import { MdOutlineRemoveRedEye } from "react-icons/md";
// import { MdOutlineRemoveRedEye } from "react-icons/md";
import {
SelectContent,
SelectItem,

View File

@@ -6,7 +6,7 @@ import DataTable from "../../components/DataTable";
import AlertDailog from "../../components/AlertDailog";
import { Switch } from "../../components/ui/switch";
import img from "../../assets/waterfall.jpg";
import { RiDeleteBin5Line } from "react-icons/ri";
// import { RiDeleteBin5Line } from "react-icons/ri";
import ViewDailog from "./ViewDailog";
import Delete from "../../components/ActionIcons/Delete";
// import ViewDailog from './ViewDailog'

View File

@@ -1,5 +1,5 @@
import { Field, Icon, Image, Input, Span, Stack } from "@chakra-ui/react"
import { TbEdit } from "react-icons/tb"
import { Field, Image, Input, Span, Stack } from "@chakra-ui/react"
// import { TbEdit } from "react-icons/tb"
import img from "../../assets/waterfall.jpg"
import { DialogBody, DialogCloseTrigger, DialogContent, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
import Edit from "../../components/ActionIcons/Edit"

View File

@@ -1,5 +1,5 @@
import { MdOutlineRemoveRedEye } from "react-icons/md";
import { Field, Icon, Input, Span, Stack } from "@chakra-ui/react";
// import { MdOutlineRemoveRedEye } from "react-icons/md";
import { Field, Input, Span, Stack } from "@chakra-ui/react";
import {
DialogActionTrigger,
DialogBody,
@@ -11,9 +11,9 @@ import {
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import { BiEdit } from "react-icons/bi";
// import { BiEdit } from "react-icons/bi";
import { Button } from "../../../components/ui/button";
import { TbEdit } from "react-icons/tb";
// import { TbEdit } from "react-icons/tb";
import Edit from "../../../components/ActionIcons/Edit";
function EditRegisterUsers() {

View File

@@ -1,7 +1,7 @@
import { Box, HStack, Image, Input, Span, Text } from "@chakra-ui/react";
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame";
import AlertDailog from "../../../components/AlertDailog";
import { RiDeleteBin5Line } from "react-icons/ri";
// import { RiDeleteBin5Line } from "react-icons/ri";
import DataTable from "../../../components/DataTable";
import { Switch } from "../../../components/ui/switch";
import { InputGroup } from "../../../components/ui/input-group";

View File

@@ -7,6 +7,8 @@ import { Switch } from "../../../components/ui/switch";
import EditAgencyMaster from "./EditAgencyMaster";
import ViewAgencyAddModel from "./ViewAgencyAddModel";
import ViewAgencyMaster from "./ViewAgencyMaster";
import {useAgencyMasterToggleMutation, useGetAgencyMasterQuery } from "../../../Redux/Service/agency.master.module.service";
import { useEffect, useState } from "react";
// table data
@@ -21,32 +23,95 @@ const tableHeadRow = [
"Website/Domain",
"GST no.",
"Action"
];
const managepost: any[] = [
...Array.from({ length: 12 }, (_, i) => ({
"Sr. No": i + 1,
"Agency Name": "Lorem Ipsum",
"RC no.": "Lorem Ipsum",
"State": "Lorem Ipsum",
"RC Status": "Active",
"Registered Office Address": "Lorem Ipsum",
"Website/Domain": "Lorem Ipsum",
"GST no.": "Lorem Ipsum",
// const managepost: any[] = [
// ...Array.from({ length: 12 }, (_, i) => ({
// "Sr. No": i + 1,
// "Agency Name": "Lorem Ipsum",
// "RC no.": "Lorem Ipsum",
// "State": "Lorem Ipsum",
// "RC Status": "Active",
// "Registered Office Address": "Lorem Ipsum",
// "Website/Domain": "Lorem Ipsum",
// "GST no.": "Lorem Ipsum",
// "Action": (
// <HStack justifyContent="center">
// <ViewAgencyMaster/>
// <EditAgencyMaster />
// <Box>
// <Switch colorPalette={'teal'} size={"xs"}/>
// </Box>
// </HStack>
// ),
// })),
// ];
const AgencyMaster = () => {
const { data, refetch } = useGetAgencyMasterQuery()
const [agencyMasterToggle] = useAgencyMasterToggleMutation()
const [localData, setLocalData] = useState<any[]>([]);
useEffect(() => {
if (data?.data?.data) {
setLocalData(data?.data.data);
}
}, [data]);
const handleToggle = async (agencyId: string, currentStatus: number) => {
const newStatus = currentStatus ? 0 : 1;
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
)
);
try {
await agencyMasterToggle({ id: agencyId, is_active: newStatus }).unwrap();
refetch()
} catch (error) {
console.error("Error updating privacy policy:", error);
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
)
);
}
};
const managepost = localData?.map((agency: any, index: number) => ({
'id': agency.id,
"Sr. No": index + 1,
"Agency Name": agency.name,
"RC no.": agency.rc_number,
"State": agency.state,
"RC Status": agency.rc_status,
"Registered Office Address": agency.registered_office,
"Website/Domain": agency.domain_name,
"GST no.": agency.gst_number,
"is_active": agency.is_active,
"Action": (
<HStack justifyContent="center">
<ViewAgencyMaster/>
<ViewAgencyMaster agency={localData} id={agency.id}/>
<EditAgencyMaster />
<Box>
<Switch colorPalette={'teal'} size={"xs"}/>
<Switch
colorPalette={"teal"}
size={"xs"}
onChange={() => handleToggle(agency.id, agency.is_active ?? 0)}
checked={agency.is_active}
/>
</Box>
</HStack>
),
})),
];
}));
useEffect(() => {
console.log("Fetched data:", data);
console.log("Local data:", localData);
console.log("Managepost data:", managepost);
}, [data, localData, managepost]);
const AgencyMaster = () => {
return (
<MainFrame>
@@ -59,11 +124,11 @@ const AgencyMaster = () => {
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
Agency Master
Agency Master
</Text>
<HStack >
<InputGroup
<InputGroup
startElement={
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
}
@@ -90,9 +155,9 @@ const AgencyMaster = () => {
<DataTable
sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow}
data={managepost}
data={managepost || []}
/>
</Box>
</Box>
</MainFrame>
)
}

View File

@@ -9,7 +9,7 @@ import {
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import { Field, Icon, Input, Span, Stack } from "@chakra-ui/react";
import { Field, Input, Span, Stack } from "@chakra-ui/react";
import Edit from "../../../components/ActionIcons/Edit";
function EditAgencyMaster() {

View File

@@ -2,18 +2,20 @@ import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
// DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import { Field, Icon, Input, Span, Stack } from "@chakra-ui/react";
import { MdOutlineRemoveRedEye } from "react-icons/md";
import { Button } from "../../../components/ui/button";
import { Field, Input, Span, Stack } from "@chakra-ui/react";
// import { MdOutlineRemoveRedEye } from "react-icons/md";
// import { Button } from "../../../components/ui/button";
import View from "../../../components/ActionIcons/View";
import { Agency } from "../../../Redux/Service/agency.master.module.service";
function ViewAgencyMaster({ agency, id }: { agency: Agency[], id:number }) {
function ViewAgencyMaster() {
return (
<DialogRoot placement="center">
<DialogTrigger asChild>
@@ -32,107 +34,130 @@ function ViewAgencyMaster() {
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Add
View
</DialogTitle>
</DialogHeader>
{agency.map((data) => (
<DialogBody bg="white">
{data.id === id && <Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Agency name
</Field.Label>
<Input
value={data.name}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
disabled
/>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Agency name
</Field.Label>
<Input
value="Lorem Ipsum"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
RC No.
</Field.Label>
<Input
value={data.rc_number}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
disabled
/>
<Field.Label color="black" pt={1} fontSize="12px">
RC No.
</Field.Label>
<Input
value="Lorem Ipsum"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
State
</Field.Label>
<Input
value={data.state}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
disabled
/>
<Field.Label color="black" pt={1} fontSize="12px">
State
</Field.Label>
<Input
value="Lorem Ipsum"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
RC Status
</Field.Label>
<Input
value={data.rc_status}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
disabled
/>
<Field.Label color="black" pt={1} fontSize="12px">
Registered Office Address
</Field.Label>
<Input
value="Active"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
Registered Office Address
</Field.Label>
<Input
value={data.registered_office}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
disabled
/>
<Field.Label color="black" pt={1} fontSize="12px">
Website/Domain
</Field.Label>
<Input
value="Lorem Ipsum"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
Website/Domain
</Field.Label>
<Input
value={data.domain_name}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
disabled
/>
<Field.Label color="black" pt={1} fontSize="12px">
GST no.
</Field.Label>
<Input
value="Lorem Ipsum"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
GST no.
</Field.Label>
<Input
value={data.gst_number}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
disabled
/>
<Field.Label color="black" pt={1} fontSize="12px">
Action
</Field.Label>
<Input
value="Lorem Ipsum"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
{/* <Field.Label color="black" pt={1} fontSize="12px">
Action
</Field.Label>
<Input
value={data}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
disabled
/> */}
</Field.Root>
</Stack>}
</DialogBody>
))}
{/* <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button
w="100%"
bg="#02A0A0"
@@ -142,7 +167,7 @@ function ViewAgencyMaster() {
>
Save
</Button>
</DialogFooter>
</DialogFooter> */}
<DialogCloseTrigger color="black" />
</DialogContent>

View File

@@ -1,5 +1,5 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
import { Field, Input, Stack, Text } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button"

View File

@@ -1,30 +1,30 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Box, Field, IconButton, Input, Span, Stack, Text, Textarea } from "@chakra-ui/react"
import { Field, Input, Span, Stack } from "@chakra-ui/react"
import { Button } from "../../../components/ui/button"
import { FaRegEdit } from "react-icons/fa";
// import { FaRegEdit } from "react-icons/fa";
import Edit from "../../../components/ActionIcons/Edit";
function EditJobStatusModel() {
return (
<DialogRoot placement="center">
<DialogTrigger asChild>
<Span><Edit /></Span>
<Span><Edit /></Span>
</DialogTrigger>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'auto'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Edit</DialogTitle>

View File

@@ -1,4 +1,4 @@
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
import { Box, HStack, Input, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame"
import { InputGroup } from "../../../components/ui/input-group";
import { LuSearch } from "react-icons/lu";
@@ -15,7 +15,7 @@ const tableHeadRow = [
"Sr. No",
"Title",
"Action"
];
const managepost: any[] = [
@@ -26,7 +26,7 @@ const managepost: any[] = [
<HStack justifyContent="center">
<EditJobStatusModel />
<Box>
<Switch colorPalette={'teal'} size={"xs"}/>
<Switch colorPalette={'teal'} size={"xs"} />
</Box>
</HStack>
),
@@ -46,11 +46,11 @@ const JobStatus = () => {
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
Job Status
Job Status
</Text>
<HStack >
<InputGroup
<InputGroup
startElement={
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
}
@@ -79,7 +79,7 @@ const JobStatus = () => {
tableHeadRow={tableHeadRow}
data={managepost}
/>
</Box>
</Box>
</MainFrame>
)
}

View File

@@ -1,5 +1,5 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
import { Field, Input, Stack, Text } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button"

View File

@@ -1,5 +1,5 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
import { Field, Input, Stack, Text } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button"

View File

@@ -1,50 +1,132 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
import { Box, Field, Input, Stack, Text } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button"
import { FiUpload } from "react-icons/fi";
import { useState } from "react";
// import { useCreateTemplatePostMutation } from "../../../Redux/Service/template.master.service";
import { Toaster, toaster } from "../../../components/ui/toaster"
import axios from "axios";
function TemplateAddModel() {
function TemplateAddModel({ id }: { id: number }) {
const [title, setTitle] = useState("");
const [subTitle, setSubTitle] = useState("");
const [userType, setUserType] = useState<number | "">("");
const [images, setImages] = useState<(File | string)[]>([]);
// const [createTemplatePost] = useCreateTemplatePostMutation()
const [isOpen, setIsOpen] = useState(false);
const token = localStorage.getItem("token");
if (!token) {
console.error("No token found in localStorage!");
return;
}
const [images, setImages] = useState<string[]>([]);
const handleImageChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.files) {
const selectedFiles = Array.from(event.target.files);
const newImages = selectedFiles.map((file) => {
return URL.createObjectURL(file); // Convert to preview URL
});
setImages((prevImages) => [...prevImages, ...newImages]); // Append new images
}
const handleOpenModal = () => {
setIsOpen(true); // Open modal when clicking "Add"
};
const handleImageChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.files) {
const file = event.target.files[0];
if (!["image/jpeg", "image/jpg", "image/png"].includes(file.type)) {
toaster.create({
title: "Error",
description: "Only JPEG, JPG, and PNG files are allowed.",
type: "error",
});
return;
}
setImages((prevImages) => [...prevImages, file]);
}
};
const handleSubmit = async () => {
if (!title || !subTitle || !userType || images.length === 0) {
toaster.create({
title: "Error",
description: "Please fill in all required fields and upload at least one image.",
type: "error",
});
return;
}
// const payload = {
// id: id,
// principle_type_xid: userType,
// title,
// sub_title: subTitle,
// image_name: images.filter((img) => typeof img === "string"), // Send only Base64 strings
// };
const formData = new FormData();
formData.append("id", `${id}`);
formData.append("principle_type_xid", `${userType}`);
formData.append("title", title);
formData.append("sub_title", subTitle);
images.forEach((image, index) => {
if (image instanceof File) {
formData.append(`image_name[${index}]`, image, image.name); // Ensure indexed naming
}
});
if (token) {
const payload = JSON.parse(atob(token.split(".")[1]));
console.log("Token Payload:", payload);
}
try {
// await createTemplatePost(formData)
if (token) {
await axios.post(`https://ssa.betadelivery.com/apia/v1/template-store`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
'access-token': `${token}`,
},
// withCredentials: true,
});
}
setTitle("");
setSubTitle("");
setUserType("");
setImages([]);
setIsOpen(false)
} catch (error) {
console.error("Error creating template:", error);
// alert("Failed to create template");
}
};
console.log("Token stored:", window.localStorage.getItem("token"));
return (
<DialogRoot placement="center">
<DialogRoot placement="center" open={isOpen}>
<DialogTrigger asChild>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Button px={5} size={"xs"} bg={"#02A0A0"}>
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
<IoMdAdd /> <Text>Add</Text>
</Button>
</DialogTrigger>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'auto'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
@@ -54,30 +136,79 @@ function TemplateAddModel() {
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Template Name</Field.Label>
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
<Field.Label color="black" pt={1} fontSize="12px">Title</Field.Label>
<Input
placeholder="Enter Title"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
</Field.Root>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Subtitle</Field.Label>
<Input
placeholder="Enter subtitle"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={subTitle}
onChange={(e) => setSubTitle(e.target.value)}
/>
</Field.Root>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Select User Type</Field.Label>
<Box bgColor="#EEEEEE" borderRadius="md" p={1}>
<select
style={{
width: "100%",
background: "transparent",
color: "black",
border: "none",
fontSize: "12px",
height: "30px",
outline: "none",
}}
value={userType}
onChange={(e) => setUserType(Number(e.target.value))}
>
<option value="">Select User Type</option>
<option value="2">Recruiter</option>
<option value="3">Jobseeker</option>
</select>
</Box>
</Field.Root>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Images</Field.Label>
<Box display="flex" alignItems="center" justifyContent="space-between" px={3} bgColor="#EEEEEE" border="none" width="100%" height="50px" cursor="pointer" position="relative">
<Input type="file" accept="image/*" opacity={0} position="absolute" bgColor="#EEEEEE" border="none" pl={1} width="100%" height="100%" cursor="pointer" onChange={handleImageChange}/>
<Box display="flex" gap={2} overflow="hidden">
{images.length > 0 ? (
images.map((img, index) => (
<img
key={index}
src={img}
alt={`Uploaded ${index}`}
style={{ maxHeight: "40px", maxWidth: "70px", objectFit: "contain" }}
/>
))
) : (
<Box width="70px" height="40px" /> // Placeholder to maintain layout
)}
<Box display="flex" alignItems="center" justifyContent="space-between" px={3} bgColor="#EEEEEE" border="none" width="100%" height="50px" cursor="pointer" position="relative">
<Input type="file" accept="image/*" opacity={0} position="absolute" bgColor="#EEEEEE" border="none" pl={1} width="100%" height="100%" cursor="pointer" onChange={handleImageChange} />
<Box display="flex" gap={2} overflow="hidden">
{images.length > 0 ? (
images.map((img, index) => (
<img
key={index}
src={img instanceof File ? URL.createObjectURL(img) : img}
alt={`Uploaded ${index}`}
style={{ maxHeight: "40px", maxWidth: "70px", objectFit: "contain" }}
/>
))
) : (
<Box width="70px" height="40px" /> // Placeholder to maintain layout
)}
</Box>
<FiUpload color="#000" />
</Box>
<FiUpload color="#000" />
</Box>
{/* <Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" /> */}
</Field.Root>
@@ -85,13 +216,14 @@ function TemplateAddModel() {
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
<Toaster />
</DialogRoot >
)

View File

@@ -4,12 +4,14 @@ import { InputGroup } from "../../../components/ui/input-group";
import { LuSearch } from "react-icons/lu";
import DataTable from "../../../components/DataTable";
import { Switch } from "../../../components/ui/switch";
import img from "../../../assets/waterfall.jpg"
import Templateimg from "../../../assets/Template_img.png"
// import img from "../../../assets/waterfall.jpg"
// import Templateimg from "../../../assets/Template_img.png"
import TemplateAddModel from "./TemplateAddModel";
import EditTemplateModel from "./EditTemplateModel";
import { Template, useGetTemplateMasterQuery, useTemplateMasterToggleMutation } from "../../../Redux/Service/template.master.service";
import { useEffect, useState } from "react";
const APIURL = import.meta.env.VITE_IMG_TEMPLATES
// table data
@@ -18,35 +20,95 @@ const tableHeadRow = [
"Title",
"Images",
"Action"
];
const managepost: any[] = [
...Array.from({ length: 12 }, (_, i) => ({
"Sr. No": i + 1,
"Title": "Lorem Ipsum",
// const managepost: any[] = [
// ...Array.from({ length: 12 }, (_, i) => ({
// "Sr. No": i + 1,
// "Title": "Lorem Ipsum",
// "Images": (
// // <Image w={50} src={img} />
// <HStack >
// <Image rounded={'lg'} w={100} h={50} src={img} />
// <Image rounded={'lg'} w={100} h={50} src={Templateimg} />
// </HStack>
// ),
// "Action": (
// <HStack justifyContent="center">
// <EditTemplateModel />
// <Box>
// <Switch colorPalette={'teal'} size={"xs"} />
// </Box>
// </HStack>
// ),
// })),
// ];
const TemplateMaster = () => {
const { data, refetch } = useGetTemplateMasterQuery()
const [localData, setLocalData] = useState<any[]>([]);
const [templateMasterToggle] = useTemplateMasterToggleMutation()
console.log('DATA', data?.data.data);
useEffect(() => {
if (data?.data?.data) {
setLocalData(data?.data.data);
}
}, [data]);
const handleToggle = async (agencyId: string, currentStatus: number) => {
const newStatus = currentStatus ? 0 : 1;
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
)
);
try {
await templateMasterToggle({ id: agencyId, is_active: newStatus }).unwrap();
refetch()
} catch (error) {
console.error("Error updating privacy policy:", error);
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
)
);
}
};
const managepost = localData?.map((agency: Template, index: number) => ({
'id': agency.id,
"Sr. No": index + 1,
"Title": agency.post_template_translate.length > 0
? agency.post_template_translate[0].title
: "N/A",
"Images": (
// <Image w={50} src={img} />
<HStack >
<Image rounded={'lg'} w={100} h={50} src={img} />
<Image rounded={'lg'} w={100} h={50} src={Templateimg} />
{agency.post_template_image.map((img) => (
<Image rounded={'lg'} w={100} h={50} src={`${APIURL}${img.image_name}`} />
))}
{/* <Image rounded={'lg'} w={100} h={50} src={Templateimg} /> */}
</HStack>
),
"Action": (
<HStack justifyContent="center">
<EditTemplateModel />
<EditTemplateModel id={agency.id} localData={localData} />
<Box>
<Switch colorPalette={'teal'} size={"xs"}/>
<Switch
colorPalette={'teal'}
size={"xs"}
onChange={() => handleToggle(agency.id.toString(), Number(agency.is_active ?? 0))}
checked={Boolean(Number(agency.is_active))}
/>
</Box>
</HStack>
),
})),
];
}));
const TemplateMaster = () => {
return (
<MainFrame>
@@ -59,11 +121,11 @@ const TemplateMaster = () => {
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
Template Master
Template Master
</Text>
<HStack >
<InputGroup
<InputGroup
startElement={
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
}
@@ -84,7 +146,9 @@ const TemplateMaster = () => {
/>
</InputGroup>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
<TemplateAddModel />
{localData?.map((item: any) => (
<TemplateAddModel id={item.id} />
))}
</HStack>
</HStack>
<DataTable
@@ -92,7 +156,7 @@ const TemplateMaster = () => {
tableHeadRow={tableHeadRow}
data={managepost}
/>
</Box>
</Box>
</MainFrame>
)
}

View File

@@ -9,17 +9,13 @@ import {
DialogTrigger,
} from "../../../components/ui/dialog";
import {
Box,
Field,
IconButton,
Input,
Span,
Stack,
Text,
Textarea,
} from "@chakra-ui/react";
import { Button } from "../../../components/ui/button";
import { FaRegEdit } from "react-icons/fa";
// import { FaRegEdit } from "react-icons/fa";
import Edit from "../../../components/ActionIcons/Edit";
function EditWorkModel() {

View File

@@ -1,5 +1,5 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
import {Field, Input, Stack, Text } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button"

View File

@@ -1,4 +1,4 @@
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
import { Box, HStack, Input, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame"
import { InputGroup } from "../../../components/ui/input-group";
import { LuSearch } from "react-icons/lu";

View File

@@ -0,0 +1,133 @@
import {
Box,
Center,
HStack,
Image,
Input,
Stack,
Text,
VStack,
} from "@chakra-ui/react";
import axios from "axios";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import logo from "../assets/logo.svg";
import { Button } from "../components/ui/button";
import { toaster, Toaster } from "../components/ui/toaster";
const SetNewPassword = () => {
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [isLoading, setIsLoading] = useState(false);
const navigate = useNavigate();
const handlePasswordSubmit = async () => {
// Validation
if (password.length < 8) {
toaster.create({
title: "Password must be at least 8 characters long",
type: "error",
});
return;
}
if (password !== confirmPassword) {
toaster.create({
title: "Passwords do not match",
type: "error",
});
return;
}
setIsLoading(true);
try {
const res = await axios.post(`${import.meta.env.VITE_API_URL}/reset-password`, {
password: password,
confirm_password: confirmPassword,
// id: id
});
if (res.status === 200) {
toaster.create({
title: "Password updated successfully",
type: "success",
});
navigate("/login"); // Redirect to login page
} else {
toaster.create({
title: res.data.message || "Failed to update password",
type: "error",
});
}
} catch (error: any) {
toaster.create({
title: error.response?.data?.message || "Something went wrong",
type: "error",
});
} finally {
setIsLoading(false);
}
};
return (
<VStack w="100%" h="100vh" bg="#ffffff">
<HStack
boxShadow="rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"
w="100%"
ps={8}
h="7%"
justifyContent="flex-start"
>
<Image w={50} src={logo} />
</HStack>
<Center w="100%" h="93%" p={8}>
<Box p={8} borderWidth={1} borderRadius="lg" boxShadow="lg">
<Text fontSize="24px" fontWeight="bold" color="#313039" textAlign="center">
Create a Password
</Text>
<Stack p={2}>
<Text color="black" pt={1} fontSize="12px">New password</Text>
<Input
color="black"
pl={1}
fontSize="12px"
type="password"
border="1px solid grey"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<Text color="black" pt={1} fontSize="12px">Confirm password</Text>
<Input
color="black"
pl={1}
fontSize="12px"
type="password"
border="1px solid grey"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
/>
</Stack>
<Button
loading={isLoading}
mt={6}
w="100%"
bg="#02A0A0"
color="white"
onClick={handlePasswordSubmit}
>
Confirm Password
</Button>
</Box>
</Center>
<Toaster />
</VStack>
);
};
export default SetNewPassword;

View File

@@ -4,7 +4,7 @@ import { InputGroup } from "../../components/ui/input-group"
import { LuSearch } from "react-icons/lu"
import DataTable from "../../components/DataTable"
import AlertDailog from "../../components/AlertDailog"
import { RiDeleteBin5Line } from "react-icons/ri";
// import { RiDeleteBin5Line } from "react-icons/ri";
import AddModel from "./AddModel"
import EditSubAdmin from "../../components/EditSubAdmin"
import ViewSubAdmin from "./ViewSubAdmin"

View File

@@ -1,4 +1,4 @@
import { Button } from "../../components/ui/button";
// import { Button } from "../../components/ui/button";
import {
DialogBody,
DialogCloseTrigger,
@@ -13,17 +13,20 @@ import {
Field,
Grid,
Heading,
Icon,
Input,
Span,
Stack,
Text,
} from "@chakra-ui/react";
import { Checkbox } from "../../components/ui/checkbox";
import { MdOutlineRemoveRedEye } from "react-icons/md";
import { FaRegEdit } from "react-icons/fa";
// import { MdOutlineRemoveRedEye } from "react-icons/md";
// import { FaRegEdit } from "react-icons/fa";
import View from "../../components/ActionIcons/View";
import { useGetSubAdminQuery } from "../../Redux/Service/manage.subadmin.service";
function ViewSubAdmin() {
const { data} = useGetSubAdminQuery();
console.log('data', data);
return (
<DialogRoot placement="center">
<DialogTrigger asChild>

View File

@@ -0,0 +1,155 @@
import {
Box,
Center,
HStack,
Image,
Input,
Text,
VStack,
} from "@chakra-ui/react";
import axios from "axios";
import { useState } from "react";
import { useNavigate, useLocation } from "react-router-dom";
import logo from "../assets/logo.svg";
import { Button } from "../components/ui/button";
import { toaster, Toaster } from "../components/ui/toaster";
const VerifyOTP = () => {
const [otp, setOtp] = useState<string[]>(["", "", "", ""]);
const navigate = useNavigate();
const location = useLocation();
const queryParams = new URLSearchParams(location.search);
const phoneNumber = queryParams.get("phone");
const [isLoading, setIsLoading] = useState(false);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>, index: number): void => {
const value = e.target.value;
// Prevent non-numeric input
if (/[^0-9]/.test(value)) return;
// Update the OTP state with the new value
const newOtp = [...otp];
newOtp[index] = value;
setOtp(newOtp);
// Move focus to the next input automatically
if (value && index < otp.length - 1) {
const nextInput = document.getElementById(`otp-input-${index + 1}`) as HTMLInputElement;
if (nextInput) nextInput.focus();
}
};
const handleOtpSubmit = async () => {
if (otp.length !== 4) {
toaster.create({
title: "OTP must be 4 digits",
type: "error",
});
return;
}
setIsLoading(true);
try {
const res = await axios.post(`${import.meta.env.VITE_API_URL}/verify-otp`, {
mobile_number: phoneNumber,
otp: otp,
});
if (res.status === 200) {
toaster.create({
title: "OTP Verified Successfully",
type: "success",
});
navigate("/forgot-password/reset-password"); // Navigate to reset password page
} else {
toaster.create({
title: res.data.message || "Invalid OTP",
type: "error",
});
}
} catch (error: any) {
toaster.create({
title: error.response?.data?.message || "Something went wrong",
type: "error",
});
} finally {
setIsLoading(false);
}
};
return (
<VStack w="100%" h="100vh" bg="#ffffff">
<HStack
boxShadow="rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"
w="100%"
ps={8}
h="7%"
justifyContent="flex-start"
>
<Image w={50} src={logo} />
</HStack>
<Center w="100%" h="93%" p={8}>
<Box p={8} borderWidth={1} borderRadius="lg" boxShadow="lg">
<Text fontSize="24px" fontWeight="bold" color="#313039" textAlign="center">
Enter OTP
</Text>
<Text fontSize="14px" color="gray.600" textAlign="center" mt={2}>
OTP sent to {phoneNumber}
</Text>
<HStack gap={4} mt={6} justify="center">
{otp.map((digit, index) => (
<Input
key={index}
id={`otp-input-${index}`}
value={digit}
maxW="50px"
color={"black"}
textAlign="center"
fontSize="20px"
placeholder="0"
border="1px solid grey"
onChange={(e) => handleChange(e, index)}
maxLength={1} // Only allows 1 character per input
/>
))}
</HStack>
{/* <Box textAlign="center">
<Text
color="#4746F4"
textDecoration="underline"
fontWeight="bold"
mt={3}
cursor="pointer"
display="inline-block"
px={2}
>
Resend OTP
</Text>
</Box> */}
<Button
loading={isLoading}
mt={6}
w="100%"
bg="#02A0A0"
color="white"
onClick={handleOtpSubmit}
>
Verify OTP
</Button>
</Box>
</Center>
<Toaster />
</VStack>
);
};
export default VerifyOTP;

View File

@@ -0,0 +1,60 @@
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQueryWithReauth } from "./apiSlice";
export interface Agency {
id: number;
name: string;
state: string;
rc_status: string;
rc_number: string;
domain_name: string;
gst_number: string;
is_active: boolean,
registered_office:string,
}
export interface AgencyData {
current_page: number;
data: Agency[];
first_page_url: string;
from: number;
last_page: number;
last_page_url: string;
per_page: number;
total: number;
}
export interface AgencyResponse {
status: "success" | "error";
status_code: number;
message: string;
data: AgencyData;
}
export interface UpdatePrivacyPolicyPayload {
id: number,
is_active: boolean,
}
export const agencyMasterModule = createApi({
reducerPath: "agencyMasterModule",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
getAgencyMaster: builder.query<AgencyResponse, void>({ query: () => "/agency-master" }),
agencyMasterToggle: builder.mutation({
query: ({ id, is_active }) => ({
url: `/agency-status`,
method: "POST",
body: { id, is_active },
}),
}),
}),
});
export const { useGetAgencyMasterQuery, useAgencyMasterToggleMutation } = agencyMasterModule;

View File

@@ -1,36 +0,0 @@
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQueryWithReauth } from "./apiSlice";
export const forgetPassword = createApi({
reducerPath: "aboutUs",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
// 🔹 GET: Fetch all posts
getAboutUs: builder.query<AboutUs[], void>({
query: () => "/send-otp",
}),
}),
});
export const {
useGetAboutUsQuery,
} = forgetPassword;
// Define Post type
export type Post = {
id: number;
title: string;
body: string;
};
export type AboutUs = {
id: number;
language_master_xid: number;
content: string;
is_active: boolean;
};

View File

@@ -0,0 +1,97 @@
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQueryWithReauth } from "./apiSlice";
interface JobTypeResponse {
status: string;
status_code: number;
message: string;
data: PaginationData;
}
interface PaginationData {
current_page: number;
data: JobTypeData[];
first_page_url: string;
from: number;
last_page: number;
last_page_url: string;
links: PaginationLink[];
next_page_url: string | null;
path: string;
per_page: number;
prev_page_url: string | null;
to: number;
total: number;
}
export interface JobTypeData {
id: number;
is_active: boolean;
en_name: string;
hi_name: string;
mr_name:string,
te_name:string,
ta_name:string,
bn_name:string,
or_name:string,
}
interface PaginationLink {
url: string | null;
label: string;
active: boolean;
}
export interface Post {
id: number,
principle_type_xid: number,
title: string,
sub_title: string,
image_name: string[]
}
export const jobType = createApi({
reducerPath: "jobType",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
createTemplatePost: builder.mutation<Post, FormData>({
query: (data) => ({
url: "/template-store",
method: "POST",
body: data,
headers: {
token_access: `Bearer ${localStorage.getItem("token")}`,
},
}),
}),
// 🔹 GET: Fetch all posts
getJobType: builder.query<JobTypeResponse, void>({
query: () => "/job-type",
}),
updateTemplateMaster: builder.mutation({
query: (updatedData) => ({
url: "/template-update",
method: "POST",
body: updatedData,
}),
}),
templateMasterToggle: builder.mutation({
query: ({ id, is_active }) => ({
url: `/template-status`,
method: "POST",
body: { id, is_active },
}),
}),
}),
});
export const {
useGetJobTypeQuery,
useCreateTemplatePostMutation,
useUpdateTemplateMasterMutation,
useTemplateMasterToggleMutation,
} = jobType;

View File

@@ -14,9 +14,6 @@ export const aboutUs = createApi({
}),
// 🔹 GET: Fetch a single post by ID
getPostById: builder.query<Post, number>({
query: (id) => `/posts/${id}`,
@@ -42,7 +39,7 @@ export const aboutUs = createApi({
updateAboutUs: builder.mutation({
query: (updatedData) => ({
url: "/about-us/update", // ✅ Updated URL
method: "POST",
method: "PUT",
body: updatedData,
}),
}),
@@ -59,17 +56,6 @@ export const aboutUs = createApi({
export const {
useGetAboutUsQuery,
useUpdateAboutUsMutation,
useGetPostByIdQuery,
useCreatePostMutation,
useDeletePostMutation

View File

@@ -1,23 +1,30 @@
import { createApi } from "@reduxjs/toolkit/query";
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQueryWithReauth } from "./apiSlice";
export type SubAdminPost = {
id: number;
first_name: string,
last_name: string,
unique_id:string,
date_of_birth:string,
gender: string,
}
export const manageSubAdmin = createApi({
reducerPath: "manageSubAdmin",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
getPosts: builder.query<Post[], void>({ query: () => "/posts" }),
tagTypes: ['SubAdmin'],
endpoints: (builder) => ({
getSubAdmin: builder.query<SubAdminPost[], void>({
query: () => `/sub-admin-view/2` }),
}),
});
export const { } = manageSubAdmin;
export const {
useGetSubAdminQuery,
} = manageSubAdmin;
export type Post = {
id: number;

View File

@@ -1,26 +0,0 @@
import { createApi } from "@reduxjs/toolkit/query";
import { baseQueryWithReauth } from "./apiSlice";
export const masterModule = createApi({
reducerPath: "masterModule",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
getPosts: builder.query<Post[], void>({ query: () => "/posts" }),
}),
});
export const { } = masterModule;
export type Post = {
id: number;
title: string;
body: string;
};

View File

@@ -9,8 +9,16 @@ export const privacyPolicy = createApi({
getPrivacyPolicy: builder.query<PrivacyPolicyResponse, void>({ // Fix types here
query: () => "/privacy-policy",
}),
updatePrivacyPolicy: builder.mutation({
query: (updatedData) => ({
url: "/privacy-policy/update", // ✅ Updated URL
method: "POST",
body: updatedData,
}),
}),
}),
});
// Export hook
export const { useGetPrivacyPolicyQuery } = privacyPolicy;
export const { useGetPrivacyPolicyQuery, useUpdatePrivacyPolicyMutation } = privacyPolicy;

View File

@@ -0,0 +1,104 @@
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQueryWithReauth } from "./apiSlice";
interface TemplateResponse {
status: string;
status_code: number;
message: string;
data: PaginationData;
}
interface PaginationData {
current_page: number;
data: Template[];
first_page_url: string;
from: number;
last_page: number;
last_page_url: string;
links: PaginationLink[];
next_page_url: string | null;
path: string;
per_page: number;
prev_page_url: string | null;
to: number;
total: number;
}
export interface Template {
id: number;
is_active: boolean;
post_template_translate: PostTemplateTranslate[];
post_template_image: PostTemplateImage[];
}
export interface PostTemplateTranslate {
id: number;
title: string;
sub_title: string;
post_template_xid: number;
}
interface PostTemplateImage {
id: number;
post_template_xid: number;
image_name: string;
}
interface PaginationLink {
url: string | null;
label: string;
active: boolean;
}
export interface Post {
id: number,
principle_type_xid: number,
title: string,
sub_title: string,
image_name: string[]
}
export const templateMaster = createApi({
reducerPath: "templateMaster",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
createTemplatePost: builder.mutation<Post, FormData>({
query: (data) => ({
url: "/template-store",
method: "POST",
body: data,
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
}),
}),
// 🔹 GET: Fetch all posts
getTemplateMaster: builder.query<TemplateResponse, void>({
query: () => "/template-master",
}),
updateTemplateMaster: builder.mutation({
query: (updatedData) => ({
url: "/template-update",
method: "POST",
body: updatedData,
}),
}),
templateMasterToggle: builder.mutation({
query: ({ id, is_active }) => ({
url: `/template-status`,
method: "POST",
body: { id, is_active },
}),
}),
}),
});
export const {
useGetTemplateMasterQuery,
useCreateTemplatePostMutation,
useUpdateTemplateMasterMutation,
useTemplateMasterToggleMutation,
} = templateMaster;

View File

@@ -1,26 +1,40 @@
import { createApi } from "@reduxjs/toolkit/query";
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQueryWithReauth } from "./apiSlice";
export interface Terms {
id: number,
language_master_xid: number,
content: string,
is_active: boolean,
terms_cond_language: {
id: number,
language_name: string,
language_code: string,
}
}
export const termsAndCondition = createApi({
reducerPath: "api",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
getPosts: builder.query<Post[], void>({ query: () => "/posts" }),
reducerPath: "termsAndCondition",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
getTerms: builder.query<{ data: Terms[] }, void>({ query: () => "/term-and-condition" }),
updateTerms: builder.mutation({
query: (updatedData) => ({
url: "/term-and-condition/update", // ✅ Updated URL
method: "POST",
body: updatedData,
}),
}),
});
export const { } = termsAndCondition;
export type Post = {
id: number;
title: string;
body: string;
};
}),
});
export const {
useGetTermsQuery,
useUpdateTermsMutation,
} = termsAndCondition;

View File

@@ -13,7 +13,10 @@ import { aboutUs } from "./Service/manage.aboutus.service";
import { privacyPolicy } from "./Service/privacy.policy.service";
import { privacy } from "./Service/privacy.service";
import { myProfile } from "./Service/myprofie.service";
import { masterModule } from "./Service/master.module.service";
import { agencyMasterModule } from "./Service/agency.master.module.service";
import { termsAndCondition } from "./Service/terms.and.condition.service";
import { templateMaster } from "./Service/template.master.service";
import { jobType } from "./Service/job.type.service";
export const store = configureStore({
reducer: {
@@ -30,7 +33,10 @@ export const store = configureStore({
[privacyPolicy.reducerPath]: privacyPolicy.reducer,
[privacy.reducerPath]: privacy.reducer,
[myProfile.reducerPath]: myProfile.reducer,
[masterModule.reducerPath]: masterModule.reducer,
[agencyMasterModule.reducerPath]: agencyMasterModule.reducer,
[termsAndCondition.reducerPath]: termsAndCondition.reducer,
[templateMaster.reducerPath]: templateMaster.reducer,
[jobType.reducerPath]: jobType.reducer,
auth: authReducer,
},
middleware: (getDefaultMiddleware) =>
@@ -47,7 +53,10 @@ export const store = configureStore({
privacyPolicy.middleware,
privacy.middleware,
myProfile.middleware,
masterModule.middleware,
agencyMasterModule.middleware,
termsAndCondition.middleware,
templateMaster.middleware,
jobType.middleware,
),
});

View File

@@ -11,7 +11,7 @@ import FAQ from "../Pages/ManageCMS/FAQ/FAQ";
import AboutUs from "../Pages/ManageCMS/AboutUs/AboutUs";
import PrivacyPolicy from "../Pages/ManageCMS/PrivacyPolicy/PrivacyPolicy";
import TermsAndConditions from "../Pages/ManageCMS/TermsAndConditions/TermsAndConditions";
import Privacy from "../Pages/ManageCMS/Privacy/Privacy";
// import Privacy from "../Pages/ManageCMS/Privacy/Privacy";
import MyProfile from "../Pages/MyProfile/MyProfile";
import Notification from "../Pages/Notification/Notification";
import AgencyMaster from "../Pages/MasterModule/AgencyMaster/AgencyMaster";

View File

@@ -1,4 +1,4 @@
import { Icon, Image } from "@chakra-ui/react";
import { Icon } from "@chakra-ui/react";
import { Tooltip } from "../ui/tooltip";
import { RiDeleteBin5Line } from "react-icons/ri";

View File

@@ -1,4 +1,4 @@
import React from "react";
import { Bar } from "react-chartjs-2";
import {
Chart as ChartJS,
@@ -9,7 +9,7 @@ import {
Tooltip,
Legend,
} from "chart.js";
import { BiBorderRadius } from "react-icons/bi";
// import { BiBorderRadius } from "react-icons/bi";
// ✅ Register the required components
ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend);

View File

@@ -1,4 +1,4 @@
import React from "react";
import { Doughnut } from "react-chartjs-2";
import {
Chart as ChartJS,

View File

@@ -1,4 +1,4 @@
import { useState } from "react";
import { useEffect, useState } from "react";
import { HStack, Stack, Table } from "@chakra-ui/react";
import { PaginationItems, PaginationNextTrigger, PaginationPrevTrigger, PaginationRoot } from "./ui/pagination";
// import {
@@ -25,6 +25,10 @@ const DataTable: React.FC<TableProps> = ({
direction: "asc" | "desc";
} | null>(null);
useEffect(() => {
setSortedData(data);
}, [data]);
const handleSort = (column: string) => {
if (!sortableColumns.includes(column)) return;

View File

@@ -1,5 +1,5 @@
import { Field, Grid, Heading, Icon, Input, Span, Stack, Text } from "@chakra-ui/react";
import { TbEdit } from "react-icons/tb";
import { Field, Grid, Heading, Input, Span, Stack, Text } from "@chakra-ui/react";
// import { TbEdit } from "react-icons/tb";
import { Button } from "./ui/button";
import { Checkbox } from "./ui/checkbox";
import {

View File

@@ -1,6 +1,6 @@
import { Center } from '@chakra-ui/react'
import './Spinner.css'
import MainFrame from '../MainFrame'
// import MainFrame from '../MainFrame'
export const Spinner = () =><Center boxShadow={'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'} rounded={'lg'} w={'100%'} h={'89vh'} bg={'#fff'} > <div className='loader'/></Center>

View File

@@ -4,7 +4,6 @@ import type { ButtonProps, TextProps } from "@chakra-ui/react";
import {
Button,
Pagination as ChakraPagination,
HStack,
IconButton,
Text,
createContext,
@@ -151,7 +150,7 @@ export const PaginationNextTrigger = React.forwardRef<
HTMLButtonElement,
ChakraPagination.NextTriggerProps
>(function PaginationNextTrigger(props, ref) {
const { size, variantMap, getHref } = useRootProps();
const { variantMap, getHref } = useRootProps();
const { nextPage } = usePaginationContext();
if (getHref) {
@@ -204,7 +203,7 @@ export const PaginationItems = (props: React.HTMLAttributes<HTMLElement>) => {
<PaginationItem
key={index}
type="page"
value={page.value}
value={page.type === "page" ? page.value : 0}
{...props}
/>
))

View File

@@ -0,0 +1,27 @@
import { PinInput as ChakraPinInput, Group } from "@chakra-ui/react"
import * as React from "react"
export interface PinInputProps extends ChakraPinInput.RootProps {
rootRef?: React.Ref<HTMLDivElement>
count?: number
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
attached?: boolean
}
export const PinInput = React.forwardRef<HTMLInputElement, PinInputProps>(
function PinInput(props, ref) {
const { count = 4, inputProps, rootRef, attached, ...rest } = props
return (
<ChakraPinInput.Root ref={rootRef} {...rest}>
<ChakraPinInput.HiddenInput ref={ref} {...inputProps} />
<ChakraPinInput.Control>
<Group attached={attached}>
{Array.from({ length: count }).map((_, index) => (
<ChakraPinInput.Input key={index} index={index} />
))}
</Group>
</ChakraPinInput.Control>
</ChakraPinInput.Root>
)
},
)

View File

@@ -10,24 +10,23 @@ import {
} from "@chakra-ui/react"
export const toaster = createToaster({
placement:'bottom',
placement: "bottom-end",
pauseOnPageIdle: true,
max:1
})
export const Toaster = () => {
return (
<Portal >
<Portal>
<ChakraToaster toaster={toaster} insetInline={{ mdDown: "4" }}>
{(toast) => (
<Toast.Root width={{ md: "sm" }}>
<Toast.Root width={{ md: "sm" }}>
{toast.type === "loading" ? (
<Spinner size="sm" color="blue.solid" />
) : (
<Toast.Indicator />
)}
<Stack appearance={'light'} rounded={'full'} gap="1" flex="1" maxWidth="100%">
{toast.title && <Toast.Title p={2} color="#02A0A0">{toast.title}</Toast.Title>}
<Stack gap="1" flex="1" maxWidth="100%">
{toast.title && <Toast.Title>{toast.title}</Toast.Title>}
{toast.description && (
<Toast.Description>{toast.description}</Toast.Description>
)}