13 Commits
testing ... R1

149 changed files with 5705 additions and 16694 deletions

23
.env
View File

@@ -1,23 +0,0 @@
# VITE_API_URL='https://ssa.betadelivery.com/apia/v1'
# # VITE_API_URL='http://192.16.50.44/seo-backend/apia/v1'
# VITE_USER_NAME="Admin"
# VITE_PASSWORD="71%@L%es^bUX94`J9XT*@bh,._WWM{$%^^&&"
# VITE_APP_NAME=MyViteApp
# VITE_IMG_TEMPLATES='https://ssa.betadelivery.com/storage/app/public/uploads/post_templates/'
# VITE_API_URL='https://ssa.betadelivery.com/testing/apia/v1'
# VITE_API_URL='https://ssa.betadelivery.com/apia/v1'
# VITE_USER_NAME="Admin"
# VITE_PASSWORD="71%@L%es^bUX94`J9XT*@bh,._WWM{$%^^&&"
# # VITE_PASSWORD="71%@L%es^bUX94`J9XT*%4&^%tUU^%Q^ffgt"
# VITE_APP_NAME=MyViteApp
# VITE_IMG_TEMPLATES='https://ssa.betadelivery.com/testing/storage/app/public/uploads/post_templates/'
# VITE_MAIN_URL='https://ssa.betadelivery.com/testing'
# VITE_POST_IMG=`${VITE_MAIN_URL}/storage/app/public/uploads/post/`
VITE_API_URL='https://ssa.betadelivery.com/testing/apia/v1'
VITE_USER_NAME="Admin"
VITE_PASSWORD="71%@L%es^bUX94`J9XT*@bh,._WWM{$%^^&&"
VITE_APP_NAME=MyViteApp
VITE_MAIN_URL='https://ssa.betadelivery.com/testing'
VITE_IMG_TEMPLATES=`${VITE_MAIN_URL}/storage/app/public/uploads/post_templates/`
VITE_IMG_PROFILE=`${VITE_MAIN_URL}/storage/app/public/uploads/profile/`
VITE_POST_IMG=`${VITE_MAIN_URL}/storage/app/public/uploads/post/`

View File

@@ -1,7 +0,0 @@
VITE_API_URL='https://ssa.betadelivery.com/testing/apia/v1'
VITE_USER_NAME="Admin"
VITE_PASSWORD="71%@L%es^bUX94`J9XT*@bh,._WWM{$%^^&&"
VITE_APP_NAME=MyViteApp
VITE_IMG_TEMPLATES='https://ssa.betadelivery.com/storage/app/public/uploads/post_templates/'
VITE_MAIN_URL='https://ssa.betadelivery.com/testing'
VITE_POST_IMG=`${VITE_MAIN_URL}/storage/app/public/uploads/post/`

1
.gitignore vendored
View File

@@ -22,4 +22,3 @@ dist-ssr
*.njsproj
*.sln
*.sw?
*.env

View File

@@ -82,7 +82,7 @@ define(['./workbox-54d0af47'], (function (workbox) { 'use strict';
"revision": "3ca0b8505b4bec776b69afdba2768812"
}, {
"url": "index.html",
"revision": "0.73grfmd27h8"
"revision": "0.4goaulr6o2o"
}], {});
workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {

View File

@@ -1,17 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" name="referrer" content="strict-origin-when-cross-origin" />
<!-- <link rel="icon" type="image/png+xml" href="/src/assets/favicon.png" /> -->
<link rel="icon" type="image/png" href="/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SEO Admin</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/assets/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SEO Admin</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

5513
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -13,26 +13,18 @@
"@chakra-ui/react": "^3.2.3",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@reduxjs/toolkit": "^2.5.1",
"axios": "^1.7.9",
"chart.js": "^4.4.7",
"framer-motion": "^11.18.0",
"js-cookie": "^3.0.5",
"next-themes": "^0.4.4",
"react": "^18.3.1",
"react-chartjs-2": "^5.3.0",
"react-dom": "^18.3.1",
"react-hook-form": "^7.54.2",
"react-icons": "^5.4.0",
"react-quill": "^2.0.0",
"react-redux": "^9.2.0",
"react-router-dom": "^7.1.1",
"vite-plugin-pwa": "^0.21.1"
},
"devDependencies": {
"@chakra-ui/cli": "^2.4.1",
"@chakra-ui/cli": "^3.2.3",
"@eslint/js": "^9.17.0",
"@types/js-cookie": "^3.0.6",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
"@vitejs/plugin-react": "^4.3.4",

View File

@@ -1,62 +1,41 @@
import { useContext, useEffect } from "react";
import { BrowserRouter as Router, Routes, Route, Navigate } from "react-router-dom";
import { useContext } from "react";
import { Route, BrowserRouter as Router, Routes } from "react-router-dom";
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";
import LoginOtp from "./Pages/OnBoarding/LoginOtp";
import CreatePass from "./Pages/OnBoarding/CreatePass";
function App() {
const context = useContext(GlobalStateContext);
if (!context) throw new Error("App must be used within a GlobalStateProvider");
const { isAuthenticate, setIsAuthenticate } = context;
useEffect(() => {
const token = localStorage.getItem("token");
setIsAuthenticate(!!token); // Converts token to boolean
}, [setIsAuthenticate]);
console.log("Auth Status:", isAuthenticate);
if (!context)
throw new Error("App must be used within a GlobalStateProvider");
const { isAuthenticate } = context;
return (
<Router>
<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 path="/login" element={<Login />} />
<Route path="/login/login-otp" element={<LoginOtp />} />
<Route path="/login/create-password" element={<CreatePass/>}/>
<Route
path="/*"
element={isAuthenticate && localStorage.getItem("token") ? (
<DefaultLayout>
<Routes>
{RouteLink.map(({ path, Component }, index) => (
<Route key={index} path={path} element={<Component />} />
))}
</Routes>
</DefaultLayout>
) : (
<Routes>
{/* Allow only forgot password flows */}
<Route path="/forgot-password" element={<ForgotPassword />} />
<Route path="/forgot-password/verify" element={<VerifyEnterOTP />} /> {/* ✅ Add this line */}
<Route path="/forgot-password/verify-otp" element={<VerifyEnterOTP />} />
<Route path="/forgot-password/reset-password" element={<SetNewPassword />} />
{/* Default to login */}
<Route path="*" element={<Navigate to="/login" />} />
</Routes>
)}
element={
isAuthenticate === true ? (
<DefaultLayout>
<Routes>
{RouteLink.map(({ path, Component }, index) => (
<Route key={index} path={path} element={<Component />} />
))}
</Routes>
</DefaultLayout>
) : (
<Login />
)
}
/>
{/* Catch-all route to prevent unauthorized access */}
<Route path="*" element={<Navigate to="/login" />} />
<Route path="*" element={<Login />} />
</Routes>
</Router>
);

View File

@@ -0,0 +1,19 @@
export const getTitle = (location: string): string => {
const titles: { [key: string]: string } = {
'/': 'Dashboard',
'/manage-user/register-user': 'Manage User',
'/manage-user/active-user': 'Manage User',
'/manage-post': 'Manage Post',
'/manage-sub-admin': 'Manage Sub Admin',
'/manage-jobs': 'Manage Jobs',
'/manage-contact-us': 'Manage Contact Us',
'/manage-cms/faq': 'Manage CMS',
'/manage-cms/about-us': 'Manage CMS',
'/manage-cms/privacy-policy': 'Manage CMS',
'/manage-cms/terms-and-condition': 'Manage CMS',
'/profile': 'My Profile',
};
return titles[location] || 'Page Not Found';
};

View File

@@ -2,14 +2,11 @@
import { createContext, Dispatch, SetStateAction } from 'react';
// Define the shape of your context value
export interface GlobalStateContextType {
type GlobalStateContextType = {
isAuthenticate: boolean;
setIsAuthenticate: Dispatch<SetStateAction<boolean>>;
isBarLoading: boolean;
setIsBarLoading: Dispatch<SetStateAction<boolean>>;
userAccess: string[];
setUserAccess: Dispatch<SetStateAction<string[]>>;
}
};
// Create the context with a default value of `undefined`
const GlobalStateContext = createContext<GlobalStateContextType | undefined>(undefined);

View File

@@ -1,27 +1,14 @@
import { ReactNode, useState } from "react";
import GlobalStateContext from "./GlobalStateContext";
import { ReactNode, useState } from 'react';
import GlobalStateContext from './GlobalStateContext';
const GlobalStateProvider = ({ children }: { children: ReactNode }) => {
const GlobalStateProvider = ({ children }:{children:ReactNode}) => {
const [isAuthenticate, setIsAuthenticate] = useState<boolean>(true);
const [isBarLoading, setIsBarLoading] = useState<boolean>(false); // ✅ Fixed typo
const [userAccess, setUserAccess] = useState<string[]>(() => {
const stored = sessionStorage.getItem('userAccess');
return stored ? JSON.parse(stored) : [];
});
return (
<GlobalStateContext.Provider value={{
isAuthenticate,
setIsAuthenticate,
isBarLoading,
setIsBarLoading, // ✅ Fixed typo
userAccess,
setUserAccess
}}>
<GlobalStateContext.Provider value={{ isAuthenticate, setIsAuthenticate }}>
{children}
</GlobalStateContext.Provider>
);

View File

@@ -1,98 +1,206 @@
import { HStack, Image, Text, VStack } from "@chakra-ui/react";
import React, { FC, useContext } from "react";
// import { RiNotificationLine } from "react-icons/ri";
import React, { FC } from "react";
import { RiNotificationLine } from "react-icons/ri";
import { NavLink, useLocation, useNavigate } from "react-router-dom";
import { nav } from "../Routes/Nav";
import logo from '../assets/logo.svg';
import { AccordionItem, AccordionItemContent, AccordionItemTrigger, AccordionRoot } from "../components/ui/accordion";
import logo from "../assets/logo.svg";
import {
AccordionItem,
AccordionItemContent,
AccordionItemTrigger,
AccordionRoot,
} from "../components/ui/accordion";
import { Avatar } from "../components/ui/avatar";
import { LuLogOut } from "react-icons/lu";
import { logout } from "../Redux/Service/authSlice";
import { useDispatch } from "react-redux";
import GlobalStateContext from "../Contexts/GlobalStateContext";
import { useLogOutMutation } from "../Redux/Service/apiSlice";
import ProgressBar from "../components/ProgressBar/ProgressBar";
import { useGetProfileQuery } from "../Redux/Service/profile.password";
const PROFILEIMGURL = import.meta.env.VITE_IMG_PROFILE
import { getTitle } from "../Constants/Constants";
const DefaultLayout: FC<{ children: React.ReactNode }> = ({ children }) => {
const { data } = useGetProfileQuery()
const dispatch = useDispatch()
const navigate = useNavigate()
const location = useLocation()
const context = useContext(GlobalStateContext);
if (!context) {
throw new Error('App must be used within a GlobalStateProvider');
}
const { setIsAuthenticate, isBarLoading, userAccess } = context;
const [logOutAdmin] = useLogOutMutation()
const filteredNav = nav.filter(item =>
userAccess.includes('*') || !item.resourceTitle || userAccess.includes(item.resourceTitle)
);
// Logout function
const handleLogout = async () => {
try {
// ✅ Call mutation and wait for the response
const res = await logOutAdmin().unwrap();
console.log("Logout Success:", res);
// ✅ Clear local storage & update authentication state
dispatch(logout());
localStorage.removeItem("token");
setIsAuthenticate(false);
// ✅ Redirect to login page
navigate("/login");
} catch (error) {
console.error("Logout Failed:", error);
}
};
const navigate = useNavigate();
const location = useLocation();
const headerTitle = getTitle(location?.pathname);
console.log(location);
return (
<VStack gap={0} w="100%" h="100vh" bg="#F2F2F2">
<ProgressBar isLoading={isBarLoading} />
<HStack overflow={'hidden'} position={'relative'} bg="#F2F2F2" backgroundPosition="center" backgroundRepeat="repeat" backgroundSize="cover" gap={0} w="100%" h="calc(100% - 4px)" p={0}>
<VStack pt={0} zIndex={1} gap={0} rounded={'lg'} h="100%" w="15%" overflow={'auto'} >
<HStack w={'100%'} p={3} h={'7%'} justifyContent={'center'}>
<Image w={55} src={logo} />
</HStack>
<VStack w={'100%'} p={2} pt={0}>
{filteredNav?.map(({ title, path, Icon, type, children, initPath }, index) => type === 'single' ?
<NavLink className="link" key={index} to={path || ''} style={{ cursor: 'pointer', borderRadius: '8px', padding: '6px', width: '100%', display: 'flex', alignItems: 'center', gap: 6, border: '1px solid #ffffff', backgroundColor: '#fff', color: '#000', boxShadow: 'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px' }} ><Icon style={{ fontSize: '20px' }} /> <Text fontSize={'xs'} w={'100%'}>{title}</Text></NavLink> :
<AccordionRoot border={location?.pathname.startsWith(initPath ?? path) ? "1px solid #02A0A0" : '1px'} key={index} bg={'#fff'} rounded={'lg'} collapsible>
<AccordionItem rounded={'lg'} bg={'#fff'} boxShadow={'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'} borderBottom={'none'} p={0} key={index} value={title}>
<AccordionItemTrigger className="Oxygen" color={'#fff'} onClick={() => navigate(path || '')} gap={0} style={{ cursor: 'pointer', borderRadius: '8px', padding: '5px', width: '100%', display: 'flex', alignItems: 'center', border: '1px solid #ffffff', backgroundColor: '#fff', color: '#000', fontSize: '14px', }}> <Text fontSize={'xs'} gap={1} display={'flex'} alignItems={'center'} ><Icon style={{ fontSize: '20px' }} />{title}</Text></AccordionItemTrigger>
{children?.map(({ title, path, Icon }, index) => <AccordionItemContent className={`linkChild Oxygen ${location?.pathname === path && 'activeChild'}`} key={index} onClick={() => navigate(path)} style={{ marginTop: 6, cursor: 'pointer', borderRadius: '8px', padding: '6px', width: '100%', display: 'flex', alignItems: 'center', gap: 6, border: '1px solid #ffffff', backgroundColor: '#fff', color: '#919198' }} ><Icon style={{ fontSize: '20px' }} /> <Text fontSize={'xs'} w={'100%'}>{title}</Text></AccordionItemContent>)}
<HStack
position={"relative"}
bg="#F2F2F2"
backgroundPosition="center"
backgroundRepeat="repeat"
backgroundSize="cover"
gap={0}
pt={2}
w="100%"
h="100vh"
>
<VStack zIndex={1} gap={0} rounded={"lg"} h="100%" w="15%">
<HStack w={"100%"} p={3} h={"6.5%"} justifyContent={"center"}>
<Image w={55} src={logo} />
</HStack>
<VStack w={"100%"} p={3}>
{nav?.map(({ title, path, Icon, type, children, initPath }, index) =>
type === "single" ? (
<NavLink
className="link"
key={index}
to={path}
style={{
cursor: "pointer",
borderRadius: "8px",
padding: "6px",
width: "100%",
display: "flex",
alignItems: "center",
gap: 6,
border: "1px solid #ffffff",
backgroundColor: "#fff",
color: "#000",
boxShadow: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px",
}}
>
<Icon
style={{
fontSize: "20px",
backgroundColor: "#fff",
width: 28,
color: location?.pathname === path ? "#02A0A0" : "#000",
padding: 2,
borderRadius: "50%",
}}
/>{" "}
<Text fontSize={"xs"} w={"100%"}>
{title}
</Text>
</NavLink>
) : (
<AccordionRoot bg={"#fff"} rounded={"lg"} collapsible>
<AccordionItem
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
rounded={"lg"}
borderBottom={"none"}
p={0}
key={index}
value={title}
>
<AccordionItemTrigger
className={`link ${location?.pathname.startsWith(initPath ?? "") && "active"}`}
color={"#fff"}
onClick={() => navigate(path)}
gap={0}
style={{
cursor: "pointer",
borderRadius: "8px",
padding: "5px",
width: "100%",
display: "flex",
alignItems: "center",
border: "1px solid #ffffff",
backgroundColor: "#fff",
color: "#000",
fontSize: "14px",
fontWeight: "normal",
}}
>
{" "}
<Text
fontSize={"xs"}
gap={1}
display={"flex"}
alignItems={"center"}
>
<Icon
style={{
fontSize: "20px",
backgroundColor: "#fff",
width: 23,
color: location?.pathname.startsWith(initPath ?? "")
? "#02A0A0"
: "#000",
padding: 2,
borderRadius: "50%",
}}
/>
{title}
</Text>
</AccordionItemTrigger>
{children?.map(({ title, path, Icon }, index) => (
<AccordionItemContent
className={`linkChild ${location?.pathname === path && "activeChild"}`}
key={index}
onClick={() => navigate(path)}
style={{
marginTop: 6,
cursor: "pointer",
borderRadius: "8px",
padding: "6px",
width: "100%",
display: "flex",
alignItems: "center",
gap: 6,
border: "1px solid #ffffff",
backgroundColor: "#fff",
color: "#000",
}}
>
<Icon style={{ fontSize: "16px" }} />{" "}
<Text fontSize={"xs"} w={"100%"}>
{title}
</Text>
</AccordionItemContent>
))}
</AccordionItem>
</AccordionRoot>)}
</VStack>
<VStack w={'100%'} p={3} pt={0}>
<HStack onClick={handleLogout} className="link" style={{ cursor: 'pointer', borderRadius: '8px', padding: '6px', width: '100%', display: 'flex', alignItems: 'center', gap: 6, border: '1px solid #ffffff', backgroundColor: '#fff', color: '#000', boxShadow: 'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px' }} ><LuLogOut style={{ fontSize: '20px' }} /> <Text fontSize={'xs'} w={'100%'}>Logout</Text></HStack>
</VStack>
</AccordionRoot>
)
)}
</VStack>
<VStack gap={0} h="100%" w="85%" >
<HStack h={'11%'} w={'100%'} justifyContent={'flex-end'} pe={3} gap={6}>
{/* <NavLink to={'/manage-notification'}><RiNotificationLine color="#013e3e" cursor={'pointer'} style={{ fontSize: '22px' }} /></NavLink> */}
<HStack cursor={'pointer'} onClick={() => navigate('/profile')} >
<Avatar size={'sm'} src={`${PROFILEIMGURL}${data?.data.profile_photo}`} />
<VStack color={'#013e3e'} gap={0} alignItems={'flex-start'}>
<Text fontSize={'sm'} fontWeight={'bold'}>{data?.data?.first_name ? `${data?.data?.first_name.charAt(0).toUpperCase()}${data?.data.first_name.slice(1)}` : ''}</Text>
<Text fontSize={'xs'} >{data?.data?.phone_number ? data?.data?.phone_number : ''}</Text>
</VStack>
<VStack overflowY="hidden" gap={0} h="100%" w="85%">
<HStack
h={"6.5%"}
w={"100%"}
justifyContent={"space-between"}
alignItems={"flex-end"}
pe={3}
gap={6}
p={4}
>
<Text
mb={1}
fontSize={"sm"}
ms={1}
fontWeight={600}
color={"#013e3e"}
>
{headerTitle}
</Text>
<HStack
// bg={"#fff"}
h={"100%"}
justifyContent={"center"}
p={2}
rounded={"md"}
// boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
>
<RiNotificationLine
color="#013e3e"
cursor={"pointer"}
style={{ fontSize: "22px" }}
/>
<HStack cursor={"pointer"} onClick={() => navigate("/profile")}>
<Avatar
size={"sm"}
src="https://i.pinimg.com/736x/d6/cd/0f/d6cd0ffd4634b0763d3958a7325ce26e.jpg"
/>
<VStack color={"#013e3e"} gap={0} alignItems={"flex-start"}>
<Text fontSize={"sm"} fontWeight={"bold"}>
Ritesh Pandey
</Text>
<Text fontSize={"xs"}>ritesh.pandey@wdimails.com</Text>
</VStack>
</HStack>
</HStack>
{children}
</VStack>
</HStack>
</VStack>
</HStack>
{children}
</VStack>
</HStack>
);
};

6
src/Pages/CMS/CMS.tsx Normal file
View File

@@ -0,0 +1,6 @@
const CMS = () => {
return (
<div>CMS</div>
)
}
export default CMS

View File

@@ -1,68 +1,61 @@
import {
Box,
HStack,
// Image, Input, Stack,
Text
} from "@chakra-ui/react";
// import React, { useState, useEffect } from "react";
import { Box, HStack, Image, Input, Stack, Text } from "@chakra-ui/react";
import React, { useState, useEffect } from "react";
import { Button } from "../../components/ui/button";
// import { IoAddSharp } from "react-icons/io5";
// import delateIcon from "../../assets/deleteIcon.png";
// import { FaClockRotateLeft } from "react-icons/fa6";
import { Link } from "react-router-dom";
import { AgencyList } from "../../Redux/Service/dashBoard";
import { IoAddSharp } from "react-icons/io5";
import delateIcon from "../../assets/deleteIcon.png";
import { FaClockRotateLeft } from "react-icons/fa6";
// interface Todo {
// id: number;
// text: string;
// completed: boolean;
// timestamp: string;
// }
interface Todo {
id: number;
text: string;
completed: boolean;
timestamp: string;
}
const AgencyName = ({ agencyList }: { agencyList: AgencyList }) => {
// const [todos, setTodos] = useState<Todo[]>([]);
// const [input, setInput] = useState<string>("");
const AgencyName: React.FC = () => {
const [todos, setTodos] = useState<Todo[]>([]);
const [input, setInput] = useState<string>("");
const getCurrentTime = () => {
const now = new Date();
return now.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
};
// const getCurrentTime = () => {
// const now = new Date();
// return now.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
// };
// const addTodo = () => {
// if (input.trim() === "") return;
// setTodos([...todos, { id: Date.now(), text: input, completed: false, timestamp: getCurrentTime() }]);
// setInput("");
// };
const addTodo = () => {
if (input.trim() === "") return;
setTodos([...todos, { id: Date.now(), text: input, completed: false, timestamp: getCurrentTime() }]);
setInput("");
};
// Delete a task
// const deleteTodo = (id: number) => {
// setTodos(todos.filter((todo) => todo.id !== id));
// };
const deleteTodo = (id: number) => {
setTodos(todos.filter((todo) => todo.id !== id));
};
// useEffect(() => {
// const savedTodos = localStorage.getItem("todos");
// if (savedTodos) {
// setTodos(JSON.parse(savedTodos));
// }
// }, []); // Runs only on mount
useEffect(() => {
const savedTodos = localStorage.getItem("todos");
if (savedTodos) {
setTodos(JSON.parse(savedTodos));
}
}, []); // Runs only on mount
// // 🔹 Save todos to localStorage whenever they change
// useEffect(() => {
// if (todos.length > 0) {
// localStorage.setItem("todos", JSON.stringify(todos));
// }
// }, [todos]); // Runs when `todos` changes
// 🔹 Save todos to localStorage whenever they change
useEffect(() => {
if (todos.length > 0) {
localStorage.setItem("todos", JSON.stringify(todos));
}
}, [todos]); // Runs when `todos` changes
return (
<Box p={"10px"}>
<HStack justifyContent={"space-between"} mb={5}>
<Text fontSize={"xs"} fontWeight={500}>
Agency List
Add Agency Name
</Text>
{/* <Button
<Button
bg={"#fff"}
color={"#222222CC"}
px={3}
@@ -71,18 +64,9 @@ const AgencyName = ({ agencyList }: { agencyList: AgencyList }) => {
onClick={addTodo}
>
<IoAddSharp /> Add
</Button> */}
<Button
bg={"#fff"}
color={"#222222CC"}
px={3}
fontSize={"12px"}
h={"28px"}
>
<Link to="/master-module/agency-master">View ALL</Link>
</Button>
</HStack>
{/* <Input
<Input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
@@ -92,14 +76,14 @@ const AgencyName = ({ agencyList }: { agencyList: AgencyList }) => {
w={"100%"}
p={2}
mb={4}
/> */}
{agencyList?.data.map((todo) => (
/>
{todos.map((todo) => (
<HStack key={todo.id} backgroundColor={"#fff"} rounded={5} mb={3} p={4} justifyContent={'space-between'} alignItems={'inherit'}>
<Text fontSize={'sm'} color={'#222222bd'} fontWeight={400}>{todo.name}</Text>
{/* <Stack display={'flex'} alignItems={'end'} w={'130px'}>
<Text fontSize={'sm'} color={'#222222bd'} fontWeight={400}>{todo.text}</Text>
<Stack display={'flex'} alignItems={'end'} w={'130px'}>
<Box display={'flex'} alignItems={'center'} gap={2}>
<FaClockRotateLeft fontSize={'10px'} style={{ fontSize: '13px', color: '#222222bd' }} />
<Text fontSize={"xs"} color={"#222222bd"}>{todo.timestamp}</Text>
<FaClockRotateLeft fontSize={'10px'} style={{fontSize:'13px',color:'#222222bd'}} />
<Text fontSize={"xs"} color={"#222222bd"}>{todo.timestamp}</Text>
</Box>
<Box
onClick={() => deleteTodo(todo.id)}
@@ -109,7 +93,7 @@ const AgencyName = ({ agencyList }: { agencyList: AgencyList }) => {
>
<Image w={"16px"} src={delateIcon} />
</Box>
</Stack> */}
</Stack>
</HStack>
))}
</Box>

View File

@@ -1,214 +1,11 @@
import {
Box,
createListCollection,
Heading,
HStack,
Status,
Tabs,
Text,
} from "@chakra-ui/react";
import BarChart from "../../components/Charts/BarChart";
import CircularApp from "../../components/Charts/CircularProgress";
import SemiDoughnutChart from "../../components/Charts/SemiDoughnutChart";
import MainFrame from "../../components/MainFrame";
import {
AccordionItem,
AccordionItemContent,
AccordionItemTrigger,
AccordionRoot,
} from "../../components/ui/accordion";
import { Button } from "../../components/ui/button";
import {
SelectContent,
SelectItem,
SelectRoot,
SelectTrigger,
SelectValueText
} from "../../components/ui/select";
import AgencyName from "./AgencyName";
import { useGetAgencyListQuery, useGetFaqListQuery, useGetNewUserQuery, useGetPastUserQuery, useGetTotalUserQuery } from "../../Redux/Service/dashBoard";
import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import MainFrame from "../../components/MainFrame"
const Dashboard = () => {
const { data: totalUsers } = useGetTotalUserQuery()
const { data: pastUsers } = useGetPastUserQuery()
const { data: newUsers } = useGetNewUserQuery()
const {data: agencyList} = useGetAgencyListQuery()
const { data: faqList } = useGetFaqListQuery()
const [activeTab, setActiveTab] = useState("tab-1");
const [totalUser, setTotalUser] = useState<any>(null);
console.log("data", totalUser)
useEffect(() => {
if (activeTab === "tab-1") {
setTotalUser( pastUsers?.data)
} else if (activeTab === "tab-2") {
setTotalUser(totalUsers?.data)
} else if (activeTab === "tab-3") {
setTotalUser(newUsers?.data)
}
}, [totalUsers?.data, pastUsers?.data, newUsers?.data, activeTab]);
const frameworks = createListCollection({
items: [
{ label: "Today", value: "Today" },
{ label: "Week", value: "Week" },
{ label: "Month", value: "Month" },
{ label: "Year", value: "Year" },
],
});
// const accItems = [
// {
// value: "1",
// title: "How to create new account?",
// text: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since. Lorem Ipsum has been the industry's standard dummy text ever since.",
// },
// {
// value: "2",
// title: "How to create new account?",
// text: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since. Lorem Ipsum has been the industry's standard dummy text ever since.",
// },
// {
// value: "3",
// title: "How to create new account?",
// text: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since. Lorem Ipsum has been the industry's standard dummy text ever since.",
// },
// {
// value: "4",
// title: "How to create new account?",
// text: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since. Lorem Ipsum has been the industry's standard dummy text ever since.",
// },
// ];
return (
<MainFrame>
<Box display={"flex"} p={"20px"} pe={'20px'} gap={5}>
<Box rounded={'lg'} w={"30%"} boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}>
<Heading fontSize={"sm"} p={2}>
Total Users : {totalUsers?.data?.totalUserCount ?? 0}
</Heading>
<Tabs.Root
size={"sm"}
w={"80%"}
m={"auto"}
variant="enclosed"
fitted
defaultValue={"tab-1"}
value={activeTab}
onValueChange={(details) => setActiveTab(details.value)}
mb={6}
>
<Tabs.List>
<Tabs.Trigger fontSize={"xs"} value="tab-1">
Past 24 hrs
</Tabs.Trigger>
<Tabs.Trigger fontSize={"xs"} value="tab-2">
Total Users
</Tabs.Trigger>
<Tabs.Trigger fontSize={"xs"} value="tab-3">
New Signups
</Tabs.Trigger>
</Tabs.List>
</Tabs.Root>
<Box>
{totalUser && <SemiDoughnutChart totalUser={totalUser} />}
</Box>
<Box
w={"80%"}
m={"auto"}
display={"flex"}
justifyContent={"space-between"}
mt={8}
>
<Status.Root colorPalette="blue">
<Status.Indicator />
Recruiter <Text fontWeight={500}>{totalUser?.past24hourRecruiterCount ?? totalUser?.totalRecruiterCount ?? totalUser?.newRecuiterCount }</Text>
</Status.Root>
<Status.Root colorPalette="blue">
<Status.Indicator />
Customer <Text fontWeight={500}>{totalUser?.past24hourCustomercount ?? totalUser?.totalCustomerCount ?? totalUser?.newCustomerCount}</Text>
</Status.Root>
</Box>
</Box>
<Box
p={"20px"}
w={"49%"}
rounded={'lg'}
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
>
<HStack alignItems={"center"} mb={4}>
<Text fontSize={"sm"}>Item approvals in</Text>
<SelectRoot collection={frameworks} size="xs" width="200px">
<SelectTrigger>
<SelectValueText p={2} placeholder="Select movie" />
</SelectTrigger>
<SelectContent p={2}>
{frameworks.items.map((movie) => (
<SelectItem item={movie} key={movie.value}>
{movie.label}
</SelectItem>
))}
</SelectContent>
</SelectRoot>
</HStack>
<BarChart />
</Box>
<Box
w={"20%"}
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
p={'10px'}
rounded={'lg'}
>
<Text fontSize={"sm"} fontWeight={500} pt={3}>Number Of Groups created</Text>
<CircularApp />
</Box>
</Box>
<Box p={"20px"} pt={0} display={"flex"} gap={5}>
<Box w={"50%"} rounded={'lg'} bg={"#f2f2f2"} h={'100%'} p={"10px"} overflowY={'scroll'} height={'292px'}>
<HStack justifyContent={"space-between"} mb={5}>
<Text fontSize={"xs"} fontWeight={500}>Faqs</Text>
<Button
bg={"#fff"}
color={"#222222CC"}
px={3}
fontSize={"12px"}
h={"28px"}
>
<Link to="/manage-cms/faq">View ALL</Link>
</Button>
</HStack>
<AccordionRoot collapsible defaultValue={["b"]}>
{faqList?.data.map((item) => (
<AccordionItem
boxShadow={'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'}
key={item.id}
value={item.faqs_xid.toString()}
bg={"#fff"}
mb={2}
p={"12px"}
rounded={5}
borderBottom={0}
>
<AccordionItemTrigger fontSize={"sm"} >
{item.question}
</AccordionItemTrigger>
<AccordionItemContent fontSize={"xs"} color={'#222222CC'} pt={2}>
{item.answer}
</AccordionItemContent>
</AccordionItem>
))}
</AccordionRoot>
</Box>
<Box w={"50%"} rounded={'lg'} bg={"#f2f2f2"} alignItems={'flex-start'} overflowY={'scroll'} height={'292px'}>
{agencyList && <AgencyName agencyList={agencyList}/>}
</Box>
</Box>
</MainFrame>
);
};
)
}
export default Dashboard;
export default Dashboard

View File

@@ -1,65 +0,0 @@
import { Field, Input, Stack, Text } from "@chakra-ui/react";
import { Button } from "../components/ui/button";
import {
DialogBody,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../components/ui/dialog";
function ForgetPassword() {
return (
<DialogRoot placement="center">
<DialogTrigger asChild>
<Text w={"100%"} textAlign={"end"} mt={2} cursor={"pointer"}>
Forgot password?
</Text>
</DialogTrigger>
<DialogContent
bg={"#fff"}
w={{ base: "90%", md: "400px" }}
p={2}
bgSize={"md"}
>
<DialogHeader bg="white" pt={3} pb={2}>
<DialogTitle
alignSelf="center"
color="black"
fontSize="18px"
textAlign={"center"}
>
Forgot Password
</DialogTitle>
</DialogHeader>
<DialogBody bg="white" pt={5}>
<Stack p={2}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Please Enter Email Address
</Field.Label>
<Input
color="black"
p={2}
fontSize="sm"
type="text"
border="1px solid grey"
size={"sm"}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" mt={2} p={2}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Reset Password
</Button>
</DialogFooter>
</DialogContent>
</DialogRoot>
);
}
export default ForgetPassword;

View File

@@ -1,171 +0,0 @@
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) => {
const username = import.meta.env.VITE_USER_NAME || ""; // Replace with actual username
const password = import.meta.env.VITE_PASSWORD || ""; // Replace with actual password
const basicAuth = `${username}:${password}`; // Encode to Base64
setIsLoading(true);
try {
const res = await axios.post(
`${import.meta.env.VITE_API_URL}/send-otp`,
{
mobile_number: Number(data.mobileNumber),
},
{
headers: {
Authorization: `Basic ${basicAuth}`,
"Content-Type": "application/json",
},
}
);
if (res.status === 200) {
navigate(`/forgot-password/verify?phone=${data.mobileNumber}`)
} else {
// alert(res.data.message || "Something went wrong");
toaster.create({
// title: error?.response?.data?.message,
title: res.data.message || "Something went wrong",
type: "error",
})
setIsLoading(false);
}
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

@@ -1,101 +1,48 @@
import {
Box,
Center,
HStack,
Image,
Input,
Text,
VStack,
} from "@chakra-ui/react";
import axios from "axios";
import { Center, HStack, Image, Input, Text, VStack } from "@chakra-ui/react";
import { useContext, useState } from "react";
import { useForm } from "react-hook-form";
import { useDispatch } from "react-redux";
import GlobalStateContext from "../Contexts/GlobalStateContext";
import { setToken } from "../Redux/Service/authSlice";
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 { PasswordInput } from "../components/ui/password-input";
import { Link, useNavigate } from "react-router-dom";
// import ForgetPassword from "./ForgetPassword";
import { Toaster, toaster } from "../components/ui/toaster";
import { LuUser } from "react-icons/lu";
interface FormValues {
mobileNumber: number;
password: string;
}
const Login = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const [isLoading, setIsLoading] = useState<boolean>(false);
const context = useContext(GlobalStateContext);
if (!context) {
throw new Error("App must be used within a GlobalStateProvider");
}
const { setIsAuthenticate, setUserAccess } = context;
const { setIsAuthenticate } = context;
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormValues>();
const onSubmit = handleSubmit(async (data) => {
const onSubmit = handleSubmit((data) => {
setIsLoading(true);
const username = import.meta.env.VITE_USER_NAME || "";
const password = import.meta.env.VITE_PASSWORD || "";
const basicAuth = `${username}:${password}`;
try {
const res = await axios.post(
`${import.meta.env.VITE_API_URL}/login`,
{
mobile_number: Number(data.mobileNumber),
password: data.password,
},
{
headers: {
Authorization: `Basic ${basicAuth}`,
"Content-Type": "application/json",
},
}
);
const loginData = res.data?.data;
const { principal_type_xid, role_permission } = loginData;
const isAdmin = principal_type_xid === 1;
const allowedTitles = isAdmin
? ['*']
: role_permission?.get_resource_action_link
?.filter((link: unknown) => (link as any).is_active)
.map((link: unknown) => (link as any).app_resource.app_resource_title) ?? [];
setIsAuthenticate(true);
setUserAccess(allowedTitles);
dispatch(setToken(String(loginData["access-token"])));
sessionStorage.setItem('userAccess', JSON.stringify(allowedTitles));
navigate("/dashboard");
setIsLoading(false);
} catch (error: any) {
console.log('error', error?.response?.data?.message);
if (data?.mobileNumber === 1234567890) {
setTimeout(() => {
setIsAuthenticate(true);
setIsLoading(false);
}, 3000); // 3-second delay
} else {
toaster.create({
title: "Error",
description: error?.response?.data?.message || "Login failed",
title: `Invalid Credentials`,
type: "error",
});
setIsLoading(false);
}
});
// console.log("User Access in Context:", userAccess);
return (
<VStack appearance={'light'} w={"100%"} h={"100vh"} bg={"#ffffff"}>
<VStack w={"100%"} h={"100vh"} bg={"#ffffff"}>
<HStack
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
w={"100%"}
@@ -117,14 +64,14 @@ const Login = () => {
<Image w={250} src={logo} />
</Center>
<Box
<Center
as={"form"}
onSubmit={onSubmit}
p={{ base: 4, md: 16 }}
w={{ base: "100%", md: "50%" }}
h={"100%"}
>
<VStack gap={2} w={"100%"}>
<VStack gap={2} w={"100%"} alignItems={"flex-start"}>
<Text
w={"100%"}
textAlign={"center"}
@@ -135,39 +82,24 @@ const Login = () => {
LOGIN
</Text>
<Box mt={6} gap={4} w={"full"}>
<VStack 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}
{...register("mobileNumber", {
required: "Mobile Number address is required",
})}
placeholder="Mobile Number Address"
/>
{/* <Text as={'span'} w={'100%'} fontSize={'xs'} fontWeight={'normal'} color={'#686677'}>Forget password</Text> */}
</Field>
<Field
color={"#313039"}
label={"Enter password."}
w={"100%"}
invalid={!!errors.password}
errorText={errors.password?.message}
mb={2}
>
<PasswordInput
ps={3}
{...register("password", { required: "Pasword is required" })}
placeholder="Enter password"
/>
{/* <Text as={'span'} w={'100%'} fontSize={'xs'} fontWeight={'normal'} color={'#686677'}>Forget password</Text> */}
<Text cursor="pointer" as={'span'} w={'100%'} fontSize={'xs'} fontWeight={'normal'} color={'#686677'}>Forget password</Text>
</Field>
<Button
loading={isLoading}
@@ -179,21 +111,13 @@ const Login = () => {
color={"#ffffff"}
type="submit"
>
Login
Send OTP
</Button>
{/* <ForgetPassword /> */}
<Box textAlign={"center"} mt={4}>
<Link
to={'/forgot-password'}
style={{ color: "black", fontSize: "16px" }}
>
Forgot Password
</Link>
</Box>
</Box>
<Text>Forgot password</Text>
</VStack>
</VStack>
</Box>
</Center>
<Toaster />
</HStack>
</VStack>

View File

@@ -1,132 +1,11 @@
// import { Badge, HStack, Text, VStack } from "@chakra-ui/react";
// import MainFrame from "../../../components/MainFrame"
// import { useGetAboutUsQuery } from "../../../Redux/Service/manage.aboutus.service";
// import { Spinner } from "../../../components/Sipnner/Spinner";
// import GlobalStateContext from "../../../Contexts/GlobalStateContext";
// import { useContext, useEffect } from "react";
// import AboutUsAddModel from "./AboutUsAddModel";
// const AboutUs = () => {
// const { data, isLoading, isFetching } = useGetAboutUsQuery();
// // const content = data?.data
// console.log('====================================');
// console.log(data);
// console.log('====================================');
// const context = useContext(GlobalStateContext);
// if (!context) throw new Error('App must be used within a GlobalStateProvider');
// const { setIsBarLoading } = context;
// useEffect(() => {
// setIsBarLoading(isFetching)
// }, [data])
// return (
// <MainFrame transperant={true}>
// <VStack gap={4} pb={4} pt={0}>
// {isLoading || isFetching ?
// <Spinner /> : data?.data?.map(({ id, content, about_language }) => <VStack bg={'#fff'}
// boxShadow={'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'} rounded={'lg'} p={3} key={id}>
// <HStack
// w={"100%"}
// justifyContent={"space-between"}
// py={0}
// px={0}
// >
// <Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
// About Us <Badge variant={'surface'} colorPalette="cyan" ms={2} size={'sm'} fontSize={'xs'} px={2}>🎓 {about_language?.language_name}</Badge>
// </Text>
// {/* <AboutUsAddModel /> */}
// <AboutUsAddModel/>
// </HStack>
// <Text
// as="p"
// fontSize="sm"
// fontWeight={400}
// color="#1D1D1D"
// >
// {content}
// </Text>
// </VStack>)}
// </VStack>
// </MainFrame>
// )
// }
// export default AboutUs
import { Badge, HStack, Stack, Text, VStack } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame";
import { useGetAboutUsQuery } from "../../../Redux/Service/manage.aboutus.service";
import { Spinner } from "../../../components/Sipnner/Spinner";
import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import { useContext, useEffect } from "react";
import AboutUsAddModel from "./AboutUsAddModel";
import MainFrame from '../../../components/MainFrame'
const AboutUs = () => {
const { data, isLoading, isFetching } = useGetAboutUsQuery();
console.log("Fetched About Us Data:", data);
const context = useContext(GlobalStateContext);
if (!context) throw new Error("App must be used within a GlobalStateProvider");
const { setIsBarLoading } = context;
useEffect(() => {
setIsBarLoading(isFetching);
}, [isFetching, setIsBarLoading]);
return (
<MainFrame transperant={true}>
<VStack gap={4} pb={4} pt={0}>
<Stack bg={"#fff"} w={"100%"} mt={2} p={4} borderRadius={4}><Text color={"black"} textAlign={"left"} fontWeight={"600"} > About Us
</Text></Stack>
{isLoading || isFetching ? (
<Spinner />
) : (
data?.data?.map(({ id, content, about_language }) => (
<VStack
bg={"#fff"}
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
rounded={"lg"}
p={3}
key={id}
>
<HStack w={"100%"} justifyContent={"space-between"} py={0} px={0}>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
<Badge
variant={"surface"}
colorPalette="cyan"
ms={2}
size={"sm"}
fontSize={"xs"}
px={2}
>
🎓 {about_language?.language_name}
</Badge>
</Text>
{/* Pass Data to AboutUsAddModel */}
<AboutUsAddModel aboutUsData={{ id, content, about_language }} />
</HStack>
<Text as="p" fontSize="sm" fontWeight={400} color="#1D1D1D">
{/* {content} */}
<div dangerouslySetInnerHTML={{ __html: content }} />
</Text>
</VStack>
))
)}
</VStack>
<MainFrame>
</MainFrame>
);
};
)
}
export default AboutUs;
export default AboutUs

View File

@@ -1,152 +1,53 @@
import { FaRegEdit } from "react-icons/fa";
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import { Field, Stack, Text } from "@chakra-ui/react";
import { Button } from "../../../components/ui/button";
import ReactQuill from "react-quill";
import "react-quill/dist/quill.snow.css"; // Import the styles
import { useState } from "react";
import { useUpdateAboutUsMutation } from "../../../Redux/Service/manage.aboutus.service";
import { useForm, Controller } from "react-hook-form"; // Import React Hook Form
import { toaster, Toaster } from "../../../components/ui/toaster";
function AboutUsAddModel({ aboutUsData }: { aboutUsData: any }) {
const [isOpen, setIsOpen] = useState(false);
// RTK Query Mutation Hook
const [updateAboutUs, { isLoading }] = useUpdateAboutUsMutation();
// React Hook Form
const {
control,
handleSubmit,
reset,
setValue,
} = useForm({
defaultValues: {
content: "",
languageCode: "",
},
});
// Function to handle edit click (pre-fill the editor)
const handleEditClick = (data: any) => {
setValue("content", data.content); // Pre-fill the content field
setValue("languageCode", data.about_language.language_code); // Pre-fill the language code
setIsOpen(true); // Open dialog
};
// Function to handle update submission
const onSubmit = async (formData: any) => {
if (!formData.content.trim()) return; // Prevent empty updates
try {
await updateAboutUs({
id: aboutUsData.id,
content: formData.content,
language_code: formData.languageCode,
}).unwrap();
setIsOpen(false); // Close dialog on success
reset(); // Reset the form
} catch (error: any) {
console.error("Update failed:", error);
toaster.create({
title: "Error",
description: `${error.data.message || "Failed to update"}`,
type: "error",
});
}
};
import { FaRegEdit } from "react-icons/fa"
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Field, Stack, Text, Textarea } from "@chakra-ui/react"
import { Button } from "../../../components/ui/button"
function AboutUsAddModel() {
return (
<>
<DialogRoot placement="center" open={isOpen}>
<DialogTrigger asChild>
<Button
bgColor="#EEEEEE"
pl={3}
pr={3}
size="xs"
color="#000"
onClick={() => handleEditClick(aboutUsData)} // Set content before opening modal
>
<FaRegEdit color="#000" style={{ height: "14px", width: "14px" }} />
<Text color="#000" mt={1}>Edit</Text>
<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>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={"auto"}
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Edit</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3} >
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">AboutUs</Field.Label>
<Textarea placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" pt={1.5} />
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogTrigger>
</DialogFooter>
<DialogContent bg="#fff" w={{ base: "90%", md: "1200px" }} height="auto" p={3}>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit About Us
</DialogTitle>
</DialogHeader>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
<DialogBody bg="white">
<Stack py={3} mb={8}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
About Us Content
</Field.Label>
{/* Use Controller to integrate ReactQuill with React Hook Form */}
<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"
// isLoading={isLoading}
disabled={isLoading}
onClick={handleSubmit(onSubmit)} // Use handleSubmit to trigger form submission
>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
</DialogRoot>
<Toaster />
</>
);
)
}
export default AboutUsAddModel;
export default AboutUsAddModel

View File

@@ -1,161 +1,56 @@
import { Button } from "../../../components/ui/button";
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import { Field, Input, Stack, Textarea } from "@chakra-ui/react";
import Edit from "../../../components/ActionIcons/Edit";
import { useUpdateFaqMutation } from "../../../Redux/Service/faqs.service";
import { useEffect, useState } from "react";
import { Toaster, toaster } from "../../../components/ui/toaster";
import { Button } from "../../../components/ui/button"
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Field, Grid, Input, Stack, Text, Textarea } from "@chakra-ui/react"
import { FaRegEdit } from "react-icons/fa";
function EditDetails() {
return (
interface RowData {
id: number;
principal_type_xid: number;
question: string;
answer: string;
<DialogRoot placement="center">
<DialogTrigger asChild>
<Button bg={"transparent"} size="sm">
<FaRegEdit style={{ cursor: "pointer", }} color="#000" />
</Button>
{/* <Button><FaRegEdit /></Button> */}
</DialogTrigger>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={"auto"}
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Edit Details</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3} >
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Questions</Field.Label>
<Input placeholder="Questions" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
<Field.Label color="black" pt={1} fontSize="12px">Answer</Field.Label>
<Textarea placeholder="Answer" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" pt={1.5} />
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
)
}
function EditDetails({ rowData, refetch }: {rowData: RowData, refetch: VoidFunction}) {
const [faqQuestion, setFaqQuestion] = useState(rowData?.question);
const [faqAnswer, setFaqAnswer] = useState(rowData?.answer);
const [isOpen, setIsOpen] = useState(false);
const [updateFaq, { isLoading }] = useUpdateFaqMutation()
// console.log('ROWDATA', rowData);
useEffect(() => {
if (rowData) {
setFaqQuestion(rowData.question);
setFaqAnswer(rowData.answer);
}
}, [rowData]);
const handleOpenModal = () => {
setIsOpen(true);
};
const handleSubmit = async () => {
if (!faqQuestion.trim() || !faqAnswer.trim()) {
toaster.create({
title: "Error",
description: "Input fields cannot be empty",
type: "error",
});
return;
}
const payload = {
id: rowData?.id,
question: faqQuestion,
answer: faqAnswer,
principal_type_xid: rowData?.principal_type_xid,
};
try {
const response = await updateFaq(payload).unwrap();
if (response?.status === "success") {
toaster.create({
title: "Success",
description: "FAQ updated successfully",
type: "success",
});
refetch()
setIsOpen(false);
} else {
toaster.create({
title: "Error",
description: "Failed to update FAQ",
type: "error",
});
}
} catch (error) {
console.error("Error updating template:", error);
// alert("Failed to update template");
toaster.create({
title: "Error",
description: "Something went wrong",
type: "error",
});
}
};
return (
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogTrigger asChild>
<Button bg="transparent" color={"black"} h={"18px"} onClick={handleOpenModal}><Edit /></Button>
</DialogTrigger>
<DialogContent
bg={"#fff"}
w={{ base: "90%", md: "400px" }}
height={"auto"}
p={3}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit Details (ID: {rowData?.id})
</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Question
</Field.Label>
<Input
placeholder="Question"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={faqQuestion}
onChange={(e) => setFaqQuestion(e.target.value)}
/>
<Field.Label color="black" pt={1} fontSize="12px">
Answer
</Field.Label>
<Textarea
placeholder="Answer"
bgColor="#EEEEEE"
color="black"
border="none"
p={2}
fontSize="12px"
height="auto"
pt={1.5}
value={faqAnswer}
onChange={(e) => setFaqAnswer(e.target.value)}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
<Toaster />
</DialogRoot>
);
}
export default EditDetails;
export default EditDetails

View File

@@ -1,206 +1,52 @@
import { Box, HStack, Image, Spinner, Text } from "@chakra-ui/react";
import { Box, Button, HStack, Image, Input, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame"
import EditDetails from "./EditDetails";
// import { InputGroup } from "../../../components/ui/input-group";
// import { LuSearch } from "react-icons/lu";
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 { Switch } from "../../../components/ui/switch";
import FaqAddModel from "./FaqAddModel";
import Delete from "../../../components/ActionIcons/Delete";
import { useEffect, useState } from "react";
import { FaqData, useDeleteFaqPostMutation, useFaqToggleMutation, useGetFaqQuery } from "../../../Redux/Service/faqs.service";
import SearchComponent from "../../../components/SearchComponent";
import NoData from "../../../components/NoData";
import { Toaster, toaster } from "../../../components/ui/toaster";
// table data
const tableHeadRow = [
"Sr. No",
'Category',
"Question",
"Answer",
"Action",
];
// const managepost: any[] = [
// ...Array.from({ length: 12 }, (_, i) => ({
// "Sr. No": i + 1,
// "Question": "Lorem Ipsum",
// "Answer": "Lorem Ipsum",
// "Action": (
// <HStack justifyContent="center">
// <Box>
// <Switch colorPalette={'teal'} size={"xs"} />
// </Box>
// {/* <EditDetails /> */}
// <EditDetails id={(i + 1).toString()} question="Lorem Ipsum" answer="Lorem Ipsum" />
// <AlertDailog
// AltertTiggerIcon={() => <Delete />}
// alertText="Delete Users"
// alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
// alertCaption="are you sure you want to delete ?"
// onConfirm={() => {
// console.log("User deleted:", i + 1);
// }}
// />
// </HStack>
// ),
// })),
// ];
const managepost: any[] = [
...Array.from({ length: 12 }, (_, i) => ({
"Sr. No": i + 1,
"Question": "Lorem Ipsum",
"Answer": "Lorem Ipsum",
"Action": (
<HStack justifyContent="center">
<Box>
<Switch colorPalette={'teal'} size={"xs"}/>
</Box>
<EditDetails />
<AlertDailog
AltertTiggerIcon={RiDeleteBin5Line}
alertText="Delete Users"
alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
alertCaption="are you sure you want to delete ?"
onConfirm={() => {
console.log("User deleted:", i + 1);
}}
/>
</HStack>
),
})),
];
const FAQ = () => {
const [currentPage, setCurrentPage] = useState(1);
const { data, refetch, isLoading, isFetching, isError } = useGetFaqQuery(currentPage)
const [localData, setLocalData] = useState<any[]>([]);
const [faqToggle] = useFaqToggleMutation()
const [deleteFaqPost] = useDeleteFaqPostMutation()
const [searchTerm, setSearchTerm] = useState("");
const [deleteModal, setDeleteModal] = useState(false)
const [selectedFaqId, setSelectedFaqId] = useState<number | null>(null);
console.log('DATA', data?.data.data);
useEffect(() => {
if (data) {
setLocalData(data?.data.data);
}
}, [data]);
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
const handleToggle = async (agencyId: number, currentStatus: string) => {
const newStatus = currentStatus === '1' ? '0' : '1';
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
)
);
try {
await faqToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
setTimeout(() => {
refetch();
}, 500);
} catch (error) {
console.error("Error updating privacy policy:", error);
toaster.create({
title: "Error",
description: "Someting went wrong.",
type: "error",
});
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
)
);
}
};
const handleDeleteFaq = async (faqId: number) => {
try {
const response = await deleteFaqPost({ id: faqId }).unwrap();
if (response?.status === "success") {
toaster.create({
title: "Success",
description: "FAQ deleted successfully",
type: "success",
});
refetch()
console.log("FAQ deleted successfully:", response);
}
// Optionally, refetch data or update state after deletion
} catch (error) {
console.error("Error deleting FAQ:", error);
toaster.create({
title: "Error",
description: "Something went wrong",
type: "error",
});
}
};
const filteredData = localData?.filter((agency) =>
agency.translations.some((translation: any) => {
const searchLower = searchTerm.toLowerCase();
const questionMatch = translation.question?.toLowerCase().includes(searchLower);
const answerMatch = translation.answer?.toLowerCase().includes(searchLower);
return questionMatch || answerMatch;
})
);
console.log("filteredData", filteredData);
const managepost = filteredData?.flatMap((agency: FaqData, index: number) =>
agency.translations.map((translation: any) => ({
'id': translation.id,
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
"Question": translation.question,
"Answer": translation.answer,
'Category': agency.principal_type_xid === 2 ? "Recruiter" : "Job Seeker",
"Action": (
<HStack justifyContent="center">
<EditDetails rowData={{ id: agency.id, question: translation.question, answer: translation.answer, principal_type_xid: agency.principal_type_xid }} refetch={refetch} />
<AlertDailog
isOpen={deleteModal}
AltertTiggerIcon={() => <Delete onClick={() => {
setSelectedFaqId(agency.id);
setDeleteModal(true)
}} />}
alertText="Delete FAQ"
alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
alertCaption="are you sure you want to delete ?"
onClose={() => setDeleteModal(false)}
onConfirm={() => {
// console.log("Deleting FAQ with ID:", selectedFaqId); // Correct ID
if (selectedFaqId) {
setDeleteModal(false);
handleDeleteFaq(selectedFaqId);
}
}}
/>
<Box>
<Switch
colorPalette={'teal'}
size={"xs"}
onChange={() => handleToggle(Number(agency.id), agency.is_active.toString())}
checked={Boolean(Number(agency.is_active))}
key={`switch-${agency.id}`}
/>
</Box>
</HStack>
),
})))
if (isFetching) {
return (
<HStack
w={"100%"}
justifyContent={"center"}
mb={4}
py={0}
px={3}
>
<Spinner color={'teal'} />
</HStack>
)
}
return (
<MainFrame>
<Box>
<HStack
@@ -211,37 +57,40 @@ const FAQ = () => {
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
FAQs
FAQs
</Text>
<HStack >
<SearchComponent
value={searchTerm}
onChange={setSearchTerm}
/>
<InputGroup
startElement={
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
}
color={"#000"}
>
<Input
p={3}
w={300}
bg={"#fff"}
colorPalette={"blue"}
_focus={{ border: "1px solid #02A0A0" }}
rounded={"md"}
size={"2xs"}
fontSize={"2sm"}
placeholder="Search..."
bgColor={'#EEEEEE'}
ps={8}
/>
</InputGroup>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
<FaqAddModel refetch={refetch} />
<FaqAddModel />
</HStack>
</HStack>
{isFetching && <Spinner />}
{!isLoading && !data?.data ? (
<NoData message={'No data found'} text={'Please add new data'} />
) : (<DataTable
sortableColumns={["Name"]}
<DataTable
sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow}
data={managepost}
paginationData={{
current_page: data?.data.current_page || 1,
last_page: data?.data.last_page || 1,
per_page: data?.data.per_page || 10,
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>)}
</Box>
<Toaster />
/>
</Box>
</MainFrame>
)
}

View File

@@ -1,174 +1,57 @@
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import { Box, Field, Input, Stack, Text, Textarea } from "@chakra-ui/react";
import { IoMdAdd } from "react-icons/io";
import { Button } from "../../../components/ui/button";
import { useState } from "react";
import { Toaster, toaster } from "../../../components/ui/toaster";
import { useCreateFaqPostMutation } from "../../../Redux/Service/faqs.service";
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Field, Input, Stack, Text, Textarea } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button"
function FaqAddModel({ refetch }: { refetch: VoidFunction }) {
const [faqQuestion, setFaqQuestion] = useState('');
const [faqAnswer, setFaqAnswer] = useState('');
const [userType, setUserType] = useState("");
const [isOpen, setIsOpen] = useState(false);
const [createFaqPost, { isLoading }] = useCreateFaqPostMutation()
function FaqAddModel() {
return (
const handleOpenModal = () => {
setIsOpen(true); // Open modal when clicking "Add"
};
<DialogRoot placement="center">
<DialogTrigger asChild>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Button px={5} size={"xs"} bg={"#02A0A0"}><IoMdAdd /> <Text>Add</Text></Button>
const handleSubmit = async () => {
if (userType === "" || isNaN(Number(userType))) {
toaster.create({
title: "Error",
description: "Please select a valid user type.",
type: "error",
});
return;
}
</DialogTrigger>
if (!faqQuestion.trim() || !faqAnswer.trim()) {
toaster.create({
title: "Error",
description: "Please fill in all required fields",
type: "error",
});
return;
}
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={"auto"}
const payload = {
principal_type_xid: Number(userType),
language_code: 'en',
question: faqQuestion,
answer: faqAnswer
};
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
</DialogHeader>
try {
const response = await createFaqPost(payload).unwrap();
if (response) {
toaster.create({
title: "Success",
description: "FAQ updated successfully",
type: "success",
});
refetch()
setIsOpen(false);
} else {
toaster.create({
title: "Error",
description: "Failed to update FAQ",
type: "error",
});
}
} catch (error) {
console.error("Error updating template:", error);
// alert("Failed to update template");
}
};
<DialogBody bg="white">
<Stack py={3} >
return (
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogTrigger asChild>
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
<IoMdAdd /> <Text>Add</Text>
</Button>
</DialogTrigger>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Questions</Field.Label>
<Input placeholder="Questions" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: "90%", md: "400px" }}
height={"auto"}
p={3} // Reduced padding
bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Add
</DialogTitle>
</DialogHeader>
<Field.Label color="black" pt={1} fontSize="12px">Answer</Field.Label>
<Textarea placeholder="Answer" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" pt={1.5} />
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Select User Type</Field.Label>
<Box bgColor="#EEEEEE" borderRadius="md" p={1} w={'100%'}>
<select
style={{
width: "100%",
background: "transparent",
color: "black",
border: "none",
fontSize: "12px",
height: "30px",
outline: "none",
}}
value={userType}
onChange={(e) => setUserType(e.target.value)}
>
<option value="" disabled>Select User Type</option>
<option value="2">Recruiter</option>
<option value="3">Jobseeker</option>
</select>
</Box>
</Field.Root>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Questions
</Field.Label>
<Input
placeholder="Questions"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
_focusVisible={{ outline: 'none' }}
size={'sm'}
value={faqQuestion}
onChange={(e) => setFaqQuestion(e.target.value)}
/>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
<Field.Label color="black" pt={1} fontSize="12px">
Answer
</Field.Label>
<Textarea
placeholder="Answer"
bgColor="#EEEEEE"
color="black"
border="none"
p={2}
fontSize="12px"
height="120px"
resize={'none'}
_focusVisible={{ outline: 'none' }}
value={faqAnswer}
onChange={(e) => setFaqAnswer(e.target.value)}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
<Toaster />
</DialogRoot>
);
)
}
export default FaqAddModel;
export default FaqAddModel

View File

@@ -0,0 +1,12 @@
import { Text } from '@chakra-ui/react'
import MainFrame from '../../../components/MainFrame'
const FreqAskQuestion = () => {
return (
<MainFrame>
<Text>hello</Text>
</MainFrame>
)
}
export default FreqAskQuestion

View File

@@ -1,82 +1,11 @@
import { Badge, HStack, Stack, Text, VStack } from "@chakra-ui/react";
import { useGetPrivacyPolicyQuery } from "../../../Redux/Service/privacy.policy.service";
import MainFrame from "../../../components/MainFrame";
import { Spinner } from "../../../components/Sipnner/Spinner";
import PrivacyPolicyAddModel from "./PrivacyPolicyAddModel";
import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import { useContext, useEffect } from "react";
import MainFrame from '../../../components/MainFrame'
const PrivacyPolicy = () => {
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");
const { setIsBarLoading } = context;
useEffect(() => {
setIsBarLoading(isFetching);
}, [data]);
console.log("Privacy Policy Data:", data?.data);
return (
<MainFrame transperant={true}>
<Stack bg={"#fff"} w={"100%"} p={4} borderRadius={4} mb={4}>
<Text color={"black"} textAlign={"left"} fontWeight={"600"}>
Privacy Policy
</Text>
</Stack>
<VStack gap={4} pb={4} pt={0}>
{isLoading || isFetching ? (
<Spinner />
) : (
data?.data?.map(({ id, content, privacy_language }) => (
<VStack
bg={"#fff"}
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
rounded={"lg"}
p={3}
key={id}
>
<HStack w={"100%"} justifyContent={"space-between"} py={0} px={0}>
<Text
as={"span"}
fontSize={"sm"}
fontWeight={500}
color={"#000"}
>
<Badge
variant={"surface"}
colorPalette="cyan"
size={"sm"}
fontSize={"xs"}
px={2}
>
🎓 {privacy_language?.language_name}
</Badge>
</Text>
<PrivacyPolicyAddModel
policyData={{ id, content, privacy_language }}
refetch={refetch}
/>
</HStack>
<Text
as="p"
fontSize="sm"
fontWeight={400}
color="#1D1D1D"
dangerouslySetInnerHTML={{ __html: content }}
/>
</VStack>
))
)}
</VStack>
<MainFrame>
</MainFrame>
);
};
)
}
export default PrivacyPolicy;
export default PrivacyPolicy

View File

@@ -1,153 +1,53 @@
import { FaRegEdit } from "react-icons/fa";
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogRoot,
DialogTrigger,
} from "../../../components/ui/dialog";
import { Box, 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";
import { FaRegEdit } from "react-icons/fa"
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Field, Input, Stack, Text, Textarea } from "@chakra-ui/react"
import { Button } from "../../../components/ui/button"
function PrivacyPolicyAddModel({ policyData, refetch }: { policyData: any, refetch: VoidFunction }) {
const [isOpen, setIsOpen] = useState(false);
const [updatePrivacyPolicy, { isLoading }] = useUpdatePrivacyPolicyMutation()
const {
control,
handleSubmit,
reset,
setValue,
} = useForm({
defaultValues: {
content: "",
languageCode: "",
},
});
function PrivacyPolicyAddModel() {
return (
console.log('POLICY', policyData);
<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>
const handleEditClick = (data: any) => {
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
};
</DialogTrigger>
const onSubmit = async (formData: any) => {
if (!formData.content.trim()) return; // Prevent empty updates
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={"auto"}
try {
await updatePrivacyPolicy({
id: policyData.id,
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);
}
};
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Edit</DialogTitle>
</DialogHeader>
return (
<DialogRoot placement="center" open={isOpen}>
<Box key={policyData.id}>
<DialogTrigger asChild>
<Button
bgColor={"#EEEEEE"}
pl={3} pr={3}
size={"xs"}
color={"#000"}
onClick={() => handleEditClick(policyData)}
>
{" "}
<FaRegEdit
color="#000"
style={{ height: "14px", width: "14px" }}
/>{" "}
<Text color={"#000"} mt={1}>
Edit
</Text>
</Button>
</DialogTrigger>
</Box>
<DialogBody bg="white">
<Stack py={3} >
<DialogContent
bg={"#fff"}
minW={'600px'}
// w={{ base: "90%", md: "400px" }}
height={"auto"}
p={3} // Reduced padding
bgSize={"md"}
>
{/* <DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit
</DialogTitle>
</DialogHeader> */}
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">PrivacyPolicy</Field.Label>
<Textarea placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" pt={1.5} />
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
PrivacyPolicy
</Field.Label>
{/* <Textarea
placeholder=""
bgColor="#EEEEEE"
color="black"
border="none"
p={2}
fontSize="12px"
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: "220px", width: "100%",marginBottom:'20px' }}
/>
)}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} mt={'4'} onClick={handleSubmit(onSubmit)} disabled={isLoading}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
</DialogRoot>
);
)
}
export default PrivacyPolicyAddModel;
export default PrivacyPolicyAddModel

View File

@@ -1,15 +0,0 @@
import { Box, Skeleton } from '@chakra-ui/react'
const PrivacyPolicySkeleton = () => {
return (
<Box px={3} pb={3} w="90%">
<Skeleton height="20px" mb="10px" width="90%" />
<Skeleton height="20px" mb="15px" width="90%" />
<Skeleton height="20px" mb="10px" width="90%" />
<Skeleton height="20px" mb="10px" width="80%" />
<Skeleton height="20px" width="60%" />
</Box>
)
}
export default PrivacyPolicySkeleton

View File

@@ -0,0 +1,11 @@
import MainFrame from '../../../components/MainFrame'
const TermsAndCondition = () => {
return (
<MainFrame>
</MainFrame>
)
}
export default TermsAndCondition

View File

@@ -1,67 +1,38 @@
import { Badge, HStack, Spinner, Stack, Text, VStack } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame";
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, isLoading, isFetching } = useGetTermsQuery();
console.log(data);
return (
<MainFrame transperant={true}>
<VStack gap={4} pb={4} pt={0}>
<Stack bg={"#fff"} w={"100%"} mt={2} p={4} borderRadius={4}>
<Text color={"black"} textAlign={"left"} fontWeight={"600"}>
Terms and Conditions
<MainFrame>
<Box>
<HStack
w={"100%"}
justifyContent={"space-between"}
mb={4}
py={0}
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
Terms And Conditions
</Text>
</Stack>
{isLoading || isFetching ? (
<Spinner />
) : (
data?.data?.map(({ id, content, terms_cond_language }) => (
<VStack
bg={"#fff"}
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
rounded={"lg"}
p={3}
key={id}
>
<HStack w={"100%"} justifyContent={"space-between"} py={0} px={0}>
<Text
as={"span"}
fontSize={"sm"}
fontWeight={500}
color={"#000"}
>
<Badge
variant={"surface"}
colorPalette="cyan"
ms={2}
size={"sm"}
fontSize={"xs"}
px={2}
>
🎓 {terms_cond_language?.language_name}
</Badge>
</Text>
{/* Pass Data to AboutUsAddModel */}
<TermsAndConditionsAddModel
termsData={{ id, content, terms_cond_language }}
refetch={refetch}
/>
</HStack>
<Text as="p" fontSize="sm" fontWeight={400} color="#1D1D1D">
{/* {content} */}
<div dangerouslySetInnerHTML={{ __html: content }} />
</Text>
</VStack>
))
)}
</VStack>
<HStack mr={5}>
<TermsAndConditionsAddModel />
</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?
</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>
);
};
export default TermsAndConditions;
)
}
export default TermsAndConditions

View File

@@ -1,150 +1,53 @@
import { FaRegEdit } from "react-icons/fa";
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
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";
import { FaRegEdit } from "react-icons/fa"
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Field, Stack, Text, Textarea } from "@chakra-ui/react"
import { Button } from "../../../components/ui/button"
function TermsAndConditionsAddModel({ termsData, refetch }: { termsData: any, refetch: VoidFunction }) {
const [isOpen, setIsOpen] = useState(false);
const [updateTerms, { isLoading }] = useUpdateTermsMutation()
const {
control,
handleSubmit,
reset,
setValue,
} = useForm({
defaultValues: {
content: "",
languageCode: "",
},
});
function TermsAndConditionsAddModel() {
return (
const handleEditClick = (data: any) => {
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
};
<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>
const onSubmit = async (formData: any) => {
if (!formData.content.trim()) return; // Prevent empty updates
</DialogTrigger>
try {
await updateTerms({
id: termsData.id,
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);
}
};
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={"auto"}
return (
<DialogRoot placement="center" open={isOpen}>
<DialogTrigger asChild>
<Button
bgColor={"#EEEEEE"}
pl={3} pr={3}
size={"xs"}
color={"#000"}
onClick={() => handleEditClick(termsData)}
>
{" "}
<FaRegEdit
color="#000"
style={{ height: "14px", width: "14px" }}
/>{" "}
<Text color={"#000"} mt={1}>
Edit
</Text>
</Button>
</DialogTrigger>
<DialogContent
bg={"#fff"}
maxW={'600px'}
// w={{ base: "90%", md: "600px" }}
height={"auto"}
p={3} // Reduced padding
bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit
</DialogTitle>
</DialogHeader>
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">Edit</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
TermsAndConditions
</Field.Label>
{/* <Textarea
placeholder=""
bgColor="#EEEEEE"
color="black"
border="none"
p={2}
fontSize="12px"
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: "220px", width: "100%",marginBottom:'20px' }}
/>
)}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} mt={'4'} onClick={handleSubmit(onSubmit)} disabled={isLoading}>
Save
</Button>
</DialogFooter>
<DialogBody bg="white">
<Stack py={3}>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
</DialogRoot>
);
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">TermsAndConditions</Field.Label>
<Textarea placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" pt={1.5} />
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
)
}
export default TermsAndConditionsAddModel;
export default TermsAndConditionsAddModel

View File

@@ -1,99 +1,39 @@
import { Box, HStack, Text } from "@chakra-ui/react";
import MainFrame from "../../components/MainFrame";
import PendingRequests from "../../Pages/ManageContact/PendingRequests";
// import { InputGroup } from "../../components/ui/input-group";
// import { LuSearch } from "react-icons/lu";
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
import MainFrame from "../../components/MainFrame"
import PendingRequests from "../../Pages/ManageContact/PendingRequests"
import { InputGroup } from "../../components/ui/input-group";
import { LuSearch } from "react-icons/lu";
import DataTable from "../../components/DataTable";
import { useGetContactQuery } from "../../Redux/Service/manage.contactus.service";
import { useEffect, useState } from "react";
import { Spinner } from "../../components/Sipnner/Spinner";
import { useDebounce } from "../../components/Hooks/useDebounce";
import SearchComponent from "../../components/SearchComponent";
// table data
const tableHeadRow = ["Sr. No", "Email id", "Name", "Date", "Action"];
const ManageContact = () => {
const [currentPage, setCurrentPage] = useState(1);
const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = useDebounce(searchTerm, 500);
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
const { data, isLoading, isError, refetch, isFetching } = useGetContactQuery(queryArgs);
const tableHeadRow = [
"Sr. No",
"Email id",
"Name",
"Date",
"Action",
];
useEffect(() => {
if (data) {
setLocalData((data as any)?.data?.data || []);
}
}, [data]);
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
const filteredData = localData?.filter((agency) =>
agency?.first_name.toLowerCase().includes(searchTerm.toLowerCase()) ||
agency?.email.toLowerCase().includes(searchTerm.toLowerCase())
);
const formatDateOfBirth = (dob: string): string => {
return new Date(dob).toLocaleDateString("en-GB", {
day: "2-digit",
month: "2-digit",
year: "numeric",
});
};
const managepost = filteredData?.map((agency: any, index: number) => ({
"Sr. No": index + 1, // Typically Sr. No starts from 1, not using id which might not be sequential
"Email id": agency?.email || "-",
Name: agency?.first_name || "-",
Date: formatDateOfBirth(agency?.created_at) || "-",
Action: (
<HStack justifyContent="center" cursor={agency.response_status === 0 ? 'pointer' : 'default'}>
{agency.response_status === 0 ? <PendingRequests data={agency} refetch={refetch} /> : 'Resolved'}
{/* <PendingRequests data={agency} refetch={refetch} /> */}
const managepost: any[] = [
...Array.from({ length: 12 }, (_, i) => ({
"Sr. No": i + 1,
"Email id": "ABC@gmail.com",
"Name": "Pooja",
"Date": "11/02/1989",
"Action": (
<HStack justifyContent="center">
<PendingRequests />
</HStack>
),
}));
if (isLoading) {
return (
<MainFrame>
<Box
display="flex"
justifyContent="center"
alignItems="center"
height="100%"
>
<Spinner />
</Box>
</MainFrame>
);
}
if (isError) {
return (
<MainFrame>
<Box
display="flex"
justifyContent="center"
alignItems="center"
height="100%"
>
<Text>Error loading data</Text>
</Box>
</MainFrame>
);
}
})),
];
const ManageContact = () => {
return (
<MainFrame>
<Box>
<HStack
@@ -104,33 +44,40 @@ const ManageContact = () => {
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
Contact Requests
Contact Requests
</Text>
<HStack>
<SearchComponent
value={searchTerm}
onChange={handleSearchChange}
/>
<HStack mr={5}>
<InputGroup marginRight={"1rem"}
startElement={
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
}
color={"#000"}
>
<Input
p={3}
w={300}
bg={"#fff"}
colorPalette={"blue"}
_focus={{ border: "1px solid #02A0A0" }}
rounded={"md"}
size={"2xs"}
fontSize={"2sm"}
placeholder="Search..."
bgColor={'#EEEEEE'}
ps={8}
/>
</InputGroup>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
</HStack>
</HStack>
<DataTable
sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow}
data={managepost || []} // Ensure an empty array is passed if managepost is undefined
paginationData={{
current_page: (data?.data as any)?.current_page || 1,
last_page: (data?.data as any)?.last_page || 1,
per_page: (data?.data as any)?.per_page || 10,
total: (data?.data as any)?.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
data={managepost}
/>
</Box>
</Box>
</MainFrame>
);
};
export default ManageContact;
)
}
export default ManageContact

View File

@@ -1,170 +1,77 @@
import { Button } from "../../components/ui/button";
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../components/ui/dialog";
import { Badge, Field, HStack, Input, Stack, Textarea } from "@chakra-ui/react";
import { usePendingRequestMutation } from "../../Redux/Service/manage.contactus.service";
import { useState } from "react";
import { Toaster, toaster } from "../../components/ui/toaster";
import { Button } from "../../components/ui/button"
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
import { Field, HStack, Input, Stack, Textarea, } from "@chakra-ui/react"
function PendingRequests() {
return (
function PendingRequests({ data, refetch }: { data: any, refetch: VoidFunction }) {
const [isOpen, setIsOpen] = useState(false);
const [res, setRes] = useState({
contact_us_xid: data.id,
message: data.message,
solution: '',
})
const [pendingRequest, { isLoading }] = usePendingRequestMutation()
<DialogRoot placement="center">
<DialogTrigger asChild>
<Button bg={"transparent"} fontSize={"xs"} color="#000000CC" fontWeight="700" textDecoration="underline">
{/* <MdOutlineRemoveRedEye style={{ cursor: "pointer", }} /> */}
Answer request
</Button>
{/* <Button><FaRegEdit /></Button> */}
const handleOpenModal = () => {
setIsOpen(true);
};
</DialogTrigger>
<DialogContent
bg={"#fff"}
w={{ base: '90%', md: '400px' }}
height={"auto"}
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">Pending Requests</DialogTitle>
</DialogHeader>
const handleSubmit = async (status: string) => {
const payload = { ...res, response_status: status };
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Request Type</Field.Label>
<Input placeholder="Message" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
if(res.solution === ''){
toaster.create({
title: "Error",
description: "All fields are required",
type: "error",
});
return;
}
try {
const response = await pendingRequest(payload).unwrap()
if (response?.status === "success") {
toaster.create({
title: "Success",
description: "Country updated successfully",
type: "success",
});
setIsOpen(false);
refetch()
} else {
toaster.create({
title: "Error",
description: "Failed to update Country",
type: "error",
});
}
} catch (error: any) {
toaster.create({
title: "Error",
description: error?.data?.message || "Something went wrong",
type: "error",
});
}
}
<Field.Label color="black" pt={1} fontSize="12px">Solution</Field.Label>
<Textarea placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="80px" pt={1.5} />
</Field.Root>
return (
<>
<DialogRoot placement="center" key={data.id} open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogTrigger asChild>
<Badge fontSize={"xs"} px={2} bg={'#02a0a01f'} onClick={handleOpenModal}>
Answer request
</Badge>
</DialogTrigger>
</Stack>
</DialogBody>
<DialogFooter display={{ base: 'block', md: 'flex' }} justifyContent="center" gap={1} pt={2}>
<DialogContent
bg={"#fff"}
w={{ base: "90%", md: "400px" }}
height={"auto"}
p={3} // Reduced padding
bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Pending Requests
</DialogTitle>
</DialogHeader>
<HStack mt={2} width={"100%"}
justifyContent={"space-between"}>
<Button
width={"48%"}
color="black"
_hover={{ bgColor: "white" }}
variant="outline"
borderRadius="sm"
border="1px solid black"
size={"xs"}
>
Unresolved
</Button>
<Button
width={"48%"}
borderRadius="sm"
// bgColor="#007F33"
bgColor={'#02A0A0'}
color="white"
// colorPalette="#007F33"
size={"xs"}
>
Resolved{" "}
</Button>
</HStack>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Request Type
</Field.Label>
<Input
placeholder="Message"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={res.message}
disabled
// onChange={(e) => setRes({ ...res, message: e.target.value })}
/>
</DialogFooter>
<Field.Label color="black" pt={1} fontSize="12px">
Solution
</Field.Label>
<Textarea
placeholder=""
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="80px"
pt={1.5}
onChange={(e) => setRes({ ...res, solution: e.target.value })}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter
display={{ base: "block", md: "flex" }}
justifyContent="center"
gap={1}
pt={2}
>
<HStack mt={2} mb={3} width={"100%"} justifyContent={"space-between"}>
<Button
width={"48%"}
color="black"
_hover={{ bgColor: "white" }}
variant="outline"
borderRadius="sm"
border="1px solid #02A0A0"
size={"xs"}
onClick={() => handleSubmit('1')}
disabled={isLoading}
>
Unresolved
</Button>
<Button
width={"48%"}
borderRadius="sm"
// bgColor="#007F33"
bgColor={"#02A0A0"}
color="white"
// colorPalette="#007F33"
size={"xs"}
onClick={() => handleSubmit('0')}
disabled={isLoading}
>
Resolved
</Button>
</HStack>
</DialogFooter>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot>
<Toaster />
</>
);
)
}
export default PendingRequests;
export default PendingRequests

View File

@@ -0,0 +1,11 @@
import MainFrame from '../../components/MainFrame'
const ManageContactUs = () => {
return (
<MainFrame>
</MainFrame>
)
}
export default ManageContactUs

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 { Field, Heading, Input, Stack, Text } from "@chakra-ui/react"
import { Avatar, Box, 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

@@ -1,119 +1,85 @@
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, Span, Stack } from "@chakra-ui/react";
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 { Switch } from "../../components/ui/switch";
import { FaRegEdit } from "react-icons/fa";
import { AvatarGroup } from "../../components/ui/avatar";
import Edit from "../../components/ActionIcons/Edit";
function EditDetailGroups() {
return (
<DialogRoot placement="center">
<DialogTrigger asChild>
<Span><Edit /></Span>
</DialogTrigger>
return (
<DialogContent
bg={"#fff"}
w={{ base: "90%", md: "400px" }}
height={"auto"}
p={3} // Reduced padding
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit details
</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Group Name
</Field.Label>
<Input
value="Priyanka"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
readOnly
/>
<DialogRoot placement="center" >
<DialogTrigger asChild>
<Button bg={"transparent"} size="sm">
<FaRegEdit style={{ cursor: "pointer", }} color="#000"/>
</Button>
{/* <Button><FaRegEdit /></Button> */}
<Field.Label color="black" pt={1} fontSize="12px">
Description
</Field.Label>
<Input
value="Joshi"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
readOnly
/>
</DialogTrigger>
<Field.Label color="black" pt={1} fontSize="12px">
Members
</Field.Label>
<DialogContent
bg={"#fff"}
w={{ base: '90%', md: '400px' }}
height={"auto"}
p={3} // Reduced padding
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">Edit details</DialogTitle>
</DialogHeader>
<Box
bgColor="#EEEEEE"
border="none"
w="100%"
display="flex"
p={1}
rounded={4}
>
<AvatarGroup gap="0" spaceX="-3" size={"xs"}>
<Avatar.Root border={"none"}>
<Avatar.Fallback />
<Avatar.Image src="https://cdn.myanimelist.net/r/84x124/images/characters/9/131317.webp?s=d4b03c7291407bde303bc0758047f6bd" />
</Avatar.Root>
<DialogBody bg="white">
<Stack py={3} >
<Avatar.Root border={"none"}>
<Avatar.Fallback />
<Avatar.Image src="https://cdn.myanimelist.net/r/84x124/images/characters/7/284129.webp?s=a8998bf668767de58b33740886ca571c" />
</Avatar.Root>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Group Name</Field.Label>
<Input value="Priyanka" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly />
<Avatar.Root border={"none"}>
<Avatar.Fallback />
<Avatar.Image src="https://cdn.myanimelist.net/r/84x124/images/characters/9/105421.webp?s=269ff1b2bb9abe3ac1bc443d3a76e863" />
</Avatar.Root>
<Avatar.Root
variant="solid"
border={"none"}
backgroundColor={"transparent"}
>
<Avatar.Fallback ml={5}>+3</Avatar.Fallback>
</Avatar.Root>
</AvatarGroup>
</Box>
</Field.Root>
<Heading color="black" pt={1} fontSize="12px">
public/Private
</Heading>
<Switch />
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button size={"xs"} w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>{" "}
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot>
);
<Field.Label color="black" pt={1} fontSize="12px">Description</Field.Label>
<Input value="Joshi" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly />
<Field.Label color="black" pt={1} fontSize="12px">Members</Field.Label>
<Box
bgColor="#EEEEEE"
border="none"
w="100%"
display="flex"
p={1}
rounded={4}
>
<AvatarGroup gap="0" spaceX="-3" size={"xs"} >
<Avatar.Root border={'none'}>
<Avatar.Fallback />
<Avatar.Image src="https://cdn.myanimelist.net/r/84x124/images/characters/9/131317.webp?s=d4b03c7291407bde303bc0758047f6bd" />
</Avatar.Root>
<Avatar.Root border={'none'}>
<Avatar.Fallback />
<Avatar.Image src="https://cdn.myanimelist.net/r/84x124/images/characters/7/284129.webp?s=a8998bf668767de58b33740886ca571c" />
</Avatar.Root>
<Avatar.Root border={'none'}>
<Avatar.Fallback />
<Avatar.Image src="https://cdn.myanimelist.net/r/84x124/images/characters/9/105421.webp?s=269ff1b2bb9abe3ac1bc443d3a76e863" />
</Avatar.Root>
<Avatar.Root variant="solid" border={'none'} backgroundColor={'transparent'} >
<Avatar.Fallback ml={5}>+3</Avatar.Fallback>
</Avatar.Root>
</AvatarGroup>
</Box>
</Field.Root>
<Heading color="black" pt={1} fontSize="12px">public/Private</Heading>
<Switch />
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button size={'xs'} w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter> <DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
)
}
export default EditDetailGroups;
export default EditDetailGroups

View File

@@ -1,18 +1,16 @@
import { Box, HStack,
// Image,
Input, Text } from "@chakra-ui/react";
import MainFrame from "../../components/MainFrame";
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 ViewManageGroup from "./ViewManageGroup";
import EditDetailGroups from "./EditDetailGroup";
import AddGroup from "./AddGroup";
// import Delete from "../../components/ActionIcons/Delete";
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react"
import MainFrame from "../../components/MainFrame"
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 ViewManageGroup from "./ViewManageGroup"
import EditDetailGroups from "./EditDetailGroup"
import AddGroup from "./AddGroup"
// import ViewSubAdmin from "./ViewSubAdmin"
// table data
const tableHeadRow = [
@@ -28,32 +26,36 @@ const managepost: any[] = [
...Array.from({ length: 12 }, (_, i) => ({
"Sr. No": i + 1,
"Group Name": "ABC",
Description: "Lorem ipsum",
Date: "12/01/1987",
"Description": "Lorem ipsum",
"Date": "12/01/1987",
"Group type": "Private",
Action: (
"Action": (
<HStack justifyContent="center">
{/* <MdOutlineRemoveRedEye
style={{ cursor: "pointer", fontSize: "16px" }}
/> */}
<ViewManageGroup />
<EditDetailGroups />
{/* <AlertDailog
AltertTiggerIcon={() => <Delete />}
{/* <RiDeleteBin5Line style={{ cursor: "pointer" }} /> */}
<AlertDailog
AltertTiggerIcon={RiDeleteBin5Line}
alertText="Delete Users"
alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
alertCaption="are you sure you want to delete ?"
onConfirm={() => {
console.log("User deleted:", i + 1);
}}
/> */}
/>
</HStack>
),
})),
];
const ManageGroups = () => {
return (
<MainFrame>
<MainFrame >
<Box>
<HStack
w={"100%"}
@@ -66,13 +68,10 @@ const ManageGroups = () => {
Manage Groups
</Text>
<HStack>
<HStack >
<InputGroup
startElement={
<LuSearch
fontSize={"xs"}
style={{ position: "relative", left: "10px" }}
/>
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
}
color={"#000"}
>
@@ -83,12 +82,12 @@ const ManageGroups = () => {
colorPalette={"blue"}
_focus={{ border: "1px solid #02A0A0" }}
rounded={"md"}
size={"xs"}
fontSize={"sm"}
size={"2xs"}
fontSize={"2sm"}
placeholder="Search..."
bgColor={"#EEEEEE"}
bgColor={'#EEEEEE'}
ps={8}
border={"none"}
border={'none'}
/>
</InputGroup>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
@@ -100,8 +99,7 @@ const ManageGroups = () => {
tableHeadRow={tableHeadRow}
data={managepost}
/>
</Box>{" "}
</MainFrame>
);
};
export default ManageGroups;
</Box> </MainFrame>
)
}
export default ManageGroups

View File

@@ -1,116 +1,86 @@
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../components/ui/dialog";
import { Avatar, Box, Field, Heading, Input, Span, Stack } from "@chakra-ui/react";
import { Button } from "../../components/ui/button"
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
import { Avatar, Box, Field, Grid, Heading, Input, Stack, Text } from "@chakra-ui/react"
import { Checkbox } from "../../components/ui/checkbox"
import { MdOutlineRemoveRedEye } from "react-icons/md";
import { Switch } from "../../components/ui/switch";
import { AvatarGroup } from "../../components/ui/avatar";
import View from "../../components/ActionIcons/View";
function ViewManageGroup() {
return (
<DialogRoot placement="center">
<DialogTrigger asChild>
<Span><View /></Span>
</DialogTrigger>
return (
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: "90%", md: "400px" }}
height={"auto"}
p={3} // Reduced padding
bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
View details
</DialogTitle>
</DialogHeader>
<DialogRoot placement="center" >
<DialogTrigger asChild>
<Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", }} color="#000"/>
</Button>
{/* <Button><FaRegEdit /></Button> */}
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Group Name
</Field.Label>
<Input
value="Priyanka"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
readOnly
/>
</DialogTrigger>
<Field.Label color="black" pt={1} fontSize="12px">
Description
</Field.Label>
<Input
value="Joshi"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
readOnly
/>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={"auto"}
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">View details</DialogTitle>
</DialogHeader>
<Field.Label color="black" pt={1} fontSize="12px">
Members
</Field.Label>
<DialogBody bg="white">
<Stack py={3} >
<Box
bgColor="#EEEEEE"
border="none"
w="100%"
display="flex"
p={1}
rounded={4}
>
<AvatarGroup gap="0" spaceX="-3" size={"xs"}>
<Avatar.Root border={"none"}>
<Avatar.Fallback />
<Avatar.Image src="https://cdn.myanimelist.net/r/84x124/images/characters/9/131317.webp?s=d4b03c7291407bde303bc0758047f6bd" />
</Avatar.Root>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Group Name</Field.Label>
<Input value="Priyanka" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly />
<Avatar.Root border={"none"}>
<Avatar.Fallback />
<Avatar.Image src="https://cdn.myanimelist.net/r/84x124/images/characters/7/284129.webp?s=a8998bf668767de58b33740886ca571c" />
</Avatar.Root>
<Field.Label color="black" pt={1} fontSize="12px">Description</Field.Label>
<Input value="Joshi" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly />
<Avatar.Root border={"none"}>
<Avatar.Fallback />
<Avatar.Image src="https://cdn.myanimelist.net/r/84x124/images/characters/9/105421.webp?s=269ff1b2bb9abe3ac1bc443d3a76e863" />
</Avatar.Root>
<Avatar.Root
variant="solid"
border={"none"}
backgroundColor={"transparent"}
>
<Avatar.Fallback ml={5}>+3</Avatar.Fallback>
</Avatar.Root>
</AvatarGroup>
</Box>
</Field.Root>
<Heading color="black" pt={1} fontSize="12px">
public/Private
</Heading>
<Switch />
</Stack>
</DialogBody>
<Field.Label color="black" pt={1} fontSize="12px">Members</Field.Label>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot>
);
<Box
bgColor="#EEEEEE"
border="none"
w="100%"
display="flex"
p={1}
rounded={4}
>
<AvatarGroup gap="0" spaceX="-3" size={"xs"} >
<Avatar.Root border={'none'}>
<Avatar.Fallback />
<Avatar.Image src="https://cdn.myanimelist.net/r/84x124/images/characters/9/131317.webp?s=d4b03c7291407bde303bc0758047f6bd" />
</Avatar.Root>
<Avatar.Root border={'none'}>
<Avatar.Fallback />
<Avatar.Image src="https://cdn.myanimelist.net/r/84x124/images/characters/7/284129.webp?s=a8998bf668767de58b33740886ca571c" />
</Avatar.Root>
<Avatar.Root border={'none'}>
<Avatar.Fallback />
<Avatar.Image src="https://cdn.myanimelist.net/r/84x124/images/characters/9/105421.webp?s=269ff1b2bb9abe3ac1bc443d3a76e863" />
</Avatar.Root>
<Avatar.Root variant="solid" border={'none'} backgroundColor={'transparent'} >
<Avatar.Fallback ml={5}>+3</Avatar.Fallback>
</Avatar.Root>
</AvatarGroup>
</Box>
</Field.Root>
<Heading color="black" pt={1} fontSize="12px">public/Private</Heading>
<Switch />
</Stack>
</DialogBody>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
)
}
export default ViewManageGroup;
export default ViewManageGroup

View File

@@ -1,184 +1,11 @@
import {
Box,
HStack,
Image,
// Image,
Text,
} from "@chakra-ui/react";
// import { LuSearch } from "react-icons/lu";
// import { RiDeleteBin5Line } from "react-icons/ri";
// import AlertDailog from "../../components/AlertDailog";
import DataTable from "../../components/DataTable";
import MainFrame from "../../components/MainFrame";
// import { InputGroup } from "../../components/ui/input-group";
import ManageJobsAdd from "./ManageJobsAdd";
import ViewManageJob from "./ViewManageJob";
import {
useDeleteJobsPostMutation,
useGetManageJobsQuery,
} from "../../Redux/Service/manage.jobs.service";
import { useEffect, useState } from "react";
import { Spinner } from "../../components/Sipnner/Spinner";
import Delete from "../../components/ActionIcons/Delete";
import { Toaster, toaster } from "../../components/ui/toaster";
import AlertDailog from "../../components/AlertDailog";
import { useDebounce } from "../../components/Hooks/useDebounce";
import SearchComponent from "../../components/SearchComponent";
// import { useState } from "react";
// import { useGetManageJobsQuery } from "../../Redux/Service/manage.jobs.service";
// import Delete from "../../components/ActionIcons/Delete";
// table data
const tableHeadRow = [
"Sr. No",
"Job Title",
"Workspace mode",
"Category",
"Sub-category",
"Salary",
"Action",
];
import MainFrame from "../../components/MainFrame"
const ManageJobs = () => {
const [currentPage, setCurrentPage] = useState(1);
const [localData, setLocalData] = useState([]);
const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = useDebounce(searchTerm, 500);
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
const { data, refetch, isLoading, isError, isFetching } = useGetManageJobsQuery(queryArgs);
const [deleteJobsPost] = useDeleteJobsPostMutation();
const [deleteModal, setDeleteModal] = useState(false);
const [selectedJobsId, setSelectedJobsId] = useState<number | null>(null);
useEffect(() => {
if (data) {
setLocalData((data as any)?.data?.data || []);
}
}, [data]);
// console.log(data?.data.data);
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
const handleDeleteJobs = async (jobsId: number) => {
try {
const response = await deleteJobsPost({ id: jobsId }).unwrap();
if (response?.status === "success") {
toaster.create({
title: "Success",
description: "Jobs deleted successfully",
type: "Success",
});
refetch();
}
} catch (error) {
console.error("Error deleting FAQ:", error);
toaster.create({
title: "Error",
description: "Something went wrong",
type: "error",
});
}
};
const managepost = localData?.map((agency: any, index: number) => ({
"Sr. No": index + 1,
"Job Title": agency?.job_title,
"Workspace mode": agency?.workspace?.en_name,
Category: agency?.industry?.en_name,
"Sub-category": agency?.department?.en_name,
Salary: agency?.ctc_amount,
Action: (
<HStack justifyContent="center">
<ViewManageJob data={agency} />
<ManageJobsAdd data={agency} refetch={refetch}/>
<AlertDailog
isOpen={deleteModal}
AltertTiggerIcon={() => (
<Delete
onClick={() => {
setSelectedJobsId(agency.id);
setDeleteModal(true);
}}
/>
)}
alertText="Delete FAQ"
alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
alertCaption="are you sure you want to delete ?"
onClose={() => setDeleteModal(false)}
onConfirm={() => {
// console.log("Deleting FAQ with ID:", selectedFaqId); // Correct ID
if (selectedJobsId) {
setDeleteModal(false);
handleDeleteJobs(selectedJobsId);
}
}}
/>
</HStack>
),
}));
if (isLoading) {
return (
<MainFrame>
<Box
display="flex"
justifyContent="center"
alignItems="center"
height="100%"
>
<Spinner />
</Box>
</MainFrame>
);
}
return (
<MainFrame>
<Box>
<HStack
w={"100%"}
justifyContent={"space-between"}
mb={4}
py={0}
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
View job Posting
</Text>
<HStack>
<SearchComponent
value={searchTerm}
onChange={handleSearchChange}
/>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
</HStack>
</HStack>
<DataTable
sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow}
data={managepost}
paginationData={{
current_page: data?.data.current_page || 1,
last_page: data?.data.last_page || 1,
per_page: data?.data.per_page || 10,
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
<Toaster />
</MainFrame>
);
};
export default ManageJobs;
)
}
export default ManageJobs

View File

@@ -1,505 +1,118 @@
import {
Field,
Input,
Span,
Stack,
} from "@chakra-ui/react";
import { Button } from "../../components/ui/button";
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../components/ui/dialog";
import { Button } from "../../components/ui/button"
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
import { createListCollection, Field, Input, SelectValueText, Stack } from "@chakra-ui/react"
// import { TbEdit } from "react-icons/tb";
import Edit from "../../components/ActionIcons/Edit";
import { JobStatusData, useGetCountryQuery, useGetDepartmentQuery, useGetIndustryQuery, useGetManageJobTypeQuery, useGetWorkspaceModesQuery, useUpdateJobsMutation, WorkSpace } from "../../Redux/Service/manage.jobs.service";
import { useReducer, useRef } from "react";
import { Toaster, toaster } from "../../components/ui/toaster";
import { FaRegEdit } from "react-icons/fa"
import { SelectContent, SelectItem, SelectLabel, SelectRoot, SelectTrigger } from "../../components/ui/select"
const reducerFunction = (state: any, action: any) => {
switch (action.type) {
case "SET_JOB_TITLE":
return { ...state, jobTitle: action.payload };
case "SET_WORKSPACE_MODE":
return { ...state, workspaceMode: action.payload };
case "SET_CATEGORY":
return { ...state, category: action.payload };
case "SET_SUB_CATEGORY":
return { ...state, subCategory: action.payload };
case "SET_SALARY":
return { ...state, salary: action.payload };
case "SET_EXPERIENCE":
return { ...state, experience: action.payload };
case "SET_JOB_LOCATION":
return { ...state, jobLocation: action.payload };
case "SET_COUNTRY_SELECTION":
return { ...state, countrySelection: action.payload };
case "SET_JOB_TYPE":
return { ...state, jobType: action.payload };
case "SET_SKILLS_REQUIRED":
return { ...state, skillsRequired: action.payload };
case "SET_JOB_DESCRIPTION":
return { ...state, jobDescription: action.payload };
default:
return state;
}
};
const frameworks = createListCollection({
items: [
{ label: "React.js", value: "react" },
{ label: "Vue.js", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
],
})
function ManageJobsAdd() {
return (
function ManageJobsAdd({ data, refetch }: { data: JobStatusData, refetch: () => void }) {
const { data: workspaceModes } = useGetWorkspaceModesQuery({});
const { data: industryData } = useGetIndustryQuery({});
const { data: departmentData } = useGetDepartmentQuery({});
const { data: countryData } = useGetCountryQuery({});
const { data: jobTypeData } = useGetManageJobTypeQuery({});
const [updateJobs, { isLoading}] = useUpdateJobsMutation();
// console.log('Modes:', jobTypeData?.data.data);
const initialState = {
jobTitle: data?.job_title || "",
workspaceMode: data?.workspace_mode_xid || "",
category: data?.industry_xid || "",
subCategory: data?.department_xid || "",
salary: data?.ctc_amount || "",
experience: data?.experience || "",
jobLocation: data?.job_location || "",
countrySelection: data?.country_xid || "",
jobType: data?.job_type_xid || "",
skillsDescription: data?.skill_description || "",
jobDescription: data?.job_description || "",
};
<DialogRoot placement="center">
<DialogTrigger asChild>
<Button bg={"transparent"} size="sm">
<FaRegEdit style={{ cursor: "pointer", fontSize: "14px" }} color="#000" />
</Button>
</DialogTrigger>
const [state, dispatch] = useReducer(reducerFunction, initialState);
const closeRef = useRef<HTMLButtonElement>(null);
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'80vh'}
overflow={'scroll'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add Details</DialogTitle>
</DialogHeader>
const getDisplayName = (name: string, maxLength = 30) =>
name.length > maxLength ? name.slice(0, maxLength) + "..." : name;
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Job title</Field.Label>
<Input placeholder="Enter the Job Title" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
<Field.Root>
const handleSubmit = async () => {
const {
jobTitle,
workspaceMode,
category,
subCategory,
salary,
experience,
jobLocation,
countrySelection,
jobType,
skillsDescription,
jobDescription,
} = state;
<Field.Label color="black" pt={1} fontSize="12px">Workspace mode</Field.Label>
<Input placeholder="Enter the Workspace Mode" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Category</Field.Label>
<Input placeholder="Enter the Category" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Sub-Category</Field.Label>
<Input placeholder="Enter the Sub-Category" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Salary</Field.Label>
<Input placeholder="Enter the Salary" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Experience</Field.Label>
<Input placeholder="Enter the Experience" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Job Location</Field.Label>
<Input placeholder="Enter the Job Location" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
{/* <Field.Label pt={1} color="black" fontSize="12px">Country Selection</Field.Label>
<Input placeholder="Enter the Country Selection" /> */}
<SelectRoot collection={frameworks} size="sm" w={'100%'}>
<SelectLabel pt={1} color="black" fontSize="12px">Country Selection</SelectLabel>
<SelectTrigger bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
borderRadius={"5px"}>
<SelectValueText placeholder="Enter the Country Selection" pb={"6px"} fontSize={"12px"} />
</SelectTrigger>
<SelectContent position={'relative'} zIndex={'9999'} bg={"#fff"}>
{frameworks.items.map((movie) => (
<SelectItem item={movie} key={movie.value} color={"black"} pl={2} p={1} _hover={{ bg: "#F0F0F0" }} // Light grey background on hover
fontSize="12px" >
{movie.label}
</SelectItem>
))}
</SelectContent>
</SelectRoot>
<Field.Root>
if (
!jobTitle ||
!workspaceMode ||
!category ||
!subCategory ||
!salary ||
!experience ||
!jobLocation ||
!countrySelection ||
!jobType ||
!skillsDescription ||
!jobDescription
) {
toaster.create({
title: "Missing Fields",
description: "Please fill in all required fields before submitting.",
type: "error",
});
return;
}
// Only en_name is editable, so we only need to send that in the payload.
const payload = {
id: data?.id,
job_title: state.jobTitle,
workspace_mode_xid: state.workspaceMode,
industry_xid: state.category,
department_xid: state.subCategory,
ctc_amount: state.salary,
experience: state.experience,
job_location: state.jobLocation,
country_xid: state.countrySelection,
job_type_xid: state.jobType,
skill_description: state.skillsDescription,
job_description: state.jobDescription,
};
// console.log('payload', payload)
try {
const response = await updateJobs(payload).unwrap();
if (response?.status === "success") {
toaster.create({
title: "Success",
description: "Country updated successfully",
type: "success",
});
closeRef.current?.click();
refetch()
} else {
toaster.create({
title: "Error",
description: "Failed to update Country",
type: "error",
});
}
} catch (error) {
console.error("Error updating template:", error);
// alert("Failed to update template");
toaster.create({
title: "Error",
description: "Something went wrong",
type: "error",
});
}
};
<Field.Label pt={1} color="black" fontSize="12px">Job type</Field.Label>
<Input placeholder="Enter the Job Type" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Skills required</Field.Label>
<Input placeholder="Enter the Skills Required" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Job Description*</Field.Label>
<Input placeholder="Enter the Job Description" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} fontSize="12px" height="30px">
Save
</Button>
</DialogFooter>
return (
<DialogRoot placement="center">
<DialogTrigger asChild>
<Span><Edit /></Span>
</DialogTrigger>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: "90%", md: "400px" }}
height={"80vh"}
overflow={"scroll"}
overflowX="hidden"
p={3} // Reduced padding
bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Add Details
</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Job title
</Field.Label>
<Input
placeholder="Enter the Job Title"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={state.jobTitle}
onChange={(e) =>
dispatch({
type: "SET_JOB_TITLE",
payload: e.target.value,
})
}
/>
</Field.Root>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Workspace mode
</Field.Label>
<select
style={{
backgroundColor: "#EEEEEE",
color: "black",
border: "none",
height: "30px",
fontSize: "12px",
padding: "4px",
borderRadius: "4px",
width: "100%",
}}
value={state.workspace_mode_xid}
onChange={(e) =>
dispatch({
type: "SET_WORKSPACE_MODE",
payload: Number(e.target.value),
})
}
>
<option value="" disabled>
Select country
</option>
{workspaceModes && workspaceModes?.data.map((mode: WorkSpace) => (
<option key={mode.id} value={mode.id}>
{getDisplayName(mode.en_name)}
</option>
))}
</select>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Category
</Field.Label>
<select
style={{
backgroundColor: "#EEEEEE",
color: "black",
border: "none",
height: "30px",
fontSize: "12px",
padding: "4px",
borderRadius: "4px",
width: "100%",
}}
value={state.industry_xid}
onChange={(e) =>
dispatch({
type: "SET_INDUSTRY",
payload: Number(e.target.value),
})
}
>
<option value="" disabled>
Select department
</option>
{industryData && industryData?.data.map((mode: WorkSpace) => (
<option key={mode.id} value={mode.id}>
{getDisplayName(mode.en_name)}
</option>
))}
</select>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Sub-Category
</Field.Label>
<select
style={{
backgroundColor: "#EEEEEE",
color: "black",
border: "none",
height: "30px",
fontSize: "12px",
padding: "4px",
borderRadius: "4px",
width: "100%",
}}
value={state.department_xid}
onChange={(e) =>
dispatch({
type: "SET_DEPARTMENT",
payload: Number(e.target.value),
})
}
>
<option value="" disabled>
Select department
</option>
{departmentData && departmentData?.data.map((mode: WorkSpace) => (
<option key={mode.id} value={mode.id}>
{getDisplayName(mode.en_name)}
</option>
))}
</select>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Country
</Field.Label>
<select
style={{
backgroundColor: "#EEEEEE",
color: "black",
border: "none",
height: "30px",
fontSize: "12px",
padding: "4px",
borderRadius: "4px",
width: "100%",
}}
value={state.country_xid}
onChange={(e) =>
dispatch({
type: "SET_COUNTRY",
payload: Number(e.target.value),
})
}
>
<option value="" disabled>
Select country
</option>
{countryData && countryData?.data.map((mode: WorkSpace) => (
<option key={mode.id} value={mode.id}>
{getDisplayName(mode.en_name)}
</option>
))}
</select>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Job type
</Field.Label>
<select
style={{
backgroundColor: "#EEEEEE",
color: "black",
border: "none",
height: "30px",
fontSize: "12px",
padding: "4px",
borderRadius: "4px",
width: "100%",
}}
value={state.job_type_xid}
onChange={(e) =>
dispatch({
type: "SET_JOB_TYPE",
payload: Number(e.target.value),
})
}
>
<option value="" disabled>
Select Job Type
</option>
{jobTypeData && jobTypeData?.data.data.map((mode: WorkSpace) => (
<option key={mode.id} value={mode.id}>
{getDisplayName(mode.en_name)}
</option>
))}
</select>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Salary
</Field.Label>
<Input
placeholder="Enter the Salary"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={state.salary}
onChange={(e) =>
dispatch({
type: "SET_SALARY",
payload: e.target.value,
})
}
/>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Experience
</Field.Label>
<Input
placeholder="Enter the Experience in years"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={state.experience}
onChange={(e) =>
dispatch({
type: "SET_EXPERIENCE",
payload: e.target.value,
})
}
/>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Job Location
</Field.Label>
<Input
placeholder="Enter the Job Location"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={state.jobLocation}
onChange={(e) =>
dispatch({
type: "SET_JOB_LOCATION",
payload: e.target.value,
})
}
/>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Skills description
</Field.Label>
<Input
placeholder="Enter the Skills description"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={state.skillsDescription}
onChange={(e) =>
dispatch({
type: "SET_SKILLS_DESCRIPTION",
payload: e.target.value,
})
}
/>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Job Description*
</Field.Label>
<Input
placeholder="Enter the Job Description"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={state.jobDescription}
onChange={(e) =>
dispatch({
type: "SET_JOB_DESCRIPTION",
payload: e.target.value,
})
}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button
w="100%"
bg="#02A0A0"
color={"#fff"}
fontSize="12px"
height="30px"
onClick={handleSubmit}
disabled={isLoading}
>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" ref={closeRef} />
</DialogContent>
<Toaster />
</DialogRoot>
);
)
}
export default ManageJobsAdd;
export default ManageJobsAdd

View File

@@ -1,307 +1,113 @@
import {
Field,
Input,
Stack,
} from "@chakra-ui/react";
import { Button } from "../../components/ui/button";
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../components/ui/dialog";
import { Button } from "../../components/ui/button"
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
import { createListCollection, Field, Input, SelectValueText, Stack, } from "@chakra-ui/react"
// import { MdOutlineRemoveRedEye } from "react-icons/md";
import View from "../../components/ActionIcons/View";
import { JobStatusData, useLazyViewJobsQuery } from "../../Redux/Service/manage.jobs.service";
import { FaRegEdit } from "react-icons/fa"
import { SelectContent, SelectItem, SelectLabel, SelectRoot, SelectTrigger } from "../../components/ui/select"
import { MdOutlineRemoveRedEye } from "react-icons/md"
function ViewManageJob({ data }: { data: JobStatusData }) {
const [trigger] = useLazyViewJobsQuery();
const frameworks = createListCollection({
items: [
{ label: "React.js", value: "react" },
{ label: "Vue.js", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
],
})
function ViewManageJob() {
return (
console.log(data);
const handleView = () => {
trigger(data.id);
};
<DialogRoot placement="center">
<DialogTrigger asChild>
<Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "14px" }} color="#000"/>
</Button>
</DialogTrigger>
// const viewJobs = data;
console.log();
return (
<DialogRoot placement="center">
<DialogTrigger asChild>
<Button
onClick={handleView}
bg={'transparent'}
color={"black"}
>
<View />
</Button>
</DialogTrigger>
{/* {viewJobs?.map((data: any) => ( */}
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: "90%", md: "400px" }}
height={"80vh"}
overflow={"scroll"}
overflowX="hidden"
p={3} // Reduced padding
bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Add Details
</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Job title
</Field.Label>
<Input
placeholder="Enter the Job Title"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.job_title}
/>
</Field.Root>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Workspace mode
</Field.Label>
<Input
placeholder="Enter the Workspace Mode"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.workspace?.en_name}
/>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Category
</Field.Label>
<Input
placeholder="Enter the Category"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.industry?.en_name}
/>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Sub-Category
</Field.Label>
<Input
placeholder="Enter the Sub-Category"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.department?.en_name}
/>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Salary
</Field.Label>
<Input
placeholder="Enter the Salary"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.ctc_amount}
/>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Experience
</Field.Label>
<Input
placeholder="Enter the Experience"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.experience}
/>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Job Location
</Field.Label>
<Input
placeholder="Enter the Job Location"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.job_location}
/>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Country
</Field.Label>
<Input
placeholder="Enter the Country"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.country.en_name}
/>
</Field.Root>
{/* <SelectRoot collection={frameworks} size="sm" w={"100%"}>
<SelectLabel pt={1} color="black" fontSize="12px">
Country Selection
</SelectLabel>
<SelectTrigger
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
borderRadius={"5px"}
>
<SelectValueText
placeholder="Enter the Country Selection"
pb={"6px"}
fontSize={"12px"}
/>
</SelectTrigger>
<SelectContent
position={"relative"}
zIndex={"9999"}
<DialogContent
bg={"#fff"}
>
{frameworks.items.map((movie) => (
<SelectItem
item={movie}
key={movie.value}
color={"black"}
pl={2}
p={1}
_hover={{ bg: "#F0F0F0" }} // Light grey background on hover
fontSize="12px"
>
{movie.label}
</SelectItem>
))}
</SelectContent>
</SelectRoot> */}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'80vh'}
overflow={'scroll'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add Details</DialogTitle>
</DialogHeader>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Job type
</Field.Label>
<Input
placeholder="Enter the Job Type"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.job_type?.en_name}
/>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Skills required
</Field.Label>
<Input
placeholder="Enter the Skills Required"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.skill_description}
/>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Job Description*
</Field.Label>
<Input
placeholder="Enter the Job Description"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.job_description}
/>
</Field.Root>
{/* <Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Upload Image
</Field.Label>
<Input
placeholder="Upload Image"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
/>
</Field.Root> */}
</Stack>
</DialogBody>
{/* <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button
w="100%"
bg="#02A0A0"
color={"#fff"}
fontSize="12px"
height="30px"
>
Save
</Button>
</DialogFooter> */}
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Job title</Field.Label>
<Input placeholder="Enter the Job Title" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root><Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Workspace mode</Field.Label>
<Input placeholder="Enter the Workspace Mode" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root><Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Category</Field.Label>
<Input placeholder="Enter the Category" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root><Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Sub-Category</Field.Label>
<Input placeholder="Enter the Sub-Category" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root><Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Salary</Field.Label>
<Input placeholder="Enter the Salary" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root><Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Experience</Field.Label>
<Input placeholder="Enter the Experience" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root><Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Job Location</Field.Label>
<Input placeholder="Enter the Job Location" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
{/* <Field.Label pt={1} color="black" fontSize="12px">Country Selection</Field.Label>
<Input placeholder="Enter the Country Selection" /> */}
<SelectRoot collection={frameworks} size="sm" w={'100%'}>
<SelectLabel pt={1} color="black" fontSize="12px">Country Selection</SelectLabel>
<SelectTrigger bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
borderRadius={"5px"}>
<SelectValueText placeholder="Enter the Country Selection" pb={"6px"} fontSize={"12px"} />
</SelectTrigger>
<SelectContent position={'relative'} zIndex={'9999'} bg={"#fff"}>
{frameworks.items.map((movie) => (
<SelectItem item={movie} key={movie.value} color={"black"} pl={2} p={1} _hover={{ bg: "#F0F0F0" }} // Light grey background on hover
fontSize="12px" >
{movie.label}
</SelectItem>
))}
</SelectContent>
</SelectRoot>
<DialogCloseTrigger color="black" />
</DialogContent>
{/* ))} */}
</DialogRoot>
);
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Job type</Field.Label>
<Input placeholder="Enter the Job Type" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root><Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Skills required</Field.Label>
<Input placeholder="Enter the Skills Required" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root><Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Job Description*</Field.Label>
<Input placeholder="Enter the Job Description" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root><Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">Upload Image</Field.Label>
<Input placeholder="Upload Image" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} fontSize="12px" height="30px">
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot>
)
}
export default ViewManageJob;
export default ViewManageJob

View File

@@ -1,254 +1,11 @@
import {
Box, HStack, Icon, Image,
// Span,
Text
} from "@chakra-ui/react";
import MainFrame from "../../components/MainFrame";
// import { InputGroup } from "../../components/ui/input-group";
// import { LuSearch } from "react-icons/lu";
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 ViewDailog from "./ViewDailog";
import { useGetManagePostsQuery, usePostStatusToggleMutation } from "../../Redux/Service/manage.post.service";
import { useEffect, useState } from "react";
import { Toaster, toaster } from "../../components/ui/toaster";
import { FaVideo } from "react-icons/fa";
import SearchComponent from "../../components/SearchComponent";
import { delay } from "../../components/Utils";
// import Delete from "../../components/ActionIcons/Delete";
// import ViewDailog from './ViewDailog'
const APIURL = import.meta.env.VITE_POST_IMG
const tableHeadRow = [
"Sr. No",
"Images",
"Description",
"Publish Data",
// "Activate/Deactivate",
"Action",
];
// const managepost: any[] = [
// ...Array.from({ length: 12 }, (_, i) => ({
// "Sr. No": i + 1,
// Images: (
// // <Image w={50} src={img} />
// <Image rounded={"lg"} w={100} h={50} src={img} />
// ),
// Description: (
// <Text>
// {`Lorem ipsum dolor, sit amet consectetur adipisicing elit.}`.slice(
// 0,
// 30
// ) + "..."}
// </Text>
// ),
// "Publish Data": "12/01/2025",
// "Activate/Deactivate": (
// <Box w={"100%"}>
// <Switch size={"sm"} colorPalette={"teal"} />
// </Box>
// ),
// Action: (
// <HStack justifyContent="center">
// <ViewDailog />
// {/* <AlertDailog
// AltertTiggerIcon={() => <Span><Delete /> </Span>}
// alertText="Delete Users"
// alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
// alertCaption="are you sure you want to delete ?"
// onConfirm={() => {
// console.log("User deleted:", i + 1);
// }}
// /> */}
// </HStack>
// ),
// })),
// ];
import MainFrame from "../../components/MainFrame"
const ManagePost = () => {
const [currentPage, setCurrentPage] = useState(1);
const { data, refetch, isFetching, isError } = useGetManagePostsQuery(currentPage)
const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const [postStatusToggle] = usePostStatusToggleMutation()
console.log('POSTS', data?.data.data);
useEffect(() => {
if (data?.data?.data) {
setLocalData(data?.data.data);
}
}, [data]);
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
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 postStatusToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch()
} catch (error) {
console.error("Error updating:", error);
toaster.create({
title: "Error",
description: "Someting went wrong.",
type: "error",
});
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
)
);
}
};
function formatAPIDate(apiDateString: any) {
const date = new Date(apiDateString);
// Get month, day, and year
const month = date.getMonth() + 1; // Months are 0-indexed
const day = date.getDate();
const year = date.getFullYear();
// Pad with leading zeros if needed
const formattedMonth = month.toString().padStart(2, '0');
const formattedDay = day.toString().padStart(2, '0');
return `${formattedMonth}/${formattedDay}/${year}`;
}
const filteredData = localData?.filter((agency) => {
return (agency.post_content_translation.some((item: any) => {
const searchLower = searchTerm.toLowerCase();
const title = item.content?.toLowerCase().includes(searchLower);
return title;
}))
});
const managepost = filteredData?.flatMap((agency: any, index: number) => (agency.post_content_translation.map((translation: any) => ({
'id': agency.id,
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
Images: (
agency.images.length > 0 ?
agency.images[0].type === "image" ? (
<HStack>
<Image
rounded={"lg"}
w={100}
h={50}
src={`${APIURL}${agency.images[0].image_name}`}
/>
<Text fontSize="xs" color={'lightgray'}>
{`${Number(agency.images.length) > 1 ? '+' + (Number(agency.images.length) - 1) : ''}`}
</Text>
</HStack>
) : (
<HStack>
<Box
rounded={"lg"}
w={100}
h={50}
bg="gray.200"
display="flex"
alignItems="center"
justifyContent="center"
>
<Icon as={FaVideo} color="gray.500" />
</Box>
<Text fontSize="xs" color={'lightgray'}>
{`${Number(agency.images.length) > 1 ? '+' + (Number(agency.images.length) - 1) : ''}`}
</Text>
</HStack>
) : ''
// <Image rounded={"lg"} w={100} h={50} src={img} />
),
Description: (
<Text>
{translation?.content?.length > 30
? `${translation.content.slice(0, 30)}...`
: translation?.content}
</Text>
),
"Publish Data": formatAPIDate(agency.created_at),
"is_active": agency.is_active,
"Action": (
<HStack justifyContent="center">
{/* <ViewAgencyMaster agency={localData} id={agency.id} /> */}
<ViewDailog localData={{ ...agency, translation }} refetch={refetch} />
<Box>
<Switch
colorPalette={"teal"}
size={"xs"}
onChange={() => handleToggle(agency.id, Number(agency.is_active))}
checked={Boolean(Number(agency.is_active))}
/>
</Box>
</HStack>
),
}))));
return (
<MainFrame>
<Box>
<HStack
w={"100%"}
justifyContent={"space-between"}
mb={4}
py={0}
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
{/* Manage Post */}
</Text>
<HStack>
<SearchComponent
value={searchTerm}
onChange={(value) => {
setSearchTerm(value);
// setCurrentPage(1);
refetch()
}}
/>
</HStack>
</HStack>
<DataTable
sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow}
data={managepost}
paginationData={{
current_page: data?.data.current_page || 1,
last_page: data?.data.last_page || 1,
per_page: data?.data.per_page || 10,
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
<Toaster />
</MainFrame>
);
};
)
}
export default ManagePost;
export default ManagePost

View File

@@ -1,18 +1,16 @@
import { Field, HStack, Image, Input, Stack } from "@chakra-ui/react"
// import { TbEdit } from "react-icons/tb"
// import img from "../../assets/waterfall.jpg"
import { MdOutlineRemoveRedEye } from "react-icons/md"
import { Button } from "../../components/ui/button"
import { DialogBody, DialogCloseTrigger, DialogContent, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
// import Edit from "../../components/ActionIcons/Edit"
import { LuEye } from "react-icons/lu"
const APIURL = import.meta.env.VITE_POST_IMG
function ViewDailog({ localData }: { localData: any, refetch: VoidFunction }) {
import { Field, Image, Input, Stack } from "@chakra-ui/react"
import img from "../../assets/waterfall.jpg"
function ViewDailog() {
return (
<DialogRoot placement="center">
<DialogTrigger asChild>
{/* <Span><Edit /></Span> */}
<LuEye fontSize={"xm"} cursor={'pointer'} />
<Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} color="#000" />
</Button>
</DialogTrigger>
<DialogContent
@@ -28,49 +26,17 @@ function ViewDailog({ localData }: { localData: any, refetch: VoidFunction }) {
<DialogBody bg="white">
<Stack py={3} >
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Title</Field.Label>
<Input placeholder="Enter the Title" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly />
<Field.Label color="black" pt={1} fontSize="12px">Subtitle</Field.Label>
<Input placeholder="Enter the Subtitle" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly />
<Field.Label color="black" pt={1} fontSize="12px">Description</Field.Label>
<Input
// placeholder="Enter the Title"
value={localData.translation.content}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
readOnly
/>
<Input placeholder="Enter the Description" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly />
{/* <Field.Label color="black" pt={1} fontSize="12px">Subtitle</Field.Label>
<Input placeholder="Enter the Subtitle" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly /> */}
{/* <Field.Label color="black" pt={1} fontSize="12px">Description</Field.Label>
<Input placeholder="Enter the Description" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly /> */}
<Field.Label color="black" pt={1} fontSize="12px">Image</Field.Label>
<HStack w="fit-content" flexWrap={'wrap'}>
{localData.images.map((img: any) => (
img.type === 'image' ? (
<Image
key={img.id}
src={`${APIURL}${img.image_name}`}
w="30%"
maxH="150px"
objectFit="contain"
/>
) : (
<video
key={img.id}
width="45%"
height="50"
controls
>
<source src={`${APIURL}${img.image_name}`} type="video/mp4" />
</video>
)
))}
</HStack>
{/* <Image src={img} w="100%" maxH="150px" objectFit="contain" /> */}
<Image src={img} w="100%" maxH="150px" objectFit="contain" />
</Field.Root>
</Stack>
</DialogBody>

View File

@@ -0,0 +1,11 @@
import MainFrame from '../../components/MainFrame'
const ManageSubAdmin = () => {
return (
<MainFrame>
</MainFrame>
)
}
export default ManageSubAdmin

View File

@@ -0,0 +1,11 @@
import MainFrame from '../../../components/MainFrame'
const DeactivatedAccounts = () => {
return (
<MainFrame>
</MainFrame>
)
}
export default DeactivatedAccounts

View File

@@ -0,0 +1,233 @@
import { Box, HStack, Input, Stack, Table, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame";
import { InputGroup } from "../../../components/ui/input-group";
import { LuSearch } from "react-icons/lu";
import DataTable from "../../../components/DataTable";
// Table setup
const tableHeadRow = [
"Sr. No",
"First Name",
"Mobile number",
"Gender",
"DOB",
"Type of User",
"Language",
"Status",
"Action",
];
const usersData: any[] = [
{
"Sr. No": 1,
"First Name": "Ritesh",
"Mobile number": "9876543210",
Gender: "Male",
DOB: "15-01-1990",
"Type of User": "Admin",
Language: "English",
Status: "Active",
Action: "Edit/Delete",
},
{
"Sr. No": 2,
"First Name": "Anjali",
"Mobile number": "9123456789",
Gender: "Female",
DOB: "21-06-1995",
"Type of User": "Customer",
Language: "Hindi",
Status: "Inactive",
Action: "Edit/Delete",
},
{
"Sr. No": 3,
"First Name": "Rajesh",
"Mobile number": "9871234560",
Gender: "Male",
DOB: "12-12-1985",
"Type of User": "Vendor",
Language: "English",
Status: "Active",
Action: "Edit/Delete",
},
{
"Sr. No": 4,
"First Name": "Priya",
"Mobile number": "9988776655",
Gender: "Female",
DOB: "05-05-1998",
"Type of User": "Customer",
Language: "Tamil",
Status: "Active",
Action: "Edit/Delete",
},
{
"Sr. No": 5,
"First Name": "Amit",
"Mobile number": "8899665544",
Gender: "Male",
DOB: "03-03-1992",
"Type of User": "Admin",
Language: "Gujarati",
Status: "Inactive",
Action: "Edit/Delete",
},
{
"Sr. No": 6,
"First Name": "Amit",
"Mobile number": "8899665544",
Gender: "Male",
DOB: "03-03-1992",
"Type of User": "Admin",
Language: "Gujarati",
Status: "Inactive",
Action: "Edit/Delete",
},
{
"Sr. No": 7,
"First Name": "Amit",
"Mobile number": "8899665544",
Gender: "Male",
DOB: "03-03-1992",
"Type of User": "Admin",
Language: "Gujarati",
Status: "Inactive",
Action: "Edit/Delete",
},
{
"Sr. No": 5,
"First Name": "Amit",
"Mobile number": "8899665544",
Gender: "Male",
DOB: "03-03-1992",
"Type of User": "Admin",
Language: "Gujarati",
Status: "Inactive",
Action: "Edit/Delete",
},
{
"Sr. No": 6,
"First Name": "Amit",
"Mobile number": "8899665544",
Gender: "Male",
DOB: "03-03-1992",
"Type of User": "Admin",
Language: "Gujarati",
Status: "Inactive",
Action: "Edit/Delete",
},
{
"Sr. No": 7,
"First Name": "Amit",
"Mobile number": "8899665544",
Gender: "Male",
DOB: "03-03-1992",
"Type of User": "Admin",
Language: "Gujarati",
Status: "Inactive",
Action: "Edit/Delete",
},
{
"Sr. No": 8,
"First Name": "Amit",
"Mobile number": "8899665544",
Gender: "Male",
DOB: "03-03-1992",
"Type of User": "Admin",
Language: "Gujarati",
Status: "Inactive",
Action: "Edit/Delete",
},
{
"Sr. No": 9,
"First Name": "Amit",
"Mobile number": "8899665544",
Gender: "Male",
DOB: "03-03-1992",
"Type of User": "Admin",
Language: "Gujarati",
Status: "Inactive",
Action: "Edit/Delete",
},
{
"Sr. No": 10,
"First Name": "Amit",
"Mobile number": "8899665544",
Gender: "Male",
DOB: "03-03-1992",
"Type of User": "Admin",
Language: "Gujarati",
Status: "Inactive",
Action: "Edit/Delete",
},
{
"Sr. No": 11,
"First Name": "Amit",
"Mobile number": "8899665544",
Gender: "Male",
DOB: "03-03-1992",
"Type of User": "Admin",
Language: "Gujarati",
Status: "Inactive",
Action: "Edit/Delete",
},
{
"Sr. No": 12,
"First Name": "Amit",
"Mobile number": "8899665544",
Gender: "Male",
DOB: "03-03-1992",
"Type of User": "Admin",
Language: "Gujarati",
Status: "Inactive",
Action: "Edit/Delete",
},
{
"Sr. No": 13,
"First Name": "Amit",
"Mobile number": "8899665544",
Gender: "Male",
DOB: "03-03-1992",
"Type of User": "Admin",
Language: "Gujarati",
Status: "Inactive",
Action: "Edit/Delete",
},
];
const RegisterUsers = () => {
return (
<MainFrame>
<HStack w={"100%"} justifyContent={"space-between"} p={3}>
<Text as={"span"} fontSize={"sm"} fontWeight={"bolder"} color={"#000"}>
Register User
</Text>
<Box w={"30%"}>
<InputGroup
bgSize={"xs"}
flex="1"
startElement={<LuSearch />}
w={"100%"}
color={"#000"}
>
<Input
w={"100%"}
bg={"#EEEEEE"}
_focus={{ border: "1px #02A0A0 solid" }}
border={"1px #EEEEEE solid"}
rounded={"full"}
size={"sm"}
placeholder="Search..."
/>
</InputGroup>
</Box>
</HStack>
<DataTable tableHeadRow={tableHeadRow} data={usersData} />
</MainFrame>
);
};
export default RegisterUsers;

View File

@@ -1,129 +1,37 @@
import { Box, HStack, Text } from "@chakra-ui/react";
import { Box, HStack, Input, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame";
import DataTable from "../../../components/DataTable";
import { Switch } from "../../../components/ui/switch";
// import { InputGroup } from "../../../components/ui/input-group";
// import { LuSearch } from "react-icons/lu";
// import { useGetContactQuery } from "../../../Redux/Service/deactivated.account.service";
import { useEffect, useState } from "react";
import { Spinner } from "../../../components/Sipnner/Spinner";
import { useGetDeactivateUserQuery, useUserDeactivateToggleMutation } from "../../../Redux/Service/manage.user";
import SearchComponent from "../../../components/SearchComponent";
import { Toaster, toaster } from "../../../components/ui/toaster";
import { delay } from "../../../components/Utils";
import { InputGroup } from "../../../components/ui/input-group";
import { LuSearch } from "react-icons/lu";
const tableHeadRow = [
"Sr. No",
"First Name",
"Last Name",
"User Type",
"Company name",
"Activate/Deactivate",
];
const DeactivatedAccounts = () => {
const [currentPage, setCurrentPage] = useState(1);
const { data, isLoading, refetch, isError, isFetching } = useGetDeactivateUserQuery(currentPage);
const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const [userDeactivateToggle] = useUserDeactivateToggleMutation()
useEffect(() => {
if (data) {
setLocalData((data as any)?.data?.data || []);
}
}, [data]);
const handlePageChange = (page: number) => {
setCurrentPage(page);
}
const filteredData = localData?.filter((agency) => {
const searchLower = searchTerm.toLowerCase();
const firstName = agency.first_name?.toLowerCase().includes(searchLower);
const lastName = agency.last_name?.toLowerCase().includes(searchLower);
// const email = agency.capital?.toLowerCase().includes(searchLower);
return firstName || lastName;
});
const handleToggle = async (agencyId: number, currentStatus: string) => {
const newStatus = currentStatus === '1' ? '0' : '1';
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
)
);
try {
await userDeactivateToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch()
} catch (error) {
console.error("Error updating privacy policy:", error);
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
)
);
}
}
const manageUser = filteredData?.map((agency: any, index: number) => ({
"Sr. No": index + 1,
"First Name": agency?.first_name,
"Last Name": agency?.last_name,
"User Type": agency?.principal_type_xid === 3 ? "JobSeeker" : "Recruiter",
const manageUser: any[] = [
...Array.from({ length: 12 }, (_, i) => ({
"Sr. No": i + 1,
"First Name": "Ritesh",
"Last Name": "akanksha@gmail.com",
"Company name": "9876543210",
"Activate/Deactivate": (
<Box display={"flex"} justifyContent={"center"}>
<Switch
size={"sm"}
colorPalette={"teal"}
checked={agency.is_active === true}
onChange={() => handleToggle(agency.id, agency.is_active ? "1" : "0")}
/>
<Box display={'flex'} justifyContent={'center'}>
<Switch colorPalette={'teal'} />
</Box>
),
}));
if (isLoading) {
return (
<MainFrame>
<Box
display="flex"
justifyContent="center"
alignItems="center"
height="100%"
>
<Spinner />
</Box>
</MainFrame>
);
}
// if (isError) {
// return (
// <MainFrame>
// <Box
// display="flex"
// justifyContent="center"
// alignItems="center"
// height="100%"
// >
// <Text>Error loading data</Text>
// </Box>
// </MainFrame>
// );
// }
})),
];
const DeactivatedAccounts = () => {
return (
<MainFrame>
<Box>
<HStack
<HStack
w={"100%"}
justifyContent={"space-between"}
mb={4}
@@ -131,36 +39,38 @@ const DeactivatedAccounts = () => {
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
Deactivated User Accounts
Deactivated User Accounts
</Text>
<HStack>
<SearchComponent
value={searchTerm}
onChange={(value) => {
setSearchTerm(value);
// setCurrentPage(1);
refetch()
}}
/>
<InputGroup
startElement={
<LuSearch fontSize={"xs"} style={{position:'relative',left:'10px'}} />
}
color={"#000"}
>
<Input
p={4}
w={300}
bg={"#fff"}
colorPalette={"blue"}
_focus={{ border: "1px solid #02A0A0" }}
rounded={"md"}
size={"2xs"}
fontSize={"2sm"}
placeholder="Search..."
bgColor={'#EEEEEE'}
ps={8}
/>
</InputGroup>
</HStack>
</HStack>
<DataTable
sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow}
data={manageUser}
paginationData={{
current_page: data?.data.current_page || 1,
last_page: data?.data.last_page || 1,
per_page: data?.data.per_page || 10,
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
<Toaster />
</MainFrame>
);
};

View File

@@ -1,4 +1,4 @@
import { Box, Field, Input, Stack } from "@chakra-ui/react";
import { Field, Input, Stack } from "@chakra-ui/react";
import {
DialogActionTrigger,
DialogBody,
@@ -12,32 +12,8 @@ import {
} from "../../../components/ui/dialog";
import { Button } from "../../../components/ui/button";
import { IoMdAdd } from "react-icons/io";
import { useState } from "react";
// import { useCreateUserMutation } from "../../../Redux/Service/manage.user";
// import { useState } from "react";
function AddRegisterUsers() {
// const [createUser] = useCreateUserMutation();
const [userType, setUserType] = useState<number | "">("");
const [user, setUser] = useState<{
principal_type_xid: number;
principal_source_xid: number | "";
first_name: string;
last_name: string;
gender: string;
date_of_birth: string;
language_name: string[];
}>({
principal_type_xid: 1,
principal_source_xid: userType,
first_name: '',
last_name: '',
gender: '',
date_of_birth: '',
language_name: [],
});
return (
<DialogRoot placement="center">
<DialogTrigger asChild>
@@ -47,13 +23,13 @@ function AddRegisterUsers() {
</DialogTrigger>
<DialogContent
bg={"#fff"}
w={{ base: '90%', md: '400px' }}
height={'80vh'}
overflow={'scroll'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
bg={"#fff"}
w={{ base: '90%', md: '400px' }}
height={'80vh'}
overflow={'scroll'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">
@@ -68,110 +44,42 @@ function AddRegisterUsers() {
First Name
</Field.Label>
<Input
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={user.first_name}
onChange={(e) => setUser({ ...user, first_name: e.target.value })}
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
Last Name
</Field.Label>
<Input
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={user.last_name}
onChange={(e) => setUser({ ...user, last_name: e.target.value })}
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
Gender
</Field.Label>
<Input
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={user.gender}
onChange={(e) => setUser({ ...user, gender: e.target.value })}
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
DOB
</Field.Label>
<Input
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
type="date"
value={user.date_of_birth}
onChange={(e) => setUser({ ...user, date_of_birth: e.target.value })}
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
/>
<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.Label color="black" pt={1} fontSize="12px">
<Field.Label color="black" pt={1} fontSize="12px">
OTP Verified
</Field.Label>
<Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
/> */}
/>
<Field.Label color="black" pt={1} fontSize="12px">
Language
</Field.Label>
<Input
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={user.language_name.join(", ")} // display as comma-separated string
onChange={(e) =>
setUser({
...user,
language_name: e.target.value
.split(",")
.map(lang => lang.trim())
.filter(Boolean), // remove empty strings
})
}
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
/>
</Field.Root>
</Stack>

View File

@@ -1,6 +1,7 @@
// import { MdOutlineRemoveRedEye } from "react-icons/md";
import { Box, Field, HStack, Input, Stack } from "@chakra-ui/react";
import { MdOutlineRemoveRedEye } from "react-icons/md";
import { Field, Input, Stack } from "@chakra-ui/react";
import {
DialogActionTrigger,
DialogBody,
DialogCloseTrigger,
DialogContent,
@@ -10,336 +11,86 @@ 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 Edit from "../../../components/ActionIcons/Edit";
import { UserData, useUpdateUserMutation } from "../../../Redux/Service/manage.user";
import { useState } from "react";
import { Toaster, toaster } from "../../../components/ui/toaster";
interface UserPayload {
id: number;
principal_type_xid: number;
principal_source_xid: number;
first_name: string;
last_name: string;
gender: string;
date_of_birth: string | null;
language_xid: number; // ✅ Always an array
}
export interface UserFormData {
id: number;
principal_type_xid: number;
first_name: string;
last_name: string;
phone_number: string;
gender: string;
date_of_birth: string;
is_active: boolean;
principal_type: {
id: number;
principal_type_title: string;
};
principle_language_linkss: {
id?: number;
iam_principal_xid?: number;
language_xid: number;
};
}
function EditRegisterUsers({ data, refetch }: { data: UserData, refetch: () => void }) {
const [isOpen, setIsOpen] = useState(false);
const transformToFormData = (data: UserData): UserFormData => ({
...data,
principle_language_linkss: {
...data.principle_language_linkss,
language_xid: data.principle_language_linkss.language_xid, // wrap in array
},
});
const [formData, setFormData] = useState<UserFormData>(transformToFormData(data));
// const [formData, setFormData] = useState<UserData>({
// id: data?.id,
// first_name: data?.first_name || '',
// last_name: data?.last_name || '',
// principal_type_xid: data?.principal_type_xid,
// phone_number: data?.phone_number || '',
// gender: data?.gender || '',
// date_of_birth: data?.date_of_birth || '',
// principal_type: data?.principal_type,
// is_active: data?.is_active ?? true,
// principle_language_linkss: {
// ...data?.principle_language_linkss,
// language_xid: Array.isArray(data?.principle_language_linkss?.language_xid)
// ? data.principle_language_linkss.language_xid
// : [data?.principle_language_linkss?.language_xid].filter(Boolean),
// },
// // principle_language_linkss: data?.principle_language_linkss ?? [],
// });
const [updateUser, { isLoading }] = useUpdateUserMutation();
const handleOpenModal = () => {
setIsOpen(true);
};
const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
if (formData.first_name === '' || formData.last_name === '' || formData.phone_number === '' || formData.gender === '' || formData.date_of_birth === '') {
toaster.create({
title: "Error",
description: "Input fields cannot be empty",
type: "error",
});
return;
}
// const languageData = formData?.principle_language_linkss?.language_xid;
const payload: UserPayload = {
id: formData?.id,
principal_type_xid: formData?.principal_type_xid,
principal_source_xid: formData?.id,
first_name: formData?.first_name,
last_name: formData?.last_name,
gender: formData?.gender,
date_of_birth: formData?.date_of_birth,
// language_xid: languageData,
language_xid: formData.principle_language_linkss?.language_xid
? formData.principle_language_linkss.language_xid
: formData.principle_language_linkss?.language_xid,
};
// console.log('payload', payload)
try {
const response = await updateUser(payload).unwrap();
if (response?.status === "success") {
toaster.create({
title: "Success",
description: "Country updated successfully",
type: "success",
});
setIsOpen(false);
refetch()
} else {
toaster.create({
title: "Error",
description: "Failed to update Country",
type: "error",
});
}
} catch (error: any) {
console.error("Error updating template:", error);
// alert("Failed to update template");
toaster.create({
title: "Error",
description: error ? `${error?.data.message}` : "Something went wrong",
type: "error",
});
}
};
function EditRegisterUsers() {
return (
<>
<DialogRoot placement="center" key={formData.id} open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogTrigger asChild>
{/* <Span>
<Edit />
</Span> */}
<Button bg="transparent" color={"black"} h={"18px"} onClick={handleOpenModal}><Edit /></Button>
</DialogTrigger>
<DialogRoot placement="center">
<DialogTrigger asChild>
<BiEdit style={{ cursor: "pointer", fontSize: "16px" }} />
</DialogTrigger>
<DialogContent
bg={"#fff"}
w={{ base: "90%", md: "400px" }}
height={"80vh"}
overflow={"scroll"}
overflowX="hidden"
p={3} // Reduced padding
bgSize={"md"}
>
<DialogHeader bg="white" p={0}>
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit user Accounts
</DialogTitle>
</DialogHeader>
<DialogContent
bg={"#fff"}
w={{ base: '90%', md: '400px' }}
height={'80vh'}
overflow={'scroll'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" p={0}>
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit user Accounts
</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
First Name
</Field.Label>
<Input
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={formData.first_name}
onChange={(e) => setFormData({ ...formData, first_name: e.target.value })}
/>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
First Name
</Field.Label>
<Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
Last Name
</Field.Label>
<Input
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={formData.last_name}
onChange={(e) => setFormData({ ...formData, last_name: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px">
Last Name
</Field.Label>
<Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
Gender
</Field.Label>
<Input
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={formData.gender}
onChange={(e) => setFormData({ ...formData, gender: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px">
Gender
</Field.Label>
<Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
DOB
</Field.Label>
<Input
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={formData.date_of_birth ? new Date(formData.date_of_birth).toLocaleDateString('en-GB').replace(/\//g, '-') : 'N/A'}
onChange={(e) => setFormData({ ...formData, date_of_birth: e.target.value })}
disabled={formData.principal_type_xid === 2 ? true : false}
/>
<Field.Label color="black" pt={1} fontSize="12px">
DOB
</Field.Label>
<Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
Mobile Number
</Field.Label>
<Input
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={formData.phone_number || ''}
onChange={(e) => setFormData({ ...formData, phone_number: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px">
OTP Verified
</Field.Label>
<Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
Type Of User
</Field.Label>
{/* <Input
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={formData.principal_type?.principal_type_title || 'N/A'}
onChange={(e) => setFormData({ ...formData, principal_type: { ...formData.principal_type, principal_type_title: e.target.value } })}
/> */}
<Box>
<select
style={{
width: "100%",
background: "transparent",
color: "black",
border: "none",
fontSize: "12px",
height: "30px",
outline: "none",
}}
value={formData.principal_type_xid?.toString() || 'N/A'}
onChange={(e) => setFormData({ ...formData, principal_type_xid: Number(e.target.value) })}
>
{/* <option value="">Select User Type</option> */}
<option value="2">Recruiter</option>
<option value="3">Jobseeker</option>
</select>
</Box>
<Field.Label color="black" pt={1} fontSize="12px">
Default Language
</Field.Label>
{/* <Input
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={formData?.principle_language_linkss?.language_xid || 'N/A'}
onChange={(e) => setFormData({
...formData, principle_language_linkss: {
...formData?.principle_language_linkss, language_xid: e.target.value
.split(",")
.map(lang => lang.trim())
.filter(Boolean)
}
})}
/> */}
<HStack>
<select
style={{
width: "100%",
background: "transparent",
color: "black",
border: "none",
fontSize: "12px",
height: "30px",
outline: "none",
}}
value={formData?.principle_language_linkss?.language_xid || ""}
onChange={(e) => {
const value = Number(e.target.value);
setFormData({
...formData,
principle_language_linkss: {
...formData?.principle_language_linkss,
language_xid: value,
},
});
}}
>
<option value="1">English</option>
<option value="2">Hindi</option>
<option value="3">Marathi</option>
<option value="4">Telgu</option>
<option value="5">Tamil</option>
<option value="6">Bengali</option>
<option value="7">Odia</option>
</select>
</HStack>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter mt={5}>
<Button rounded={"md"} w={"100%"} size={"sm"} bg={"#02A0A0"} onClick={handleSubmit} disabled={isLoading}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
<Toaster />
</>
<Field.Label color="black" pt={1} fontSize="12px">
Language
</Field.Label>
<Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter mt={5}>
<DialogActionTrigger asChild>
<Button rounded={'md'} w={"100%"} size={'sm'} bg={'#02A0A0'}>Save</Button>
</DialogActionTrigger>
</DialogFooter>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot>
);
}

View File

@@ -1,204 +1,65 @@
import {
Box, HStack,
Image,
// Image,
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 AlertDailog from "../../../components/AlertDailog";
import { NavLink } from "react-router-dom";
import { RiDeleteBin5Line } from "react-icons/ri";
import DataTable from "../../../components/DataTable";
import { Switch } from "../../../components/ui/switch";
import { InputGroup } from "../../../components/ui/input-group";
import { LuSearch } from "react-icons/lu";
import { BiEdit } from "react-icons/bi";
import ViewRegisterUsers from "./ViewRegisterUsers";
import EditRegisterUsers from "./EditRegisterUsers";
// import AddRegisterUsers from "./AddRegisterUsers";
import { useEffect, useState } from "react";
import { useDeleteUserMutation, useGetManageUserQuery, UserData, useUserToggleMutation } from "../../../Redux/Service/manage.user";
import SearchComponent from "../../../components/SearchComponent";
import AlertDailog from "../../../components/AlertDailog";
import { toaster } from "../../../components/ui/toaster";
import Delete from "../../../components/ActionIcons/Delete";
import { delay } from "../../../components/Utils";
// import Delete from "../../../components/ActionIcons/Delete";
import { Button } from "../../../components/ui/button";
import { IoMdAdd } from "react-icons/io";
import AddRegisterUsers from "./AddRegisterUsers";
const tableHeadRow = [
"Sr. No",
"First Name",
"Last Name",
"Mobile Number",
"Gender",
"DOB",
"Type Of User",
"Default Language",
"Active/Deactive",
"Language",
"Activate/Deactivate",
"Action",
];
// const registerUser: any[] = [
// ...Array.from({ length: 12 }, (_, i) => ({
// "Sr. No": i + 1,
// "First Name": "Ritesh",
// "Mobile Number": "akanksha@gmail.com",
// "Gender": "9876543210",
// "DOB": "Female",
// "Type Of User": "15-01-1990",
// "Language": "Mumbai",
// "Activate/Deactivate": (
// <Box>
// <Switch size={'sm'} colorPalette={'teal'} />
// </Box>
// ),
// "Action": (
// <HStack justifyContent="center">
// <ViewRegisterUsers />
// <EditRegisterUsers />
// {/* <RiDeleteBin5Line style={{ cursor: "pointer" }} /> */}
// {/* <AlertDailog
// AltertTiggerIcon={() =><Delete /> } // Pass as function
// alertText="Delete Users"
// alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
// alertCaption="Are You Sure You Want To Delete This User ?"
// onConfirm={() => {
// console.log("User deleted:", i + 1);
// }}
// /> */}
// </HStack>
// ),
// })),
// ];
const RegisterUsers = () => {
const [currentPage, setCurrentPage] = useState(1);
const { data, refetch, isFetching, isError } = useGetManageUserQuery(currentPage)
const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const [userToggle] = useUserToggleMutation()
const [deleteFaqPost] = useDeleteUserMutation()
const [deleteModal, setDeleteModal] = useState(false)
const [selectedFaqId, setSelectedFaqId] = useState<number | null>(null);
console.log("Register Users Data", data?.data.data);
useEffect(() => {
if (data) {
setLocalData(data?.data.data);
}
}, [data]);
const handlePageChange = (page: number) => {
setCurrentPage(page);
}
const filteredData = localData?.filter((agency) => {
const searchLower = searchTerm.toLowerCase();
const firstName = agency.first_name?.toLowerCase().includes(searchLower);
// const email = agency.capital?.toLowerCase().includes(searchLower);
return firstName;
});
const handleToggle = async (agencyId: number, currentStatus: string) => {
const newStatus = currentStatus === '1' ? '0' : '1';
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
)
);
try {
await userToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch()
} catch (error) {
console.error("Error updating privacy policy:", error);
toaster.create({
title: "Error",
description: "Someting went wrong.",
type: "error",
});
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
)
);
}
}
const handleDeleteFaq = async (faqId: number) => {
try {
const response = await deleteFaqPost({ id: faqId }).unwrap();
if (response?.status === "success") {
toaster.create({
title: "Success",
description: "User deleted successfully",
type: "success",
});
refetch()
console.log("User deleted successfully:", response);
}
// Optionally, refetch data or update state after deletion
} catch (error) {
console.error("Error deleting User:", error);
toaster.create({
title: "Error",
description: "Something went wrong",
type: "error",
});
}
};
const managepost = filteredData?.flatMap((agency: UserData, index: number) => ({
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
"First Name": agency.first_name,
"Last Name": agency.last_name,
"Mobile Number": agency.phone_number,
"Gender": agency.gender,
"DOB": agency.date_of_birth ? new Date(agency.date_of_birth).toLocaleDateString('en-GB').replace(/\//g, '-') : 'N/A',
"Type Of User": agency.principal_type?.principal_type_title || 'N/A',
"Default Language": agency?.principle_language_linkss?.language?.language_name,
"Active/Deactive": agency.is_active === true ? 'Active' : 'Inactive',
const registerUser: any[] = [
...Array.from({ length: 12 }, (_, i) => ({
"Sr. No": i + 1,
"First Name": "Ritesh",
"Mobile Number": "akanksha@gmail.com",
"Gender": "9876543210",
"DOB": "Female",
"Type Of User": "15-01-1990",
"Language": "Mumbai",
"Activate/Deactivate": (
<Box>
<Switch colorPalette={'teal'} />
</Box>
),
"Action": (
<HStack justifyContent="center">
<EditRegisterUsers
data={agency}
refetch={refetch}
/>
<ViewRegisterUsers data={agency} />
<Box>
<Switch
colorPalette={'teal'}
size={"xs"}
checked={agency.is_active === true}
onChange={() => handleToggle(agency.id, agency.is_active ? '1' : '0')}
/>
</Box>
<HStack justifyContent="center">
<ViewRegisterUsers />
<EditRegisterUsers />
{/* <RiDeleteBin5Line style={{ cursor: "pointer" }} /> */}
<AlertDailog
isOpen={deleteModal}
AltertTiggerIcon={() => <Delete onClick={() => {
setSelectedFaqId(agency.id);
setDeleteModal(true)
}} />}
alertText="Do you want to delete user?"
AltertTiggerIcon={RiDeleteBin5Line}
alertText="Delete Users"
alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
alertCaption="are you sure you want to delete ?"
onClose={() => setDeleteModal(false)}
alertCaption="Are You Sure You Want To Delete This User ?"
onConfirm={() => {
// console.log("Deleting FAQ with ID:", selectedFaqId); // Correct ID
if (selectedFaqId) {
setDeleteModal(false);
handleDeleteFaq(selectedFaqId);
}
console.log("User deleted:", i + 1);
}}
/>
</HStack>
),
}))
})),
];
const RegisterUsers = () => {
return (
<MainFrame>
<Box>
@@ -214,30 +75,33 @@ const RegisterUsers = () => {
</Text>
<HStack>
<SearchComponent
value={searchTerm}
onChange={(value) => {
setSearchTerm(value);
// setCurrentPage(1);
refetch()
}}
/>
{/* <AddRegisterUsers /> */}
<InputGroup
startElement={
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
}
color={"#000"}
>
<Input
p={3}
w={300}
bg={"#fff"}
colorPalette={"blue"}
_focus={{ border: "1px solid #02A0A0" }}
rounded={"md"}
size={"2xs"}
fontSize={"2sm"}
placeholder="Search..."
bgColor={'#EEEEEE'}
ps={8}
/>
</InputGroup>
<AddRegisterUsers />
</HStack>
</HStack>
<DataTable
sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow}
data={managepost}
paginationData={{
current_page: data?.data.current_page || 1,
last_page: data?.data.last_page || 1,
per_page: data?.data.per_page || 10,
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
data={registerUser}
/>
</Box>
</MainFrame>

View File

@@ -1,5 +1,5 @@
import { Field, Input, Span, Stack } from "@chakra-ui/react";
import View from "../../../components/ActionIcons/View";
import { MdOutlineRemoveRedEye } from "react-icons/md";
import { Field, Input, Stack } from "@chakra-ui/react";
import {
DialogBody,
DialogCloseTrigger,
@@ -9,23 +9,25 @@ import {
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import { UserData } from "../../../Redux/Service/manage.user";
function ViewRegisterUsers({ data }: { data: UserData }) {
function ViewRegisterUsers() {
return (
<DialogRoot placement="center">
<DialogTrigger asChild>
<Span><View /></Span>
<MdOutlineRemoveRedEye
color="#000"
style={{ cursor: "pointer", fontSize: "16px" }}
/>
</DialogTrigger>
<DialogContent
bg={"#fff"}
w={{ base: '90%', md: '400px' }}
height={'80vh'}
overflow={'scroll'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
bg={"#fff"}
w={{ base: '90%', md: '400px' }}
height={'80vh'}
overflow={'scroll'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
@@ -40,24 +42,14 @@ function ViewRegisterUsers({ data }: { data: UserData }) {
First Name
</Field.Label>
<Input
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.first_name || ''}
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
Last Name
</Field.Label>
<Input
bgColor="#EEEEEE"
color="black"
border="none" pl={1}
fontSize="12px" height="30px"
value={data?.last_name || ''}
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
@@ -65,7 +57,6 @@ function ViewRegisterUsers({ data }: { data: UserData }) {
</Field.Label>
<Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
value={data?.gender || ''}
/>
<Field.Label color="black" pt={1} fontSize="12px">
@@ -73,41 +64,20 @@ function ViewRegisterUsers({ data }: { data: UserData }) {
</Field.Label>
<Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
value={data?.date_of_birth ? new Date(data.date_of_birth).toLocaleDateString('en-GB').replace(/\//g, '-') : 'N/A'}
/>
<Field.Label color="black" pt={1} fontSize="12px">
Mobile Number
</Field.Label>
<Input
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.phone_number || ''}
/>
<Field.Label color="black" pt={1} fontSize="12px">
Type Of User
</Field.Label>
<Input
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.principal_type?.principal_type_title || 'N/A'}
/>
<Field.Label color="black" pt={1} fontSize="12px">
Default Language
OTP Verified
</Field.Label>
<Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
/>
<Field.Label color="black" pt={1} fontSize="12px">
Language
</Field.Label>
<Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
value={data?.principle_language_linkss?.language?.language_name || 'N/A'}
/>
</Field.Root>
</Stack>

View File

@@ -1,16 +1,13 @@
import { Box, HStack, Text } from "@chakra-ui/react";
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame"
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 EditAgencyMaster from "./EditAgencyMaster";
// import ViewAgencyAddModel from "./ViewAgencyAddModel";
import ViewAgencyAddModel from "./ViewAgencyAddModel";
import ViewAgencyMaster from "./ViewAgencyMaster";
import { useAgencyMasterToggleMutation, useGetAgencyMasterQuery } from "../../../Redux/Service/agency.master.module.service";
import { useEffect, useState } from "react";
import SearchComponent from "../../../components/SearchComponent";
import { useDebounce } from "../../../components/Hooks/useDebounce";
import { toaster, Toaster } from "../../../components/ui/toaster";
import { delay } from "../../../components/Utils";
// table data
@@ -23,139 +20,33 @@ const tableHeadRow = [
"Registered Office Address",
"Website/Domain",
"GST no.",
"Agency Status",
"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",
// "Action": (
// <HStack justifyContent="center">
// <ViewAgencyMaster/>
// <EditAgencyMaster />
// <Box>
// <Switch colorPalette={'teal'} size={"xs"}/>
// </Box>
// </HStack>
// ),
// })),
// ];
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 [currentPage, setCurrentPage] = useState(1);
const [agencyMasterToggle] = useAgencyMasterToggleMutation()
const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = useDebounce(searchTerm, 500);
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
const { data, refetch, isError, isFetching } = useGetAgencyMasterQuery(queryArgs)
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();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch()
} catch (error) {
console.error("Error updating privacy policy:", error);
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
)
);
toaster.create({
title: "Error",
description: "Please try again later",
type: "error",
});
}
};
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
const filteredData = localData?.filter((agency) =>
agency?.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
agency?.rc_number.toLowerCase().includes(searchTerm.toLowerCase()) ||
agency?.state.toLowerCase().includes(searchTerm.toLowerCase()) ||
agency?.registered_office.toLowerCase().includes(searchTerm.toLowerCase()) ||
agency?.domain_name.toLowerCase().includes(searchTerm.toLowerCase()) ||
agency?.gst_number.toLowerCase().includes(searchTerm.toLowerCase())
);
// const activeCount = filteredData?.filter((a: any) => a.is_active === 1).length ?? 0;
const managepost = filteredData?.map((agency: any, index: number) => {
// const isOnlyActive = activeCount === 1 && agency.is_active === 1;
return {
id: agency.id,
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + 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,
"Agency Status": agency.is_domain_verified ? "Verified" : "Unverified",
"is_active": agency.is_active,
Action: (
<HStack justifyContent="center">
<ViewAgencyMaster agency={localData} id={agency.id} />
<EditAgencyMaster editData={agency} refetch={refetch} />
<Box>
<Switch
colorPalette={"teal"}
size={"xs"}
onChange={() => handleToggle(agency.id.toString(), Number(agency.is_active))}
checked={Boolean(Number(agency.is_active))}
// disabled={isOnlyActive}
/>
</Box>
</HStack>
),
};
});
useEffect(() => {
if (data?.data?.data) {
setLocalData(data?.data?.data);
}
}, [data, localData, managepost]);
// useEffect(() => {
// console.log("Fetched data:", data);
// console.log("Local data:", localData);
// console.log("Managepost data:", managepost);
// }, [data, localData, managepost]);
return (
<MainFrame>
@@ -168,11 +59,11 @@ const AgencyMaster = () => {
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
Agency Master
Agency Master
</Text>
<HStack >
{/* <InputGroup
<HStack mr={5}>
<InputGroup marginRight={"1rem"}
startElement={
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
}
@@ -185,36 +76,23 @@ const AgencyMaster = () => {
colorPalette={"blue"}
_focus={{ border: "1px solid #02A0A0" }}
rounded={"md"}
size={"xs"}
fontSize={"sm"}
size={"2xs"}
fontSize={"2sm"}
placeholder="Search..."
bgColor={'#EEEEEE'}
ps={8}
/>
</InputGroup> */}
<SearchComponent
value={searchTerm}
onChange={handleSearchChange}
/>
{/* <ViewAgencyAddModel refetch={refetch} /> */}
</InputGroup>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
<ViewAgencyAddModel />
</HStack>
</HStack>
<DataTable
sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow}
data={managepost || []}
paginationData={{
current_page: data?.data.current_page || 1,
last_page: data?.data.last_page || 1,
per_page: data?.data.per_page || 10,
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
data={managepost}
/>
</Box>
<Toaster />
</Box>
</MainFrame>
)
}

View File

@@ -1,283 +1,75 @@
import { Button } from "../../../components/ui/button";
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import { Field, Input, Stack } from "@chakra-ui/react";
import Edit from "../../../components/ActionIcons/Edit";
import { useEffect, useState } from "react";
import { useUpdateAgencyMasterMutation } from "../../../Redux/Service/agency.master.module.service";
import { Toaster, toaster } from "../../../components/ui/toaster";
// interface Organization {
// id: number;
// raid?: string;
// name: string;
// auth_signatory?: string;
// state: string;
// district?: string;
// rc_number: number;
// contact_details?: string;
// registered_office: string;
// branch_office?: string;
// registered_email?: string;
// other_email?: string;
// registered_contact?: string;
// website?: string;
// domain_name: string;
// staff_domain_name?: string;
// gst_number: string;
// rc_status?: "Active" | "Inactive"; // Assuming it's a status with limited values
// }
type AgencyFormData = {
id: string;
name: string;
state: string;
rc_number: string;
registered_office: string;
domain_name: string;
gst_number: string;
};
import { FaRegEdit } from "react-icons/fa"
import { Button } from "../../../components/ui/button"
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Field, Input, Stack, } from "@chakra-ui/react"
function EditAgencyMaster() {
return (
function EditAgencyMaster<T extends AgencyFormData>({ editData, refetch }: { editData: T, refetch: VoidFunction }) {
const [formData, setFormData] = useState(editData);
const [isOpen, setIsOpen] = useState(false);
const [updateAgencyMaster, { isLoading }] = useUpdateAgencyMasterMutation()
<DialogRoot placement="center">
<DialogTrigger asChild>
<Button bg={"transparent"} size="sm">
<FaRegEdit style={{ cursor: "pointer", fontSize: "14px" }} color="#000"/>
</Button>
</DialogTrigger>
console.log("Edit Data", editData);
useEffect(() => {
setFormData(editData);
}, [editData]);
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
const handleOpenModal = () => {
setIsOpen(true);
};
height={'80vh'}
overflow={'scroll'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">Edit</DialogTitle>
</DialogHeader>
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormData((prev: any) => ({
...prev,
[name]: value,
}));
}
<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" />
const handleSubmit = async () => {
// console.log("Updated Data:", formData);
if (!formData.name.trim() ||
!formData.rc_number ||
!formData.state.trim() ||
!formData.registered_office.trim() ||
!formData.domain_name.trim() ||
!formData.gst_number.trim()) {
// console.log("Validation failed: Some fields are empty.");
toaster.create({
title: "Error",
description: "Input fields cannot be empty",
type: "error",
});
return;
}
setIsOpen(false);
// Handle API call or further processing here
const payload = {
id: formData?.id,
name: formData?.name,
state: formData?.state,
rc_number: formData?.rc_number,
registered_office: formData?.registered_office,
domain_name: formData?.domain_name,
gst_number:formData?.gst_number,
};
<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" />
try {
const response = await updateAgencyMaster(payload).unwrap();
if (response?.status === "success") {
toaster.create({
title: "Success",
description: "Data updated successfully",
type: "success",
});
refetch()
setIsOpen(false);
} else {
toaster.create({
title: "Error",
description: "Failed to update",
type: "error",
});
}
} catch (error: any) {
console.error("Error updating template:", error);
toaster.create({
title: "Error",
description: `${error.data.message || "Failed to update"}`,
type: "error",
});
// alert("Failed to update template");
}
};
<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" />
return (
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogTrigger asChild>
<Button bg="transparent" color={"black"} h={"18px"} onClick={handleOpenModal}><Edit /></Button>
</DialogTrigger>
<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">Website/Domain</Field.Label>
<Input value="Lorem Ipsum" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: "90%", md: "400px" }}
height={"80vh"}
overflow={"scroll"}
overflowX="hidden"
p={3} // Reduced padding
bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit
</DialogTitle>
</DialogHeader>
<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">Action</Field.Label>
<Input value="Lorem Ipsum" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Agency name
</Field.Label>
<Input
name="name"
value={formData?.name}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={handleChange}
/>
<Field.Label color="black" pt={1} fontSize="12px">
RC No.
</Field.Label>
<Input
name='rc_number'
value={formData.rc_number}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={handleChange}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} fontSize="12px" height="30px">
Save
</Button>
</DialogFooter>
<Field.Label color="black" pt={1} fontSize="12px">
State
</Field.Label>
<Input
name="state"
value={formData.state}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={handleChange}
/>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot>
<Field.Label color="black" pt={1} fontSize="12px">
Registered Office Address
</Field.Label>
<Input
name="registered_office"
value={formData.registered_office}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={handleChange}
/>
<Field.Label color="black" pt={1} fontSize="12px">
Website/Domain
</Field.Label>
<Input
name="domain_name"
value={formData.domain_name}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={handleChange}
/>
<Field.Label color="black" pt={1} fontSize="12px">
GST no.
</Field.Label>
<Input
name="gst_number"
value={formData.gst_number}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={handleChange}
/>
{/* <Field.Label color="black" pt={1} fontSize="12px">
RC Status
</Field.Label>
<Input
value={formData.rc_status}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={handleChange}
/> */}
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button
w="100%"
bg="#02A0A0"
color={"#fff"}
fontSize="12px"
height="30px"
onClick={handleSubmit}
disabled={isLoading}
>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
<Toaster />
</DialogRoot>
);
)
}
export default EditAgencyMaster;
export default EditAgencyMaster

View File

@@ -1,100 +1,31 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Field, Input, Stack, Text } from "@chakra-ui/react"
import { Field, Input, Stack, Text, Textarea } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button"
import { AgencyPost, useCreateAgencyMasterPostMutation } from "../../../Redux/Service/agency.master.module.service"
import { useState } from "react"
import { Toaster, toaster } from "../../../components/ui/toaster"
function ViewAgencyAddModel({ refetch }: { refetch: VoidFunction }) {
const [formData, setFormData] = useState<AgencyPost>({
name: "",
rc_number: "",
state: "",
registered_office: "",
domain_name: "",
gst_number: "",
});
const [isOpen, setIsOpen] = useState(false);
const [createAgencyMasterPost] = useCreateAgencyMasterPostMutation()
const handleOpenModal = () => {
setIsOpen(true); // Open modal when clicking "Add"
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormData((prev: any) => ({
...prev,
[name]: value,
}));
}
const handleSubmit = async () => {
console.log("New Data:", formData);
const requiredFields: (keyof AgencyPost)[] = ["name", "rc_number", "state", "registered_office", "domain_name", "gst_number"];
const isEmptyField = requiredFields.some(field => !formData[field]?.trim());
if (isEmptyField) {
console.log("Validation failed: Some fields are empty.");
toaster.create({
title: "Error",
description: "All required fields must be filled.",
type: "error",
});
return;
}
const payload = {
name: formData.name
};
try {
const response = await createAgencyMasterPost(payload).unwrap();
if (response) {
toaster.create({
title: "Success",
description: "Added successfully",
type: "success",
});
refetch()
setIsOpen(false);
} else {
toaster.create({
title: "Error",
description: "Failed to add data.",
type: "error",
});
}
} catch (error) {
console.error("Error updating template:", error);
toaster.create({
title: "Error",
description: "Please try again later",
type: "error",
});
}
};
function ViewAgencyAddModel() {
return (
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogRoot placement="center">
<DialogTrigger asChild>
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
<IoMdAdd /> <Text >Add</Text>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Button px={5} size={"xs"} bg={"#02A0A0"}>
<IoMdAdd /> <Text >Add</Text>
</Button>
</DialogTrigger>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'80vh'}
overflow={'scroll'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'80vh'}
overflow={'scroll'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
@@ -105,97 +36,38 @@ function ViewAgencyAddModel({ refetch }: { refetch: VoidFunction }) {
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Agency Name</Field.Label>
<Input
name="name"
value={formData.name}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={handleChange}
/>
<Input placeholder="" 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
name='rc_number'
value={formData.rc_number}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={handleChange}
/>
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
<Field.Label color="black" pt={1} fontSize="12px">State</Field.Label>
<Input
name="state"
value={formData.state}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={handleChange}
/>
<Input placeholder="" 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
name="registered_office"
value={formData.registered_office}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={handleChange}
/>
<Input placeholder="" 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
name="domain_name"
value={formData.domain_name}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={handleChange}
/>
<Input placeholder="" 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
name="gst_number"
value={formData.gst_number}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={handleChange}
/>
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
<Field.Label color="black" pt={1} fontSize="12px">Action</Field.Label>
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
{/* <Field.Label color="black" pt={1} fontSize="12px">Action</Field.Label>
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" /> */}
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
<DialogCloseTrigger color="black" />
</DialogContent>
<Toaster />
</DialogRoot >
)

View File

@@ -1,178 +1,75 @@
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
// DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
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";
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Field, Input, Stack, } from "@chakra-ui/react"
import { MdOutlineRemoveRedEye } from "react-icons/md"
import { Button } from "../../../components/ui/button"
function ViewAgencyMaster({ agency, id }: { agency: Agency[], id:number }) {
return (
<DialogRoot placement="center">
<DialogTrigger asChild>
<Span><View /></Span>
</DialogTrigger>
function ViewAgencyMaster() {
return (
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: "90%", md: "400px" }}
height={"80vh"}
overflow={"scroll"}
overflowX="hidden"
p={3} // Reduced padding
bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
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
/>
<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
/>
<DialogRoot placement="center">
<DialogTrigger asChild>
<Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "14px" }} color="#000"/>
</Button>
</DialogTrigger>
<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
/>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
<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
/>
height={'80vh'}
overflow={'scroll'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
</DialogHeader>
<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
/>
<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">
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">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">
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">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">
Action
</Field.Label>
<Input
value={data}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
disabled
/> */}
</Field.Root>
</Stack>}
</DialogBody>
))}
<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">Website/Domain</Field.Label>
<Input value="Lorem Ipsum" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
{/* <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button
w="100%"
bg="#02A0A0"
color={"#fff"}
fontSize="12px"
height="30px"
>
Save
</Button>
</DialogFooter> */}
<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">Action</Field.Label>
<Input value="Lorem Ipsum" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot>
);
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} fontSize="12px" height="30px">
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot>
)
}
export default ViewAgencyMaster;
export default ViewAgencyMaster

View File

@@ -1,15 +1,11 @@
import { Box, HStack, Text } from "@chakra-ui/react";
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame"
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 CountryAddModel from "./CountryAddModel";
import EditCountryModel from "./EditCountryModel";
import { CountryData, useCountryToggleMutation, useGetCountryMasterQuery } from "../../../Redux/Service/country.master";
import { useEffect, useState } from "react";
import SearchComponent from "../../../components/SearchComponent";
import { useDebounce } from "../../../components/Hooks/useDebounce";
import { toaster, Toaster } from "../../../components/ui/toaster";
import { delay } from "../../../components/Utils";
@@ -19,109 +15,25 @@ const tableHeadRow = [
"Sr. No",
"Title",
"Action"
];
// const managepost: any[] = [
// ...Array.from({ length: 12 }, (_, i) => ({
// "Sr. No": i + 1,
// "Title": "Lorem Ipsum",
// "Action": (
// <HStack justifyContent="center">
// <EditCountryModel />
// <Box>
// <Switch colorPalette={'teal'} size={"xs"} />
// </Box>
// </HStack>
// ),
// })),
// ];
const Country = () => {
const [currentPage, setCurrentPage] = useState(1);
// const { data, refetch } = useGetCountryMasterQuery(currentPage)
const [countryToggle] = useCountryToggleMutation()
const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = useDebounce(searchTerm, 500);
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
const { data, refetch, isError, isFetching } = useGetCountryMasterQuery(queryArgs);
console.log("Country Data", data?.data.data)
useEffect(() => {
if (data) {
setLocalData(data?.data.data);
}
}, [data]);
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
const filteredData = localData?.filter((agency) => {
const searchLower = searchTerm.toLowerCase();
const countryName = agency.en_name?.toLowerCase().includes(searchLower);
const capitalName = agency.capital?.toLowerCase().includes(searchLower);
return countryName || capitalName;
});
const handleToggle = async (agencyId: number, currentStatus: string) => {
const newStatus = currentStatus === '1' ? '0' : '1';
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
)
);
try {
await countryToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch()
} catch (error) {
console.error("Error updating privacy policy:", error);
toaster.create({
title: "Error",
description: "Please try again later.",
type: "error",
});
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
)
);
}
}
const managepost = filteredData?.flatMap((agency: CountryData, index: number) => ({
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
"Title": agency.en_name,
const managepost: any[] = [
...Array.from({ length: 12 }, (_, i) => ({
"Sr. No": i + 1,
"Title": "Lorem Ipsum",
"Action": (
<HStack justifyContent="center">
<EditCountryModel rowData={{ id: agency.id, en_name: agency.en_name, country_code: agency.country_code, phonecode: agency.phonecode, capital: agency.capital, currency: agency.currency, currency_name: agency.currency_name, currency_symbol: agency.currency_symbol }} refetch={refetch} />
<EditCountryModel />
<Box>
<Switch
colorPalette={'teal'}
size={"xs"}
checked={agency.is_active === '1'}
onChange={() => handleToggle(agency.id, agency.is_active)}
/>
<Switch colorPalette={'teal'} size={"xs"}/>
</Box>
</HStack>
),
}))
})),
];
const Country = () => {
return (
<MainFrame>
@@ -134,11 +46,11 @@ const Country = () => {
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
Country
Country
</Text>
<HStack >
{/* <InputGroup
<HStack mr={5}>
<InputGroup marginRight={"1rem"}
startElement={
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
}
@@ -151,42 +63,23 @@ const Country = () => {
colorPalette={"blue"}
_focus={{ border: "1px solid #02A0A0" }}
rounded={"md"}
size={"xs"}
fontSize={"sm"}
size={"2xs"}
fontSize={"2sm"}
placeholder="Search..."
bgColor={'#EEEEEE'}
ps={8}
/>
</InputGroup> */}
<SearchComponent
value={searchTerm}
// onChange={(value) => {
// setSearchTerm(value);
// // setCurrentPage(1);
// refetch()
// }}
onChange={handleSearchChange}
/>
</InputGroup>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
<CountryAddModel refetch={refetch} />
<CountryAddModel />
</HStack>
</HStack>
<DataTable
sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow}
data={managepost}
paginationData={{
current_page: data?.data.current_page || 1,
last_page: data?.data.last_page || 1,
per_page: data?.data.per_page || 10,
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
<Toaster />
</Box>
</MainFrame>
)
}

View File

@@ -1,217 +1,56 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Field, Input, Stack, Text } from "@chakra-ui/react"
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button"
import { useEffect, useState } from "react";
import { PostCountry, useCreateCountryPostMutation } from "../../../Redux/Service/country.master";
import { Toaster, toaster } from "../../../components/ui/toaster";
function CountryAddModel({refetch}: { refetch: VoidFunction }) {
const [createCountryPost, { isLoading }] = useCreateCountryPostMutation()
const [isOpen, setIsOpen] = useState(false);
const [countryName, setCountryName] = useState<PostCountry>({
en_name: '',
country_code: '',
phonecode: '',
capital: '',
currency: '',
currency_name: '',
currency_symbol: '',
});
useEffect(() => {
if (!isOpen) {
setCountryName({
en_name: '',
country_code: '',
phonecode: '',
capital: '',
currency: '',
currency_name: '',
currency_symbol: '',
});
}
}, [isOpen]);
const handleOpenModal = () => {
setIsOpen(true); // Open modal when clicking "Add"
};
const handleSubmit = async () => {
if (countryName.en_name === "" || countryName.country_code === "" || countryName.phonecode === "" || countryName.capital === "" || countryName.currency === "" || countryName.currency_name === "" || countryName.currency_symbol === "") {
toaster.create({
title: "Error",
description: "Input fields cannot be empty",
type: "error",
});
return;
}
const payload: PostCountry = {
en_name: countryName.en_name,
country_code: countryName.country_code,
phonecode: countryName.phonecode,
capital: countryName.capital,
currency: countryName.currency,
currency_name: countryName.currency_name,
currency_symbol: countryName.currency_symbol,
};
try {
const response = await createCountryPost(payload).unwrap();
if (response) {
toaster.create({
title: "Success",
description: "Country added successfully",
type: "success",
});
setIsOpen(false);
refetch();
} else {
toaster.create({
title: "Error",
description: "Failed to add Country",
type: "error",
});
}
} catch (error) {
console.error("Error updating template:", error);
// alert("Failed to update template");
}
};
function CountryAddModel() {
return (
<>
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogTrigger asChild>
{/* <Button bg={"transparent"} size="sm">
<DialogRoot placement="center">
<DialogTrigger asChild>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
<IoMdAdd /> <Text>Add</Text>
<Button px={5} size={"xs"} bg={"#02A0A0"}>
<IoMdAdd /> <Text>Add</Text>
</Button>
</DialogTrigger>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'auto'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Country</Field.Label>
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
</DialogTrigger>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'auto'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Country</Field.Label>
<Input
placeholder="Enter Country Name"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={countryName.en_name}
onChange={(e) => setCountryName({ ...countryName, en_name: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px">Country Code</Field.Label>
<Input
placeholder="Please enter country code ex: IN, US"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={countryName.country_code}
onChange={(e) => setCountryName({ ...countryName, country_code: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px">Phone Code</Field.Label>
<Input
placeholder="Please enter phone code ex: +91, +1"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={countryName.phonecode}
onChange={(e) => setCountryName({ ...countryName, phonecode: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px">Capital</Field.Label>
<Input
placeholder="Enter Capital City"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={countryName.capital}
onChange={(e) => setCountryName({ ...countryName, capital: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px">Currency</Field.Label>
<Input
placeholder="Enter Currency"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={countryName.currency}
onChange={(e) => setCountryName({ ...countryName, currency: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px">Currency name</Field.Label>
<Input
placeholder="Enter Currency Name"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={countryName.currency_name}
onChange={(e) => setCountryName({ ...countryName, currency_name: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px">Currency Symbol</Field.Label>
<Input
placeholder="Enter Currency Symbol"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={countryName.currency_symbol}
onChange={(e) => setCountryName({ ...countryName, currency_symbol: e.target.value })}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
<Toaster />
</>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
)
}

View File

@@ -1,161 +1,61 @@
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import { Field, Input, Stack } from "@chakra-ui/react";
import { Button } from "../../../components/ui/button";
import Edit from "../../../components/ActionIcons/Edit";
import { useUpdateCountryMutation } from "../../../Redux/Service/country.master";
import { Toaster, toaster } from "../../../components/ui/toaster";
import { useEffect, useState } from "react";
export interface EditCountryModelProps {
id?: number;
en_name?: string;
hi_name?: string;
mr_name?: string;
te_name?: string;
ta_name?: string;
bn_name?: string;
or_name?: string;
country_code?: string;
phonecode?: string;
capital?: string;
currency?: string;
currency_name?: string;
currency_symbol?: string;
}
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 { Button } from "../../../components/ui/button"
import { FaRegEdit } from "react-icons/fa";
function EditCountryModel() {
function EditCountryModel({ rowData, refetch }: { rowData: EditCountryModelProps, refetch: VoidFunction }) {
const [updateCountry, { isLoading }] = useUpdateCountryMutation()
const [editData, setEditData] = useState(rowData)
const [isOpen, setIsOpen] = useState(false);
useEffect(() => {
if(rowData){
setEditData(rowData)
}
}, [rowData])
return (
const handleOpenModal = () => {
setIsOpen(true);
};
<DialogRoot placement="center">
<DialogTrigger asChild>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Button bg={"transparent"} size="sm">
<FaRegEdit style={{ cursor: "pointer", fontSize: "14px" }} color="#000"/>
</Button>
const handleSubmit = async () => {
if (editData?.en_name === '') {
toaster.create({
title: "Error",
description: "Input fields cannot be empty",
type: "error",
});
return;
}
</DialogTrigger>
// Only en_name is editable, so we only need to send that in the payload.
const payload = {
id: rowData?.id,
en_name: editData?.en_name,
country_code: rowData?.country_code,
phonecode: rowData?.phonecode,
capital: rowData?.capital,
currency: rowData?.currency,
currency_name: rowData?.currency_name,
currency_symbol: rowData?.currency_symbol,
};
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'auto'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Edit</DialogTitle>
</DialogHeader>
// console.log('payload', payload)
<DialogBody bg="white">
<Stack py={3}>
try {
const response = await updateCountry(payload).unwrap();
if (response?.status === "success") {
toaster.create({
title: "Success",
description: "Country updated successfully",
type: "success",
});
setIsOpen(false);
refetch()
} else {
toaster.create({
title: "Error",
description: "Failed to update Country",
type: "error",
});
}
} catch (error) {
console.error("Error updating template:", error);
// alert("Failed to update template");
toaster.create({
title: "Error",
description: "Something went wrong",
type: "error",
});
}
};
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Country</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"}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
return (
<>
<DialogRoot placement="center" key={editData.id} open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogTrigger asChild>
<Button bg="transparent" color={"black"} h={"18px"} onClick={handleOpenModal}><Edit /></Button>
</DialogTrigger>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: "90%", md: "400px" }}
height={"auto"}
overflowX="hidden"
p={3} // Reduced padding
bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit
</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Country
</Field.Label>
<Input
value={editData.en_name}
onChange={(e) => setEditData({ ...editData, en_name: e.target.value })}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot>
<Toaster />
</>
);
)
}
export default EditCountryModel;
export default EditCountryModel

View File

@@ -1,155 +0,0 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Field, Input, Stack, Text } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button"
import { useState } from "react";
import { toaster } from "../../../components/ui/toaster";
import { useCreateDepartmentPostMutation, useGetDepartmentMasterDropDownQuery } from "../../../Redux/Service/department.master";
function AddDepartmentMaster({ refetch }: { refetch: VoidFunction }) {
const [jobType, setJobType] = useState("");
const [isOpen, setIsOpen] = useState(false);
const [createDepartmentPost, { isLoading }] = useCreateDepartmentPostMutation()
const { data } = useGetDepartmentMasterDropDownQuery()
const [selectdDep, setSelectdDep] = useState<any>({
id: '',
en_name: '',
});
const handleOpenModal = () => {
setIsOpen(true); // Open modal when clicking "Add"
};
const handleSubmit = async () => {
if (!jobType.trim() || !selectdDep.id) {
toaster.create({
title: "Error",
description: "Title and Subtitle cannot be empty.",
type: "error",
});
return;
}
const payload = {
en_name: jobType,
industry_masters_xid: selectdDep.id,
};
try {
await createDepartmentPost(payload);
refetch()
setIsOpen(false);
setJobType("");
setSelectdDep({
id: '',
en_name: '',
})
} catch (error) {
console.error("Error updating template:", error);
alert("Failed to update template");
}
};
console.log("Selected Department", selectdDep);
return (
<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"} onClick={handleOpenModal}>
<IoMdAdd /> <Text>Add</Text>
</Button>
</DialogTrigger>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'auto'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Select Industry
</Field.Label>
<select
value={selectdDep.id}
onChange={(e) => {
const selectedId = e.target.value;
const selectedIndustry = data?.data.find((item: any) => item.id.toString() === selectedId);
if (selectedIndustry) {
setSelectdDep({
id: selectedIndustry.id,
en_name: selectedIndustry.en_name,
});
}
}}
style={{
backgroundColor: "#EEEEEE",
color: "black",
border: "none",
height: "30px",
fontSize: "12px",
padding: "4px",
borderRadius: "4px",
width: "100%",
}}
>
<option value="" disabled>
Select department
</option>
{data?.data.map((item: any) => (
<option value={item.id} key={item.id}>
{item.en_name}
</option>
))}
</select>
</Field.Root>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Department</Field.Label>
<Input
placeholder=""
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={jobType}
onChange={(e) => setJobType(e.target.value)}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
</DialogRoot >
)
}
export default AddDepartmentMaster

View File

@@ -1,162 +0,0 @@
import { Box, HStack, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame"
// 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 { useEffect, useState } from "react";
import SearchComponent from "../../../components/SearchComponent";
import { useDepartmentToggleMutation, useGetDepartmentMasterQuery } from "../../../Redux/Service/department.master";
import AddDepartmentMaster from "./AddDepartmentMaster";
import EditDepartmentMaster from "./EditDepartmentMaster";
import { useDebounce } from "../../../components/Hooks/useDebounce";
import { Toaster, toaster } from "../../../components/ui/toaster";
import { delay } from "../../../components/Utils";
// table data
const tableHeadRow = [
"Sr. No",
"Title",
"Action"
];
const DepartmentMasterList = () => {
const [currentPage, setCurrentPage] = useState(1);
const [departmentToggle] = useDepartmentToggleMutation()
const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = useDebounce(searchTerm, 500);
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
const { data, refetch, isError, isFetching } = useGetDepartmentMasterQuery(queryArgs)
console.log("Department Data", data?.data.data)
useEffect(() => {
if (data?.data?.data) {
setLocalData(data?.data.data);
}
}, [data]);
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
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 departmentToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch()
} catch (error) {
console.error("Error updating privacy policy:", error);
toaster.create({
title: "Error",
description: "Someting went wrong.",
type: "error",
});
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
)
);
}
};
const filteredData = localData?.filter((agency) => {
const searchLower = searchTerm.toLowerCase();
const title = agency.en_name?.toLowerCase().includes(searchLower);
return title;
});
const managepost = filteredData?.map((agency: any, index: number) => ({
'id': agency.id,
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
"Title": agency.en_name,
"is_active": agency.is_active,
"Action": (
<HStack justifyContent="center">
{/* <ViewAgencyMaster agency={localData} id={agency.id} /> */}
<EditDepartmentMaster localData={agency} refetch={refetch} />
<Box>
<Switch
colorPalette={"teal"}
size={"xs"}
onChange={() => handleToggle(agency.id, Number(agency.is_active))}
checked={Boolean(Number(agency.is_active))}
/>
</Box>
</HStack>
),
}));
// useEffect(() => {
// console.log("Fetched data:", data);
// console.log("Local data:", localData);
// console.log("Managepost data:", managepost);
// }, [data, localData, managepost]);
return (
<MainFrame>
<Box>
<HStack
w={"100%"}
justifyContent={"space-between"}
mb={4}
py={0}
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
Department Master
</Text>
<HStack >
<SearchComponent
value={searchTerm}
onChange={handleSearchChange}
/>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
{/* <ViewAgencyAddModel /> */}
<AddDepartmentMaster refetch={refetch} />
</HStack>
</HStack>
<DataTable
sortableColumns={["Name"]}
tableHeadRow={tableHeadRow}
data={managepost || []}
paginationData={{
current_page: data?.data.current_page || 1,
last_page: data?.data.last_page || 1,
per_page: data?.data.per_page || 10,
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
<Toaster />
</MainFrame>
)
}
export default DepartmentMasterList

View File

@@ -1,160 +0,0 @@
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import { Box, Field, Input, Stack } from "@chakra-ui/react";
import { Button } from "../../../components/ui/button";
import Edit from "../../../components/ActionIcons/Edit";
import { useState } from "react";
import { Toaster, toaster } from "../../../components/ui/toaster";
import { useGetDepartmentMasterDropDownQuery, useUpdateDepartmentMutation } from "../../../Redux/Service/department.master";
function EditDepartmentMaster({ localData, refetch }: { localData: any, refetch: VoidFunction }) {
const [jobtype, setJobType] = useState("");
const [updateDepartment, { isLoading }] = useUpdateDepartmentMutation()
const { data } = useGetDepartmentMasterDropDownQuery()
const [isOpen, setIsOpen] = useState(false);
const [selectdDep, setSelectdDep] = useState<any>({
id: localData.industry_master.id,
en_name: localData.industry_master.en_name,
});
const handleOpenModal = () => {
// const template = localData?.find((item: any) => item.id === id);
if (localData) {
setJobType(localData.en_name);
setSelectdDep({
id: localData.industry_master.id,
en_name: localData.industry_master.en_name,
})
setIsOpen(true);
}
};
const handleSubmit = async () => {
if (!jobtype.trim()) {
toaster.create({
title: "Error",
description: "Title and Subtitle cannot be empty.",
type: "error",
});
return;
}
const payload = {
id: localData.id,
industry_masters_xid: selectdDep.id != null ? selectdDep.id : localData.industry_master.id,
en_name: jobtype
};
try {
await updateDepartment(payload).unwrap();
refetch()
setIsOpen(false);
} catch (error) {
console.error("Error updating template:", error);
alert("Failed to update template");
}
};
console.log("Dropdown Data", selectdDep);
console.log("Dep Data", localData)
return (
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogTrigger asChild>
<Box bg={"transparent"} onClick={handleOpenModal}>
<Edit />
</Box>
</DialogTrigger>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: "90%", md: "400px" }}
height={"auto"}
overflowX="hidden"
p={3} // Reduced padding
bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit Title
</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Select Industry
</Field.Label>
<select
value={selectdDep.id}
onChange={(e) => {
const selected = data?.data.find((item: any) => item.id === Number(e.target.value));
if (selected) {
setSelectdDep({ id: selected.id, en_name: selected.en_name });
}
}}
style={{
backgroundColor: "#EEEEEE",
color: "black",
border: "none",
height: "30px",
fontSize: "12px",
padding: "4px",
borderRadius: "4px",
width: "100%",
}}
>
<option value="" disabled>
Select department
</option>
{data?.data.map((item: any) => (
<option value={item.id} key={item.id}>
{item.en_name}
</option>
))}
</select>
</Field.Root>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Department
</Field.Label>
<Input
value={jobtype}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={(e) => setJobType(e.target.value)}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
<Toaster />
</DialogRoot>
);
}
export default EditDepartmentMaster;

View File

@@ -1,103 +0,0 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Field, Input, Stack, Text } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button"
import { useState } from "react";
import { toaster } from "../../../components/ui/toaster";
import { useCreateIndustryMasterPostMutation } from "../../../Redux/Service/industry.master.service";
function AddIndustryMaster({ refetch }: { refetch: VoidFunction }) {
const [jobType, setJobType] = useState("");
const [isOpen, setIsOpen] = useState(false);
const [createIndustryMasterPost, { isLoading }] = useCreateIndustryMasterPostMutation()
const handleOpenModal = () => {
setIsOpen(true); // Open modal when clicking "Add"
};
const handleSubmit = async () => {
if (!jobType.trim()) {
toaster.create({
title: "Error",
description: "Title and Subtitle cannot be empty.",
type: "error",
});
return;
}
const payload = {
en_name: jobType,
categories_masters_xid:4
};
try {
await createIndustryMasterPost(payload);
refetch()
setIsOpen(false);
} catch (error) {
console.error("Error updating template:", error);
alert("Failed to update template");
}
};
return (
<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"} onClick={handleOpenModal}>
<IoMdAdd /> <Text>Add</Text>
</Button>
</DialogTrigger>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'auto'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Job Type</Field.Label>
<Input
placeholder=""
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={jobType}
onChange={(e) => setJobType(e.target.value)}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
</DialogRoot >
)
}
export default AddIndustryMaster

View File

@@ -1,112 +0,0 @@
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import { Box, Field, Input, Stack } from "@chakra-ui/react";
import { Button } from "../../../components/ui/button";
import Edit from "../../../components/ActionIcons/Edit";
import { useState } from "react";
import { toaster } from "../../../components/ui/toaster";
import { useUpdateIndustryMasterMutation } from "../../../Redux/Service/industry.master.service";
function EditIndustryMaster({ id, localData, refetch, categories }: { id: number, localData: any, refetch: VoidFunction, categories: any }) {
const [jobtype, setJobType] = useState("");
const [updateIndustryMaster, { isLoading }] = useUpdateIndustryMasterMutation()
const [isOpen, setIsOpen] = useState(false);
const handleOpenModal = () => {
const template = localData?.find((item: any) => item.id === id);
if (template) {
setJobType(template.en_name);
setIsOpen(true);
}
};
const handleSubmit = async () => {
if (!jobtype.trim()) {
toaster.create({
title: "Error",
description: "Title and Subtitle cannot be empty.",
type: "error",
});
return;
}
const payload = {
id: id,
en_name: jobtype,
categories_masters_xid: categories
};
try {
await updateIndustryMaster(payload);
refetch()
setIsOpen(false);
} catch (error) {
console.error("Error updating template:", error);
alert("Failed to update template");
}
};
return (
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogTrigger asChild>
<Box bg={"transparent"} onClick={handleOpenModal}>
<Edit />
</Box>
</DialogTrigger>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: "90%", md: "400px" }}
height={"auto"}
overflowX="hidden"
p={3} // Reduced padding
bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit
</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Job Type
</Field.Label>
<Input
value={jobtype}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={(e) => setJobType(e.target.value)}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
</DialogRoot>
);
}
export default EditIndustryMaster;

View File

@@ -1,180 +0,0 @@
import { Box, HStack, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame"
// 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 { useEffect, useState } from "react";
import { useGetIndustryMasterQuery, useIndustryMasterToggleMutation } from "../../../Redux/Service/industry.master.service";
import EditIndustryMaster from "./EditIndustryMaster";
import AddIndustryMaster from "./AddIndustryMaster";
import SearchComponent from "../../../components/SearchComponent";
import { useDebounce } from "../../../components/Hooks/useDebounce";
import { Toaster, toaster } from "../../../components/ui/toaster";
import { delay } from "../../../components/Utils";
// table data
const tableHeadRow = [
"Sr. No",
"Title",
"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",
// "Action": (
// <HStack justifyContent="center">
// <ViewAgencyMaster/>
// <EditAgencyMaster />
// <Box>
// <Switch colorPalette={'teal'} size={"xs"}/>
// </Box>
// </HStack>
// ),
// })),
// ];
const IndustryMasterList = () => {
const [currentPage, setCurrentPage] = useState(1);
const [industryMasterToggle] = useIndustryMasterToggleMutation()
const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = useDebounce(searchTerm, 500);
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
const { data, refetch, isError, isFetching } = useGetIndustryMasterQuery(queryArgs)
useEffect(() => {
if (data?.data?.data) {
setLocalData(data?.data.data);
}
}, [data]);
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
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 industryMasterToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch()
} catch (error) {
console.error("Error updating privacy policy:", error);
toaster.create({
title: "Error",
description: "Someting went wrong.",
type: "error",
});
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
)
);
}
};
const filteredData = localData?.filter((agency) => {
const searchLower = searchTerm.toLowerCase();
const title = agency.en_name?.toLowerCase().includes(searchLower);
return title;
});
const managepost = filteredData?.map((agency: any, index: number) => ({
'id': agency.id,
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
"Title": agency.en_name,
"is_active": agency.is_active,
"Action": (
<HStack justifyContent="center">
{/* <ViewAgencyMaster agency={localData} id={agency.id} /> */}
<EditIndustryMaster id={agency.id} localData={localData} refetch={refetch} categories={agency.categories_masters_xid} />
<Box>
<Switch
colorPalette={"teal"}
size={"xs"}
onChange={() => handleToggle(agency.id, Number(agency.is_active))}
checked={Boolean(Number(agency.is_active))}
/>
</Box>
</HStack>
),
}));
// useEffect(() => {
// console.log("Fetched data:", data);
// console.log("Local data:", localData);
// console.log("Managepost data:", managepost);
// }, [data, localData, managepost]);
return (
<MainFrame>
<Box>
<HStack
w={"100%"}
justifyContent={"space-between"}
mb={4}
py={0}
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
Industry Master
</Text>
<HStack >
<SearchComponent
value={searchTerm}
onChange={handleSearchChange}
/>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
{/* <ViewAgencyAddModel /> */}
<AddIndustryMaster refetch={refetch} />
</HStack>
</HStack>
<DataTable
sortableColumns={["Name"]}
tableHeadRow={tableHeadRow}
data={managepost || []}
paginationData={{
current_page: data?.data.current_page || 1,
last_page: data?.data.last_page || 1,
per_page: data?.data.per_page || 10,
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
<Toaster />
</MainFrame>
)
}
export default IndustryMasterList

View File

@@ -1,69 +1,35 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Box, Field, Input, Stack } from "@chakra-ui/react"
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
import { Button } from "../../../components/ui/button"
// import { FaRegEdit } from "react-icons/fa";
import Edit from "../../../components/ActionIcons/Edit";
import { useState } from "react";
import { useUpdateJobStatusMutation } from "../../../Redux/Service/job.status";
import { Toaster, toaster } from "../../../components/ui/toaster";
import { FaRegEdit } from "react-icons/fa";
function EditJobStatusModel({ localData, refetch }: { localData: any, refetch: VoidFunction }) {
const [updateJobStatus, { isLoading }] = useUpdateJobStatusMutation()
const [title, setTitle] = useState(localData.translation.title);
const [isOpen, setIsOpen] = useState(false);
function EditJobStatusModel() {
console.log(localData);
const handleOpenModal = () => {
if (localData) {
setIsOpen(true);
}
};
const handleSubmit = async () => {
if (!title.trim()) {
toaster.create({
title: "Error",
description: "Title field cannot be empty.",
type: "error",
});
return;
}
const payload = {
id: localData?.id,
title: title
};
try {
await updateJobStatus(payload).unwrap();
refetch()
setIsOpen(false);
} catch (error) {
console.error("Error updating template:", error);
alert("Failed to update template");
}
};
return (
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogRoot placement="center">
<DialogTrigger asChild>
<Box bg={"transparent"} onClick={handleOpenModal}>
<Edit />
</Box>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Button bg={"transparent"} size="sm">
<FaRegEdit style={{ cursor: "pointer", fontSize: "14px" }} color="#000"/>
</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">Edit</DialogTitle>
@@ -74,30 +40,21 @@ function EditJobStatusModel({ localData, refetch }: { localData: any, refetch: V
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Job Status</Field.Label>
<Input
value={title}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={(e) => setTitle(e.target.value)}
/>
<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"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
</DialogContent>
<Toaster />
</DialogRoot >
)
}

View File

@@ -1,15 +1,11 @@
import { Box, HStack, Text } from "@chakra-ui/react";
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame"
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 JobStatusAddModel from "./JobStatusAddModel";
import EditJobStatusModel from "./EditJobStatusModel";
import { useGetJobStatusQuery, useJobStatusToggleMutation } from "../../../Redux/Service/job.status";
import { useEffect, useState } from "react";
import SearchComponent from "../../../components/SearchComponent";
import { toaster, Toaster } from "../../../components/ui/toaster";
import { useDebounce } from "../../../components/Hooks/useDebounce";
import { delay } from "../../../components/Utils";
@@ -19,109 +15,25 @@ const tableHeadRow = [
"Sr. No",
"Title",
"Action"
];
// const managepost: any[] = [
// ...Array.from({ length: 12 }, (_, i) => ({
// "Sr. No": i + 1,
// "Title": "Lorem Ipsum",
// "Action": (
// <HStack justifyContent="center">
// <EditJobStatusModel />
// <Box>
// <Switch colorPalette={'teal'} size={"xs"} />
// </Box>
// </HStack>
// ),
// })),
// ];
const JobStatus = () => {
const [currentPage, setCurrentPage] = useState(1);
const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = useDebounce(searchTerm, 500);
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
const { data, refetch, isError, isFetching } = useGetJobStatusQuery(queryArgs)
const [localData, setLocalData] = useState<any[]>([]);
const [jobStatusToggle] = useJobStatusToggleMutation()
console.log(data?.data.data)
useEffect(() => {
if (data?.data?.data) {
setLocalData(data?.data.data);
}
}, [data]);
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
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 jobStatusToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch()
} catch (error) {
console.error("Error updating:", error);
toaster.create({
title: "Error",
description: "Someting went wrong.",
type: "error",
});
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
)
);
}
};
const filteredData = localData?.filter((agency) => {
return (agency.job_status_translation.map((item: any) => {
const searchLower = searchTerm.toLowerCase();
const title = item.title?.toLowerCase().includes(searchLower);
return title;
}))
});
const managepost = filteredData?.flatMap((agency: any, index: number) => (agency.job_status_translation.map((translation: any) => ({
'id': agency.id,
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
"Title": translation.title,
"is_active": agency.is_active,
const managepost: any[] = [
...Array.from({ length: 12 }, (_, i) => ({
"Sr. No": i + 1,
"Title": "Lorem Ipsum",
"Action": (
<HStack justifyContent="center">
{/* <ViewAgencyMaster agency={localData} id={agency.id} /> */}
<EditJobStatusModel localData={{ ...agency, translation }} refetch={refetch} />
<EditJobStatusModel />
<Box>
<Switch
colorPalette={"teal"}
size={"xs"}
onChange={() => handleToggle(agency.id, Number(agency.is_active))}
checked={Boolean(Number(agency.is_active))}
/>
<Switch colorPalette={'teal'} size={"xs"}/>
</Box>
</HStack>
),
}))));
})),
];
const JobStatus = () => {
return (
<MainFrame>
@@ -134,34 +46,40 @@ const JobStatus = () => {
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
Job Status
Job Status
</Text>
<HStack >
<SearchComponent
value={searchTerm}
onChange={handleSearchChange}
/>
<HStack mr={5}>
<InputGroup marginRight={"1rem"}
startElement={
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
}
color={"#000"}
>
<Input
p={3}
w={300}
bg={"#fff"}
colorPalette={"blue"}
_focus={{ border: "1px solid #02A0A0" }}
rounded={"md"}
size={"2xs"}
fontSize={"2sm"}
placeholder="Search..."
bgColor={'#EEEEEE'}
ps={8}
/>
</InputGroup>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
<JobStatusAddModel refetch={refetch} />
<JobStatusAddModel />
</HStack>
</HStack>
<DataTable
sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow}
data={managepost}
paginationData={{
current_page: data?.data.current_page || 1,
last_page: data?.data.last_page || 1,
per_page: data?.data.per_page || 10,
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
<Toaster />
</Box>
</MainFrame>
)
}

View File

@@ -1,67 +1,32 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Field, Input, Stack, Text } from "@chakra-ui/react"
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button"
import { useCreateJobStatusPostMutation } from "../../../Redux/Service/job.status"
import { toaster } from "../../../components/ui/toaster"
import { useState } from "react"
function JobStatusAddModel({ refetch }: { refetch: VoidFunction }) {
const [title, setTitle] = useState('')
const [isOpen, setIsOpen] = useState(false);
const [createJobStatusPost, { isLoading }] = useCreateJobStatusPostMutation()
const handleOpenModal = () => {
setIsOpen(true);
};
const handleSubmit = async () => {
if (!title.trim()) {
toaster.create({
title: "Error",
description: "Title field cannot be empty.",
type: "error",
});
return;
}
const payload = {
title: title,
};
try {
await createJobStatusPost(payload).unwrap();
refetch()
setIsOpen(false);
setTitle('')
} catch (error) {
console.error("Error updating template:", error);
alert("Failed to update template");
}
};
function JobStatusAddModel() {
return (
<DialogRoot placement="center" open={isOpen}>
<DialogRoot placement="center">
<DialogTrigger asChild>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
<Button px={5} size={"xs"} bg={"#02A0A0"}>
<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>
@@ -72,28 +37,18 @@ function JobStatusAddModel({ refetch }: { refetch: VoidFunction }) {
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Job Status</Field.Label>
<Input
placeholder=""
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >

View File

@@ -1,111 +1,62 @@
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import { Box, Field, Input, Stack } from "@chakra-ui/react";
import { Button } from "../../../components/ui/button";
import Edit from "../../../components/ActionIcons/Edit";
import { useState } from "react";
import { useUpdateJobTypeMutation } from "../../../Redux/Service/job.type.service";
import { toaster } from "../../../components/ui/toaster";
function EditJobeModel({ id, localData, refetch }: { id: number, localData: any, refetch: VoidFunction }) {
const [jobtype, setJobType] = useState("");
const [updateJobType, { isLoading }] = useUpdateJobTypeMutation()
const [isOpen, setIsOpen] = useState(false);
const handleOpenModal = () => {
const template = localData?.find((item: any) => item.id === id);
if (template) {
setJobType(template.en_name);
setIsOpen(true);
}
};
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 { Button } from "../../../components/ui/button"
import { FiUpload } from "react-icons/fi";
import { FaRegEdit } from "react-icons/fa";
const handleSubmit = async () => {
if (!jobtype.trim()) {
toaster.create({
title: "Error",
description: "Title and Subtitle cannot be empty.",
type: "error",
});
return;
}
function EditJobeModel() {
const payload = {
id: id,
en_name: jobtype,
};
try {
await updateJobType(payload);
refetch()
setIsOpen(false);
} catch (error) {
console.error("Error updating template:", error);
alert("Failed to update template");
}
};
return (
return (
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogTrigger asChild>
<Box bg={"transparent"} onClick={handleOpenModal}>
<Edit />
</Box>
</DialogTrigger>
<DialogRoot placement="center">
<DialogTrigger asChild>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Button bg={"transparent"} size="sm">
<FaRegEdit style={{ cursor: "pointer", fontSize: "14px" }} color="#000"/>
</Button>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: "90%", md: "400px" }}
height={"auto"}
overflowX="hidden"
p={3} // Reduced padding
bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit
</DialogTitle>
</DialogHeader>
</DialogTrigger>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Job Type
</Field.Label>
<Input
value={jobtype}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={(e) => setJobType(e.target.value)}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save
</Button>
</DialogFooter>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'auto'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Edit</DialogTitle>
</DialogHeader>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
</DialogRoot>
);
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Job Type</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"}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
)
}
export default EditJobeModel;
export default EditJobeModel

View File

@@ -1,66 +1,32 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Field, Input, Stack, Text } from "@chakra-ui/react"
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button"
import { useState } from "react";
import { useCreateJobTypePostMutation } from "../../../Redux/Service/job.type.service";
import { toaster } from "../../../components/ui/toaster";
function JobAddModel({ refetch }: { refetch: VoidFunction }) {
const [jobType, setJobType] = useState("");
const [isOpen, setIsOpen] = useState(false);
const [createJobTypePost, { isLoading }] = useCreateJobTypePostMutation()
const handleOpenModal = () => {
setIsOpen(true); // Open modal when clicking "Add"
};
const handleSubmit = async () => {
if (!jobType.trim()) {
toaster.create({
title: "Error",
description: "Title and Subtitle cannot be empty.",
type: "error",
});
return;
}
const payload = {
en_name: jobType,
};
try {
await createJobTypePost(payload);
refetch()
setIsOpen(false);
} catch (error) {
console.error("Error updating template:", error);
alert("Failed to update template");
}
};
function JobAddModel() {
return (
<DialogRoot placement="center" open={isOpen}>
<DialogRoot placement="center">
<DialogTrigger asChild>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
<Button px={5} size={"xs"} bg={"#02A0A0"}>
<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>
@@ -71,28 +37,18 @@ function JobAddModel({ refetch }: { refetch: VoidFunction }) {
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Job Type</Field.Label>
<Input
placeholder=""
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={jobType}
onChange={(e) => setJobType(e.target.value)}
/>
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >

View File

@@ -1,16 +1,11 @@
import { Box, HStack, Text } from "@chakra-ui/react";
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame"
// import { InputGroup } from "../../../components/ui/input-group";
// import { LuSearch } from "react-icons/lu";
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 JobAddModel from "./JobAddModel";
import EditJobeModel from "./EditJobModel";
import { JobTypeData, useGetJobTypeQuery, useJobTypeToggleMutation } from "../../../Redux/Service/job.type.service";
import { useEffect, useState } from "react";
import SearchComponent from "../../../components/SearchComponent";
import { toaster, Toaster } from "../../../components/ui/toaster";
import { delay } from "../../../components/Utils";
@@ -20,102 +15,25 @@ const tableHeadRow = [
"Sr. No",
"Title",
"Action"
];
// const managepost: any[] = [
// ...Array.from({ length: 12 }, (_, i) => ({
// "Sr. No": i + 1,
// "Title": "Lorem Ipsum",
// "Action": (
// <HStack justifyContent="center">
// <EditJobeModel />
// <Box>
// <Switch colorPalette={'teal'} size={"xs"} />
// </Box>
// </HStack>
// ),
// })),
// ];
const JobType = () => {
const [currentPage, setCurrentPage] = useState(1);
const { data, refetch, isFetching, isError } = useGetJobTypeQuery(currentPage)
const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const [jobTypeToggle] = useJobTypeToggleMutation()
console.log('DATA', data?.data.data);
useEffect(() => {
if (data?.data?.data) {
setLocalData(data?.data.data);
}
}, [data]);
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
const filteredData = localData?.filter((agency) => {
const searchLower = searchTerm.toLowerCase();
const title = agency.en_name?.toLowerCase().includes(searchLower);
return title;
});
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 jobTypeToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch()
} catch (error) {
console.error("Error updating privacy policy:", error);
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
)
);
toaster.create({
title: "Error",
description: "Please try again later",
type: "error",
});
}
};
const managepost = filteredData?.map((agency: JobTypeData, index: number) => ({
'id': (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
"Sr. No": index + 1,
"Title": agency.en_name,
const managepost: any[] = [
...Array.from({ length: 12 }, (_, i) => ({
"Sr. No": i + 1,
"Title": "Lorem Ipsum",
"Action": (
<HStack justifyContent="center">
<EditJobeModel id={agency.id} localData={localData} refetch={refetch} />
<EditJobeModel />
<Box>
<Switch
colorPalette={'teal'}
size={"xs"}
onChange={() => handleToggle(agency.id.toString(), Number(agency.is_active))}
checked={Boolean(Number(agency.is_active))}
/>
<Switch colorPalette={'teal'} size={"xs"}/>
</Box>
</HStack>
),
}));
})),
];
const JobType = () => {
return (
<MainFrame>
@@ -128,38 +46,40 @@ const JobType = () => {
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
Job Type
Job Type
</Text>
<HStack >
<SearchComponent
value={searchTerm}
onChange={(value) => {
setSearchTerm(value);
// setCurrentPage(1);
refetch()
}}
/>
<HStack mr={5}>
<InputGroup marginRight={"1rem"}
startElement={
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
}
color={"#000"}
>
<Input
p={3}
w={300}
bg={"#fff"}
colorPalette={"blue"}
_focus={{ border: "1px solid #02A0A0" }}
rounded={"md"}
size={"2xs"}
fontSize={"2sm"}
placeholder="Search..."
bgColor={'#EEEEEE'}
ps={8}
/>
</InputGroup>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
<JobAddModel refetch={refetch} />
<JobAddModel />
</HStack>
</HStack>
<DataTable
sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow}
data={managepost}
paginationData={{
current_page: data?.data.current_page || 1,
last_page: data?.data.last_page || 1,
per_page: data?.data.per_page || 10,
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
<Toaster />
</Box>
</MainFrame>
)
}

View File

@@ -1,319 +1,100 @@
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
} from "../../../components/ui/dialog";
import {
Box,
Field,
Input,
Stack,
} from "@chakra-ui/react";
import { Button } from "../../../components/ui/button";
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 { Button } from "../../../components/ui/button"
import { FiUpload } from "react-icons/fi";
import { useState } from "react";
// import { FaRegEdit } from "react-icons/fa";
import Edit from "../../../components/ActionIcons/Edit";
import { Toaster, toaster } from "../../../components/ui/toaster";
// import { Template } from "../../../Redux/Service/template.master.service";
import axios from "axios";
import { FaRegEdit } from "react-icons/fa";
const IMGURL = import.meta.env.VITE_IMG_TEMPLATES
const APIURL = import.meta.env.VITE_API_URL
function EditTemplateModel({ id, localData, refetch }: { id: number, localData: any, refetch: VoidFunction }) {
const [title, setTitle] = useState("");
const [subTitle, setSubTitle] = useState("");
const [userType, setUserType] = useState<number | "">("");
const [images, setImages] = useState<(File | string)[]>([]);
const [loading, setLoading] = useState(false);
// const [objectURLs, setObjectURLs] = useState<string[]>([]); // Store object URLs separately
// const [updateTemplateMaster] = useUpdateTemplateMasterMutation()
const [isOpen, setIsOpen] = useState(false);
// const [selectedTemplate, setSelectedTemplate] = useState<Template | null>(null);
const token = localStorage.getItem("token");
function EditTemplateModel() {
console.log(images);
const [images, setImages] = useState<string[]>([]);
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",
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
});
return;
setImages((prevImages) => [...prevImages, ...newImages]); // Append new images
}
};
// setImages((prevImages) => [...prevImages, file]);
if (file) {
setImages([file])
}
}
};
return (
const handleOpenModal = () => {
const template = localData?.find((item: any) => item.id === id);
if (template) {
// setSelectedTemplate(template);
setTitle(template.post_template_translate.length > 0 ? template.post_template_translate[0].title : "");
setSubTitle(template.post_template_translate.length > 0 ? template.post_template_translate[0].sub_title : "");
setUserType(template.principle_type_xid?.toString() || "");
<DialogRoot placement="center">
<DialogTrigger asChild>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Button bg={"transparent"} size="sm">
<FaRegEdit style={{ cursor: "pointer", fontSize: "14px" }} color="#000"/>
</Button>
// Convert image URLs to File objects if needed
const templateImages = template.post_template_image.map((img: any) => `${IMGURL}${img.image_name}`);
setImages(templateImages);
</DialogTrigger>
setIsOpen(true);
}
};
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'auto'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
const handleSubmit = async () => {
if (!title.trim() || !subTitle.trim()) {
toaster.create({
title: "Error",
description: "Title and Subtitle cannot be empty.",
type: "error",
});
return;
}
<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" />
if (userType === "" || isNaN(Number(userType))) {
toaster.create({
title: "Error",
description: "Please select a valid user type.",
type: "error",
});
return;
}
<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>
<FiUpload color="#000" />
</Box>
{/* <Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" /> */}
// const newImages = images.filter((image) => image instanceof File);
</Field.Root>
</Stack>
if (images.length === 0) {
toaster.create({
title: "Error",
description: "Please upload at least one image.",
type: "error",
});
return;
}
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
setLoading(true);
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
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);
}
});
try {
// await updateTemplateMaster(formData);
if (token) {
await axios.post(`${APIURL}/template-update`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
'access-token': `${token}`,
},
// withCredentials: true,
});
}
setIsOpen(false);
setLoading(false);
refetch()
} catch (error: any) {
console.error("Error updating template:", error);
setLoading(false);
toaster.create({
title: "Error",
description: `${error.response?.data?.message || "Please try again later."}`,
type: "error",
});
}
};
// const handleSubmit = async () => {
// if (!title.trim() || !subTitle.trim()) {
// toaster.create({
// title: "Error",
// description: "Title and Subtitle cannot be empty.",
// type: "error",
// });
// return;
// }
// if (userType === "" || isNaN(Number(userType))) {
// toaster.create({
// title: "Error",
// description: "Please select a valid user type.",
// type: "error",
// });
// return;
// }
// if (images.length === 0) {
// toaster.create({
// title: "Error",
// description: "Please upload at least one image.",
// type: "error",
// });
// return;
// }
// const existingImageUrls = images.filter((img) => typeof img === "string") as string[];
// const newBase64Images = images.filter((img) => typeof img === "string" && img.startsWith("data:image")) as string[];
// const payload = {
// id: id,
// principle_type_xid: userType,
// title,
// sub_title: subTitle,
// image_name: [...existingImageUrls, ...newBase64Images], // Send only Base64 strings
// };
// try {
// await updateTemplateMaster(payload)
// setIsOpen(false)
// } catch (error) {
// console.error("Error creating template:", error);
// alert("Failed to create template");
// }
// };
return (
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Box bg={"transparent"} onClick={handleOpenModal}>
<Edit />
</Box>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'auto'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Edit</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<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 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>
<Box>
</Box>
{/* <Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" /> */}
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={loading}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
<Toaster />
</DialogRoot >
);
)
}
export default EditTemplateModel;
export default EditTemplateModel

View File

@@ -1,163 +1,50 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Box, Field, Input, Stack, Text } from "@chakra-ui/react"
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button"
import { FiUpload } from "react-icons/fi";
import { useEffect, useState } from "react";
// import { useCreateTemplatePostMutation } from "../../../Redux/Service/template.master.service";
import { Toaster, toaster } from "../../../components/ui/toaster"
import axios from "axios";
const APIURL = import.meta.env.VITE_API_URL
function TemplateAddModel({ refetch }: { refetch: VoidFunction }) {
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 [isLoading, setIsLoading] = useState(false);
const token = localStorage.getItem("token");
useEffect(() => {
if (!isOpen) {
setTitle("");
setSubTitle("");
setUserType("");
setImages([]);
}
}, [isOpen]);
if (!token) {
console.error("No token found in localStorage!");
return null;
}
const handleOpenModal = () => {
setIsOpen(true); // Open modal when clicking "Add"
};
import { useState } from "react";
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;
}
function TemplateAddModel() {
// setImages((prevImages) => [...prevImages, file]);
if(file){
setImages([file])
}
}
};
const [images, setImages] = useState<string[]>([]);
const handleSubmit = async () => {
if (!title || !subTitle || images.length === 0) {
toaster.create({
title: "Error",
description: "Please fill in all required fields and upload at least one image.",
type: "error",
});
return;
}
if (userType === "" || isNaN(Number(userType))) {
toaster.create({
title: "Error",
description: "Please select a valid user type.",
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
// };
setIsLoading(true);
const formData = new FormData();
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
}
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
});
if (token) {
const payload = JSON.parse(atob(token.split(".")[1]));
console.log("Token Payload:", payload);
}
try {
// await createTemplatePost(formData)
if (token) {
await axios.post(`${APIURL}/template-store`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
'access-token': `${token}`,
},
// withCredentials: true,
});
}
refetch();
setTitle("");
setSubTitle("");
setUserType("");
setImages([]);
setIsOpen(false)
setIsLoading(false);
} catch (error: any) {
console.error("Error creating template:", error);
// alert("Failed to create template");
toaster.create({
title: "Error",
description: `${error.response?.data?.message || "Please try again later."}`,
type: "error",
});
}
setImages((prevImages) => [...prevImages, ...newImages]); // Append new images
}
};
// console.log("Token stored:", window.localStorage.getItem("token"))
return (
<DialogRoot placement="center" open={isOpen}>
<DialogRoot placement="center">
<DialogTrigger asChild>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
<Button px={5} size={"xs"} bg={"#02A0A0"}>
<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>
@@ -167,79 +54,30 @@ function TemplateAddModel({ refetch }: { refetch: VoidFunction }) {
<Stack py={3}>
<Field.Root>
<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.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.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 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 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>
<FiUpload color="#000" />
</Box>
{/* <Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" /> */}
</Field.Root>
@@ -247,14 +85,13 @@ function TemplateAddModel({ refetch }: { refetch: VoidFunction }) {
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
<DialogCloseTrigger color="black" />
</DialogContent>
<Toaster />
</DialogRoot >
)

View File

@@ -1,145 +1,52 @@
import { Box, HStack, Image, Text } from "@chakra-ui/react";
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame"
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";
import SearchComponent from "../../../components/SearchComponent";
import { toaster, Toaster } from "../../../components/ui/toaster";
import { delay } from "../../../components/Utils";
const APIURL = import.meta.env.VITE_IMG_TEMPLATES
// table data
const tableHeadRow = [
"Sr. No",
"Title",
"User Type",
"Images",
"Action"
];
// 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>
// ),
const managepost: any[] = [
...Array.from({ length: 12 }, (_, i) => ({
"Sr. No": i + 1,
"Title": "Lorem Ipsum",
"Images": (
// <Image w={50} src={img} />
<HStack >
<Image w={100} h={50} src={img} />
<Image w={100} h={50} src={Templateimg} />
</HStack>
// "Action": (
// <HStack justifyContent="center">
// <EditTemplateModel />
// <Box>
// <Switch colorPalette={'teal'} size={"xs"} />
// </Box>
// </HStack>
// ),
// })),
// ];
),
"Action": (
<HStack justifyContent="center">
<EditTemplateModel />
<Box>
<Switch colorPalette={'teal'} size={"xs"}/>
</Box>
</HStack>
),
})),
];
const TemplateMaster = () => {
const [currentPage, setCurrentPage] = useState(1);
const { data, refetch, isFetching, isError } = useGetTemplateMasterQuery(currentPage)
const [localData, setLocalData] = useState<any[]>([]);
const [templateMasterToggle] = useTemplateMasterToggleMutation();
const [searchTerm, setSearchTerm] = useState("");
console.log('DATA', data?.data.data);
useEffect(() => {
if (data?.data?.data) {
setLocalData(data?.data.data);
}
}, [data]);
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
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();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch()
} catch (error) {
console.error("Error updating privacy policy:", error);
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
)
);
toaster.create({
title: "Error",
description: "Please try again later",
type: "error",
});
}
};
const filteredData = localData?.filter((agency) =>
agency.post_template_translate[0].title.toLowerCase().includes(searchTerm.toLowerCase())
);
const activeCount = filteredData?.filter((a: any) => a.is_active === 1).length ?? 0;
const managepost = filteredData?.map((agency: Template, index: number) => {
const isOnlyActive = activeCount === 1 && Number(agency.is_active) === 1;
return {
'id': agency.id,
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
"Title": agency.post_template_translate.length > 0
? agency.post_template_translate[0].title
: "N/A",
"User Type": agency.principle_type_xid === 2 ? 'Recruiter' : 'Job Seeker',
"Images": (
// <Image w={50} src={img} />
<HStack>
{agency.post_template_image.map((img) => (
<Image key={img.id} 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 id={agency.id} localData={localData} refetch={refetch} />
<Box>
<Switch
colorPalette={'teal'}
size={"xs"}
onChange={() => handleToggle(agency.id.toString(), Number(agency.is_active ?? 0))}
checked={Boolean(Number(agency.is_active))}
disabled={isOnlyActive}
/>
</Box>
</HStack>
)
}
});
return (
<MainFrame>
@@ -152,11 +59,11 @@ const TemplateMaster = () => {
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
Template Master
Template Master
</Text>
<HStack >
{/* <InputGroup
<HStack mr={5}>
<InputGroup marginRight={"1rem"}
startElement={
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
}
@@ -169,36 +76,23 @@ const TemplateMaster = () => {
colorPalette={"blue"}
_focus={{ border: "1px solid #02A0A0" }}
rounded={"md"}
size={"xs"}
fontSize={"sm"}
size={"2xs"}
fontSize={"2sm"}
placeholder="Search..."
bgColor={'#EEEEEE'}
ps={8}
/>
</InputGroup> */}
<SearchComponent
value={searchTerm}
onChange={setSearchTerm}
/>
<TemplateAddModel refetch={refetch} />
</InputGroup>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
<TemplateAddModel />
</HStack>
</HStack>
<DataTable
sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow}
data={managepost}
paginationData={{
current_page: data?.data.current_page || 1,
last_page: data?.data.last_page || 1,
per_page: data?.data.per_page || 10,
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
<Toaster />
</Box>
</MainFrame>
)
}

View File

@@ -1,118 +1,61 @@
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../../components/ui/dialog";
import {
Box,
Field,
Input,
Stack,
} from "@chakra-ui/react";
import { Button } from "../../../components/ui/button";
// import { FaRegEdit } from "react-icons/fa";
import Edit from "../../../components/ActionIcons/Edit";
import { useState } from "react";
import { toaster } from "../../../components/ui/toaster";
import { useUpdateWorkSpaceMutation } from "../../../Redux/Service/workspace.mode";
function EditWorkModel({ localData, refetch }: {localData: any, refetch: VoidFunction}) {
const [title, setTitle] = useState(localData?.en_name);
const [isOpen, setIsOpen] = useState(false);
const [updateWorkSpace, { isLoading }] = useUpdateWorkSpaceMutation()
console.log("localData", localData)
const handleOpenModal = () => {
// const template = localData?.find((item: any) => item.id === id);
if (localData) {
setIsOpen(true);
// setTitle(localData?.localData.en_name);
}
};
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 { Button } from "../../../components/ui/button"
import { FaRegEdit } from "react-icons/fa";
const handleSubmit = async () => {
if (!title.trim()) {
toaster.create({
title: "Error",
description: "Title field cannot be empty.",
type: "error",
});
return;
}
function EditWorkModel() {
const payload = {
id: localData?.id,
en_name: title
};
try {
await updateWorkSpace(payload).unwrap();
refetch()
setIsOpen(false);
} catch (error) {
console.error("Error updating template:", error);
alert("Failed to update template");
}
};
return (
return (
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogTrigger asChild>
<Box bg={"transparent"} onClick={handleOpenModal}>
<Edit />
</Box>
</DialogTrigger>
<DialogRoot placement="center">
<DialogTrigger asChild>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Button bg={"transparent"} size="sm">
<FaRegEdit style={{ cursor: "pointer", fontSize: "14px" }} color="#000"/>
</Button>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: "90%", md: "400px" }}
height={"auto"}
overflowX="hidden"
p={3} // Reduced padding
bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit
</DialogTitle>
</DialogHeader>
</DialogTrigger>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Workspace Mode
</Field.Label>
<Input
value={title}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
onChange={(e) => setTitle(e.target.value)}
/>
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save
</Button>
</DialogFooter>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'auto'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px">Edit</DialogTitle>
</DialogHeader>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot>
);
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Workspace Mode</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"}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
)
}
export default EditWorkModel;
export default EditWorkModel

View File

@@ -1,73 +1,32 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
import { Field, Input, Stack, Text } from "@chakra-ui/react"
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button"
import { useEffect, useState } from "react";
import { useCreateWorkspacePostMutation } from "../../../Redux/Service/workspace.mode";
import { Toaster, toaster } from "../../../components/ui/toaster";
function WorkAddModel({ refetch }: { refetch: VoidFunction }) {
const [title, setTitle] = useState('')
const [isOpen, setIsOpen] = useState(false);
const [createWorkspacePost, { isLoading }] = useCreateWorkspacePostMutation()
const handleOpenModal = () => {
setIsOpen(true);
};
const handleSubmit = async () => {
if (!title.trim()) {
toaster.create({
title: "Error",
description: "Title field cannot be empty.",
type: "error",
});
return;
}
const payload = {
en_name: title,
};
try {
await createWorkspacePost(payload);
refetch()
setIsOpen(false);
setTitle('')
} catch (error) {
console.error("Error updating template:", error);
alert("Failed to update template");
}
};
useEffect(() => {
if (!isOpen) {
setTitle("");
}
}, [isOpen]);
function WorkAddModel() {
return (
<DialogRoot placement="center" open={isOpen}>
<DialogRoot placement="center">
<DialogTrigger asChild>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
<Button px={5} size={"xs"} bg={"#02A0A0"}>
<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>
@@ -78,30 +37,19 @@ function WorkAddModel({ refetch }: { refetch: VoidFunction }) {
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Workspace Mode</Field.Label>
<Input
placeholder=""
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
<DialogCloseTrigger color="black" />
</DialogContent>
<Toaster />
</DialogRoot >
)

View File

@@ -1,13 +1,11 @@
import { Box, HStack, Text } from "@chakra-ui/react";
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame"
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 WorkAddModel from "./WorkAddModel";
import EditWorkModel from "./EditWorkModel";
import { useEffect, useState } from "react";
import { useGetWorkSpaceModeQuery, useWorkspaceToggleMutation } from "../../../Redux/Service/workspace.mode";
import SearchComponent from "../../../components/SearchComponent";
import { Toaster, toaster } from "../../../components/ui/toaster";
@@ -17,102 +15,25 @@ const tableHeadRow = [
"Sr. No",
"Title",
"Action"
];
// const managepost: any[] = [
// ...Array.from({ length: 12 }, (_, i) => ({
// "Sr. No": i + 1,
// "Title": "Lorem Ipsum",
// "Action": (
// <HStack justifyContent="center">
// <EditWorkModel />
// <Box>
// <Switch colorPalette={'teal'} size={"xs"} />
// </Box>
// </HStack>
// ),
// })),
// ];
const WorkspaceMode = () => {
const [currentPage, setCurrentPage] = useState(1);
const { data, refetch, isError, isFetching } = useGetWorkSpaceModeQuery(currentPage)
const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const [workspaceToggle] = useWorkspaceToggleMutation()
console.log("Workspace Data", data?.data.data)
useEffect(() => {
if (data?.data?.data) {
setLocalData(data?.data.data);
}
}, [data]);
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
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 workspaceToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
refetch()
} catch (error) {
console.error("Error updating privacy policy:", error);
toaster.create({
title: "Error",
description: "Please try again later.",
type: "error",
});
setLocalData((prevData) =>
prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
)
);
}
};
const filteredData = localData?.filter((agency) => {
const searchLower = searchTerm.toLowerCase();
const title = agency.en_name?.toLowerCase().includes(searchLower);
return title;
});
const managepost = filteredData?.map((agency: any, index: number) => ({
'id': agency.id,
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
"Title": agency.en_name.length > 12
? agency.en_name.slice(0, 12) + '...'
: agency.en_name,
"is_active": agency.is_active,
const managepost: any[] = [
...Array.from({ length: 12 }, (_, i) => ({
"Sr. No": i + 1,
"Title": "Lorem Ipsum",
"Action": (
<HStack justifyContent="center">
{/* <ViewAgencyMaster agency={localData} id={agency.id} /> */}
<EditWorkModel localData={agency} refetch={refetch} />
<EditWorkModel />
<Box>
<Switch
colorPalette={"teal"}
size={"xs"}
onChange={() => handleToggle(agency.id, Number(agency.is_active))}
checked={Boolean(Number(agency.is_active))}
/>
<Switch colorPalette={'teal'} size={"xs"}/>
</Box>
</HStack>
),
}));
})),
];
const WorkspaceMode = () => {
return (
<MainFrame>
@@ -125,38 +46,40 @@ const WorkspaceMode = () => {
px={3}
>
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
Workspace Mode
Workspace Mode
</Text>
<HStack >
<SearchComponent
value={searchTerm}
onChange={(value) => {
setSearchTerm(value);
// setCurrentPage(1);
refetch()
}}
/>
<HStack mr={5}>
<InputGroup marginRight={"1rem"}
startElement={
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
}
color={"#000"}
>
<Input
p={3}
w={300}
bg={"#fff"}
colorPalette={"blue"}
_focus={{ border: "1px solid #02A0A0" }}
rounded={"md"}
size={"2xs"}
fontSize={"2sm"}
placeholder="Search..."
bgColor={'#EEEEEE'}
ps={8}
/>
</InputGroup>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
<WorkAddModel refetch={refetch} />
<WorkAddModel />
</HStack>
</HStack>
<DataTable
sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow}
data={managepost}
paginationData={{
current_page: data?.data.current_page || 1,
last_page: data?.data.last_page || 1,
per_page: data?.data.per_page || 10,
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
<Toaster />
</Box>
</MainFrame>
)
}

View File

@@ -0,0 +1,149 @@
import { Center, HStack, Image, Input, Text, VStack } from "@chakra-ui/react";
import { useContext, useState } from "react";
import { useForm } from "react-hook-form";
import GlobalStateContext from "../../Contexts/GlobalStateContext";
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";
interface FormValues {
password: string;
confirmPassword: string;
}
const CreatePass = () => {
const [isLoading, setIsLoading] = useState<boolean>(false);
const context = useContext(GlobalStateContext);
if (!context) {
throw new Error("App must be used within a GlobalStateProvider");
}
const { setIsAuthenticate } = context;
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormValues>();
const onSubmit = handleSubmit((data) => {
setIsLoading(true);
if (data?.password === "password123") {
setTimeout(() => {
setIsAuthenticate(true);
setIsLoading(false);
}, 3000);
} else {
toaster.create({
title: `Invalid Credentials`,
type: "error",
});
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>
<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>
<Center
as={"form"}
onSubmit={onSubmit}
p={{ base: 4, md: 16 }}
w={{ base: "100%", md: "50%" }}
h={"100%"}
>
<VStack gap={2} w={"100%"} alignItems={"flex-start"}>
<Text
w={"100%"}
textAlign={"center"}
fontSize={"24px"}
fontWeight={"normal"}
color={"#313039"}
textTransform={"uppercase"}
>
create a password
</Text>
<VStack mt={6} gap={4} w={"full"}>
<Field
color={"#313039"}
label={"Enter password"}
w={"100%"}
invalid={!!errors.password}
errorText={errors.password?.message}
>
<Input
ps={3}
type="password"
{...register("password", {
required: "Password is required",
minLength: {
value: 6,
message: "Password must be at least 6 characters long",
},
})}
placeholder="Enter your password"
/>
</Field>
<Field
color={"#313039"}
label={"Confirm password"}
w={"100%"}
invalid={!!errors.confirmPassword}
errorText={errors.confirmPassword?.message}
>
<Input
ps={3}
type="password"
{...register("confirmPassword", {
required: "Please confirm your password",
validate: (value) =>
value === getValues("password") || "Passwords do not match",
})}
placeholder="Confirm your password"
/>
</Field>
<Button
loading={isLoading}
mt={4}
size={"sm"}
bg={"#02A0A0"}
rounded={"md"}
w={"100%"}
color={"#ffffff"}
type="submit"
textTransform="capitalize"
>
Confirm Password
</Button>
<Text>Forgot password</Text>
</VStack>
</VStack>
</Center>
<Toaster />
</HStack>
</VStack>
);
};
export default CreatePass;

View File

@@ -0,0 +1,142 @@
import { Center, HStack, Image, Input, Text, VStack } from "@chakra-ui/react";
import { useContext, useState } from "react";
import { useForm } from "react-hook-form";
import GlobalStateContext from "../../Contexts/GlobalStateContext";
import logo from "../../assets/logo.svg";
import uiEdit from "../../assets/icons/edit.png";
import { Button } from "../../components/ui/button";
import { Field } from "../../components/ui/field";
import { Toaster, toaster } from "../../components/ui/toaster";
import { PinInput } from "../../components/ui/pin-input";
interface FormValues {
mobileNumber: number;
}
const LoginOtp = () => {
const [isLoading, setIsLoading] = useState<boolean>(false);
const context = useContext(GlobalStateContext);
if (!context) {
throw new Error("App must be used within a GlobalStateProvider");
}
const { setIsAuthenticate } = context;
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormValues>();
const onSubmit = handleSubmit((data) => {
setIsLoading(true);
if (data?.mobileNumber === 1234567890) {
setTimeout(() => {
setIsAuthenticate(true);
setIsLoading(false);
}, 3000); // 3-second delay
} else {
toaster.create({
title: `Invalid Credentials`,
type: "error",
});
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>
<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>
<Center
as={"form"}
onSubmit={onSubmit}
p={{ base: 4, md: 16 }}
w={{ base: "100%", md: "50%" }}
h={"100%"}
>
<VStack gap={2} w={"100%"} alignItems={"center"}>
<Text
w={"100%"}
textAlign={"center"}
fontSize={"24px"}
fontWeight={"normal"}
color={"#313039"}
>
Enter otp
</Text>
<Text
w={"100%"}
textAlign={"center"}
fontSize={"sm"}
fontWeight={"normal"}
color={"#49475A"}
>
OTP has been send to your E-mail Address
</Text>
<HStack>
<Image src={uiEdit} h="24px" w="24px" />
<Text
w={"100%"}
textAlign={"center"}
fontSize={"sm"}
fontWeight={"normal"}
color={"#49475A"}
>
9619565889
</Text>
</HStack>
<VStack mt={6} gap={4} w={"full"}>
<PinInput />
<Text
w={"100%"}
textAlign={"center"}
fontSize={"sm"}
fontWeight={"600"}
color={"#4746F4"}
textDecoration="underline"
>
Resend OTP
</Text>
<Button
loading={isLoading}
mt={4}
size={"sm"}
bg={"#02A0A0"}
rounded={"md"}
w={"100%"}
color={"#ffffff"}
type="submit"
>
Send OTP
</Button>
<Text>Forgot password</Text>
</VStack>
</VStack>
</Center>
<Toaster />
</HStack>
</VStack>
);
};
export default LoginOtp;

View File

@@ -1,247 +1,57 @@
import { DialogCloseTrigger, Field, IconButton, Input, Stack, Text } from "@chakra-ui/react";
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
import { Field, Grid, Heading, Input, Stack, Text } from "@chakra-ui/react"
import { FaRegEdit } from "react-icons/fa";
import { Button } from "../../components/ui/button";
import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle } from "../../components/ui/dialog";
// import EnterPassword from "./EnterPassword";
import { useForm } from "react-hook-form";
import { useEffect, useState } from "react";
import { toaster, Toaster } from "../../components/ui/toaster";
import { useNewPasswordSetMutation } from "../../Redux/Service/profile.password";
import { LuEye, LuEyeOff } from "react-icons/lu";
import { InputGroup } from "../../components/ui/input-group";
type EnterPasswordProps = {
onClose: () => void;
isOpen: boolean;
};
type FormData = {
new_password: string;
confirm_password: string;
};
function Changepassword({ onClose, isOpen }: EnterPasswordProps) {
const [showOldPassword, setShowOldPassword] = useState(false);
const [showNewPassword, setShowNewPassword] = useState(false);
const [newPasswordSet] = useNewPasswordSetMutation()
const [isLoading, setIsLoading] = useState(false);
const {
register,
handleSubmit,
formState: { errors },
setError,
clearErrors,
watch,
reset,
} = useForm<FormData>({
defaultValues: {
new_password: '',
confirm_password: ''
}
});
const newPassword = watch("new_password");
const confirmPassword = watch("confirm_password");
useEffect(() => {
if (newPassword && confirmPassword && newPassword !== confirmPassword) {
setError("confirm_password", {
type: "manual",
message: "Passwords do not match"
});
} else if (confirmPassword) {
clearErrors("confirm_password");
}
}, [newPassword, confirmPassword, setError, clearErrors]);
const onSubmit = async (data: FormData) => {
if (data.new_password === '' || data.confirm_password === '') {
return
}
if (data.new_password !== data.confirm_password) {
setError("confirm_password", {
type: "manual",
message: "Passwords do not match"
});
return;
}
console.log('ERROR', errors)
console.log('Change submitted:', data);
clearErrors("confirm_password");
setIsLoading(true);
const payload = {
new_password: data.new_password,
confirm_password: data.confirm_password
}
try {
const res = await newPasswordSet(payload).unwrap()
if (res.status === 'success') {
toaster.create({
title: "Password changed Successfully",
type: "success",
});
onClose()
} else {
toaster.create({
title: res.data.message || "Invalid password",
type: "error",
});
}
reset()
} catch (error: any) {
toaster.create({
title: error.data.message || "Something went wrong",
type: "error",
});
} finally {
setIsLoading(false);
}
};
import EnterPassword from "./EnterPassword";
function Changepassword() {
return (
<>
<DialogRoot
placement="center"
open={isOpen}
onOpenChange={(open) => !open && onClose()}
<DialogRoot placement="center">
<DialogTrigger asChild>
<Button bg="#02A0A0" color={"#fff"} p={4} fontSize={"12px"} mt={2}>
Change Password
</Button>
</DialogTrigger>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
// height={'80vh'}
// overflow={'scroll'}
p={2} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" pt={3} pb={2} >
<DialogTitle alignSelf="center" color="black" fontSize="18px" textAlign={"center"}>CHANGE PASSWORD</DialogTitle>
</DialogHeader>
{/* <DialogTrigger asChild>
<Button bg="#02A0A0" size={'2xs'} color={"#fff"} px={2} >
Change Password
</Button>
</DialogTrigger> */}
<DialogBody bg="white" pt={5}>
<Stack p={2} >
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">New password</Field.Label>
<Input color="black" pl={1} fontSize="12px" height="30px" type="password" border="1px solid grey" /></Field.Root>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Confirm password</Field.Label>
<Input color="black" pl={1} fontSize="12px" height="30px" type="password" border="1px solid grey" /></Field.Root>
<DialogContent
bg={"#fff"}
w={{ base: '90%', md: '400px' }}
p={2}
bgSize={'md'}
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" mt={2} p={2}
>
<DialogHeader bg="white" pt={3} pb={2} >
<DialogTitle alignSelf="center" color="black" fontSize="18px" textAlign={"center"}>CHANGE PASSWORD</DialogTitle>
</DialogHeader>
<form onSubmit={handleSubmit(onSubmit)}>
<DialogBody bg="white" pt={5}>
<Stack p={2} >
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">New password</Field.Label>
<InputGroup
width={'100%'}
endElement={
<IconButton
aria-label={showOldPassword ? "Hide password" : "Show password"}
size="sm"
// variant="outline"
onClick={() => setShowOldPassword(!showOldPassword)}
_hover={{ bg: "transparent" }}
height={'fit-content'}
mr={2}
>
{showOldPassword ? <LuEye /> : <LuEyeOff />}
</IconButton>
}>
<Input
color="black"
pl={1}
fontSize="12px"
height="30px"
type={showOldPassword ? "text" : "password"}
border={errors.new_password ? "1px solid red" : "1px solid grey"}
{...register("new_password", {
required: "Password is required",
minLength: {
value: 8,
message: "Password must be at least 8 characters",
},
})}
/>
</InputGroup>
{/* <IconButton
aria-label={showPassword ? "Hide password" : "Show password"}
size="sm"
variant="ghost"
onClick={() => setShowPassword(!showPassword)}
>
{showPassword ? <LuEye /> : <LuEyeOff />}
</IconButton> */}
{/* <Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button> */}
<EnterPassword />
</DialogFooter>
{errors.new_password && (
<Text color="red.500" fontSize="xs" mt={1}>
{errors.new_password.message}
</Text>
)}
{/* <DialogCloseTrigger color="black" /> */}
</DialogContent>
</DialogRoot >
</Field.Root>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Confirm password</Field.Label>
<InputGroup
width={'100%'}
endElement={
<IconButton
aria-label={showNewPassword ? "Hide password" : "Show password"}
size="sm"
// variant="outline"
onClick={() => setShowNewPassword(!showNewPassword)}
_hover={{ bg: "transparent" }}
height={'fit-content'}
mr={2}
>
{showNewPassword ? <LuEye /> : <LuEyeOff />}
</IconButton>
}>
<Input
color="black"
pl={1}
fontSize="12px"
height="30px"
type={showNewPassword ? "text" : "password"}
border={errors.confirm_password ? "1px solid red" : "1px solid grey"}
{...register("confirm_password", {
required: "Please confirm your password",
validate: (value) =>
value === newPassword || "Passwords do not match",
})}
/>
</InputGroup>
{errors.confirm_password && (
<Text color="red.500" fontSize="xs" mt={1}>
{errors.confirm_password.message}
</Text>
)}
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" mt={2} p={2}
>
{/* <EnterPassword /> */}
<Button
loading={isLoading}
mt={6}
w="100%"
bg="#02A0A0"
color="white"
type="submit"
>
Submit
</Button>
</DialogFooter>
</form>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
<Toaster />
</>
)
}

View File

@@ -1,87 +1,11 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle } from "../../components/ui/dialog"
import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
import { Box, Input, Stack, Text } from "@chakra-ui/react"
import { Button } from "../../components/ui/button";
import { useEffect, useState } from "react";
// import { BiSolidEdit } from "react-icons/bi";
import { Toaster, toaster } from "../../components/ui/toaster";
import { useGetProfileQuery, useResendOtpMutation, useVerifyOTPMutation } from "../../Redux/Service/profile.password";
import { useForm } from "react-hook-form";
import Changepassword from "./ChangePassword";
import { useState } from "react";
import { BiSolidEdit } from "react-icons/bi";
type EnterOTPProps = {
onClose: () => void;
isOpen: boolean;
};
type FormData = {
otp: string[];
};
function EnterOTP({ onClose, isOpen }: EnterOTPProps) {
const [isLoading, setIsLoading] = useState(false);
const [timer, setTimer] = useState(60);
const [isResendDisabled, setIsResendDisabled] = useState(true);
const [verifyOTP] = useVerifyOTPMutation()
const [otpSuccess, setOtpSuccess] = useState(false);
const [resendOtp] = useResendOtpMutation()
const { data } = useGetProfileQuery()
const id = data?.data.id
const {
register,
handleSubmit,
formState: { errors },
reset,
} = useForm<FormData>({
defaultValues: {
otp: ["", "", "", ""] // Initialize with empty strings for each digit
}
});
useEffect(() => {
let interval: NodeJS.Timeout;
if (timer > 0 && isResendDisabled) {
interval = setInterval(() => {
setTimer((prevTimer) => prevTimer - 1);
}, 1000);
} else if (timer === 0) {
setIsResendDisabled(false);
}
return () => clearInterval(interval);
}, [timer, isResendDisabled]);
const handleResendOTP = async () => {
setIsResendDisabled(true);
setTimer(60); // Reset timer to 1 minute
try {
const res = await resendOtp({ mobile_number: Number(id) }).unwrap()
if (res.status === 200) {
toaster.create({
title: "OTP resent successfully",
type: "success",
});
} else {
toaster.create({
title: res.data.message || "Failed to resend OTP",
type: "error",
});
setIsResendDisabled(false); // Enable button if failed
}
} catch (error: any) {
toaster.create({
title: error.response?.data?.message || "Failed to resend OTP",
type: "error",
});
setIsResendDisabled(false); // Enable button if error
}
};
function EnterOTP() {
const [otp, setOtp] = useState<string[]>(["", "", "", ""]);
// Handle change for OTP inputs
const handleChange = (e: React.ChangeEvent<HTMLInputElement>, index: number): void => {
@@ -91,174 +15,94 @@ function EnterOTP({ onClose, isOpen }: EnterOTPProps) {
if (/[^0-9]/.test(value)) return;
// Update the OTP state with the new value
// const newOtp = [...otp];
// newOtp[index] = value;
// setOtp(newOtp);
if (value && index < 3) {
const nextInput = document.getElementById(`otp-input-${index + 1}`) as HTMLInputElement;
if (nextInput) nextInput.focus();
}
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();
// }
if (value === "" && index > 0) {
const prevInput = document.getElementById(`otp-input-${index - 1}`) as HTMLInputElement;
if (prevInput) prevInput.focus();
}
};
const onSubmit = async (data: FormData) => {
console.log('ERROR', errors)
if (data.otp.length !== 4) {
toaster.create({
title: "OTP must be 4 digits",
type: "error",
});
return;
}
const fullOtp = data.otp.join('');
console.log('OTP submitted:', fullOtp);
setIsLoading(true);
try {
const res = await verifyOTP({ otp: fullOtp }).unwrap()
if (res.status === 'success') {
toaster.create({
title: "OTP Verified Successfully",
type: "success",
});
setOtpSuccess(true);
reset();
} else {
toaster.create({
title: res.data.message || "Invalid OTP",
type: "error",
});
}
reset()
} catch (error: any) {
toaster.create({
title: error.data?.message || "Something went wrong",
type: "error",
});
setOtpSuccess(false);
} finally {
setIsLoading(false);
if (value && index < otp.length - 1) {
const nextInput = document.getElementById(`otp-input-${index + 1}`) as HTMLInputElement;
if (nextInput) nextInput.focus();
}
};
return (
<>
<DialogRoot placement="center"
open={isOpen}
onOpenChange={(open) => !open && onClose()}>
{/* <DialogTrigger asChild>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Submit
</Button>
</DialogTrigger> */}
<DialogRoot placement="center">
<DialogTrigger asChild>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
</DialogTrigger>
// height={'80vh'}
// overflow={'scroll'}
p={2} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" pt={3} alignSelf="center">
<DialogTitle alignSelf="center" color="black" fontSize="18px" textAlign={"center"}>ENTER OTP</DialogTitle>
</DialogHeader>
<form onSubmit={handleSubmit(onSubmit)}>
<DialogBody bg="white" pt={2}>
<Text color={"black"} textAlign={"center"}>OTP has been sent successfully</Text>
{/* <Box display="flex" flexDirection="row" alignItems="center" justifyContent="center" p={3}>
<BiSolidEdit color="black" />
<Text color="black" textAlign="center" ml={2}>9619565889</Text>
</Box> */}
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
// height={'80vh'}
// overflow={'scroll'}
p={2} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" pt={3}>
<DialogTitle alignSelf="center" color="black" fontSize="18px" textAlign={"center"}>ENTER OTP</DialogTitle>
</DialogHeader>
<DialogBody bg="white" pt={2}>
<Text color={"black"} textAlign={"center"}>OTP has been send to your E-mail Address</Text>
<Box display="flex" flexDirection="row" alignItems="center" justifyContent="center" p={3}>
<BiSolidEdit color="black" />
<Text color="black" textAlign="center" ml={2}>9619565889</Text>
</Box>
<Stack direction="row" justify="center" pt={2}>
<Stack direction="row" justify="center" pt={2}>
{/* 4 OTP Inputs */}
{Array.from({ length: 4 }).map((_, index) => (
<Input
key={index}
id={`otp-input-${index}`}
maxW="50px"
color="black"
textAlign="center"
fontSize="20px"
placeholder="0"
border={errors.otp?.[index] ? "1px solid red" : "1px solid grey"}
maxLength={1}
{...register(`otp.${index}`, {
required: "Digit required",
pattern: {
value: /^[0-9]$/,
message: "Must be a single digit"
},
onChange: (e) => handleChange(e, index)
})}
/>
))}
</Stack>
<Box textAlign="center" mt={4}>
{isResendDisabled ? (
<Text color="gray.500">
Resend OTP in {timer} seconds
</Text>
) : (
<Text
color="#4746F4"
textDecoration="underline"
fontWeight="bold"
cursor="pointer"
onClick={handleResendOTP}
>
Resend OTP
</Text>
)}
</Box>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" mt={2} p={2}
{/* 4 OTP Inputs */}
{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
/>
))}
</Stack>
<Box textAlign="center">
<Text
color="#4746F4"
textDecoration="underline"
fontWeight="bold"
mt={3}
cursor="pointer"
display="inline-block"
px={2} // Adds padding for better appearance
>
<Button
loading={isLoading}
mt={6}
w="100%"
bg="#02A0A0"
color="white"
type="submit"
>
Verify OTP
</Button>
</DialogFooter>
</form>
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
{otpSuccess && (<Changepassword
onClose={() => {
setOtpSuccess(false);
onClose()
}}
isOpen={otpSuccess}
/>)}
<Toaster />
</>
Resend OTP
</Text>
</Box>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" mt={2} p={2}
>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
{/* <DialogCloseTrigger color="black" /> */}
</DialogContent>
</DialogRoot >
)
}

View File

@@ -1,127 +1,53 @@
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
import { Field, Input, Stack, Text } from "@chakra-ui/react"
import { useForm } from "react-hook-form";
import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
import { Field, Input, Stack } from "@chakra-ui/react"
import { Button } from "../../components/ui/button";
import EnterOTP from "./EnterOTP";
import { useProfilePasswordMutation } from "../../Redux/Service/profile.password";
import { useState } from "react";
import { Toaster, toaster } from "../../components/ui/toaster";
type FormData = {
password: string;
};
function EnterPassword() {
const [profilePassword] = useProfilePasswordMutation();
const [isSuccess, setIsSuccess] = useState(false);
const [isDialogOpen, setIsDialogOpen] = useState(false);
const {
register,
handleSubmit,
formState: { errors },
reset,
} = useForm<FormData>();
const onSubmit = async (data: FormData) => {
if (!data.password) {
return
}
try {
await profilePassword({ password: data.password }).unwrap();
setIsSuccess(true);
reset();
setIsDialogOpen(false);
// Handle success (e.g., show a success message or redirect)
} catch (error: any) {
// Handle error (e.g., show an error message)
toaster.create({
title: error?.data.message || "Invalid password",
type: "error",
});
console.error("Password change failed:", error.data.message);
setIsSuccess(false);
}
};
return (
<>
<DialogRoot placement="center"
open={isDialogOpen}
onOpenChange={(details) => setIsDialogOpen(details.open)}
<DialogRoot placement="center">
<DialogTrigger asChild>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogTrigger>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
// height={'80vh'}
// overflow={'scroll'}
p={2} // Reduced padding
bgSize={'md'}
>
<DialogTrigger asChild>
<Button bg="#02A0A0" size={'2xs'} color={"#fff"} px={2} >
Change Password
</Button>
<DialogHeader bg="white" pt={3} pb={2} >
<DialogTitle alignSelf="center" color="black" fontSize="18px" textAlign={"center"}>ENTER PASSWORD</DialogTitle>
</DialogHeader>
</DialogTrigger>
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
<DialogBody bg="white" pt={5}>
<Stack p={2} >
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Password</Field.Label>
<Input color="black" pl={1} fontSize="12px" height="30px" type="password" border="1px solid grey" /></Field.Root>
// height={'80vh'}
// overflow={'scroll'}
p={2} // Reduced padding
bgSize={'md'}
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" mt={2} p={2}
>
<DialogHeader bg="white" pt={3} pb={2} >
<DialogTitle alignSelf="center" color="black" fontSize="18px" textAlign={"center"}>ENTER PASSWORD</DialogTitle>
</DialogHeader>
<form onSubmit={handleSubmit(onSubmit)}>
<DialogBody bg="white" pt={5}>
<Stack p={2} >
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Password</Field.Label>
<Input
color="black"
pl={1}
fontSize="12px"
height="30px"
type="password"
border={errors.password ? "1px solid red" : "1px solid grey"}
{...register("password", {
required: "Password is required",
minLength: {
value: 8,
message: "Password must be at least 8 characters",
},
})}
/>
{errors.password && (
<Text color="red.500" fontSize="xs" mt={1}>
{errors.password.message}
</Text>
)}
</Field.Root>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" mt={2} p={2}
>
{/* <Button w="100%" bg="#02A0A0" color={"#fff"}>
{/* <Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button> */}
<Button type="submit" w="100%" bg="#02A0A0" color={"#fff"}>
Submit
</Button>
</DialogFooter>
<EnterOTP />
</DialogFooter>
<DialogCloseTrigger color="black" />
</form>
</DialogContent>
</DialogRoot >
{isSuccess && (<EnterOTP
onClose={() => {
setIsSuccess(false);
setIsDialogOpen(false);
}}
isOpen={isSuccess}
/>)
}
<Toaster />
</>
{/* <DialogCloseTrigger color="black" /> */}
</DialogContent>
</DialogRoot >
)
}

View File

@@ -1,147 +1,10 @@
import { Avatar, Box, HStack, Text, VStack } from "@chakra-ui/react";
import { FaCamera } from "react-icons/fa";
import EditableInput from "../../components/EditableInput";
import MainFrame from "../../components/MainFrame";
import { Field } from "../../components/ui/field";
// import Changepassword from "./ChangePassword";
import EnterPassword from "./EnterPassword";
import { useGetProfileQuery } from "../../Redux/Service/profile.password";
// import { useUpdateImageMutation } from "../../Redux/Service/myprofie.service";
import { useEffect, useRef, useState } from "react";
import { Toaster, toaster } from "../../components/ui/toaster";
import axios from "axios";
const APIURL = import.meta.env.VITE_API_URL
const PROFILEIMGURL = import.meta.env.VITE_IMG_PROFILE
import MainFrame from "../../components/MainFrame"
const Profile = () => {
const { data, refetch } = useGetProfileQuery()
const fileInputRef = useRef<HTMLInputElement>(null);
const [avatarSrc, setAvatarSrc] = useState<string>("");
// const [updateImage] = useUpdateImageMutation();
useEffect(() => {
if (data?.data.profile_photo) {
setAvatarSrc(data.data.profile_photo);
}
}, [data?.data.profile_photo]);
const handleClick = () => {
fileInputRef.current?.click();
};
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
if (file.size > 2 * 1024 * 1024) {
alert("File size exceeds 2MB limit.");
return;
}
// Preview the image
const previewUrl = URL.createObjectURL(file);
setAvatarSrc(previewUrl);
// Prepare FormData
const formData = new FormData();
formData.append("profile_photo", file, file.name);
const token = localStorage.getItem("token");
try {
if (token) {
await axios.post(`${APIURL}/profile-image-edit`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
'access-token': `${token}`,
},
// withCredentials: true,
});
toaster.create({
title: "Success",
description: "Updated successfully",
type: "success",
});
refetch();
}
} catch (error) {
console.error("Error updating image:", error);
toaster.create({
title: "Error",
description: "Something went wrong",
type: "error",
});
}
};
console.log('PROFILE DATA:', data?.data);
return (
<MainFrame >
<HStack alignItems={'flex-start'} justifyContent={'center'} pt={0} h={'89vh'} w={'100%'} >
<VStack w={'50%'} p={3} rounded={'lg'} mb={3}>
<HStack shadow={'md'} rounded={'lg'} justifyContent={'space-between'} alignItems={'flex-end'} w={'100%'} px={3} py={3} >
<VStack w={'100%'} alignItems={'flex-start'} gap={0}>
<Box mb={2} position="relative" width="fit-content"
cursor="pointer" onClick={handleClick}>
<Avatar.Root size={"2xl"} style={{ display: "flex", width: "50px", height: '50px', justifyContent: 'center' }}>
<Avatar.Fallback />
{/* <Avatar.Image src="https://i.pinimg.com/736x/d6/cd/0f/d6cd0ffd4634b0763d3958a7325ce26e.jpg" /> */}
{avatarSrc && <Avatar.Image src={`${PROFILEIMGURL}${avatarSrc}`} />}
</Avatar.Root>
<Box
position="absolute"
bottom="-2px"
left={"39px"}
p="2px"
>
<FaCamera color="#ccc" size={16} />
</Box>
<input
type="file"
accept="image/*"
ref={fileInputRef}
style={{ display: "none" }}
onChange={handleFileChange}
/>
</Box>
<Text color={"black"} as={'span'} fontSize={'sm'} fontWeight={"bold"}>{`${data?.data?.first_name.charAt(0).toUpperCase()}${data?.data.first_name.slice(1)}`}
</Text>
{/* <Text color="black" as={'span'} fontSize={'xs'}>
Employee ID: <span>#1245679</span>
</Text> */}
</VStack>
<EnterPassword />
{/* <Changepassword /> */}
</HStack>
<VStack w={"100%"} >
<Field mt={4} label="First Name" fontSize="xs" required>
<EditableInput value={`${data?.data.first_name}`} placeholder="Enter first name" isDisabled />
</Field>
<Field mt={4} label="Last Name" fontSize="xs" required>
<EditableInput value={`${data?.data.last_name}`} placeholder="Enter last name" isDisabled />
</Field>
<Field mt={4} label="Mobile Number" fontSize="xs" required>
<EditableInput value={`${data?.data.phone_number}`} placeholder="Mobile Number" type='number' isDisabled />
</Field>
</VStack>
</VStack>
</HStack>
<Toaster />
</MainFrame >
</MainFrame>
)
}

View File

@@ -1,197 +0,0 @@
import {
Box,
Center,
HStack,
IconButton,
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";
import { InputGroup } from "../components/ui/input-group";
import { LuEye, LuEyeOff } from "react-icons/lu";
const SetNewPassword = () => {
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [isLoading, setIsLoading] = useState(false);
const navigate = useNavigate();
const queryParams = new URLSearchParams(window.location.search);
const id = queryParams.get("id");
const [showOldPassword, setShowOldPassword] = useState(false);
const [showNewPassword, setShowNewPassword] = useState(false);
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}/update-password`,
{
password: password,
confirm_password: confirmPassword,
id: Number(id),
}
);
if (res.data.status === "success") {
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" w={"400px"}>
<Text
fontSize="20px"
fontWeight="bold"
color="#313039"
marginBottom={"20px"}
>
Create a Password
</Text>
<Stack>
<Box mb={3}>
<Text color="black" fontSize="12px" mb={2}>
New password
</Text>
<InputGroup
width={"100%"}
endElement={
<IconButton
aria-label={
showOldPassword ? "Hide password" : "Show password"
}
size="sm"
onClick={() => setShowOldPassword(!showOldPassword)}
// _hover={{ bg: "transparent" }}
bg={"transparent"}
color={"#000"}
height={"fit-content"}
mr={2}
>
{showOldPassword ? <LuEyeOff /> : <LuEye />}
</IconButton>
}
>
<Input
color="black"
pl={1}
fontSize="12px"
type={showOldPassword ? "password" : "text"}
border="1px solid grey"
value={password}
onChange={(e) => setPassword(e.target.value)}
size={"sm"}
/>
</InputGroup>
</Box>
<Box>
<Text color="black" mb={2} fontSize="12px">
Confirm password
</Text>
<InputGroup
width={"100%"}
endElement={
<IconButton
aria-label={
showNewPassword ? "Hide password" : "Show password"
}
size="sm"
// variant="outline"
onClick={() => setShowNewPassword(!showNewPassword)}
bg={"transparent"}
color={"#000"}
mr={2}
>
{showNewPassword ? <LuEyeOff /> : <LuEye />}
</IconButton>
}
>
<Input
color="black"
pl={1}
fontSize="12px"
type={showNewPassword ? "password" : "text"}
border="1px solid grey"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
size={"sm"}
/>
</InputGroup>
</Box>
</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

@@ -1,319 +1,80 @@
import { Button } from "../../components/ui/button";
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../components/ui/dialog";
import { Field, Grid, Heading, Input, Stack, Text } from "@chakra-ui/react";
import { IoMdAdd } from "react-icons/io";
import { Checkbox } from "../../components/ui/checkbox";
import { PermissionResponse, useCreateSubAdminPostMutation } from "../../Redux/Service/manage.subadmin.service";
import { toaster, Toaster } from "../../components/ui/toaster";
import { useEffect, useState } from "react";
import { Button } from "../../components/ui/button"
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
import { Field, Grid, Heading, Input, Stack, Text } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io"
import { Checkbox } from "../../components/ui/checkbox"
function AddModel({ refetch, allPermissions }: { refetch: VoidFunction, allPermissions?: PermissionResponse }) {
const [createSubAdminPost, { isLoading }] = useCreateSubAdminPostMutation();
function AddModel() {
return (
// State fields
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
// const [userName, setUserName] = useState("");
const [dateOfBirth, setDateOfBirth] = useState("");
const [gender, setGender] = useState("");
const [email, setEmail] = useState("");
const [phonenumber, setPhonenumber] = useState("");
const [permissions, setPermission] = useState<number[]>([]);
const [isOpen, setIsOpen] = useState(false);
// const [ setIsOpen] = useState(false);
<DialogRoot placement="center">
<DialogTrigger asChild>
{/* <Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
</Button> */}
<Button px={4} size={"xs"} bg={"#02A0A0"}><IoMdAdd /> <Text>Add</Text></Button>
const handleOpenModal = () => {
setIsOpen(true);
};
</DialogTrigger>
const handleCheckboxToggle = (permissionId: number) => {
setPermission((prevData) =>
prevData.includes(permissionId)
? prevData.filter((id) => id !== permissionId)
: [...prevData, permissionId]
);
};
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'80vh'}
overflow={'scroll'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white" >
<DialogTitle alignSelf="center" color="black" fontSize="14px"
>Add Sub Admin Account</DialogTitle>
</DialogHeader>
useEffect(() => {
if (!isOpen) {
setFirstName("");
setLastName("");
// setUserName("");
setDateOfBirth("");
setGender("");
setEmail("");
setPhonenumber("");
setPermission([]);
}
}, [isOpen]);
<DialogBody bg="white">
<Stack py={3} >
const handleSubmit = async () => {
if (
!firstName.trim() ||
!lastName.trim() ||
!dateOfBirth.trim() ||
!gender.trim()
) {
toaster.create({
title: "Error",
description: "Please fill in all required fields",
type: "error",
});
return;
}
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">First Name</Field.Label>
<Input placeholder="Enter the First Name" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
toaster.create({
title: "Invalid Email",
description: "Please enter a valid email address",
type: "error",
});
return;
}
<Field.Label color="black" pt={1} fontSize="12px">Last Name</Field.Label>
<Input placeholder="Enter the Last Name" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
if (phonenumber.length !== 10) {
toaster.create({
title: "Invalid Phone Number",
description: "Phone number must be exactly 10 digits",
type: "error",
});
return;
}
<Field.Label color="black" pt={1} fontSize="12px">DOB</Field.Label>
<Input placeholder="Enter the DOB" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
const payload = {
// user_name: userName,
first_name: firstName,
last_name: lastName,
date_of_birth: dateOfBirth,
gender: gender,
email_address: email,
phone_number: phonenumber,
permission: permissions.filter((id) => typeof id === "number"),
// created_by: 1,
};
<Field.Label color="black" pt={1} fontSize="12px">Gender</Field.Label>
<Input placeholder="Enter the Gender" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
<Heading mt={5} color={'#000'} fontSize={'sm'}>Permissions</Heading>
</Field.Root>
<Grid templateColumns="repeat(2, 1fr)" gap={4}>
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>Dashboard</Text></Checkbox>
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>Manage contact us</Text></Checkbox>
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>manage User</Text></Checkbox>
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>Manage CMS</Text></Checkbox>
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>Manage Post</Text></Checkbox>
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>Manage Reports</Text></Checkbox>
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>manage Sub-Admin</Text></Checkbox>
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>My profile</Text></Checkbox>
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>Manage Jobs</Text> </Checkbox>
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}> manage feedbacks</Text></Checkbox>
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>Manage community</Text> </Checkbox>
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}> Notification</Text></Checkbox>
</Grid>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button>
</DialogFooter>
try {
const response = await createSubAdminPost(payload).unwrap();
if (response) {
toaster.create({
title: "Success",
description: "Sub-admin created successfully",
type: "success",
});
refetch();
setFirstName("");
setLastName("");
// setUserName("");
setDateOfBirth("");
setGender("");
setIsOpen(false);
}
} catch (error:any) {
console.error("Error creating sub-admin:", error);
toaster.create({
title: "Error",
description: error ? error.data.message : "Failed to create sub-admin",
type: "error",
});
}
};
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
return (
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogTrigger asChild>
<Button
rounded={"md"}
px={4} py={2}
size={"xs"}
bg={"#02A0A0"}
onClick={handleOpenModal}>
<IoMdAdd /> Add
</Button>
</DialogTrigger>
<DialogContent
bg={"#fff"}
w={{ base: "90%", md: "400px" }}
height={"80vh"}
overflow={"scroll"}
overflowX="hidden"
p={3}
bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Add Sub Admin Account
</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
First Name
</Field.Label>
<Input
placeholder="Enter the First Name"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
/>
<Field.Label color="black" pt={1} fontSize="12px">
Last Name
</Field.Label>
<Input
placeholder="Enter the Last Name"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={lastName}
onChange={(e) => setLastName(e.target.value)}
/>
{/* <Field.Label color="black" pt={1} fontSize="12px">
Username
</Field.Label>
<Input
placeholder="Enter the Username"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={userName}
onChange={(e) => setUserName(e.target.value)}
/> */}
<Field.Label color="black" pt={1} fontSize="12px">
DOB
</Field.Label>
<Input
placeholder="Enter the DOB"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
type="date"
value={dateOfBirth}
onChange={(e) => setDateOfBirth(e.target.value)}
/>
<Field.Label color="black" pt={1} fontSize="12px">
Gender
</Field.Label>
<Input
placeholder="Enter the Gender"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={gender}
onChange={(e) => setGender(e.target.value)}
/>
<Field.Label color="black" pt={1} fontSize="12px">
Email Address
</Field.Label>
<Input
placeholder="Enter Email address"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
type="email"
fontSize="12px"
height="30px"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<Field.Label color="black" pt={1} fontSize="12px">
Phone Number
</Field.Label>
<Input
placeholder="Enter phone number"
bgColor="#EEEEEE"
color="black"
border="none"
type="tel"
pl={1}
fontSize="12px"
height="30px"
value={phonenumber}
onChange={(e) => {
const value = e.target.value;
if (/^\d*$/.test(value)) { // Only allow digits
setPhonenumber(value);
}
}}
/>
<Heading mt={5} color={"#000"} fontSize={"sm"}>
Permissions
</Heading>
</Field.Root>
<Grid templateColumns="repeat(2, 1fr)" gap={4}>
{Array.isArray(allPermissions?.data?.permission)
? allPermissions.data.permission.map((permission: any) => (
<Checkbox
size="sm"
color="black"
key={permission.id}
checked={permissions.includes(permission.id)}
onChange={() => handleCheckboxToggle(permission.id)}
>
<Text fontSize={12}>{permission.app_resource_title}</Text>
</Checkbox>
))
: <Text fontSize={12} color="gray.500">Loading permissions...</Text>
}
</Grid>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button
size={"xs"}
w="100%"
bg="#02A0A0"
color={"#fff"}
onClick={handleSubmit}
disabled={isLoading}
>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
<Toaster />
</DialogRoot>
);
)
}
export default AddModel;
export default AddModel

View File

@@ -1,301 +0,0 @@
import { Field, Grid, Heading, Input, Stack, Text } from "@chakra-ui/react";
// import { TbEdit } from "react-icons/tb";
import { Button } from "../../components/ui/button";
import { Checkbox } from "../../components/ui/checkbox";
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../components/ui/dialog";
import Edit from "../../components/ActionIcons/Edit";
import { PermissionResponse, useLazyViewSubAdminQuery, useUpdateSubAdminMutation } from "../../Redux/Service/manage.subadmin.service";
import { useEffect, useState } from "react";
import { Toaster, toaster } from "../../components/ui/toaster";
const resourceIdToLabel: { [key: number]: string } = {
1: 'Dashboard',
2: 'Manage User',
3: 'Manage Post',
4: 'Manage Subadmin',
5: 'Manage Jobs',
6: 'Manage Groups',
7: 'Manage Contact Us',
8: 'Manage CMS',
9: 'My Profile',
10: 'Master Module',
};
interface ResourceActionLink {
id: number;
app_resource_xid: number;
is_active: boolean;
app_resource: {
id: number,
app_resource_title: string
}
}
function EditSubAdmin({ id, refetch, allPermissions }: { id: number, refetch: VoidFunction, allPermissions?: PermissionResponse }) {
const [trigger, { data }] = useLazyViewSubAdminQuery();
const [updateSubAdmin, {isLoading}] = useUpdateSubAdminMutation()
const [isOpen, setIsOpen] = useState(false);
const [editData, setEditData] = useState<{
id: string;
unique_id?: string,
first_name: string;
last_name: string;
date_of_birth: string;
gender?: string,
permission: ResourceActionLink[];
}>({
id: '',
unique_id: '',
first_name: '',
last_name: '',
date_of_birth: '',
gender: '',
permission: [],
})
useEffect(() => {
if (data?.data?.length && allPermissions?.data?.permission?.length) {
const subAdmin = data.data[0];
const activePermissionIds = subAdmin.get_resource_action_link
.filter((perm: any) => perm.is_active)
.map((perm: any) => perm.app_resource_xid);
const mergedPermissions: ResourceActionLink[] = allPermissions.data.permission.map((perm) => ({
id: perm.id,
app_resource_xid: perm.id,
is_active: activePermissionIds.includes(perm.id),
app_resource: {
id: perm.id,
app_resource_title: perm.app_resource_title,
},
}));
// Map the API response to editData
setEditData({
id: subAdmin.id.toString(),
unique_id: subAdmin.unique_id,
first_name: subAdmin.first_name,
last_name: subAdmin.last_name,
date_of_birth: formatDateOfBirth(subAdmin.date_of_birth),
gender: subAdmin.gender,
permission: mergedPermissions,
});
}
}, [data, allPermissions]);
const formatDateOfBirth = (dob: string): string => {
// Convert the date to the desired format with slashes
const formattedDate = new Date(dob).toLocaleDateString("en-GB", {
day: "2-digit",
month: "2-digit",
year: "numeric",
});
// Replace slashes with hyphens
return formattedDate.replace(/\//g, '-');
};
const handleOpenModal = () => {
trigger(id)
setIsOpen(true);
};
const handleCheckboxToggle = (permissionId: number) => {
setEditData((prevData) => ({
...prevData,
permission: prevData.permission.map((permission) =>
permission.app_resource_xid === permissionId
? { ...permission, is_active: !permission.is_active }
: permission
),
}));
};
const handleSubmit = async () => {
console.log('Updated Data:', editData);
// Call your API here with the updated editData
const payload = {
id: Number(editData.id),
// unique_id: editData.unique_id,
first_name: editData.first_name,
last_name: editData.last_name,
date_of_birth: editData.date_of_birth,
gender: editData.gender,
permission: editData.permission
.filter((p) => p.is_active)
.map((p) => p.app_resource_xid),
};
try {
const response = await updateSubAdmin(payload).unwrap();
if (response?.status === "success") {
toaster.create({
title: "Success",
description: "FAQ updated successfully",
type: "success",
});
refetch()
setIsOpen(false);
} else {
toaster.create({
title: "Error",
description: "Failed to update FAQ",
type: "error",
});
}
} catch (error) {
console.error("Error updating template:", error);
// alert("Failed to update template");
}
};
return (
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogTrigger asChild>
{/* <FaRegEdit style={{ cursor: "pointer" }} color="#000" /> */}
<Button bg="transparent" color={"black"} h={"18px"} onClick={handleOpenModal}><Edit /></Button>
{/* <Button><FaRegEdit /></Button> */}
</DialogTrigger>
<DialogContent
bg={"#fff"}
w={{ base: "90%", md: "400px" }}
height={"80vh"}
overflow={"scroll"}
overflowX="hidden"
p={3} // Reduced padding
bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit Sub Admin Account
</DialogTitle>
</DialogHeader>
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
{/* <Field.Label color="black" pt={1} fontSize="12px">
ID
</Field.Label>
<Input
placeholder="Enter the First Name"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={editData.unique_id}
onChange={(e) => setEditData({ ...editData, unique_id: e.target.value })}
/> */}
<Field.Label color="black" pt={1} fontSize="12px">
First Name
</Field.Label>
<Input
placeholder="Enter the First Name"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={editData.first_name}
onChange={(e) => setEditData({ ...editData, first_name: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px">
Last Name
</Field.Label>
<Input
placeholder="Enter the Last Name"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={editData.last_name}
onChange={(e) => setEditData({ ...editData, last_name: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px">
DOB
</Field.Label>
<Input
placeholder="Enter the DOB"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={editData.date_of_birth}
onChange={(e) => setEditData({ ...editData, date_of_birth: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px">
Gender
</Field.Label>
<Input
placeholder="Enter the Gender"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={editData.gender}
onChange={(e) => setEditData({ ...editData, gender: e.target.value })}
/>
<Heading mt={5} color={"#000"} fontSize={"sm"}>
Permissions
</Heading>
</Field.Root>
<Grid templateColumns="repeat(2, 1fr)" gap={4}>
{editData.permission.map((permission) => {
const label = resourceIdToLabel[permission.app_resource_xid];
return (
<Checkbox
key={permission.id}
size="sm"
color="black"
checked={permission.is_active}
onChange={() => handleCheckboxToggle(permission.app_resource_xid)}
cursor={'pointer'}
>
<Text fontSize={12}>{label}</Text>
</Checkbox>
);
})}
</Grid>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button size={"xs"} w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
<Toaster />
</DialogRoot>
);
}
export default EditSubAdmin;

View File

@@ -1,26 +1,20 @@
import { Box, HStack, Image, Text } from "@chakra-ui/react"
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react"
import MainFrame from "../../components/MainFrame"
// import { InputGroup } from "../../components/ui/input-group"
// import { LuSearch } from "react-icons/lu"
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 AlertDailog from "../../components/AlertDailog"
import { RiDeleteBin5Line } from "react-icons/ri";
import AddModel from "./AddModel"
import EditSubAdmin from "./EditSubAdmin"
import EditSubAdmin from "../../components/EditSubAdmin"
import ViewSubAdmin from "./ViewSubAdmin"
import Delete from "../../components/ActionIcons/Delete"
import { PermissionResponse, useDeleteSubAdminPostMutation, useGetPermissionQuery, useGetSubAdminQuery } from "../../Redux/Service/manage.subadmin.service"
import { useEffect, useState } from "react"
import { Toaster, toaster } from "../../components/ui/toaster"
import { useDebounce } from "../../components/Hooks/useDebounce"
import SearchComponent from "../../components/SearchComponent"
// table data
const tableHeadRow = [
"Sr. No",
"Emp ID",
"Id",
"First Name",
"last Name",
"DOB",
@@ -28,137 +22,39 @@ const tableHeadRow = [
"Action",
];
// const managepost: any[] = [
// ...Array.from({ length: 12 }, (_, i) => ({
// "Sr. No": i + 1,
// "Id": 12565,
// "First Name": "Kamlesh",
// "last Name": "Pandey",
// "DOB": "12/01/1987",
// "Gender": "Male",
// "Action": (
// <HStack justifyContent="center">
// <ViewSubAdmin />
// <EditSubAdmin />
// <AlertDailog
// AltertTiggerIcon={() => <Delete />}
// alertText="Delete Users"
// alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
// alertCaption="are you sure you want to delete ?"
// onConfirm={() => {
// console.log("User deleted:", i + 1);
// }}
// />
// </HStack>
// ),
// })),
// ];
const SubAdmin = () => {
const [currentPage, setCurrentPage] = useState(1);
// const { data, refetch } = useGetSubAdminQuery()
const { data: permissions } = useGetPermissionQuery()
const [localData, setLocalData] = useState<any[]>([]);
const [allPermissions, setAllPermissions] = useState<PermissionResponse>();
const [deleteModal, setDeleteModal] = useState(false)
const [deleteSubAdminPost] = useDeleteSubAdminPostMutation()
const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = useDebounce(searchTerm, 500);
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
const { data, refetch, isError, isFetching } = useGetSubAdminQuery(queryArgs);
useEffect(() => {
if (data?.data.data) {
setLocalData(data?.data.data);
setAllPermissions(permissions);
}
}, [data, permissions]);
console.log("============================", allPermissions);
console.log('localData', localData);
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
const handleDeleteAdmin = async (faqId: number) => {
try {
const response = await deleteSubAdminPost(faqId).unwrap();
if (response.success) {
toaster.create({
title: "Success",
description: "Sub Admin deleted successfully",
type: "success",
});
refetch()
console.log("Sub Admin deleted successfully:", response);
}
// Optionally, refetch data or update state after deletion
} catch (error) {
console.error("Error deleting Sub Admin:", error);
toaster.create({
title: "Error",
description: "Something went wrong",
type: "error",
});
}
};
const formatDateOfBirth = (dob: string): string => {
return new Date(dob).toLocaleDateString("en-GB", {
day: "2-digit",
month: "2-digit",
year: "numeric",
});
};
const filteredData = localData?.filter((agency) => {
const searchLower = searchTerm.toLowerCase();
const userName = agency.user_name?.toLowerCase().includes(searchLower);
const firstName = agency.first_name?.toLowerCase().includes(searchLower);
const lastName = agency.last_name?.toLowerCase().includes(searchLower);
return userName || firstName || lastName;
});
const managepost = filteredData?.map((agency: any, index: number) => ({
'id': agency.id,
"Sr. No": index + 1,
"Emp ID": agency.unique_id,
"First Name": agency.first_name,
"last Name": agency.last_name,
"DOB": formatDateOfBirth(agency.date_of_birth),
"Gender": agency.gender,
const managepost: any[] = [
...Array.from({ length: 12 }, (_, i) => ({
"Sr. No": i + 1,
"Id": 12565,
"First Name": "Kamlesh",
"last Name": "Pandey",
"DOB": "12/01/1987",
"Gender": "Male",
"Action": (
<HStack justifyContent="center">
{/* <EditDetails rowData={{ id: agency.id, question: agency.question, answer: agency.answer }} refetch={refetch} /> */}
<ViewSubAdmin id={agency.id} />
<EditSubAdmin id={agency.id} refetch={refetch} allPermissions={permissions} />
{/* <MdOutlineRemoveRedEye
style={{ cursor: "pointer", fontSize: "16px" }}
/> */}
{/* <ViewDailog /> */}
<ViewSubAdmin />
<EditSubAdmin />
{/* <RiDeleteBin5Line style={{ cursor: "pointer" }} /> */}
<AlertDailog
isOpen={deleteModal}
AltertTiggerIcon={() => <Delete onClick={() => setDeleteModal(prev => !prev)} />}
alertText="Delete sub admin"
AltertTiggerIcon={RiDeleteBin5Line}
alertText="Delete Users"
alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
alertCaption="are you sure you want to delete ?"
onClose={() => setDeleteModal(false)}
onConfirm={() => {
// console.log("User deleted:", index + 1);
setDeleteModal(false);
handleDeleteAdmin(agency.id)
console.log("User deleted:", i + 1);
}}
/>
</HStack>
),
}));
})),
];
const SubAdmin = () => {
return (
<MainFrame >
@@ -175,31 +71,36 @@ const SubAdmin = () => {
</Text>
<HStack>
<SearchComponent
value={searchTerm}
onChange={handleSearchChange}
/>
<InputGroup
startElement={
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
}
color={"#000"}
>
<Input
p={3}
w={300}
bg={"#fff"}
colorPalette={"blue"}
_focus={{ border: "1px solid #02A0A0" }}
rounded={"md"}
size={"2xs"}
fontSize={"2sm"}
placeholder="Search..."
bgColor={'#EEEEEE'}
ps={8}
/>
</InputGroup>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
<AddModel refetch={refetch} allPermissions={permissions} />
<AddModel />
</HStack>
</HStack>
<DataTable
sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow}
data={managepost}
paginationData={{
current_page: data?.data.current_page || 1,
last_page: data?.data.last_page || 1,
per_page: data?.data.per_page || 10,
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
<Toaster />
</MainFrame>
</Box> </MainFrame>
)
}
export default SubAdmin

View File

@@ -1,218 +1,82 @@
// import { Button } from "../../components/ui/button";
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../components/ui/dialog";
import {
Field,
Grid,
Heading,
Input,
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 View from "../../components/ActionIcons/View";
import { Button } from "../../components/ui/button";
import {useLazyViewSubAdminQuery } from "../../Redux/Service/manage.subadmin.service";
import { Button } from "../../components/ui/button"
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
import { Field, Grid, Heading, Input, Stack, Text } from "@chakra-ui/react"
import { Checkbox } from "../../components/ui/checkbox"
import { MdOutlineRemoveRedEye } from "react-icons/md";
function ViewSubAdmin() {
return (
function ViewSubAdmin({ id, }: { id: number}) {
const [trigger, { data }] = useLazyViewSubAdminQuery();
<DialogRoot placement="center" >
<DialogTrigger asChild>
<Button bg={"transparent"} size="sm">
<MdOutlineRemoveRedEye style={{ cursor: "pointer", }} color="#000"/>
</Button>
{/* <Button><FaRegEdit /></Button> */}
const handleView = () => {
trigger(id)
}
const viewSubAdmin = data?.data
</DialogTrigger>
const formatDateOfBirth = (dob: string): string => {
return new Date(dob).toLocaleDateString("en-GB", {
day: "2-digit",
month: "2-digit",
year: "numeric",
});
};
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: '90%', md: '400px' }}
height={'80vh'}
overflow={'scroll'}
overflowX="hidden"
p={3} // Reduced padding
bgSize={'md'}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">View Sub Admin Account</DialogTitle>
</DialogHeader>
console.log('data', data?.data);
return (
<DialogRoot placement="center">
<DialogTrigger asChild>
<Button
onClick={handleView}
bg={'transparent'}
color={"black"}
>
<View />
</Button>
</DialogTrigger>
<DialogBody bg="white">
<Stack py={3} >
{viewSubAdmin?.map((data: any) => (
<DialogContent
bg={"#fff"}
// w={{ lg: "60%", md: "230px" }}
w={{ base: "90%", md: "400px" }}
height={"80vh"}
overflow={"scroll"}
overflowX="hidden"
p={3} // Reduced padding
bgSize={"md"}
key={data.id}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
View Sub Admin Account
</DialogTitle>
</DialogHeader>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">First Name</Field.Label>
<Input value="Priyanka" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly />
<DialogBody bg="white">
<Stack py={3}>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
First Name
</Field.Label>
<Input
value={data.first_name}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
readOnly
/>
<Field.Label color="black" pt={1} fontSize="12px">Last Name</Field.Label>
<Input value="Joshi" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly />
<Field.Label color="black" pt={1} fontSize="12px">
Last Name
</Field.Label>
<Input
value={data.last_name}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
readOnly
/>
<Field.Label color="black" pt={1} fontSize="12px">ID</Field.Label>
<Input value="ID" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly />
<Field.Label color="black" pt={1} fontSize="12px">
ID
</Field.Label>
<Input
value={data.unique_id}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
readOnly
/>
<Field.Label color="black" pt={1} fontSize="12px">DOB</Field.Label>
<Input value="11/02/1989" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly />
<Field.Label color="black" pt={1} fontSize="12px">
DOB
</Field.Label>
<Input
value={formatDateOfBirth(data.date_of_birth)}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
readOnly
/>
<Field.Label color="black" pt={1} fontSize="12px">
Gender
</Field.Label>
<Input
value={data.gender}
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
readOnly
/>
<Heading mt={5} color={"#000"} fontSize={"sm"}>
Permissions
</Heading>
</Field.Root>
<Grid templateColumns="repeat(2, 1fr)" gap={4}>
{data.get_resource_action_link.map((check: any) => (
<Checkbox size={"sm"} color={"black"} checked={check.is_active} key={check.id}>
<Text fontSize={12}>{check?.app_resource.app_resource_title}</Text>
</Checkbox>
// <>
// <Checkbox size={"sm"} color={"black"}>
// <Text fontSize={12}>Dashboard</Text>
// </Checkbox>
// <Checkbox size={"sm"} color={"black"}>
// {" "}
// <Text fontSize={12}>Manage contact us</Text>
// </Checkbox>
// <Checkbox size={"sm"} color={"black"}>
// {" "}
// <Text fontSize={12}>manage User</Text>
// </Checkbox>
// <Checkbox size={"sm"} color={"black"}>
// {" "}
// <Text fontSize={12}>Manage CMS</Text>
// </Checkbox>
// <Checkbox size={"sm"} color={"black"}>
// {" "}
// <Text fontSize={12}>Manage Post</Text>
// </Checkbox>
// <Checkbox size={"sm"} color={"black"}>
// {" "}
// <Text fontSize={12}>Manage Reports</Text>
// </Checkbox>
// <Checkbox size={"sm"} color={"black"}>
// {" "}
// <Text fontSize={12}>manage Sub-Admin</Text>
// </Checkbox>
// <Checkbox size={"sm"} color={"black"}>
// {" "}
// <Text fontSize={12}>My profile</Text>
// </Checkbox>
// <Checkbox size={"sm"} color={"black"}>
// <Text fontSize={12}>Manage Jobs</Text>{" "}
// </Checkbox>
// <Checkbox size={"sm"} color={"black"}>
// <Text fontSize={12}> manage feedbacks</Text>
// </Checkbox>
// <Checkbox size={"sm"} color={"black"}>
// <Text fontSize={12}>Manage community</Text>{" "}
// </Checkbox>
// <Checkbox size={"sm"} color={"black"}>
// <Text fontSize={12}> Notification</Text>
// </Checkbox>
// </>
))}
</Grid>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
{/* <Button w="100%" bg="#02A0A0" color={"#fff"}>
<Field.Label color="black" pt={1} fontSize="12px">Gender</Field.Label>
<Input value="Male" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly
/>
<Heading mt={5} color={'#000'} fontSize={'sm'}>Permissions</Heading>
</Field.Root>
<Grid templateColumns="repeat(2, 1fr)" gap={4}>
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>Dashboard</Text></Checkbox>
<Checkbox size={'sm'} color={"black"}> <Text fontSize={12}>Manage contact us</Text></Checkbox>
<Checkbox size={'sm'} color={"black"}> <Text fontSize={12}>manage User</Text></Checkbox>
<Checkbox size={'sm'} color={"black"}> <Text fontSize={12}>Manage CMS</Text></Checkbox>
<Checkbox size={'sm'} color={"black"}> <Text fontSize={12}>Manage Post</Text></Checkbox>
<Checkbox size={'sm'} color={"black"}> <Text fontSize={12}>Manage Reports</Text></Checkbox>
<Checkbox size={'sm'} color={"black"}> <Text fontSize={12}>manage Sub-Admin</Text></Checkbox>
<Checkbox size={'sm'} color={"black"}> <Text fontSize={12}>My profile</Text></Checkbox>
<Checkbox size={'sm'} color={"black"}><Text fontSize={12}>Manage Jobs</Text> </Checkbox>
<Checkbox size={'sm'} color={"black"}><Text fontSize={12}> manage feedbacks</Text></Checkbox>
<Checkbox size={'sm'} color={"black"}><Text fontSize={12}>Manage community</Text> </Checkbox>
<Checkbox size={'sm'} color={"black"}><Text fontSize={12}> Notification</Text></Checkbox>
</Grid>
</Stack>
</DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"} >
<Button w="100%" bg="#02A0A0" color={"#fff"}>
Save
</Button> */}
</DialogFooter>
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
</DialogContent>
))}
</DialogRoot>
);
<DialogCloseTrigger color="black" />
</DialogContent>
</DialogRoot >
)
}
export default ViewSubAdmin;
export default ViewSubAdmin

View File

@@ -1,219 +0,0 @@
import {
Box,
Center,
HStack,
Image,
Input,
Text,
VStack,
} from "@chakra-ui/react";
import axios from "axios";
import { useEffect, 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 [isLoading, setIsLoading] = useState(false);
const [timer, setTimer] = useState(60);
const [isResendDisabled, setIsResendDisabled] = useState(true);
const navigate = useNavigate();
const location = useLocation();
const queryParams = new URLSearchParams(location.search);
const phoneNumber = queryParams.get("phone");
useEffect(() => {
let interval: NodeJS.Timeout;
if (timer > 0 && isResendDisabled) {
interval = setInterval(() => {
setTimer((prevTimer) => prevTimer - 1);
}, 1000);
} else if (timer === 0) {
setIsResendDisabled(false);
}
return () => clearInterval(interval);
}, [timer, isResendDisabled]);
const handleResendOTP = async () => {
setIsResendDisabled(true);
setTimer(60); // Reset timer to 1 minute
try {
const res = await axios.post(`${import.meta.env.VITE_API_URL}/send-otp`, {
mobile_number: phoneNumber,
});
if (res.status === 200) {
toaster.create({
title: "OTP resent successfully",
type: "success",
});
} else {
toaster.create({
title: res.data.message || "Failed to resend OTP",
type: "error",
});
setIsResendDisabled(false); // Enable button if failed
}
} catch (error: any) {
toaster.create({
title: error.response?.data?.message || "Failed to resend OTP",
type: "error",
});
setIsResendDisabled(false); // Enable button if error
}
};
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;
}
const fullOtp = otp.join('');
setIsLoading(true);
try {
const res = await axios.post(`${import.meta.env.VITE_API_URL}/verify-otp`, {
mobile_number: phoneNumber,
otp: fullOtp,
});
if (res.status === 200) {
toaster.create({
title: "OTP Verified Successfully",
type: "success",
});
const userid = res.data.data.id;
navigate(`/forgot-password/reset-password?id=${userid}`);
} 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> */}
<Box textAlign="center" mt={4}>
{isResendDisabled ? (
<Text color="gray.500">
Resend OTP in {timer} seconds
</Text>
) : (
<Text
color="#4746F4"
textDecoration="underline"
fontWeight="bold"
cursor="pointer"
onClick={handleResendOTP}
>
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

@@ -1,112 +0,0 @@
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 interface AgencyPost {
raid?: string;
name: string;
auth_signatory?: string;
state: string;
district?: string;
rc_number: string;
contact_details?: string;
registered_office: string;
branch_office?: string;
registered_email?: string;
other_email?: string;
registered_contact?: string;
website?: string;
domain_name: string;
staff_domain_name?: string;
gst_number: string;
rc_status?: "Active" | "Inactive"; // Assuming it's a status with limited values
}
export const agencyMasterModule = createApi({
reducerPath: "agencyMasterModule",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
createAgencyMasterPost: builder.mutation<AgencyPost, Partial<AgencyPost>>({
query: (data) => ({
url: "/agency-store",
method: "POST",
body: data,
}),
}),
// getAgencyMaster: builder.query<AgencyResponse, number>({
// query: (page = 1) => `/agency-master?page=${page}`
// }),
getAgencyMaster: builder.query<AgencyResponse, { page?: number; search?: string }>({
query: ({ page, search }) => {
const params = new URLSearchParams();
if (page) params.append("page", page.toString());
if (search) params.append("search", search);
return `/agency-master?${params.toString()}`;
},
}),
agencyMasterToggle: builder.mutation({
query: ({ id, is_active }) => ({
url: `/agency-status`,
method: "POST",
body: { id, is_active },
}),
}),
updateAgencyMaster: builder.mutation({
query: (updatedData) => ({
url: "/agency-update",
method: "POST",
body: updatedData,
}),
}),
}),
});
export const {
useCreateAgencyMasterPostMutation,
useGetAgencyMasterQuery,
useAgencyMasterToggleMutation,
useUpdateAgencyMasterMutation,
} = agencyMasterModule;

View File

@@ -1,75 +0,0 @@
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { BaseQueryFn, FetchArgs, FetchBaseQueryError } from "@reduxjs/toolkit/query";
import { logout } from "./authSlice"; // Import logout action from authSlice
import { RootState } from "../Store";
const baseQuery = fetchBaseQuery({
baseUrl: `${import.meta.env.VITE_API_URL}`,
prepareHeaders: (headers, { getState }) => {
const token = (getState() as RootState).auth.token; // Get token from Redux store
// Encode Basic Auth Credentials
const username = import.meta.env.VITE_USER_NAME||''; // Replace with actual username
const password = import.meta.env.VITE_PASSWORD||''; // Replace with actual password
const basicAuth = `${username} : ${password}`; // Encode to Base64
if (token) {
headers.set("Authorization", `Basic ${basicAuth}`);
headers.set("access-token", `${token}`);
}
headers.set("Content-Type", "application/json");
return headers;
},
});
// ✅ Handle 401 Errors (Auto Logout)
export const baseQueryWithReauth: BaseQueryFn<
string | FetchArgs,
unknown,
FetchBaseQueryError
> = async (args, api, extraOptions) => {
const result = await baseQuery(args, api, extraOptions);
if (result.error && result.error.status === 401) {
api.dispatch(logout()); // Logout user on 401 error
}
return result;
};
export const dashboard = createApi({
reducerPath: "api",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
getPosts: builder.query<Post[], void>({ query: () => "/posts" }),
// 🔹 POST: Create a new post
logOut: builder.mutation<void, void>({
query: () => ({
url: "/logout",
method: "POST",
}),
}),
}),
});
export const { useGetPostsQuery, useLogOutMutation } = dashboard;
export type Post = {
id: number;
title: string;
body: string;
};

View File

@@ -1,27 +0,0 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
type AuthState = {
token: string | null;
};
const initialState: AuthState = {
token: localStorage.getItem("token"), // Load token from localStorage
};
const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
setToken: (state, action: PayloadAction<string>) => {
state.token = action.payload;
localStorage.setItem("token", action.payload); // ✅ Store token in localStorage
},
logout: (state) => {
state.token = null;
localStorage.removeItem("token"); // ✅ Remove token from localStorage on logout
},
},
});
export const { setToken, logout } = authSlice.actions;
export default authSlice.reducer;

View File

@@ -1,120 +0,0 @@
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQueryWithReauth } from "./apiSlice";
export interface CountryData {
id: number;
en_name: string;
hi_name: string;
mr_name: string;
te_name: string;
ta_name: string;
bn_name: string;
or_name: string;
country_code: string;
phonecode: string;
capital: string;
currency: string;
currency_name: string;
currency_symbol: string;
is_active: string;
}
interface ApiResponse {
status: string;
status_code: number;
message: string;
data: {
current_page: number,
last_page: number,
total: number,
from: number,
per_page: number,
to: number,
data: CountryData[];
};
}
export interface CountryEdit {
status: string;
status_code: number;
message: string;
data: CountryData[];
}
export type PostCountry = {
en_name: string;
country_code: string;
phonecode: string;
capital: string;
currency: string;
currency_name: string;
currency_symbol: string;
};
export const countryMaster = createApi({
reducerPath: "countryMaster",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
createCountryPost: builder.mutation<PostCountry, Partial<PostCountry>>({
query: (data) => ({
url: "/country-add",
method: "POST",
body: data,
}),
}),
// 🔹 GET: Fetch all posts
// getCountryMaster: builder.query<ApiResponse, number>({
// query: (page = 1) => `/country-list?page=${page}`,
// }),
getCountryMaster: builder.query<ApiResponse, { page?: number; search?: string }>({
query: ({ page, search }) => {
const params = new URLSearchParams();
if (page) params.append("page", page.toString());
if (search) params.append("search", search);
return `/country-list?${params.toString()}`;
},
}),
getCountryMasterEdit: builder.query<CountryEdit, number>({
query: (id) => `/country-edit/${id}`,
}),
updateCountry: builder.mutation({
query: (updatedData) => ({
url: "/country-update",
method: "POST",
body: updatedData,
}),
}),
countryToggle: builder.mutation({
query: ({ id, is_active }) => ({
url: `/country-status`,
method: "POST",
body: { id, is_active },
}),
}),
// deleteFaqPost: builder.mutation<{ status: string; message: string }, { id: number }>({
// query: ({ id }) => ({
// url: `/faq-delete`,
// method: "POST",
// body: { id },
// }),
// }),
}),
});
export const {
useGetCountryMasterQuery,
useGetCountryMasterEditQuery,
useCreateCountryPostMutation,
useUpdateCountryMutation,
useCountryToggleMutation,
// useDeleteFaqPostMutation
} = countryMaster;

View File

@@ -1,77 +0,0 @@
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQueryWithReauth } from "./apiSlice";
export type TotalUser = {
data: {
totalRecruiterCount: number;
totalCustomerCount: string;
totalUserCount: string;
recruitersByMonth: Record<string, number>;
customersByMonth: Record<string, number>;
};
};
export type PastUser = {
data: {
past24hourRecruiterCount: number;
past24hourCustomercount: number;
};
};
export type NewUser = {
data: {
newRecuiterCount: number;
newCustomerCount: number;
newTotalUserCount: number;
};
};
export type AgencyList = {
data: [
{
id: number;
name: string;
created_at: string;
is_active: boolean
}
];
};
export type FaqList = {
data: [
{
id: number;
faqs_xid: number;
language_master_xid: number;
question: string;
answer: string;
is_active: boolean
}
];
};
export const dashBoard = createApi({
reducerPath: "dashBoard",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
getTotalUser: builder.query<TotalUser, void>({ query: () => "/dashboard-total-user" }),
getPastUser: builder.query<PastUser, void>({ query: () => "/dashboard-past-user" }),
getNewUser: builder.query<NewUser, void>({ query: () => "/dashboard-new-user" }),
getAgencyList: builder.query<AgencyList, void>({ query: () => "/dashboard-agency-list" }),
getFaqList: builder.query<FaqList, void>({ query: () => "/dashboard-faq-list" }),
}),
});
export const {
useGetTotalUserQuery,
useGetPastUserQuery,
useGetNewUserQuery,
useGetAgencyListQuery,
useGetFaqListQuery,
} = dashBoard;

View File

@@ -1,30 +0,0 @@
import { createApi } from "@reduxjs/toolkit/query/react"; // add /react for auto-generated hooks
import { baseQueryWithReauth } from "./apiSlice";
interface DeactivatedData {
id: number;
email: string;
first_name: string;
created_at: string;
}
interface ApiResponse {
data: {
data: DeactivatedData[];
};
}
export const deactivatedAccounts = createApi({
reducerPath: "deactivatedAccounts",
baseQuery: baseQueryWithReauth,
tagTypes: ["Deactivated"],
endpoints: (builder) => ({
getContact: builder.query<ApiResponse, void>({
query: () => "/manage-user-deactivate-list",
providesTags: ["Deactivated"],
}),
}),
});
// ✅ Export the auto-generated hook
export const { useGetContactQuery } = deactivatedAccounts;

View File

@@ -1,119 +0,0 @@
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQueryWithReauth } from "./apiSlice";
export interface DepartmentData {
id: number;
industry_masters_xid: number;
en_name: string;
hi_name: string;
mr_name: string;
te_name: string;
ta_name: string;
bn_name: string;
or_name: string;
is_active: string;
}
interface ApiResponse {
status: string;
status_code: number;
message: string;
data: {
current_page: number,
last_page: number,
total: number,
from: number,
per_page: number,
to: number,
data: DepartmentData[];
};
}
export interface CountryEdit {
status: string;
status_code: number;
message: string;
data: DepartmentData[];
}
export interface DropDown{
status: string;
status_code: number;
message: string;
data: {
id: number;
en_name: string;
}[]
}
export type PostDepartment = {
en_name: string;
industry_masters_xid: number;
};
export const departmentMaster = createApi({
reducerPath: "departmentMaster",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
createDepartmentPost: builder.mutation<PostDepartment, Partial<PostDepartment>>({
query: (data) => ({
url: "/department-master-store",
method: "POST",
body: data,
}),
}),
// 🔹 GET: Fetch all posts
// getDepartmentMaster: builder.query<ApiResponse, number>({
// query: (page = 1) => `/department-master-list?page=${page}`,
// }),
getDepartmentMaster: builder.query<ApiResponse, { page?: number; search?: string }>({
query: ({ page, search }) => {
const params = new URLSearchParams();
if (page) params.append("page", page.toString());
if (search) params.append("search", search);
return `/department-master-list?${params.toString()}`;
},
}),
getDepartmentMasterDropDown: builder.query<DropDown, void>({
query: () => `/industry-master-get-category`,
}),
updateDepartment: builder.mutation({
query: (updatedData) => ({
url: "/department-master-update",
method: "POST",
body: updatedData,
}),
}),
departmentToggle: builder.mutation({
query: ({ id, is_active }) => ({
url: `/department-master-status`,
method: "POST",
body: { id, is_active },
}),
}),
// deleteFaqPost: builder.mutation<{ status: string; message: string }, { id: number }>({
// query: ({ id }) => ({
// url: `/faq-delete`,
// method: "POST",
// body: { id },
// }),
// }),
}),
});
export const {
useGetDepartmentMasterQuery,
useGetDepartmentMasterDropDownQuery,
useCreateDepartmentPostMutation,
useUpdateDepartmentMutation,
useDepartmentToggleMutation,
// useDeleteFaqPostMutation
} = departmentMaster;

View File

@@ -1,91 +0,0 @@
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQueryWithReauth } from "./apiSlice";
export interface FaqData {
id: number;
principal_type_xid: number;
is_active: number;
translations:{
id: string,
faqs_xid: number,
language_master_xid: number,
question: string,
answer: string,
}[]
}
interface ApiResponse {
status: string;
status_code: number;
message: string;
data: {
current_page: number,
last_page: number,
total: number,
from: number,
per_page: number,
to: number,
data: FaqData[];
};
}
export type Post = {
principal_type_xid: number;
language_code: string;
question: string;
answer: string;
};
export const faqs = createApi({
reducerPath: "faqs",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
createFaqPost: builder.mutation<Post, Partial<Post>>({
query: (data) => ({
url: "/faq-store",
method: "POST",
body: data,
}),
}),
// 🔹 GET: Fetch all posts
getFaq: builder.query<ApiResponse, number>({
query: (page = 1) => `/faq-list?page=${page}`,
}),
updateFaq: builder.mutation({
query: (updatedData) => ({
url: "/faq-update",
method: "POST",
body: updatedData,
}),
}),
faqToggle: builder.mutation({
query: ({ id, is_active }) => ({
url: `/faq-status`,
method: "POST",
body: { id, is_active },
}),
}),
deleteFaqPost: builder.mutation<{ status: string; message: string }, { id: number }>({
query: ({ id }) => ({
url: `/faq-delete`,
method: "POST",
body: { id },
}),
}),
}),
});
export const {
useGetFaqQuery,
useCreateFaqPostMutation,
useUpdateFaqMutation,
useFaqToggleMutation,
useDeleteFaqPostMutation
} = faqs;

View File

@@ -1,102 +0,0 @@
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQueryWithReauth } from "./apiSlice";
interface IndustryMasterResponse {
status: string;
status_code: number;
message: string;
data: PaginationData;
}
interface PaginationData {
current_page: number;
data: IndustryMaster[];
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 IndustryMaster {
id: number;
categories_masters_xid: 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 {
en_name: string,
categories_masters_xid: number
}
export const industryMaster = createApi({
reducerPath: "industryMaster",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
createIndustryMasterPost: builder.mutation<Post, Partial<Post>>({
query: (data) => ({
url: "/industry-master-store",
method: "POST",
body: data,
}),
}),
// 🔹 GET: Fetch all posts
// getIndustryMaster: builder.query<IndustryMasterResponse, number>({
// query: (page = 1) => `/industry-master-list?page=${page}`,
// }),
getIndustryMaster: builder.query<IndustryMasterResponse, { page?: number; search?: string }>({
query: ({ page, search }) => {
const params = new URLSearchParams();
if (page) params.append("page", page.toString());
if (search) params.append("search", search);
return `/industry-master-list?${params.toString()}`;
},
}),
updateIndustryMaster: builder.mutation({
query: (updatedData) => ({
url: "industry-master-update",
method: "POST",
body: updatedData,
}),
}),
industryMasterToggle: builder.mutation({
query: ({ id, is_active }) => ({
url: `/industry-master-status`,
method: "POST",
body: { id, is_active },
}),
}),
}),
});
export const {
useGetIndustryMasterQuery,
useCreateIndustryMasterPostMutation,
useUpdateIndustryMasterMutation,
useIndustryMasterToggleMutation,
} = industryMaster;

View File

@@ -1,101 +0,0 @@
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQueryWithReauth } from "./apiSlice";
export interface JobStatusData {
id: number;
is_active: string;
job_status_translation:{
job_status_xid: number,
title:string,
language_xid:number
}[],
}
interface ApiResponse {
status: string;
status_code: number;
message: string;
data: {
current_page: number,
last_page: number,
total: number,
from: number,
per_page: number,
to: number,
data: JobStatusData[];
};
}
export interface CountryEdit {
status: string;
status_code: number;
message: string;
data: JobStatusData[];
}
export type PostJobStatus = {
title: string
};
export const jobStatus = createApi({
reducerPath: "jobStatus",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
createJobStatusPost: builder.mutation<PostJobStatus, Partial<PostJobStatus>>({
query: (data) => ({
url: "/job-status-store",
method: "POST",
body: data,
}),
}),
// 🔹 GET: Fetch all posts
// getJobStatus: builder.query<ApiResponse, number>({
// query: (page = 1) => `/job-status-list?page=${page}`,
// }),
getJobStatus: builder.query<ApiResponse, { page?: number; search?: string }>({
query: ({ page, search }) => {
const params = new URLSearchParams();
if (page) params.append("page", page.toString());
if (search) params.append("search", search);
return `/job-status-list?${params.toString()}`;
},
}),
updateJobStatus: builder.mutation({
query: (updatedData) => ({
url: "/job-status-update",
method: "POST",
body: updatedData,
}),
}),
jobStatusToggle: builder.mutation({
query: ({ id, is_active }) => ({
url: `/job-status-status`,
method: "POST",
body: { id, is_active },
}),
}),
// deleteFaqPost: builder.mutation<{ status: string; message: string }, { id: number }>({
// query: ({ id }) => ({
// url: `/faq-delete`,
// method: "POST",
// body: { id },
// }),
// }),
}),
});
export const {
useGetJobStatusQuery,
useCreateJobStatusPostMutation,
useUpdateJobStatusMutation,
useJobStatusToggleMutation,
// useDeleteFaqPostMutation
} = jobStatus;

View File

@@ -1,90 +0,0 @@
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 {
en_name: string
}
export const jobType = createApi({
reducerPath: "jobType",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
createJobTypePost: builder.mutation<Post, Partial<Post>>({
query: (data) => ({
url: "/job-type-add",
method: "POST",
body: data,
}),
}),
// 🔹 GET: Fetch all posts
getJobType: builder.query<JobTypeResponse, number>({
query: (page = 1) => `/job-type?page=${page}`,
}),
updateJobType: builder.mutation({
query: (updatedData) => ({
url: "job-type-update",
method: "POST",
body: updatedData,
}),
}),
jobTypeToggle: builder.mutation({
query: ({ id, is_active }) => ({
url: `/job-type-status`,
method: "POST",
body: { id, is_active },
}),
}),
}),
});
export const {
useGetJobTypeQuery,
useCreateJobTypePostMutation,
useUpdateJobTypeMutation,
useJobTypeToggleMutation,
} = jobType;

View File

@@ -1,88 +0,0 @@
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQueryWithReauth } from "./apiSlice";
import { AboutUsResponse } from "../../Types/aboutUsType";
export const aboutUs = createApi({
reducerPath: "aboutUs",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({
// 🔹 GET: Fetch all posts
getAboutUs: builder.query<AboutUsResponse, void>({
query: () => "/about-us",
}),
// 🔹 GET: Fetch a single post by ID
getPostById: builder.query<Post, number>({
query: (id) => `/posts/${id}`,
}),
// 🔹 POST: Create a new post
createPost: builder.mutation<Post, Partial<Post>>({
query: (data) => ({
url: "/posts",
method: "POST",
body: data,
}),
}),
// 🔹 PUT: Update an existing post
// updateAboutUs: builder.mutation<UpdateAboutUsResponse, UpdateAboutUsRequest>({
// query: ({ id, updatedData }) => ({
// url: `/posts/${id}`,
// method: "POST",
// body: updatedData,
// }),
// }),
// 🔹 PUT: Update an About Us entry
updateAboutUs: builder.mutation({
query: (updatedData) => ({
url: "/about-us/update", // ✅ Updated URL
method: "POST",
body: updatedData,
}),
}),
// 🔹 DELETE: Remove a post by ID
deletePost: builder.mutation<{ success: boolean }, number>({
query: (id) => ({
url: `/posts/${id}`,
method: "DELETE",
}),
}),
}),
});
export const {
useGetAboutUsQuery,
useUpdateAboutUsMutation,
useGetPostByIdQuery,
useCreatePostMutation,
useDeletePostMutation
} = aboutUs;
// Define Post type
export type Post = {
id: number;
title: string;
body: string;
};
export type UpdateAboutUsRequest={
id: number; updatedData: string,language_code:string
}
export type UpdateAboutUsResponse={
id: number; updatedData: string,language_code:string
}
export type AboutUs = {
id: number;
language_master_xid: number;
content: string;
is_active: boolean;
};

View File

@@ -1,45 +0,0 @@
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQueryWithReauth } from "./apiSlice";
interface ContactData {
id: number;
email: string;
first_name: string;
created_at: string;
}
interface ApiResponse {
data: {
data: ContactData[];
};
}
export const manageContactUs = createApi({
reducerPath: "manageContactUs",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
tagTypes: ["Contact"],
endpoints: (builder) => ({
getContact: builder.query<ApiResponse, { page?: number; search?: string }>({
query: ({ page, search }) => {
const params = new URLSearchParams();
if (page) params.append("page", page.toString());
if (search) params.append("search", search);
return `/contact-us?${params.toString()}`;
},
providesTags: ["Contact"],
}),
pendingRequest: builder.mutation({
query: (body) => ({
url: `/contact-us-response`,
method: "POST",
body,
}),
invalidatesTags: ["Contact"],
}),
}),
});
export const { useGetContactQuery, usePendingRequestMutation } = manageContactUs;

Some files were not shown because too many files have changed in this diff Show More