44 Commits

Author SHA1 Message Date
rockyeverlast
e2c17a3d4a updated env testing 2025-09-19 18:21:20 +05:30
rockyeverlast
0ecc030f20 env updated 2025-09-19 18:18:06 +05:30
rockyeverlast
5b37c9da1e Profile Image editiing api 2025-09-19 18:12:42 +05:30
rockyeverlast
9bfbf5ddb8 dob disabled for recruiter xid2 2025-09-17 14:04:21 +05:30
rockyeverlast
2e8f8d5a77 Fixed language update for user 2025-09-17 14:01:16 +05:30
rockyeverlast
248980d24b Added default language in user edit 2025-09-17 12:23:55 +05:30
rockyeverlast
8966295260 Bugs fixes and updates 2025-09-15 20:47:26 +05:30
rockyeverlast
df62dcda64 Cell title changed to EMP ID 2025-09-12 21:11:15 +05:30
rockyeverlast
44f34490a0 Added Agency status and fixed ResourceTitle for Manage User 2025-09-12 21:09:00 +05:30
rockyeverlast
8efb309fa9 Merge branch 'dev-rohit' of http://git.wdipl.com/Siddhesh.More/SSA-Admin-Panel into testing 2025-09-12 18:15:04 +05:30
rockyeverlast
171a92a3dc Toast updated successfully 2025-09-12 18:14:26 +05:30
rockyeverlast
ec021ee33c Merge branch 'dev-rohit' of http://git.wdipl.com/Siddhesh.More/SSA-Admin-Panel into testing 2025-09-12 17:59:15 +05:30
rockyeverlast
3aa9ebf619 Last name added to user table 2025-09-12 17:50:43 +05:30
rockyeverlast
8f19a41c57 Admin / Subadmin nav access and bugs fixing 2025-09-12 17:49:14 +05:30
rockyeverlast
638a68ff03 Merge branch 'dev-rohit' of http://git.wdipl.com/Siddhesh.More/SSA-Admin-Panel into testing 2025-09-11 20:21:13 +05:30
rockyeverlast
e5361a5d77 Bug fixes and updates 2025-09-11 20:16:37 +05:30
rockyeverlast
71c23a2125 Merge branch 'dev-rohit' of http://git.wdipl.com/Siddhesh.More/SSA-Admin-Panel into testing 2025-09-10 20:44:01 +05:30
rockyeverlast
abaae9603e env added to git ignore 2025-09-10 20:43:42 +05:30
rockyeverlast
7a3e76aa35 env added to git ignore 2025-09-10 20:42:58 +05:30
rockyeverlast
eaf8e77b79 env file updated 2025-09-10 20:42:08 +05:30
rockyeverlast
2488ab98c0 Merge branch 'dev-rohit' of http://git.wdipl.com/Siddhesh.More/SSA-Admin-Panel into dev-rohit 2025-09-10 20:37:36 +05:30
rockyeverlast
6648cd3bf3 fixed newCustomerCount / Recruiter count in dash 2025-09-10 20:36:15 +05:30
d1cc504397 Updated env with beta dev url 2025-09-10 14:53:43 +00:00
rockyeverlast
1e7b7347e4 Dashboard API integration 2025-09-10 20:18:07 +05:30
rockyeverlast
32ccea4917 commented out disable feature on toggle in agency master 2025-09-09 17:52:55 +05:30
rockyeverlast
1fafdfe54d Edit agency master updated 2025-09-09 17:44:39 +05:30
rockyeverlast
20a92a60ab optional chaining done for language in register user 2025-09-09 17:37:45 +05:30
rockyeverlast
284b5f3099 Bug fixes and updates 2025-09-09 17:30:26 +05:30
rockyeverlast
901dfb93a6 Updated subadmin add / ediit function 2025-09-05 16:56:41 +05:30
rockyeverlast
2805528ba3 Search implemented 2025-07-11 12:51:22 +05:30
rockyeverlast
a8a0e2ffef fixed Country uodated 2025-07-10 18:53:44 +05:30
rockyeverlast
897572c1f1 Merge branch 'dev-rohit' of http://git.wdipl.com/Siddhesh.More/SSA-Admin-Panel into testing 2025-07-10 18:25:27 +05:30
rockyeverlast
03ab1dcd6f Bugs fixes 2025-07-10 18:24:27 +05:30
rockyeverlast
9d8278900d Merge branch 'dev-rohit' of http://git.wdipl.com/Siddhesh.More/SSA-Admin-Panel into testing 2025-07-09 16:56:39 +05:30
rockyeverlast
f65b5f9b2d Bug fixes and API integration sub admin 2025-07-09 16:56:06 +05:30
rockyeverlast
ffda4cf04b Merge branch 'dev-rohit' of http://git.wdipl.com/Siddhesh.More/SSA-Admin-Panel into testing 2025-07-03 16:14:55 +05:30
rockyeverlast
f2d101ef16 Bug fixes 2025-07-03 16:08:52 +05:30
rockyeverlast
b91c97c6c2 Edit and view user API integrated 2025-06-23 18:57:56 +05:30
rockyeverlast
2a0517d8dc Remove .env from repo 2025-06-20 12:07:48 +05:30
rockyeverlast
0c6238c843 Merge branch 'yasin' of http://git.wdipl.com/Siddhesh.More/SSA-Admin-Panel into dev-rohit 2025-06-19 13:10:29 +05:30
rockyeverlast
49e8e5531f updated env file 2025-06-09 11:47:33 +05:30
rockyeverlast
15c9cc1d94 updated env file 2025-06-09 11:36:15 +05:30
rockyeverlast
cb7bdcdeb3 updated env file 2025-06-09 11:28:32 +05:30
rockyeverlast
8106d505a0 changes to env testing files 2025-06-09 11:23:27 +05:30
80 changed files with 3158 additions and 1538 deletions

14
.env
View File

@@ -4,12 +4,20 @@
# VITE_PASSWORD="71%@L%es^bUX94`J9XT*@bh,._WWM{$%^^&&" # VITE_PASSWORD="71%@L%es^bUX94`J9XT*@bh,._WWM{$%^^&&"
# VITE_APP_NAME=MyViteApp # VITE_APP_NAME=MyViteApp
# VITE_IMG_TEMPLATES='https://ssa.betadelivery.com/storage/app/public/uploads/post_templates/' # 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/testing/apia/v1'
# VITE_API_URL='https://ssa.betadelivery.com/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_USER_NAME="Admin"
VITE_PASSWORD="71%@L%es^bUX94`J9XT*@bh,._WWM{$%^^&&" 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_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_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/` VITE_POST_IMG=`${VITE_MAIN_URL}/storage/app/public/uploads/post/`

View File

@@ -1,5 +1,7 @@
# VITE_API_URL='https://ssa.betadelivery.com/testing/apia/' VITE_API_URL='https://ssa.betadelivery.com/testing/apia/v1'
# VITE_USER_NAME="Admin" VITE_USER_NAME="Admin"
# VITE_PASSWORD="71%@L%es^bUX94`J9XT*@bh,._WWM{$%^^&&" VITE_PASSWORD="71%@L%es^bUX94`J9XT*@bh,._WWM{$%^^&&"
# VITE_APP_NAME=MyViteApp VITE_APP_NAME=MyViteApp
# VITE_IMG_TEMPLATES='https://ssa.betadelivery.com/storage/app/public/uploads/post_templates/' 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/`

2
.gitignore vendored
View File

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

View File

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

View File

@@ -7,6 +7,8 @@ export interface GlobalStateContextType {
setIsAuthenticate: Dispatch<SetStateAction<boolean>>; setIsAuthenticate: Dispatch<SetStateAction<boolean>>;
isBarLoading: boolean; isBarLoading: boolean;
setIsBarLoading: Dispatch<SetStateAction<boolean>>; setIsBarLoading: Dispatch<SetStateAction<boolean>>;
userAccess: string[];
setUserAccess: Dispatch<SetStateAction<string[]>>;
} }
// Create the context with a default value of `undefined` // Create the context with a default value of `undefined`
const GlobalStateContext = createContext<GlobalStateContextType | undefined>(undefined); const GlobalStateContext = createContext<GlobalStateContextType | undefined>(undefined);

View File

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

View File

@@ -1,6 +1,6 @@
import { HStack, Image, Text, VStack } from "@chakra-ui/react"; import { HStack, Image, Text, VStack } from "@chakra-ui/react";
import React, { FC, useContext } from "react"; import React, { FC, useContext } from "react";
import { RiNotificationLine } from "react-icons/ri"; // import { RiNotificationLine } from "react-icons/ri";
import { NavLink, useLocation, useNavigate } from "react-router-dom"; import { NavLink, useLocation, useNavigate } from "react-router-dom";
import { nav } from "../Routes/Nav"; import { nav } from "../Routes/Nav";
import logo from '../assets/logo.svg'; import logo from '../assets/logo.svg';
@@ -14,6 +14,8 @@ import { useLogOutMutation } from "../Redux/Service/apiSlice";
import ProgressBar from "../components/ProgressBar/ProgressBar"; import ProgressBar from "../components/ProgressBar/ProgressBar";
import { useGetProfileQuery } from "../Redux/Service/profile.password"; import { useGetProfileQuery } from "../Redux/Service/profile.password";
const PROFILEIMGURL = import.meta.env.VITE_IMG_PROFILE
const DefaultLayout: FC<{ children: React.ReactNode }> = ({ children }) => { const DefaultLayout: FC<{ children: React.ReactNode }> = ({ children }) => {
const { data } = useGetProfileQuery() const { data } = useGetProfileQuery()
const dispatch = useDispatch() const dispatch = useDispatch()
@@ -25,9 +27,13 @@ const DefaultLayout: FC<{ children: React.ReactNode }> = ({ children }) => {
if (!context) { if (!context) {
throw new Error('App must be used within a GlobalStateProvider'); throw new Error('App must be used within a GlobalStateProvider');
} }
const { setIsAuthenticate, isBarLoading } = context; const { setIsAuthenticate, isBarLoading, userAccess } = context;
const [logOutAdmin] = useLogOutMutation() const [logOutAdmin] = useLogOutMutation()
const filteredNav = nav.filter(item =>
userAccess.includes('*') || !item.resourceTitle || userAccess.includes(item.resourceTitle)
);
// Logout function // Logout function
const handleLogout = async () => { const handleLogout = async () => {
@@ -57,7 +63,7 @@ const DefaultLayout: FC<{ children: React.ReactNode }> = ({ children }) => {
<Image w={55} src={logo} /> <Image w={55} src={logo} />
</HStack> </HStack>
<VStack w={'100%'} p={2} pt={0}> <VStack w={'100%'} p={2} pt={0}>
{nav?.map(({ title, path, Icon, type, children, initPath }, index) => type === 'single' ? {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> : <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> <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}> <AccordionItem rounded={'lg'} bg={'#fff'} boxShadow={'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'} borderBottom={'none'} p={0} key={index} value={title}>
@@ -74,12 +80,12 @@ const DefaultLayout: FC<{ children: React.ReactNode }> = ({ children }) => {
<HStack h={'11%'} w={'100%'} justifyContent={'flex-end'} pe={3} gap={6}> <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> {/* <NavLink to={'/manage-notification'}><RiNotificationLine color="#013e3e" cursor={'pointer'} style={{ fontSize: '22px' }} /></NavLink> */}
<HStack cursor={'pointer'} onClick={() => navigate('/profile')} > <HStack cursor={'pointer'} onClick={() => navigate('/profile')} >
<Avatar size={'sm'} src="https://i.pinimg.com/736x/d6/cd/0f/d6cd0ffd4634b0763d3958a7325ce26e.jpg" /> <Avatar size={'sm'} src={`${PROFILEIMGURL}${data?.data.profile_photo}`} />
<VStack color={'#013e3e'} gap={0} alignItems={'flex-start'}> <VStack color={'#013e3e'} gap={0} alignItems={'flex-start'}>
<Text fontSize={'sm'} fontWeight={'bold'}>{`${data?.data?.first_name.charAt(0).toUpperCase()}${data?.data.first_name.slice(1)}`}</Text> <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}</Text> <Text fontSize={'xs'} >{data?.data?.phone_number ? data?.data?.phone_number : ''}</Text>
</VStack> </VStack>
</HStack> </HStack>
</HStack> </HStack>

View File

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

View File

@@ -26,8 +26,31 @@ import {
SelectValueText SelectValueText
} from "../../components/ui/select"; } from "../../components/ui/select";
import AgencyName from "./AgencyName"; 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";
const Dashboard = () => { 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({ const frameworks = createListCollection({
items: [ items: [
{ label: "Today", value: "Today" }, { label: "Today", value: "Today" },
@@ -37,35 +60,35 @@ const Dashboard = () => {
], ],
}); });
const accItems = [ // const accItems = [
{ // {
value: "1", // value: "1",
title: "How to create new account?", // 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.", // 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", // value: "2",
title: "How to create new account?", // 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.", // 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", // value: "3",
title: "How to create new account?", // 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.", // 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", // value: "4",
title: "How to create new account?", // 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.", // 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 ( return (
<MainFrame> <MainFrame>
<Box display={"flex"} p={"20px"} pe={'20px'} gap={5}> <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"}> <Box rounded={'lg'} w={"30%"} boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}>
<Heading fontSize={"sm"} p={2}> <Heading fontSize={"sm"} p={2}>
Total Users Total Users : {totalUsers?.data?.totalUserCount ?? 0}
</Heading> </Heading>
<Tabs.Root <Tabs.Root
size={"sm"} size={"sm"}
@@ -74,6 +97,8 @@ const Dashboard = () => {
variant="enclosed" variant="enclosed"
fitted fitted
defaultValue={"tab-1"} defaultValue={"tab-1"}
value={activeTab}
onValueChange={(details) => setActiveTab(details.value)}
mb={6} mb={6}
> >
<Tabs.List> <Tabs.List>
@@ -89,7 +114,7 @@ const Dashboard = () => {
</Tabs.List> </Tabs.List>
</Tabs.Root> </Tabs.Root>
<Box> <Box>
<SemiDoughnutChart /> {totalUser && <SemiDoughnutChart totalUser={totalUser} />}
</Box> </Box>
<Box <Box
@@ -101,11 +126,11 @@ const Dashboard = () => {
> >
<Status.Root colorPalette="blue"> <Status.Root colorPalette="blue">
<Status.Indicator /> <Status.Indicator />
Recruiter <Text fontWeight={500}>2554</Text> Recruiter <Text fontWeight={500}>{totalUser?.past24hourRecruiterCount ?? totalUser?.totalRecruiterCount ?? totalUser?.newRecuiterCount }</Text>
</Status.Root> </Status.Root>
<Status.Root colorPalette="blue"> <Status.Root colorPalette="blue">
<Status.Indicator /> <Status.Indicator />
Customer <Text fontWeight={500}>1224</Text> Customer <Text fontWeight={500}>{totalUser?.past24hourCustomercount ?? totalUser?.totalCustomerCount ?? totalUser?.newCustomerCount}</Text>
</Status.Root> </Status.Root>
</Box> </Box>
</Box> </Box>
@@ -142,8 +167,8 @@ const Dashboard = () => {
<CircularApp /> <CircularApp />
</Box> </Box>
</Box> </Box>
<Box p={"20px"} pt={0} display={"flex"} gap={5}> <Box p={"20px"} pt={0} display={"flex"} gap={5}>
<Box w={"50%"} rounded={'lg'} bg={"#f2f2f2"} h={'100%'} p={"10px"} overflow={'auto'}> <Box w={"50%"} rounded={'lg'} bg={"#f2f2f2"} h={'100%'} p={"10px"} overflowY={'scroll'} height={'292px'}>
<HStack justifyContent={"space-between"} mb={5}> <HStack justifyContent={"space-between"} mb={5}>
<Text fontSize={"xs"} fontWeight={500}>Faqs</Text> <Text fontSize={"xs"} fontWeight={500}>Faqs</Text>
<Button <Button
@@ -153,15 +178,15 @@ const Dashboard = () => {
fontSize={"12px"} fontSize={"12px"}
h={"28px"} h={"28px"}
> >
View ALL <Link to="/manage-cms/faq">View ALL</Link>
</Button> </Button>
</HStack> </HStack>
<AccordionRoot collapsible defaultValue={["b"]}> <AccordionRoot collapsible defaultValue={["b"]}>
{accItems.map((item, index) => ( {faqList?.data.map((item) => (
<AccordionItem <AccordionItem
boxShadow={'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'} boxShadow={'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'}
key={index} key={item.id}
value={item.value} value={item.faqs_xid.toString()}
bg={"#fff"} bg={"#fff"}
mb={2} mb={2}
p={"12px"} p={"12px"}
@@ -169,17 +194,17 @@ const Dashboard = () => {
borderBottom={0} borderBottom={0}
> >
<AccordionItemTrigger fontSize={"sm"} > <AccordionItemTrigger fontSize={"sm"} >
{item.title} {item.question}
</AccordionItemTrigger> </AccordionItemTrigger>
<AccordionItemContent fontSize={"xs"} color={'#222222CC'} pt={2}> <AccordionItemContent fontSize={"xs"} color={'#222222CC'} pt={2}>
{item.text} {item.answer}
</AccordionItemContent> </AccordionItemContent>
</AccordionItem> </AccordionItem>
))} ))}
</AccordionRoot> </AccordionRoot>
</Box> </Box>
<Box w={"50%"} rounded={'lg'} bg={"#f2f2f2"} h={'100%'} overflow={'auto'}> <Box w={"50%"} rounded={'lg'} bg={"#f2f2f2"} alignItems={'flex-start'} overflowY={'scroll'} height={'292px'}>
<AgencyName /> {agencyList && <AgencyName agencyList={agencyList}/>}
</Box> </Box>
</Box> </Box>
</MainFrame> </MainFrame>

View File

@@ -34,7 +34,7 @@ const Login = () => {
if (!context) { if (!context) {
throw new Error("App must be used within a GlobalStateProvider"); throw new Error("App must be used within a GlobalStateProvider");
} }
const { setIsAuthenticate } = context; const { setIsAuthenticate, setUserAccess } = context;
const { const {
register, register,
handleSubmit, handleSubmit,
@@ -43,10 +43,10 @@ const Login = () => {
const onSubmit = handleSubmit(async (data) => { const onSubmit = handleSubmit(async (data) => {
setIsLoading(true); setIsLoading(true);
// Encode Basic Auth Credentials
const username = import.meta.env.VITE_USER_NAME || ""; // Replace with actual username const username = import.meta.env.VITE_USER_NAME || "";
const password = import.meta.env.VITE_PASSWORD || ""; // Replace with actual password const password = import.meta.env.VITE_PASSWORD || "";
const basicAuth = `${username}:${password}`; // Encode to Base64 const basicAuth = `${username}:${password}`;
try { try {
const res = await axios.post( const res = await axios.post(
@@ -62,35 +62,36 @@ const Login = () => {
}, },
} }
); );
console.log("============", res);
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);
if (res.data) {
setIsAuthenticate(true);
console.log("====================================");
console.log(res.data?.data);
console.log("====================================");
navigate("/dashboard");
dispatch(setToken(String(res.data?.data["access-token"])));
} else {
console.log("====================================");
console.log(res);
console.log("====================================");
}
} catch (error: any) { } catch (error: any) {
console.log('error', error.response.data.message); console.log('error', error?.response?.data?.message);
toaster.create({
if (error) { title: "Error",
toaster.create({ description: error?.response?.data?.message || "Login failed",
title: error?.response?.data?.message, type: "error",
// title: "Something Went Wrong", });
type: "info", setIsLoading(false);
})
// console.log("Login failed", error?.response?.data?.message);
setIsLoading(false);
}
} }
}); });
// console.log("User Access in Context:", userAccess);
return ( return (

View File

@@ -16,12 +16,13 @@ import "react-quill/dist/quill.snow.css"; // Import the styles
import { useState } from "react"; import { useState } from "react";
import { useUpdateAboutUsMutation } from "../../../Redux/Service/manage.aboutus.service"; import { useUpdateAboutUsMutation } from "../../../Redux/Service/manage.aboutus.service";
import { useForm, Controller } from "react-hook-form"; // Import React Hook Form import { useForm, Controller } from "react-hook-form"; // Import React Hook Form
import { toaster, Toaster } from "../../../components/ui/toaster";
function AboutUsAddModel({ aboutUsData }: { aboutUsData: any }) { function AboutUsAddModel({ aboutUsData }: { aboutUsData: any }) {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
// RTK Query Mutation Hook // RTK Query Mutation Hook
const [updateAboutUs] = useUpdateAboutUsMutation(); const [updateAboutUs, { isLoading }] = useUpdateAboutUsMutation();
// React Hook Form // React Hook Form
const { const {
@@ -55,87 +56,96 @@ function AboutUsAddModel({ aboutUsData }: { aboutUsData: any }) {
}).unwrap(); }).unwrap();
setIsOpen(false); // Close dialog on success setIsOpen(false); // Close dialog on success
reset(); // Reset the form reset(); // Reset the form
} catch (error) { } catch (error: any) {
console.error("Update failed:", error); console.error("Update failed:", error);
toaster.create({
title: "Error",
description: `${error.data.message || "Failed to update"}`,
type: "error",
});
} }
}; };
return ( return (
<DialogRoot placement="center" open={isOpen}> <>
<DialogTrigger asChild> <DialogRoot placement="center" open={isOpen}>
<Button <DialogTrigger asChild>
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>
</Button>
</DialogTrigger>
<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>
<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 <Button
w="100%" bgColor="#EEEEEE"
bg="#02A0A0" pl={3}
color="#fff" pr={3}
// isLoading={isLoading} size="xs"
onClick={handleSubmit(onSubmit)} // Use handleSubmit to trigger form submission color="#000"
onClick={() => handleEditClick(aboutUsData)} // Set content before opening modal
> >
Save <FaRegEdit color="#000" style={{ height: "14px", width: "14px" }} />
<Text color="#000" mt={1}>Edit</Text>
</Button> </Button>
</DialogFooter> </DialogTrigger>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} /> <DialogContent bg="#fff" w={{ base: "90%", md: "1200px" }} height="auto" p={3}>
</DialogContent> <DialogHeader bg="white">
</DialogRoot> <DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit About Us
</DialogTitle>
</DialogHeader>
<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 />
</>
); );
} }

View File

@@ -26,7 +26,7 @@ function EditDetails({ rowData, refetch }: {rowData: RowData, refetch: VoidFunct
const [faqQuestion, setFaqQuestion] = useState(rowData?.question); const [faqQuestion, setFaqQuestion] = useState(rowData?.question);
const [faqAnswer, setFaqAnswer] = useState(rowData?.answer); const [faqAnswer, setFaqAnswer] = useState(rowData?.answer);
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [updateFaq] = useUpdateFaqMutation() const [updateFaq, { isLoading }] = useUpdateFaqMutation()
// console.log('ROWDATA', rowData); // console.log('ROWDATA', rowData);
@@ -146,7 +146,7 @@ function EditDetails({ rowData, refetch }: {rowData: RowData, refetch: VoidFunct
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -54,7 +54,7 @@ const tableHeadRow = [
const FAQ = () => { const FAQ = () => {
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const { data, refetch, isLoading, isFetching } = useGetFaqQuery(currentPage) const { data, refetch, isLoading, isFetching, isError } = useGetFaqQuery(currentPage)
const [localData, setLocalData] = useState<any[]>([]); const [localData, setLocalData] = useState<any[]>([]);
const [faqToggle] = useFaqToggleMutation() const [faqToggle] = useFaqToggleMutation()
const [deleteFaqPost] = useDeleteFaqPostMutation() const [deleteFaqPost] = useDeleteFaqPostMutation()
@@ -85,9 +85,21 @@ const FAQ = () => {
try { try {
await faqToggle({ id: agencyId, is_active: newStatus }).unwrap(); await faqToggle({ id: agencyId, is_active: newStatus }).unwrap();
refetch() toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
setTimeout(() => {
refetch();
}, 500);
} catch (error) { } catch (error) {
console.error("Error updating privacy policy:", error); console.error("Error updating privacy policy:", error);
toaster.create({
title: "Error",
description: "Someting went wrong.",
type: "error",
});
setLocalData((prevData) => setLocalData((prevData) =>
prevData.map((agency) => prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
@@ -225,6 +237,8 @@ const FAQ = () => {
total: data?.data.total || 0 total: data?.data.total || 0
}} }}
onPageChange={handlePageChange} onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>)} />)}
</Box> </Box>
<Toaster /> <Toaster />

View File

@@ -20,7 +20,7 @@ function FaqAddModel({ refetch }: { refetch: VoidFunction }) {
const [faqAnswer, setFaqAnswer] = useState(''); const [faqAnswer, setFaqAnswer] = useState('');
const [userType, setUserType] = useState(""); const [userType, setUserType] = useState("");
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [createFaqPost] = useCreateFaqPostMutation() const [createFaqPost, { isLoading }] = useCreateFaqPostMutation()
const handleOpenModal = () => { const handleOpenModal = () => {
setIsOpen(true); // Open modal when clicking "Add" setIsOpen(true); // Open modal when clicking "Add"
@@ -159,7 +159,7 @@ function FaqAddModel({ refetch }: { refetch: VoidFunction }) {
</Stack> </Stack>
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -16,7 +16,7 @@ import ReactQuill from "react-quill";
function PrivacyPolicyAddModel({ policyData, refetch }: { policyData: any, refetch: VoidFunction }) { function PrivacyPolicyAddModel({ policyData, refetch }: { policyData: any, refetch: VoidFunction }) {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [updatePrivacyPolicy] = useUpdatePrivacyPolicyMutation() const [updatePrivacyPolicy, { isLoading }] = useUpdatePrivacyPolicyMutation()
const { const {
control, control,
handleSubmit, handleSubmit,
@@ -139,7 +139,7 @@ function PrivacyPolicyAddModel({ policyData, refetch }: { policyData: any, refet
</Stack> </Stack>
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} mt={'4'} onClick={handleSubmit(onSubmit)}> <Button w="100%" bg="#02A0A0" color={"#fff"} mt={'4'} onClick={handleSubmit(onSubmit)} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -18,7 +18,7 @@ import { useUpdateTermsMutation } from "../../../Redux/Service/terms.and.conditi
function TermsAndConditionsAddModel({ termsData, refetch }: { termsData: any, refetch: VoidFunction }) { function TermsAndConditionsAddModel({ termsData, refetch }: { termsData: any, refetch: VoidFunction }) {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [updateTerms] = useUpdateTermsMutation() const [updateTerms, { isLoading }] = useUpdateTermsMutation()
const { const {
control, control,
handleSubmit, handleSubmit,
@@ -136,7 +136,7 @@ function TermsAndConditionsAddModel({ termsData, refetch }: { termsData: any, re
</Stack> </Stack>
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} mt={'4'} onClick={handleSubmit(onSubmit)}> <Button w="100%" bg="#02A0A0" color={"#fff"} mt={'4'} onClick={handleSubmit(onSubmit)} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -1,19 +1,26 @@
import { Box, HStack, Input, Text } from "@chakra-ui/react"; import { Box, HStack, Text } from "@chakra-ui/react";
import MainFrame from "../../components/MainFrame"; import MainFrame from "../../components/MainFrame";
import PendingRequests from "../../Pages/ManageContact/PendingRequests"; import PendingRequests from "../../Pages/ManageContact/PendingRequests";
import { InputGroup } from "../../components/ui/input-group"; // import { InputGroup } from "../../components/ui/input-group";
import { LuSearch } from "react-icons/lu"; // import { LuSearch } from "react-icons/lu";
import DataTable from "../../components/DataTable"; import DataTable from "../../components/DataTable";
import { useGetContactQuery } from "../../Redux/Service/manage.contactus.service"; import { useGetContactQuery } from "../../Redux/Service/manage.contactus.service";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Spinner } from "../../components/Sipnner/Spinner"; import { Spinner } from "../../components/Sipnner/Spinner";
import { useDebounce } from "../../components/Hooks/useDebounce";
import SearchComponent from "../../components/SearchComponent";
// table data // table data
const tableHeadRow = ["Sr. No", "Email id", "Name", "Date", "Action"]; const tableHeadRow = ["Sr. No", "Email id", "Name", "Date", "Action"];
const ManageContact = () => { const ManageContact = () => {
const { data, isLoading, isError } = useGetContactQuery(); const [currentPage, setCurrentPage] = useState(1);
const [localData, setLocalData] = useState([]); 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);
useEffect(() => { useEffect(() => {
if (data) { if (data) {
@@ -21,6 +28,20 @@ const ManageContact = () => {
} }
}, [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 => { const formatDateOfBirth = (dob: string): string => {
return new Date(dob).toLocaleDateString("en-GB", { return new Date(dob).toLocaleDateString("en-GB", {
day: "2-digit", day: "2-digit",
@@ -29,14 +50,15 @@ const ManageContact = () => {
}); });
}; };
const managepost = localData?.map((agency: any, index: number) => ({ 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 "Sr. No": index + 1, // Typically Sr. No starts from 1, not using id which might not be sequential
"Email id": agency?.email || "-", "Email id": agency?.email || "-",
Name: agency?.first_name || "-", Name: agency?.first_name || "-",
Date: formatDateOfBirth(agency?.created_at) || "-", Date: formatDateOfBirth(agency?.created_at) || "-",
Action: ( Action: (
<HStack justifyContent="center"> <HStack justifyContent="center" cursor={agency.response_status === 0 ? 'pointer' : 'default'}>
<PendingRequests /> {agency.response_status === 0 ? <PendingRequests data={agency} refetch={refetch} /> : 'Resolved'}
{/* <PendingRequests data={agency} refetch={refetch} /> */}
</HStack> </HStack>
), ),
})); }));
@@ -86,35 +108,25 @@ const ManageContact = () => {
</Text> </Text>
<HStack> <HStack>
<InputGroup <SearchComponent
startElement={ value={searchTerm}
<LuSearch onChange={handleSearchChange}
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={"xs"}
fontSize={"sm"}
placeholder="Search..."
bgColor={"#EEEEEE"}
ps={8}
/>
</InputGroup>
</HStack> </HStack>
</HStack> </HStack>
<DataTable <DataTable
sortableColumns={["Name", "Registration Date "]} sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow} tableHeadRow={tableHeadRow}
data={managepost || []} // Ensure an empty array is passed if managepost is undefined 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}
/> />
</Box> </Box>
</MainFrame> </MainFrame>

View File

@@ -10,95 +10,160 @@ import {
DialogTrigger, DialogTrigger,
} from "../../components/ui/dialog"; } from "../../components/ui/dialog";
import { Badge, Field, HStack, Input, Stack, Textarea } from "@chakra-ui/react"; import { Badge, Field, HStack, Input, Stack, Textarea } from "@chakra-ui/react";
function PendingRequests() { import { usePendingRequestMutation } from "../../Redux/Service/manage.contactus.service";
import { useState } from "react";
import { Toaster, toaster } from "../../components/ui/toaster";
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()
const handleOpenModal = () => {
setIsOpen(true);
};
const handleSubmit = async (status: string) => {
const payload = { ...res, response_status: status };
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",
});
}
}
return ( return (
<DialogRoot placement="center"> <>
<DialogTrigger asChild> <DialogRoot placement="center" key={data.id} open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<Badge fontSize={"xs"} px={2} bg={'#02a0a01f'}> <DialogTrigger asChild>
Answer request <Badge fontSize={"xs"} px={2} bg={'#02a0a01f'} onClick={handleOpenModal}>
</Badge> Answer request
</DialogTrigger> </Badge>
</DialogTrigger>
<DialogContent <DialogContent
bg={"#fff"} bg={"#fff"}
w={{ base: "90%", md: "400px" }} w={{ base: "90%", md: "400px" }}
height={"auto"} height={"auto"}
p={3} // Reduced padding p={3} // Reduced padding
bgSize={"md"} bgSize={"md"}
>
<DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px">
Pending Requests
</DialogTitle>
</DialogHeader>
<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"
/>
<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>
</Stack>
</DialogBody>
<DialogFooter
display={{ base: "block", md: "flex" }}
justifyContent="center"
gap={1}
pt={2}
> >
<HStack mt={2} mb={3} width={"100%"} justifyContent={"space-between"}> <DialogHeader bg="white">
<Button <DialogTitle alignSelf="center" color="black" fontSize="14px">
width={"48%"} Pending Requests
color="black" </DialogTitle>
_hover={{ bgColor: "white" }} </DialogHeader>
variant="outline"
borderRadius="sm"
border="1px solid #02A0A0"
size={"xs"}
>
Unresolved
</Button>
<Button
width={"48%"}
borderRadius="sm"
// bgColor="#007F33"
bgColor={"#02A0A0"}
color="white"
// colorPalette="#007F33"
size={"xs"}
>
Resolved
</Button>
</HStack>
</DialogFooter>
<DialogCloseTrigger color="black" /> <DialogBody bg="white">
</DialogContent> <Stack py={3}>
</DialogRoot> <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 })}
/>
<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>
<Toaster />
</>
); );
} }

View File

@@ -3,15 +3,14 @@ import {
HStack, HStack,
Image, Image,
// Image, // Image,
Input,
Text, Text,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { LuSearch } from "react-icons/lu"; // import { LuSearch } from "react-icons/lu";
// import { RiDeleteBin5Line } from "react-icons/ri"; // import { RiDeleteBin5Line } from "react-icons/ri";
// import AlertDailog from "../../components/AlertDailog"; // import AlertDailog from "../../components/AlertDailog";
import DataTable from "../../components/DataTable"; import DataTable from "../../components/DataTable";
import MainFrame from "../../components/MainFrame"; import MainFrame from "../../components/MainFrame";
import { InputGroup } from "../../components/ui/input-group"; // import { InputGroup } from "../../components/ui/input-group";
import ManageJobsAdd from "./ManageJobsAdd"; import ManageJobsAdd from "./ManageJobsAdd";
import ViewManageJob from "./ViewManageJob"; import ViewManageJob from "./ViewManageJob";
import { import {
@@ -21,8 +20,10 @@ import {
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Spinner } from "../../components/Sipnner/Spinner"; import { Spinner } from "../../components/Sipnner/Spinner";
import Delete from "../../components/ActionIcons/Delete"; import Delete from "../../components/ActionIcons/Delete";
import { toaster } from "../../components/ui/toaster"; import { Toaster, toaster } from "../../components/ui/toaster";
import AlertDailog from "../../components/AlertDailog"; import AlertDailog from "../../components/AlertDailog";
import { useDebounce } from "../../components/Hooks/useDebounce";
import SearchComponent from "../../components/SearchComponent";
// import { useState } from "react"; // import { useState } from "react";
// import { useGetManageJobsQuery } from "../../Redux/Service/manage.jobs.service"; // import { useGetManageJobsQuery } from "../../Redux/Service/manage.jobs.service";
// import Delete from "../../components/ActionIcons/Delete"; // import Delete from "../../components/ActionIcons/Delete";
@@ -40,9 +41,12 @@ const tableHeadRow = [
]; ];
const ManageJobs = () => { const ManageJobs = () => {
const [currentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [localData, setLocalData] = useState([]); const [localData, setLocalData] = useState([]);
const { data, refetch, isLoading } = useGetManageJobsQuery(currentPage); 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 [deleteJobsPost] = useDeleteJobsPostMutation();
const [deleteModal, setDeleteModal] = useState(false); const [deleteModal, setDeleteModal] = useState(false);
const [selectedJobsId, setSelectedJobsId] = useState<number | null>(null); const [selectedJobsId, setSelectedJobsId] = useState<number | null>(null);
@@ -52,7 +56,16 @@ const ManageJobs = () => {
setLocalData((data as any)?.data?.data || []); setLocalData((data as any)?.data?.data || []);
} }
}, [data]); }, [data]);
console.log(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) => { const handleDeleteJobs = async (jobsId: number) => {
try { try {
@@ -84,8 +97,8 @@ const ManageJobs = () => {
Salary: agency?.ctc_amount, Salary: agency?.ctc_amount,
Action: ( Action: (
<HStack justifyContent="center"> <HStack justifyContent="center">
<ViewManageJob /> <ViewManageJob data={agency} />
<ManageJobsAdd /> <ManageJobsAdd data={agency} refetch={refetch}/>
<AlertDailog <AlertDailog
isOpen={deleteModal} isOpen={deleteModal}
AltertTiggerIcon={() => ( AltertTiggerIcon={() => (
@@ -142,29 +155,10 @@ const ManageJobs = () => {
</Text> </Text>
<HStack> <HStack>
<InputGroup <SearchComponent
startElement={ value={searchTerm}
<LuSearch onChange={handleSearchChange}
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={"xs"}
fontSize={"sm"}
placeholder="Search..."
bgColor={"#EEEEEE"}
ps={8}
/>
</InputGroup>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */} {/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
</HStack> </HStack>
</HStack> </HStack>
@@ -172,8 +166,18 @@ const ManageJobs = () => {
sortableColumns={["Name", "Registration Date "]} sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow} tableHeadRow={tableHeadRow}
data={managepost} 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> </Box>
<Toaster />
</MainFrame> </MainFrame>
); );
}; };

View File

@@ -1,10 +1,8 @@
import { import {
Field, Field,
Input, Input,
SelectValueText,
Span, Span,
Stack, Stack,
createListCollection,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { Button } from "../../components/ui/button"; import { Button } from "../../components/ui/button";
import { import {
@@ -19,24 +17,151 @@ import {
} from "../../components/ui/dialog"; } from "../../components/ui/dialog";
// import { TbEdit } from "react-icons/tb"; // import { TbEdit } from "react-icons/tb";
import {
SelectContent,
SelectItem,
SelectLabel,
SelectRoot,
SelectTrigger,
} from "../../components/ui/select";
import Edit from "../../components/ActionIcons/Edit"; 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";
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;
}
};
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 || "",
};
const [state, dispatch] = useReducer(reducerFunction, initialState);
const closeRef = useRef<HTMLButtonElement>(null);
const getDisplayName = (name: string, maxLength = 30) =>
name.length > maxLength ? name.slice(0, maxLength) + "..." : name;
const handleSubmit = async () => {
const {
jobTitle,
workspaceMode,
category,
subCategory,
salary,
experience,
jobLocation,
countrySelection,
jobType,
skillsDescription,
jobDescription,
} = state;
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",
});
}
};
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 ( return (
<DialogRoot placement="center"> <DialogRoot placement="center">
<DialogTrigger asChild> <DialogTrigger asChild>
@@ -73,50 +198,182 @@ function ManageJobsAdd() {
pl={1} pl={1}
fontSize="12px" fontSize="12px"
height="30px" height="30px"
value={state.jobTitle}
onChange={(e) =>
dispatch({
type: "SET_JOB_TITLE",
payload: e.target.value,
})
}
/> />
</Field.Root> </Field.Root>
<Field.Root> <Field.Root>
<Field.Label color="black" pt={1} fontSize="12px"> <Field.Label color="black" pt={1} fontSize="12px">
Workspace mode Workspace mode
</Field.Label> </Field.Label>
<Input <select
placeholder="Enter the Workspace Mode" style={{
bgColor="#EEEEEE" backgroundColor: "#EEEEEE",
color="black" color: "black",
border="none" border: "none",
pl={1} height: "30px",
fontSize="12px" fontSize: "12px",
height="30px" 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.Root> <Field.Root>
<Field.Label pt={1} color="black" fontSize="12px"> <Field.Label pt={1} color="black" fontSize="12px">
Category Category
</Field.Label> </Field.Label>
<Input <select
placeholder="Enter the Category" style={{
bgColor="#EEEEEE" backgroundColor: "#EEEEEE",
color="black" color: "black",
border="none" border: "none",
pl={1} height: "30px",
fontSize="12px" fontSize: "12px",
height="30px" 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.Root> <Field.Root>
<Field.Label pt={1} color="black" fontSize="12px"> <Field.Label pt={1} color="black" fontSize="12px">
Sub-Category Sub-Category
</Field.Label> </Field.Label>
<Input <select
placeholder="Enter the Sub-Category" style={{
bgColor="#EEEEEE" backgroundColor: "#EEEEEE",
color="black" color: "black",
border="none" border: "none",
pl={1} height: "30px",
fontSize="12px" fontSize: "12px",
height="30px" 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.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.Root>
<Field.Label pt={1} color="black" fontSize="12px"> <Field.Label pt={1} color="black" fontSize="12px">
Salary Salary
@@ -129,6 +386,13 @@ function ManageJobsAdd() {
pl={1} pl={1}
fontSize="12px" fontSize="12px"
height="30px" height="30px"
value={state.salary}
onChange={(e) =>
dispatch({
type: "SET_SALARY",
payload: e.target.value,
})
}
/> />
</Field.Root> </Field.Root>
<Field.Root> <Field.Root>
@@ -136,13 +400,20 @@ function ManageJobsAdd() {
Experience Experience
</Field.Label> </Field.Label>
<Input <Input
placeholder="Enter the Experience" placeholder="Enter the Experience in years"
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
pl={1} pl={1}
fontSize="12px" fontSize="12px"
height="30px" height="30px"
value={state.experience}
onChange={(e) =>
dispatch({
type: "SET_EXPERIENCE",
payload: e.target.value,
})
}
/> />
</Field.Root> </Field.Root>
<Field.Root> <Field.Root>
@@ -157,71 +428,34 @@ function ManageJobsAdd() {
pl={1} pl={1}
fontSize="12px" fontSize="12px"
height="30px" height="30px"
/> value={state.jobLocation}
</Field.Root> onChange={(e) =>
{/* <Field.Label pt={1} color="black" fontSize="12px">Country Selection</Field.Label> dispatch({
<Input placeholder="Enter the Country Selection" /> */} type: "SET_JOB_LOCATION",
<SelectRoot collection={frameworks} size="sm" w={"100%"}> payload: e.target.value,
<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>
<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.Root> <Field.Root>
<Field.Label pt={1} color="black" fontSize="12px"> <Field.Label pt={1} color="black" fontSize="12px">
Skills required Skills description
</Field.Label> </Field.Label>
<Input <Input
placeholder="Enter the Skills Required" placeholder="Enter the Skills description"
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
pl={1} pl={1}
fontSize="12px" fontSize="12px"
height="30px" height="30px"
value={state.skillsDescription}
onChange={(e) =>
dispatch({
type: "SET_SKILLS_DESCRIPTION",
payload: e.target.value,
})
}
/> />
</Field.Root> </Field.Root>
<Field.Root> <Field.Root>
@@ -236,6 +470,13 @@ function ManageJobsAdd() {
pl={1} pl={1}
fontSize="12px" fontSize="12px"
height="30px" height="30px"
value={state.jobDescription}
onChange={(e) =>
dispatch({
type: "SET_JOB_DESCRIPTION",
payload: e.target.value,
})
}
/> />
</Field.Root> </Field.Root>
</Stack> </Stack>
@@ -247,13 +488,16 @@ function ManageJobsAdd() {
color={"#fff"} color={"#fff"}
fontSize="12px" fontSize="12px"
height="30px" height="30px"
onClick={handleSubmit}
disabled={isLoading}
> >
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>
<DialogCloseTrigger color="black" /> <DialogCloseTrigger color="black" ref={closeRef} />
</DialogContent> </DialogContent>
<Toaster />
</DialogRoot> </DialogRoot>
); );
} }

View File

@@ -1,17 +1,13 @@
import { import {
Field, Field,
Input, Input,
SelectValueText,
Span,
Stack, Stack,
createListCollection,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { Button } from "../../components/ui/button"; import { Button } from "../../components/ui/button";
import { import {
DialogBody, DialogBody,
DialogCloseTrigger, DialogCloseTrigger,
DialogContent, DialogContent,
DialogFooter,
DialogHeader, DialogHeader,
DialogRoot, DialogRoot,
DialogTitle, DialogTitle,
@@ -19,276 +15,290 @@ import {
} from "../../components/ui/dialog"; } from "../../components/ui/dialog";
// import { MdOutlineRemoveRedEye } from "react-icons/md"; // import { MdOutlineRemoveRedEye } from "react-icons/md";
import {
SelectContent,
SelectItem,
SelectLabel,
SelectRoot,
SelectTrigger,
} from "../../components/ui/select";
import View from "../../components/ActionIcons/View"; import View from "../../components/ActionIcons/View";
import { useLazyViewJobsQuery } from "../../Redux/Service/manage.jobs.service"; import { JobStatusData, useLazyViewJobsQuery } from "../../Redux/Service/manage.jobs.service";
const frameworks = createListCollection({ function ViewManageJob({ data }: { data: JobStatusData }) {
items: [ const [trigger] = useLazyViewJobsQuery();
{ label: "React.js", value: "react" },
{ label: "Vue.js", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
],
});
function ViewManageJob() {
const [trigger, { data }] = useLazyViewJobsQuery();
console.log(data); console.log(data);
// const handleView = () => { const handleView = () => {
// trigger(id); trigger(data.id);
// }; };
const viewJobs = data; // const viewJobs = data;
console.log(); console.log();
return ( return (
<DialogRoot placement="center"> <DialogRoot placement="center">
<DialogTrigger asChild> <DialogTrigger asChild>
<Span> <Button
onClick={handleView}
bg={'transparent'}
color={"black"}
>
<View /> <View />
</Span> </Button>
</DialogTrigger> </DialogTrigger>
{/* {viewJobs?.map((data: any) => ( */} {/* {viewJobs?.map((data: any) => ( */}
<DialogContent <DialogContent
bg={"#fff"} bg={"#fff"}
// w={{ lg: "60%", md: "230px" }} // w={{ lg: "60%", md: "230px" }}
w={{ base: "90%", md: "400px" }} w={{ base: "90%", md: "400px" }}
height={"80vh"} height={"80vh"}
overflow={"scroll"} overflow={"scroll"}
overflowX="hidden" overflowX="hidden"
p={3} // Reduced padding p={3} // Reduced padding
bgSize={"md"} bgSize={"md"}
> >
<DialogHeader bg="white"> <DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px"> <DialogTitle alignSelf="center" color="black" fontSize="14px">
Add Details Add Details
</DialogTitle> </DialogTitle>
</DialogHeader> </DialogHeader>
<DialogBody bg="white"> <DialogBody bg="white">
<Stack py={3}> <Stack py={3}>
<Field.Root> <Field.Root>
<Field.Label color="black" pt={1} fontSize="12px"> <Field.Label color="black" pt={1} fontSize="12px">
Job title Job title
</Field.Label> </Field.Label>
<Input <Input
placeholder="Enter the Job Title" placeholder="Enter the Job Title"
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
pl={1} pl={1}
fontSize="12px" fontSize="12px"
height="30px" height="30px"
/> value={data?.job_title}
</Field.Root> />
<Field.Root> </Field.Root>
<Field.Label color="black" pt={1} fontSize="12px"> <Field.Root>
Workspace mode <Field.Label color="black" pt={1} fontSize="12px">
</Field.Label> Workspace mode
<Input </Field.Label>
placeholder="Enter the Workspace Mode" <Input
bgColor="#EEEEEE" placeholder="Enter the Workspace Mode"
color="black" bgColor="#EEEEEE"
border="none" color="black"
pl={1} border="none"
fontSize="12px" pl={1}
height="30px" fontSize="12px"
/> height="30px"
</Field.Root> value={data?.workspace?.en_name}
<Field.Root> />
<Field.Label pt={1} color="black" fontSize="12px"> </Field.Root>
Category <Field.Root>
</Field.Label> <Field.Label pt={1} color="black" fontSize="12px">
<Input Category
placeholder="Enter the Category" </Field.Label>
bgColor="#EEEEEE" <Input
color="black" placeholder="Enter the Category"
border="none" bgColor="#EEEEEE"
pl={1} color="black"
fontSize="12px" border="none"
height="30px" pl={1}
/> fontSize="12px"
</Field.Root> height="30px"
<Field.Root> value={data?.industry?.en_name}
<Field.Label pt={1} color="black" fontSize="12px"> />
Sub-Category </Field.Root>
</Field.Label> <Field.Root>
<Input <Field.Label pt={1} color="black" fontSize="12px">
placeholder="Enter the Sub-Category" Sub-Category
bgColor="#EEEEEE" </Field.Label>
color="black" <Input
border="none" placeholder="Enter the Sub-Category"
pl={1} bgColor="#EEEEEE"
fontSize="12px" color="black"
height="30px" border="none"
/> pl={1}
</Field.Root> fontSize="12px"
<Field.Root> height="30px"
<Field.Label pt={1} color="black" fontSize="12px"> value={data?.department?.en_name}
Salary />
</Field.Label> </Field.Root>
<Input <Field.Root>
placeholder="Enter the Salary" <Field.Label pt={1} color="black" fontSize="12px">
bgColor="#EEEEEE" Salary
color="black" </Field.Label>
border="none" <Input
pl={1} placeholder="Enter the Salary"
fontSize="12px" bgColor="#EEEEEE"
height="30px" color="black"
/> border="none"
</Field.Root> pl={1}
<Field.Root> fontSize="12px"
<Field.Label pt={1} color="black" fontSize="12px"> height="30px"
Experience value={data?.ctc_amount}
</Field.Label> />
<Input </Field.Root>
placeholder="Enter the Experience" <Field.Root>
bgColor="#EEEEEE" <Field.Label pt={1} color="black" fontSize="12px">
color="black" Experience
border="none" </Field.Label>
pl={1} <Input
fontSize="12px" placeholder="Enter the Experience"
height="30px" bgColor="#EEEEEE"
/> color="black"
</Field.Root> border="none"
<Field.Root> pl={1}
<Field.Label pt={1} color="black" fontSize="12px"> fontSize="12px"
Job Location height="30px"
</Field.Label> value={data?.experience}
<Input />
placeholder="Enter the Job Location" </Field.Root>
bgColor="#EEEEEE" <Field.Root>
color="black" <Field.Label pt={1} color="black" fontSize="12px">
border="none" Job Location
pl={1} </Field.Label>
fontSize="12px" <Input
height="30px" placeholder="Enter the Job Location"
/> bgColor="#EEEEEE"
</Field.Root> color="black"
{/* <Field.Label pt={1} color="black" fontSize="12px">Country Selection</Field.Label> border="none"
<Input placeholder="Enter the Country Selection" /> */} pl={1}
<SelectRoot collection={frameworks} size="sm" w={"100%"}> fontSize="12px"
<SelectLabel pt={1} color="black" fontSize="12px"> height="30px"
Country Selection value={data?.job_location}
</SelectLabel> />
<SelectTrigger </Field.Root>
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> <Field.Root>
<Field.Label pt={1} color="black" fontSize="12px"> <Field.Label pt={1} color="black" fontSize="12px">
Job type Country
</Field.Label> </Field.Label>
<Input <Input
placeholder="Enter the Job Type" placeholder="Enter the Country"
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
pl={1} pl={1}
fontSize="12px" fontSize="12px"
height="30px" height="30px"
/> value={data?.country.en_name}
</Field.Root> />
<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" /> {/* <SelectRoot collection={frameworks} size="sm" w={"100%"}>
</DialogContent> <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>
<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> */}
<DialogCloseTrigger color="black" />
</DialogContent>
{/* ))} */} {/* ))} */}
</DialogRoot> </DialogRoot>
); );

View File

@@ -14,9 +14,10 @@ import { Switch } from "../../components/ui/switch";
import ViewDailog from "./ViewDailog"; import ViewDailog from "./ViewDailog";
import { useGetManagePostsQuery, usePostStatusToggleMutation } from "../../Redux/Service/manage.post.service"; import { useGetManagePostsQuery, usePostStatusToggleMutation } from "../../Redux/Service/manage.post.service";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { toaster } from "../../components/ui/toaster"; import { Toaster, toaster } from "../../components/ui/toaster";
import { FaVideo } from "react-icons/fa"; import { FaVideo } from "react-icons/fa";
import SearchComponent from "../../components/SearchComponent"; import SearchComponent from "../../components/SearchComponent";
import { delay } from "../../components/Utils";
// import Delete from "../../components/ActionIcons/Delete"; // import Delete from "../../components/ActionIcons/Delete";
// import ViewDailog from './ViewDailog' // import ViewDailog from './ViewDailog'
@@ -71,7 +72,7 @@ const tableHeadRow = [
const ManagePost = () => { const ManagePost = () => {
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const { data, refetch } = useGetManagePostsQuery(currentPage) const { data, refetch, isFetching, isError } = useGetManagePostsQuery(currentPage)
const [localData, setLocalData] = useState<any[]>([]); const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
const [postStatusToggle] = usePostStatusToggleMutation() const [postStatusToggle] = usePostStatusToggleMutation()
@@ -96,6 +97,12 @@ const ManagePost = () => {
); );
try { try {
await postStatusToggle({ id: agencyId, is_active: newStatus }).unwrap(); await postStatusToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch() refetch()
} catch (error) { } catch (error) {
console.error("Error updating:", error); console.error("Error updating:", error);
@@ -149,36 +156,35 @@ const ManagePost = () => {
h={50} h={50}
src={`${APIURL}${agency.images[0].image_name}`} src={`${APIURL}${agency.images[0].image_name}`}
/> />
<Text fontSize="xs" color={'lightgray'}> <Text fontSize="xs" color={'lightgray'}>
{`${Number(agency.images.length) > 1 ? '+' + (Number(agency.images.length) - 1) : ''}`} {`${Number(agency.images.length) > 1 ? '+' + (Number(agency.images.length) - 1) : ''}`}
</Text> </Text>
</HStack> </HStack>
) : ( ) : (
<HStack> <HStack>
<Box <Box
rounded={"lg"} rounded={"lg"}
w={100} w={100}
h={50} h={50}
bg="gray.200" bg="gray.200"
display="flex" display="flex"
alignItems="center" alignItems="center"
justifyContent="center" justifyContent="center"
> >
<Icon as={FaVideo} color="gray.500" /> <Icon as={FaVideo} color="gray.500" />
</Box> </Box>
<Text fontSize="xs" color={'lightgray'}> <Text fontSize="xs" color={'lightgray'}>
{`${Number(agency.images.length) > 1 ? '+' + (Number(agency.images.length) - 1) : ''}`} {`${Number(agency.images.length) > 1 ? '+' + (Number(agency.images.length) - 1) : ''}`}
</Text> </Text>
</HStack> </HStack>
) : '' ) : ''
// <Image rounded={"lg"} w={100} h={50} src={img} /> // <Image rounded={"lg"} w={100} h={50} src={img} />
), ),
Description: ( Description: (
<Text> <Text>
{`${translation?.content}`.slice( {translation?.content?.length > 30
0, ? `${translation.content.slice(0, 30)}...`
30 : translation?.content}
) + "..."}
</Text> </Text>
), ),
"Publish Data": formatAPIDate(agency.created_at), "Publish Data": formatAPIDate(agency.created_at),
@@ -236,8 +242,11 @@ const ManagePost = () => {
total: data?.data.total || 0 total: data?.data.total || 0
}} }}
onPageChange={handlePageChange} onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/> />
</Box> </Box>
<Toaster />
</MainFrame> </MainFrame>
); );
}; };

View File

@@ -1,12 +1,16 @@
import { Box, HStack, Input, Text } from "@chakra-ui/react"; import { Box, HStack, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame"; import MainFrame from "../../../components/MainFrame";
import DataTable from "../../../components/DataTable"; import DataTable from "../../../components/DataTable";
import { Switch } from "../../../components/ui/switch"; import { Switch } from "../../../components/ui/switch";
import { InputGroup } from "../../../components/ui/input-group"; // import { InputGroup } from "../../../components/ui/input-group";
import { LuSearch } from "react-icons/lu"; // import { LuSearch } from "react-icons/lu";
import { useGetContactQuery } from "../../../Redux/Service/deactivated.account.service"; // import { useGetContactQuery } from "../../../Redux/Service/deactivated.account.service";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Spinner } from "../../../components/Sipnner/Spinner"; 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";
const tableHeadRow = [ const tableHeadRow = [
"Sr. No", "Sr. No",
@@ -17,8 +21,11 @@ const tableHeadRow = [
]; ];
const DeactivatedAccounts = () => { const DeactivatedAccounts = () => {
const { data ,isLoading} = useGetContactQuery(); const [currentPage, setCurrentPage] = useState(1);
const [localData, setLocalData] = useState([]); const { data, isLoading, refetch, isError, isFetching } = useGetDeactivateUserQuery(currentPage);
const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const [userDeactivateToggle] = useUserDeactivateToggleMutation()
useEffect(() => { useEffect(() => {
if (data) { if (data) {
@@ -26,8 +33,47 @@ const DeactivatedAccounts = () => {
} }
}, [data]); }, [data]);
const handlePageChange = (page: number) => {
setCurrentPage(page);
}
const manageUser = localData?.map((agency: any, index: number) => ({ 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, "Sr. No": index + 1,
"First Name": agency?.first_name, "First Name": agency?.first_name,
"Last Name": agency?.last_name, "Last Name": agency?.last_name,
@@ -38,13 +84,13 @@ const DeactivatedAccounts = () => {
size={"sm"} size={"sm"}
colorPalette={"teal"} colorPalette={"teal"}
checked={agency.is_active === true} checked={agency.is_active === true}
// onChange={() => handleToggle(agency.id, agency.is_active ? "1" : "0")} onChange={() => handleToggle(agency.id, agency.is_active ? "1" : "0")}
/> />
</Box> </Box>
), ),
})); }));
if (isLoading) { if (isLoading) {
return ( return (
<MainFrame> <MainFrame>
<Box <Box
@@ -89,37 +135,32 @@ const DeactivatedAccounts = () => {
</Text> </Text>
<HStack> <HStack>
<InputGroup <SearchComponent
startElement={ value={searchTerm}
<LuSearch onChange={(value) => {
fontSize={"xs"} setSearchTerm(value);
style={{ position: "relative", left: "10px" }} // setCurrentPage(1);
/> refetch()
} }}
color={"#000"} />
>
<Input
p={4}
w={300}
bg={"#fff"}
colorPalette={"blue"}
_focus={{ border: "1px solid #02A0A0" }}
rounded={"md"}
size={"2xs"}
fontSize={"sm"}
placeholder="Search..."
bgColor={"#EEEEEE"}
ps={8}
/>
</InputGroup>
</HStack> </HStack>
</HStack> </HStack>
<DataTable <DataTable
sortableColumns={["Name", "Registration Date "]} sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow} tableHeadRow={tableHeadRow}
data={manageUser} 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> </Box>
<Toaster />
</MainFrame> </MainFrame>
); );
}; };

View File

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

View File

@@ -1,7 +1,6 @@
// import { MdOutlineRemoveRedEye } from "react-icons/md"; // import { MdOutlineRemoveRedEye } from "react-icons/md";
import { Field, Input, Span, Stack } from "@chakra-ui/react"; import { Box, Field, HStack, Input, Stack } from "@chakra-ui/react";
import { import {
DialogActionTrigger,
DialogBody, DialogBody,
DialogCloseTrigger, DialogCloseTrigger,
DialogContent, DialogContent,
@@ -15,118 +14,332 @@ import {
import { Button } from "../../../components/ui/button"; import { Button } from "../../../components/ui/button";
// import { TbEdit } from "react-icons/tb"; // import { TbEdit } from "react-icons/tb";
import Edit from "../../../components/ActionIcons/Edit"; 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 ( return (
<DialogRoot placement="center"> <>
<DialogTrigger asChild> <DialogRoot placement="center" key={formData.id} open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<Span> <DialogTrigger asChild>
{/* <Span>
<Edit /> <Edit />
</Span> </Span> */}
</DialogTrigger> <Button bg="transparent" color={"black"} h={"18px"} onClick={handleOpenModal}><Edit /></Button>
</DialogTrigger>
<DialogContent <DialogContent
bg={"#fff"} bg={"#fff"}
w={{ base: "90%", md: "400px" }} w={{ base: "90%", md: "400px" }}
height={"80vh"} height={"80vh"}
overflow={"scroll"} overflow={"scroll"}
overflowX="hidden" overflowX="hidden"
p={3} // Reduced padding p={3} // Reduced padding
bgSize={"md"} bgSize={"md"}
> >
<DialogHeader bg="white" p={0}> <DialogHeader bg="white" p={0}>
<DialogTitle alignSelf="center" color="black" fontSize="14px"> <DialogTitle alignSelf="center" color="black" fontSize="14px">
Edit user Accounts Edit user Accounts
</DialogTitle> </DialogTitle>
</DialogHeader> </DialogHeader>
<DialogBody bg="white"> <DialogBody bg="white">
<Stack py={3}> <Stack py={3}>
<Field.Root> <Field.Root>
<Field.Label color="black" pt={1} fontSize="12px"> <Field.Label color="black" pt={1} fontSize="12px">
First Name First Name
</Field.Label> </Field.Label>
<Input <Input
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
pl={1} pl={1}
fontSize="12px" fontSize="12px"
height="30px" height="30px"
/> value={formData.first_name}
onChange={(e) => setFormData({ ...formData, first_name: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px"> <Field.Label color="black" pt={1} fontSize="12px">
Last Name Last Name
</Field.Label> </Field.Label>
<Input <Input
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
pl={1} pl={1}
fontSize="12px" fontSize="12px"
height="30px" height="30px"
/> value={formData.last_name}
onChange={(e) => setFormData({ ...formData, last_name: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px"> <Field.Label color="black" pt={1} fontSize="12px">
Gender Gender
</Field.Label> </Field.Label>
<Input <Input
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
pl={1} pl={1}
fontSize="12px" fontSize="12px"
height="30px" height="30px"
/> value={formData.gender}
onChange={(e) => setFormData({ ...formData, gender: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px"> <Field.Label color="black" pt={1} fontSize="12px">
DOB DOB
</Field.Label> </Field.Label>
<Input <Input
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
pl={1} pl={1}
fontSize="12px" fontSize="12px"
height="30px" 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"> <Field.Label color="black" pt={1} fontSize="12px">
OTP Verified Mobile Number
</Field.Label> </Field.Label>
<Input <Input
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
pl={1} pl={1}
fontSize="12px" fontSize="12px"
height="30px" height="30px"
/> value={formData.phone_number || ''}
onChange={(e) => setFormData({ ...formData, phone_number: e.target.value })}
/>
<Field.Label color="black" pt={1} fontSize="12px"> <Field.Label color="black" pt={1} fontSize="12px">
Language Type Of User
</Field.Label> </Field.Label>
<Input {/* <Input
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
pl={1} pl={1}
fontSize="12px" fontSize="12px"
height="30px" height="30px"
/> value={formData.principal_type?.principal_type_title || 'N/A'}
</Field.Root> onChange={(e) => setFormData({ ...formData, principal_type: { ...formData.principal_type, principal_type_title: e.target.value } })}
</Stack> /> */}
</DialogBody>
<DialogFooter mt={5}> <Box>
<DialogActionTrigger asChild> <select
<Button rounded={"md"} w={"100%"} size={"sm"} bg={"#02A0A0"}> 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 Save
</Button> </Button>
</DialogActionTrigger> </DialogFooter>
</DialogFooter> <DialogCloseTrigger color="black" />
<DialogCloseTrigger color="black" /> </DialogContent>
</DialogContent> </DialogRoot >
</DialogRoot> <Toaster />
</>
); );
} }

View File

@@ -1,7 +1,8 @@
import { import {
Box, HStack, Box, HStack,
Image,
// Image, // Image,
Text Text,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame"; import MainFrame from "../../../components/MainFrame";
// import AlertDailog from "../../../components/AlertDailog"; // import AlertDailog from "../../../components/AlertDailog";
@@ -10,21 +11,26 @@ import DataTable from "../../../components/DataTable";
import { Switch } from "../../../components/ui/switch"; import { Switch } from "../../../components/ui/switch";
import ViewRegisterUsers from "./ViewRegisterUsers"; import ViewRegisterUsers from "./ViewRegisterUsers";
import EditRegisterUsers from "./EditRegisterUsers"; import EditRegisterUsers from "./EditRegisterUsers";
import AddRegisterUsers from "./AddRegisterUsers"; // import AddRegisterUsers from "./AddRegisterUsers";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useGetManageUserQuery, UserData, useUserToggleMutation } from "../../../Redux/Service/manage.user"; import { useDeleteUserMutation, useGetManageUserQuery, UserData, useUserToggleMutation } from "../../../Redux/Service/manage.user";
import SearchComponent from "../../../components/SearchComponent"; 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 Delete from "../../../components/ActionIcons/Delete";
const tableHeadRow = [ const tableHeadRow = [
"Sr. No", "Sr. No",
"First Name", "First Name",
"Last Name",
"Mobile Number", "Mobile Number",
"Gender", "Gender",
"DOB", "DOB",
"Type Of User", "Type Of User",
"Language", "Default Language",
"Activate/Deactivate", "Active/Deactive",
"Action", "Action",
]; ];
@@ -63,10 +69,14 @@ const tableHeadRow = [
const RegisterUsers = () => { const RegisterUsers = () => {
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const { data, refetch } = useGetManageUserQuery(currentPage) const { data, refetch, isFetching, isError } = useGetManageUserQuery(currentPage)
const [localData, setLocalData] = useState<any[]>([]); const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
const [userToggle] = useUserToggleMutation() 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); console.log("Register Users Data", data?.data.data);
useEffect(() => { useEffect(() => {
@@ -97,9 +107,20 @@ const RegisterUsers = () => {
try { try {
await userToggle({ id: agencyId, is_active: newStatus }).unwrap(); await userToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch() refetch()
} catch (error) { } catch (error) {
console.error("Error updating privacy policy:", error); console.error("Error updating privacy policy:", error);
toaster.create({
title: "Error",
description: "Someting went wrong.",
type: "error",
});
setLocalData((prevData) => setLocalData((prevData) =>
prevData.map((agency) => prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
@@ -108,21 +129,46 @@ const RegisterUsers = () => {
} }
} }
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) => ({ const managepost = filteredData?.flatMap((agency: UserData, index: number) => ({
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1, "Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
"First Name": agency.first_name, "First Name": agency.first_name,
"Last Name": agency.last_name,
"Mobile Number": agency.phone_number, "Mobile Number": agency.phone_number,
"Gender": agency.gender, "Gender": agency.gender,
"DOB": agency.date_of_birth ? new Date(agency.date_of_birth).toLocaleDateString('en-GB').replace(/\//g, '-') : 'N/A', "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', "Type Of User": agency.principal_type?.principal_type_title || 'N/A',
// "Language": agency.principle_language_links.map(lang => lang.language_name).join(', ') || 'N/A', "Default Language": agency?.principle_language_linkss?.language?.language_name,
"Active/Deactive": agency.is_active === true ? 'Active' : 'Inactive',
"Action": ( "Action": (
<HStack justifyContent="center"> <HStack justifyContent="center">
<EditRegisterUsers <EditRegisterUsers
// 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 }} data={agency}
// refetch={refetch} refetch={refetch}
/> />
<ViewRegisterUsers /> <ViewRegisterUsers data={agency} />
<Box> <Box>
<Switch <Switch
colorPalette={'teal'} colorPalette={'teal'}
@@ -131,6 +177,24 @@ const RegisterUsers = () => {
onChange={() => handleToggle(agency.id, agency.is_active ? '1' : '0')} onChange={() => handleToggle(agency.id, agency.is_active ? '1' : '0')}
/> />
</Box> </Box>
<AlertDailog
isOpen={deleteModal}
AltertTiggerIcon={() => <Delete onClick={() => {
setSelectedFaqId(agency.id);
setDeleteModal(true)
}} />}
alertText="Do you want to delete user?"
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);
}
}}
/>
</HStack> </HStack>
), ),
})) }))
@@ -158,7 +222,7 @@ const RegisterUsers = () => {
refetch() refetch()
}} }}
/> />
<AddRegisterUsers /> {/* <AddRegisterUsers /> */}
</HStack> </HStack>
</HStack> </HStack>
<DataTable <DataTable
@@ -172,6 +236,8 @@ const RegisterUsers = () => {
total: data?.data.total || 0 total: data?.data.total || 0
}} }}
onPageChange={handlePageChange} onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/> />
</Box> </Box>
</MainFrame> </MainFrame>

View File

@@ -9,8 +9,9 @@ import {
DialogTitle, DialogTitle,
DialogTrigger, DialogTrigger,
} from "../../../components/ui/dialog"; } from "../../../components/ui/dialog";
import { UserData } from "../../../Redux/Service/manage.user";
function ViewRegisterUsers() { function ViewRegisterUsers({ data }: { data: UserData }) {
return ( return (
<DialogRoot placement="center"> <DialogRoot placement="center">
<DialogTrigger asChild> <DialogTrigger asChild>
@@ -18,13 +19,13 @@ function ViewRegisterUsers() {
</DialogTrigger> </DialogTrigger>
<DialogContent <DialogContent
bg={"#fff"} bg={"#fff"}
w={{ base: '90%', md: '400px' }} w={{ base: '90%', md: '400px' }}
height={'80vh'} height={'80vh'}
overflow={'scroll'} overflow={'scroll'}
overflowX="hidden" overflowX="hidden"
p={3} // Reduced padding p={3} // Reduced padding
bgSize={'md'} bgSize={'md'}
> >
<DialogHeader bg="white"> <DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px"> <DialogTitle alignSelf="center" color="black" fontSize="14px">
@@ -39,14 +40,24 @@ function ViewRegisterUsers() {
First Name First Name
</Field.Label> </Field.Label>
<Input <Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.first_name || ''}
/> />
<Field.Label color="black" pt={1} fontSize="12px"> <Field.Label color="black" pt={1} fontSize="12px">
Last Name Last Name
</Field.Label> </Field.Label>
<Input <Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" bgColor="#EEEEEE"
color="black"
border="none" pl={1}
fontSize="12px" height="30px"
value={data?.last_name || ''}
/> />
<Field.Label color="black" pt={1} fontSize="12px"> <Field.Label color="black" pt={1} fontSize="12px">
@@ -54,6 +65,7 @@ function ViewRegisterUsers() {
</Field.Label> </Field.Label>
<Input <Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
value={data?.gender || ''}
/> />
<Field.Label color="black" pt={1} fontSize="12px"> <Field.Label color="black" pt={1} fontSize="12px">
@@ -61,20 +73,41 @@ function ViewRegisterUsers() {
</Field.Label> </Field.Label>
<Input <Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" 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"> <Field.Label color="black" pt={1} fontSize="12px">
OTP Verified Mobile Number
</Field.Label> </Field.Label>
<Input <Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={data?.phone_number || ''}
/> />
<Field.Label color="black" pt={1} fontSize="12px"> <Field.Label color="black" pt={1} fontSize="12px">
Language 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
</Field.Label> </Field.Label>
<Input <Input
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
value={data?.principle_language_linkss?.language?.language_name || 'N/A'}
/> />
</Field.Root> </Field.Root>
</Stack> </Stack>

View File

@@ -2,12 +2,15 @@ import { Box, HStack, Text } from "@chakra-ui/react";
import MainFrame from "../../../components/MainFrame" import MainFrame from "../../../components/MainFrame"
import DataTable from "../../../components/DataTable"; import DataTable from "../../../components/DataTable";
import { Switch } from "../../../components/ui/switch"; import { Switch } from "../../../components/ui/switch";
// import EditAgencyMaster from "./EditAgencyMaster"; import EditAgencyMaster from "./EditAgencyMaster";
// import ViewAgencyAddModel from "./ViewAgencyAddModel"; // import ViewAgencyAddModel from "./ViewAgencyAddModel";
import ViewAgencyMaster from "./ViewAgencyMaster"; import ViewAgencyMaster from "./ViewAgencyMaster";
import { useAgencyMasterToggleMutation, useGetAgencyMasterQuery } from "../../../Redux/Service/agency.master.module.service"; import { useAgencyMasterToggleMutation, useGetAgencyMasterQuery } from "../../../Redux/Service/agency.master.module.service";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import SearchComponent from "../../../components/SearchComponent"; 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 // table data
@@ -20,6 +23,7 @@ const tableHeadRow = [
"Registered Office Address", "Registered Office Address",
"Website/Domain", "Website/Domain",
"GST no.", "GST no.",
"Agency Status",
"Action" "Action"
]; ];
@@ -48,10 +52,12 @@ const tableHeadRow = [
const AgencyMaster = () => { const AgencyMaster = () => {
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const { data, refetch } = useGetAgencyMasterQuery(currentPage)
const [agencyMasterToggle] = useAgencyMasterToggleMutation() const [agencyMasterToggle] = useAgencyMasterToggleMutation()
const [localData, setLocalData] = useState<any[]>([]); const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState(""); 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 handleToggle = async (agencyId: string, currentStatus: number) => {
const newStatus = currentStatus ? 0 : 1; const newStatus = currentStatus ? 0 : 1;
@@ -62,6 +68,12 @@ const AgencyMaster = () => {
); );
try { try {
await agencyMasterToggle({ id: agencyId, is_active: newStatus }).unwrap(); await agencyMasterToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch() refetch()
} catch (error) { } catch (error) {
console.error("Error updating privacy policy:", error); console.error("Error updating privacy policy:", error);
@@ -70,6 +82,11 @@ const AgencyMaster = () => {
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
) )
); );
toaster.create({
title: "Error",
description: "Please try again later",
type: "error",
});
} }
}; };
@@ -77,36 +94,55 @@ const AgencyMaster = () => {
setCurrentPage(page); setCurrentPage(page);
}; };
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
const filteredData = localData?.filter((agency) => const filteredData = localData?.filter((agency) =>
agency?.name.toLowerCase().includes(searchTerm.toLowerCase()) 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 managepost = filteredData?.map((agency: any, index: number) => ({ // const activeCount = filteredData?.filter((a: any) => a.is_active === 1).length ?? 0;
'id': agency.id,
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1, const managepost = filteredData?.map((agency: any, index: number) => {
"Agency Name": agency.name, // const isOnlyActive = activeCount === 1 && agency.is_active === 1;
"RC no.": agency.rc_number,
"State": agency.state, return {
"RC Status": agency.rc_status, id: agency.id,
"Registered Office Address": agency.registered_office, "Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
"Website/Domain": agency.domain_name, "Agency Name": agency.name,
"GST no.": agency.gst_number, "RC no.": agency.rc_number,
"is_active": agency.is_active, "State": agency.state,
"Action": ( "RC Status": agency.rc_status,
<HStack justifyContent="center"> "Registered Office Address": agency.registered_office,
<ViewAgencyMaster agency={localData} id={agency.id} /> "Website/Domain": agency.domain_name,
{/* <EditAgencyMaster editData={{ id: agency.id, name: agency.name, domain_name: agency.domain_name, gst_number: agency.gst_number, rc_number: agency.rc_number, rc_status: agency.rc_status, registered_office: agency.registered_office, state: agency.state }} refetch={refetch} /> */} "GST no.": agency.gst_number,
<Box> "Agency Status": agency.is_domain_verified ? "Verified" : "Unverified",
<Switch "is_active": agency.is_active,
colorPalette={"teal"} Action: (
size={"xs"} <HStack justifyContent="center">
onChange={() => handleToggle(agency.id.toString(), Number(agency.is_active))} <ViewAgencyMaster agency={localData} id={agency.id} />
checked={Boolean(Number(agency.is_active))} <EditAgencyMaster editData={agency} refetch={refetch} />
/> <Box>
</Box> <Switch
</HStack> colorPalette={"teal"}
), size={"xs"}
})); onChange={() => handleToggle(agency.id.toString(), Number(agency.is_active))}
checked={Boolean(Number(agency.is_active))}
// disabled={isOnlyActive}
/>
</Box>
</HStack>
),
};
});
useEffect(() => { useEffect(() => {
if (data?.data?.data) { if (data?.data?.data) {
@@ -158,7 +194,7 @@ const AgencyMaster = () => {
</InputGroup> */} </InputGroup> */}
<SearchComponent <SearchComponent
value={searchTerm} value={searchTerm}
onChange={setSearchTerm} onChange={handleSearchChange}
/> />
{/* <ViewAgencyAddModel refetch={refetch} /> */} {/* <ViewAgencyAddModel refetch={refetch} /> */}
</HStack> </HStack>
@@ -174,8 +210,11 @@ const AgencyMaster = () => {
total: data?.data.total || 0 total: data?.data.total || 0
}} }}
onPageChange={handlePageChange} onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/> />
</Box> </Box>
<Toaster />
</MainFrame> </MainFrame>
) )
} }

View File

@@ -15,33 +15,46 @@ import { useEffect, useState } from "react";
import { useUpdateAgencyMasterMutation } from "../../../Redux/Service/agency.master.module.service"; import { useUpdateAgencyMasterMutation } from "../../../Redux/Service/agency.master.module.service";
import { Toaster, toaster } from "../../../components/ui/toaster"; import { Toaster, toaster } from "../../../components/ui/toaster";
interface Organization { // interface Organization {
id: number; // id: number;
raid?: string; // 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; name: string;
auth_signatory?: string;
state: string; state: string;
district?: string; rc_number: string;
rc_number: number;
contact_details?: string;
registered_office: string; registered_office: string;
branch_office?: string;
registered_email?: string;
other_email?: string;
registered_contact?: string;
website?: string;
domain_name: string; domain_name: string;
staff_domain_name?: string;
gst_number: string; gst_number: string;
rc_status?: "Active" | "Inactive"; // Assuming it's a status with limited values };
}
function EditAgencyMaster({ editData, refetch }: { editData: Organization, refetch: VoidFunction }) {
function EditAgencyMaster<T extends AgencyFormData>({ editData, refetch }: { editData: T, refetch: VoidFunction }) {
const [formData, setFormData] = useState(editData); const [formData, setFormData] = useState(editData);
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [updateAgencyMaster] = useUpdateAgencyMasterMutation() const [updateAgencyMaster, { isLoading }] = useUpdateAgencyMasterMutation()
console.log("Edit Data", editData);
useEffect(() => { useEffect(() => {
setFormData(editData); setFormData(editData);
@@ -104,11 +117,11 @@ function EditAgencyMaster({ editData, refetch }: { editData: Organization, refet
type: "error", type: "error",
}); });
} }
} catch (error) { } catch (error: any) {
console.error("Error updating template:", error); console.error("Error updating template:", error);
toaster.create({ toaster.create({
title: "Error", title: "Error",
description: "Something went wrong.", description: `${error.data.message || "Failed to update"}`,
type: "error", type: "error",
}); });
// alert("Failed to update template"); // alert("Failed to update template");
@@ -254,6 +267,7 @@ function EditAgencyMaster({ editData, refetch }: { editData: Organization, refet
fontSize="12px" fontSize="12px"
height="30px" height="30px"
onClick={handleSubmit} onClick={handleSubmit}
disabled={isLoading}
> >
Save Save
</Button> </Button>

View File

@@ -70,7 +70,7 @@ function ViewAgencyAddModel({ refetch }: { refetch: VoidFunction }) {
console.error("Error updating template:", error); console.error("Error updating template:", error);
toaster.create({ toaster.create({
title: "Error", title: "Error",
description: "Something went wrong", description: "Please try again later",
type: "error", type: "error",
}); });

View File

@@ -7,6 +7,9 @@ import EditCountryModel from "./EditCountryModel";
import { CountryData, useCountryToggleMutation, useGetCountryMasterQuery } from "../../../Redux/Service/country.master"; import { CountryData, useCountryToggleMutation, useGetCountryMasterQuery } from "../../../Redux/Service/country.master";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import SearchComponent from "../../../components/SearchComponent"; import SearchComponent from "../../../components/SearchComponent";
import { useDebounce } from "../../../components/Hooks/useDebounce";
import { toaster, Toaster } from "../../../components/ui/toaster";
import { delay } from "../../../components/Utils";
@@ -36,10 +39,13 @@ const tableHeadRow = [
const Country = () => { const Country = () => {
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const { data, refetch } = useGetCountryMasterQuery(currentPage) // const { data, refetch } = useGetCountryMasterQuery(currentPage)
const [countryToggle] = useCountryToggleMutation() const [countryToggle] = useCountryToggleMutation()
const [localData, setLocalData] = useState<any[]>([]); const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState(""); 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) console.log("Country Data", data?.data.data)
useEffect(() => { useEffect(() => {
@@ -52,6 +58,11 @@ const Country = () => {
setCurrentPage(page); setCurrentPage(page);
}; };
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
const filteredData = localData?.filter((agency) => { const filteredData = localData?.filter((agency) => {
const searchLower = searchTerm.toLowerCase(); const searchLower = searchTerm.toLowerCase();
const countryName = agency.en_name?.toLowerCase().includes(searchLower); const countryName = agency.en_name?.toLowerCase().includes(searchLower);
@@ -70,9 +81,20 @@ const Country = () => {
try { try {
await countryToggle({ id: agencyId, is_active: newStatus }).unwrap(); await countryToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch() refetch()
} catch (error) { } catch (error) {
console.error("Error updating privacy policy:", error); console.error("Error updating privacy policy:", error);
toaster.create({
title: "Error",
description: "Please try again later.",
type: "error",
});
setLocalData((prevData) => setLocalData((prevData) =>
prevData.map((agency) => prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
@@ -99,6 +121,7 @@ const Country = () => {
), ),
})) }))
return ( return (
<MainFrame> <MainFrame>
@@ -137,14 +160,15 @@ const Country = () => {
</InputGroup> */} </InputGroup> */}
<SearchComponent <SearchComponent
value={searchTerm} value={searchTerm}
onChange={(value) => { // onChange={(value) => {
setSearchTerm(value); // setSearchTerm(value);
// setCurrentPage(1); // // setCurrentPage(1);
refetch() // refetch()
}} // }}
onChange={handleSearchChange}
/> />
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */} {/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
<CountryAddModel /> <CountryAddModel refetch={refetch} />
</HStack> </HStack>
</HStack> </HStack>
<DataTable <DataTable
@@ -158,8 +182,11 @@ const Country = () => {
total: data?.data.total || 0 total: data?.data.total || 0
}} }}
onPageChange={handlePageChange} onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/> />
</Box> </Box>
<Toaster />
</MainFrame> </MainFrame>
) )
} }

View File

@@ -2,12 +2,12 @@ import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHead
import { Field, Input, Stack, Text } from "@chakra-ui/react" import { Field, Input, Stack, Text } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io" import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button" import { Button } from "../../../components/ui/button"
import { useState } from "react"; import { useEffect, useState } from "react";
import { PostCountry, useCreateCountryPostMutation } from "../../../Redux/Service/country.master"; import { PostCountry, useCreateCountryPostMutation } from "../../../Redux/Service/country.master";
import { Toaster, toaster } from "../../../components/ui/toaster"; import { Toaster, toaster } from "../../../components/ui/toaster";
function CountryAddModel() { function CountryAddModel({refetch}: { refetch: VoidFunction }) {
const [createCountryPost] = useCreateCountryPostMutation() const [createCountryPost, { isLoading }] = useCreateCountryPostMutation()
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [countryName, setCountryName] = useState<PostCountry>({ const [countryName, setCountryName] = useState<PostCountry>({
en_name: '', en_name: '',
@@ -19,12 +19,26 @@ function CountryAddModel() {
currency_symbol: '', currency_symbol: '',
}); });
useEffect(() => {
if (!isOpen) {
setCountryName({
en_name: '',
country_code: '',
phonecode: '',
capital: '',
currency: '',
currency_name: '',
currency_symbol: '',
});
}
}, [isOpen]);
const handleOpenModal = () => { const handleOpenModal = () => {
setIsOpen(true); // Open modal when clicking "Add" setIsOpen(true); // Open modal when clicking "Add"
}; };
const handleSubmit = async () => { const handleSubmit = async () => {
if (countryName.en_name === "") { if (countryName.en_name === "" || countryName.country_code === "" || countryName.phonecode === "" || countryName.capital === "" || countryName.currency === "" || countryName.currency_name === "" || countryName.currency_symbol === "") {
toaster.create({ toaster.create({
title: "Error", title: "Error",
description: "Input fields cannot be empty", description: "Input fields cannot be empty",
@@ -52,6 +66,7 @@ function CountryAddModel() {
type: "success", type: "success",
}); });
setIsOpen(false); setIsOpen(false);
refetch();
} else { } else {
toaster.create({ toaster.create({
title: "Error", title: "Error",
@@ -98,7 +113,7 @@ function CountryAddModel() {
<Field.Root> <Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">Country</Field.Label> <Field.Label color="black" pt={1} fontSize="12px">Country</Field.Label>
<Input <Input
placeholder="" placeholder="Enter Country Name"
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
@@ -111,7 +126,7 @@ function CountryAddModel() {
<Field.Label color="black" pt={1} fontSize="12px">Country Code</Field.Label> <Field.Label color="black" pt={1} fontSize="12px">Country Code</Field.Label>
<Input <Input
placeholder="" placeholder="Please enter country code ex: IN, US"
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
@@ -124,7 +139,7 @@ function CountryAddModel() {
<Field.Label color="black" pt={1} fontSize="12px">Phone Code</Field.Label> <Field.Label color="black" pt={1} fontSize="12px">Phone Code</Field.Label>
<Input <Input
placeholder="" placeholder="Please enter phone code ex: +91, +1"
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
@@ -136,7 +151,7 @@ function CountryAddModel() {
/> />
<Field.Label color="black" pt={1} fontSize="12px">Capital</Field.Label> <Field.Label color="black" pt={1} fontSize="12px">Capital</Field.Label>
<Input <Input
placeholder="" placeholder="Enter Capital City"
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
@@ -148,7 +163,7 @@ function CountryAddModel() {
/> />
<Field.Label color="black" pt={1} fontSize="12px">Currency</Field.Label> <Field.Label color="black" pt={1} fontSize="12px">Currency</Field.Label>
<Input <Input
placeholder="" placeholder="Enter Currency"
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
@@ -160,7 +175,7 @@ function CountryAddModel() {
/> />
<Field.Label color="black" pt={1} fontSize="12px">Currency name</Field.Label> <Field.Label color="black" pt={1} fontSize="12px">Currency name</Field.Label>
<Input <Input
placeholder="" placeholder="Enter Currency Name"
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
@@ -172,7 +187,7 @@ function CountryAddModel() {
/> />
<Field.Label color="black" pt={1} fontSize="12px">Currency Symbol</Field.Label> <Field.Label color="black" pt={1} fontSize="12px">Currency Symbol</Field.Label>
<Input <Input
placeholder="" placeholder="Enter Currency Symbol"
bgColor="#EEEEEE" bgColor="#EEEEEE"
color="black" color="black"
border="none" border="none"
@@ -187,7 +202,7 @@ function CountryAddModel() {
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -36,7 +36,7 @@ export interface EditCountryModelProps {
function EditCountryModel({ rowData, refetch }: { rowData: EditCountryModelProps, refetch: VoidFunction }) { function EditCountryModel({ rowData, refetch }: { rowData: EditCountryModelProps, refetch: VoidFunction }) {
const [updateCountry] = useUpdateCountryMutation() const [updateCountry, { isLoading }] = useUpdateCountryMutation()
const [editData, setEditData] = useState(rowData) const [editData, setEditData] = useState(rowData)
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
@@ -145,7 +145,7 @@ function EditCountryModel({ rowData, refetch }: { rowData: EditCountryModelProps
</Stack> </Stack>
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -9,7 +9,7 @@ import { useCreateDepartmentPostMutation, useGetDepartmentMasterDropDownQuery }
function AddDepartmentMaster({ refetch }: { refetch: VoidFunction }) { function AddDepartmentMaster({ refetch }: { refetch: VoidFunction }) {
const [jobType, setJobType] = useState(""); const [jobType, setJobType] = useState("");
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [createDepartmentPost] = useCreateDepartmentPostMutation() const [createDepartmentPost, { isLoading }] = useCreateDepartmentPostMutation()
const { data } = useGetDepartmentMasterDropDownQuery() const { data } = useGetDepartmentMasterDropDownQuery()
const [selectdDep, setSelectdDep] = useState<any>({ const [selectdDep, setSelectdDep] = useState<any>({
id: '', id: '',
@@ -140,7 +140,7 @@ function AddDepartmentMaster({ refetch }: { refetch: VoidFunction }) {
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -9,6 +9,9 @@ import SearchComponent from "../../../components/SearchComponent";
import { useDepartmentToggleMutation, useGetDepartmentMasterQuery } from "../../../Redux/Service/department.master"; import { useDepartmentToggleMutation, useGetDepartmentMasterQuery } from "../../../Redux/Service/department.master";
import AddDepartmentMaster from "./AddDepartmentMaster"; import AddDepartmentMaster from "./AddDepartmentMaster";
import EditDepartmentMaster from "./EditDepartmentMaster"; import EditDepartmentMaster from "./EditDepartmentMaster";
import { useDebounce } from "../../../components/Hooks/useDebounce";
import { Toaster, toaster } from "../../../components/ui/toaster";
import { delay } from "../../../components/Utils";
// table data // table data
@@ -24,12 +27,14 @@ const tableHeadRow = [
const DepartmentMasterList = () => { const DepartmentMasterList = () => {
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const { data, refetch } = useGetDepartmentMasterQuery(currentPage)
const [departmentToggle] = useDepartmentToggleMutation() const [departmentToggle] = useDepartmentToggleMutation()
const [localData, setLocalData] = useState<any[]>([]); const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState(""); 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) console.log("Department Data", data?.data.data)
useEffect(() => { useEffect(() => {
if (data?.data?.data) { if (data?.data?.data) {
@@ -37,6 +42,11 @@ const DepartmentMasterList = () => {
} }
}, [data]); }, [data]);
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
const handlePageChange = (page: number) => { const handlePageChange = (page: number) => {
setCurrentPage(page); setCurrentPage(page);
}; };
@@ -50,9 +60,20 @@ const DepartmentMasterList = () => {
); );
try { try {
await departmentToggle({ id: agencyId, is_active: newStatus }).unwrap(); await departmentToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch() refetch()
} catch (error) { } catch (error) {
console.error("Error updating privacy policy:", error); console.error("Error updating privacy policy:", error);
toaster.create({
title: "Error",
description: "Someting went wrong.",
type: "error",
});
setLocalData((prevData) => setLocalData((prevData) =>
prevData.map((agency) => prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
@@ -112,11 +133,7 @@ const DepartmentMasterList = () => {
<HStack > <HStack >
<SearchComponent <SearchComponent
value={searchTerm} value={searchTerm}
onChange={(value) => { onChange={handleSearchChange}
setSearchTerm(value);
// setCurrentPage(1);
refetch()
}}
/> />
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */} {/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
{/* <ViewAgencyAddModel /> */} {/* <ViewAgencyAddModel /> */}
@@ -134,8 +151,11 @@ const DepartmentMasterList = () => {
total: data?.data.total || 0 total: data?.data.total || 0
}} }}
onPageChange={handlePageChange} onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/> />
</Box> </Box>
<Toaster />
</MainFrame> </MainFrame>
) )
} }

View File

@@ -17,7 +17,7 @@ import { useGetDepartmentMasterDropDownQuery, useUpdateDepartmentMutation } from
function EditDepartmentMaster({ localData, refetch }: { localData: any, refetch: VoidFunction }) { function EditDepartmentMaster({ localData, refetch }: { localData: any, refetch: VoidFunction }) {
const [jobtype, setJobType] = useState(""); const [jobtype, setJobType] = useState("");
const [updateDepartment] = useUpdateDepartmentMutation() const [updateDepartment, { isLoading }] = useUpdateDepartmentMutation()
const { data } = useGetDepartmentMasterDropDownQuery() const { data } = useGetDepartmentMasterDropDownQuery()
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [selectdDep, setSelectdDep] = useState<any>({ const [selectdDep, setSelectdDep] = useState<any>({
@@ -145,7 +145,7 @@ function EditDepartmentMaster({ localData, refetch }: { localData: any, refetch:
</Stack> </Stack>
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -9,7 +9,7 @@ import { useCreateIndustryMasterPostMutation } from "../../../Redux/Service/indu
function AddIndustryMaster({ refetch }: { refetch: VoidFunction }) { function AddIndustryMaster({ refetch }: { refetch: VoidFunction }) {
const [jobType, setJobType] = useState(""); const [jobType, setJobType] = useState("");
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [createIndustryMasterPost] = useCreateIndustryMasterPostMutation() const [createIndustryMasterPost, { isLoading }] = useCreateIndustryMasterPostMutation()
const handleOpenModal = () => { const handleOpenModal = () => {
setIsOpen(true); // Open modal when clicking "Add" setIsOpen(true); // Open modal when clicking "Add"
@@ -88,7 +88,7 @@ function AddIndustryMaster({ refetch }: { refetch: VoidFunction }) {
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -17,7 +17,7 @@ import { useUpdateIndustryMasterMutation } from "../../../Redux/Service/industry
function EditIndustryMaster({ id, localData, refetch, categories }: { id: number, localData: any, refetch: VoidFunction, categories: any }) { function EditIndustryMaster({ id, localData, refetch, categories }: { id: number, localData: any, refetch: VoidFunction, categories: any }) {
const [jobtype, setJobType] = useState(""); const [jobtype, setJobType] = useState("");
const [updateIndustryMaster] = useUpdateIndustryMasterMutation() const [updateIndustryMaster, { isLoading }] = useUpdateIndustryMasterMutation()
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const handleOpenModal = () => { const handleOpenModal = () => {
@@ -98,7 +98,7 @@ function EditIndustryMaster({ id, localData, refetch, categories }: { id: number
</Stack> </Stack>
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -9,6 +9,9 @@ import { useGetIndustryMasterQuery, useIndustryMasterToggleMutation } from "../.
import EditIndustryMaster from "./EditIndustryMaster"; import EditIndustryMaster from "./EditIndustryMaster";
import AddIndustryMaster from "./AddIndustryMaster"; import AddIndustryMaster from "./AddIndustryMaster";
import SearchComponent from "../../../components/SearchComponent"; 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 // table data
@@ -44,10 +47,12 @@ const tableHeadRow = [
const IndustryMasterList = () => { const IndustryMasterList = () => {
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const { data, refetch } = useGetIndustryMasterQuery(currentPage)
const [industryMasterToggle] = useIndustryMasterToggleMutation() const [industryMasterToggle] = useIndustryMasterToggleMutation()
const [localData, setLocalData] = useState<any[]>([]); const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState(""); 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(() => { useEffect(() => {
if (data?.data?.data) { if (data?.data?.data) {
@@ -55,6 +60,11 @@ const IndustryMasterList = () => {
} }
}, [data]); }, [data]);
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
const handlePageChange = (page: number) => { const handlePageChange = (page: number) => {
setCurrentPage(page); setCurrentPage(page);
}; };
@@ -68,9 +78,20 @@ const IndustryMasterList = () => {
); );
try { try {
await industryMasterToggle({ id: agencyId, is_active: newStatus }).unwrap(); await industryMasterToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch() refetch()
} catch (error) { } catch (error) {
console.error("Error updating privacy policy:", error); console.error("Error updating privacy policy:", error);
toaster.create({
title: "Error",
description: "Someting went wrong.",
type: "error",
});
setLocalData((prevData) => setLocalData((prevData) =>
prevData.map((agency) => prevData.map((agency) =>
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
@@ -130,11 +151,7 @@ const IndustryMasterList = () => {
<HStack > <HStack >
<SearchComponent <SearchComponent
value={searchTerm} value={searchTerm}
onChange={(value) => { onChange={handleSearchChange}
setSearchTerm(value);
// setCurrentPage(1);
refetch()
}}
/> />
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */} {/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
{/* <ViewAgencyAddModel /> */} {/* <ViewAgencyAddModel /> */}
@@ -152,8 +169,11 @@ const IndustryMasterList = () => {
total: data?.data.total || 0 total: data?.data.total || 0
}} }}
onPageChange={handlePageChange} onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/> />
</Box> </Box>
<Toaster />
</MainFrame> </MainFrame>
) )
} }

View File

@@ -9,7 +9,7 @@ import { Toaster, toaster } from "../../../components/ui/toaster";
function EditJobStatusModel({ localData, refetch }: { localData: any, refetch: VoidFunction }) { function EditJobStatusModel({ localData, refetch }: { localData: any, refetch: VoidFunction }) {
const [updateJobStatus] = useUpdateJobStatusMutation() const [updateJobStatus, { isLoading }] = useUpdateJobStatusMutation()
const [title, setTitle] = useState(localData.translation.title); const [title, setTitle] = useState(localData.translation.title);
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
@@ -89,7 +89,7 @@ function EditJobStatusModel({ localData, refetch }: { localData: any, refetch: V
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -7,7 +7,9 @@ import EditJobStatusModel from "./EditJobStatusModel";
import { useGetJobStatusQuery, useJobStatusToggleMutation } from "../../../Redux/Service/job.status"; import { useGetJobStatusQuery, useJobStatusToggleMutation } from "../../../Redux/Service/job.status";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import SearchComponent from "../../../components/SearchComponent"; import SearchComponent from "../../../components/SearchComponent";
import { toaster } from "../../../components/ui/toaster"; import { toaster, Toaster } from "../../../components/ui/toaster";
import { useDebounce } from "../../../components/Hooks/useDebounce";
import { delay } from "../../../components/Utils";
@@ -37,9 +39,11 @@ const tableHeadRow = [
const JobStatus = () => { const JobStatus = () => {
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const { data, refetch } = useGetJobStatusQuery(currentPage)
const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState(""); 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() const [jobStatusToggle] = useJobStatusToggleMutation()
console.log(data?.data.data) console.log(data?.data.data)
@@ -53,6 +57,11 @@ const JobStatus = () => {
setCurrentPage(page); setCurrentPage(page);
}; };
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
const handleToggle = async (agencyId: string, currentStatus: number) => { const handleToggle = async (agencyId: string, currentStatus: number) => {
const newStatus = currentStatus ? 0 : 1; const newStatus = currentStatus ? 0 : 1;
setLocalData((prevData) => setLocalData((prevData) =>
@@ -62,6 +71,12 @@ const JobStatus = () => {
); );
try { try {
await jobStatusToggle({ id: agencyId, is_active: newStatus }).unwrap(); await jobStatusToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch() refetch()
} catch (error) { } catch (error) {
console.error("Error updating:", error); console.error("Error updating:", error);
@@ -125,11 +140,7 @@ const JobStatus = () => {
<HStack > <HStack >
<SearchComponent <SearchComponent
value={searchTerm} value={searchTerm}
onChange={(value) => { onChange={handleSearchChange}
setSearchTerm(value);
// setCurrentPage(1);
refetch()
}}
/> />
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */} {/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
<JobStatusAddModel refetch={refetch} /> <JobStatusAddModel refetch={refetch} />
@@ -146,8 +157,11 @@ const JobStatus = () => {
total: data?.data.total || 0 total: data?.data.total || 0
}} }}
onPageChange={handlePageChange} onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/> />
</Box> </Box>
<Toaster />
</MainFrame> </MainFrame>
) )
} }

View File

@@ -9,7 +9,7 @@ import { useState } from "react"
function JobStatusAddModel({ refetch }: { refetch: VoidFunction }) { function JobStatusAddModel({ refetch }: { refetch: VoidFunction }) {
const [title, setTitle] = useState('') const [title, setTitle] = useState('')
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [createJobStatusPost] = useCreateJobStatusPostMutation() const [createJobStatusPost, { isLoading }] = useCreateJobStatusPostMutation()
const handleOpenModal = () => { const handleOpenModal = () => {
setIsOpen(true); setIsOpen(true);
@@ -88,7 +88,7 @@ function JobStatusAddModel({ refetch }: { refetch: VoidFunction }) {
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -17,7 +17,7 @@ import { toaster } from "../../../components/ui/toaster";
function EditJobeModel({ id, localData, refetch }: { id: number, localData: any, refetch: VoidFunction }) { function EditJobeModel({ id, localData, refetch }: { id: number, localData: any, refetch: VoidFunction }) {
const [jobtype, setJobType] = useState(""); const [jobtype, setJobType] = useState("");
const [updateJobType] = useUpdateJobTypeMutation() const [updateJobType, { isLoading }] = useUpdateJobTypeMutation()
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const handleOpenModal = () => { const handleOpenModal = () => {
@@ -97,7 +97,7 @@ function EditJobeModel({ id, localData, refetch }: { id: number, localData: any,
</Stack> </Stack>
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -9,7 +9,7 @@ import { toaster } from "../../../components/ui/toaster";
function JobAddModel({ refetch }: { refetch: VoidFunction }) { function JobAddModel({ refetch }: { refetch: VoidFunction }) {
const [jobType, setJobType] = useState(""); const [jobType, setJobType] = useState("");
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [createJobTypePost] = useCreateJobTypePostMutation() const [createJobTypePost, { isLoading }] = useCreateJobTypePostMutation()
const handleOpenModal = () => { const handleOpenModal = () => {
setIsOpen(true); // Open modal when clicking "Add" setIsOpen(true); // Open modal when clicking "Add"
@@ -87,7 +87,7 @@ function JobAddModel({ refetch }: { refetch: VoidFunction }) {
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -6,9 +6,11 @@ import DataTable from "../../../components/DataTable";
import { Switch } from "../../../components/ui/switch"; import { Switch } from "../../../components/ui/switch";
import JobAddModel from "./JobAddModel"; import JobAddModel from "./JobAddModel";
import EditJobeModel from "./EditJobModel"; import EditJobeModel from "./EditJobModel";
import { JobTypeData, useGetJobTypeQuery } from "../../../Redux/Service/job.type.service"; import { JobTypeData, useGetJobTypeQuery, useJobTypeToggleMutation } from "../../../Redux/Service/job.type.service";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import SearchComponent from "../../../components/SearchComponent"; import SearchComponent from "../../../components/SearchComponent";
import { toaster, Toaster } from "../../../components/ui/toaster";
import { delay } from "../../../components/Utils";
@@ -38,10 +40,10 @@ const tableHeadRow = [
const JobType = () => { const JobType = () => {
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const { data, refetch } = useGetJobTypeQuery(currentPage) const { data, refetch, isFetching, isError } = useGetJobTypeQuery(currentPage)
const [localData, setLocalData] = useState<any[]>([]); const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
// const [templateMasterToggle] = useTemplateMasterToggleMutation() const [jobTypeToggle] = useJobTypeToggleMutation()
console.log('DATA', data?.data.data); console.log('DATA', data?.data.data);
@@ -61,25 +63,36 @@ const JobType = () => {
return title; return title;
}); });
// const handleToggle = async (agencyId: string, currentStatus: number) => { const handleToggle = async (agencyId: string, currentStatus: number) => {
// const newStatus = currentStatus ? 0 : 1; const newStatus = currentStatus ? 0 : 1;
// setLocalData((prevData) => setLocalData((prevData) =>
// prevData.map((agency) => prevData.map((agency) =>
// agency.id === agencyId ? { ...agency, is_active: newStatus } : agency agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
// ) )
// ); );
// try { try {
// await templateMasterToggle({ id: agencyId, is_active: newStatus }).unwrap(); await jobTypeToggle({ id: agencyId, is_active: newStatus }).unwrap();
// refetch() toaster.create({
// } catch (error) { title: "Success",
// console.error("Error updating privacy policy:", error); description: "Status updated successfully",
// setLocalData((prevData) => type: "success",
// prevData.map((agency) => });
// agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency 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) => ({ const managepost = filteredData?.map((agency: JobTypeData, index: number) => ({
@@ -94,7 +107,7 @@ const JobType = () => {
<Switch <Switch
colorPalette={'teal'} colorPalette={'teal'}
size={"xs"} size={"xs"}
// onChange={() => handleToggle(agency.id, Number(agency.is_active))} onChange={() => handleToggle(agency.id.toString(), Number(agency.is_active))}
checked={Boolean(Number(agency.is_active))} checked={Boolean(Number(agency.is_active))}
/> />
</Box> </Box>
@@ -142,8 +155,11 @@ const JobType = () => {
total: data?.data.total || 0 total: data?.data.total || 0
}} }}
onPageChange={handlePageChange} onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/> />
</Box> </Box>
<Toaster />
</MainFrame> </MainFrame>
) )
} }

View File

@@ -19,7 +19,7 @@ import { useState } from "react";
// import { FaRegEdit } from "react-icons/fa"; // import { FaRegEdit } from "react-icons/fa";
import Edit from "../../../components/ActionIcons/Edit"; import Edit from "../../../components/ActionIcons/Edit";
import { Toaster, toaster } from "../../../components/ui/toaster"; import { Toaster, toaster } from "../../../components/ui/toaster";
import { Template } from "../../../Redux/Service/template.master.service"; // import { Template } from "../../../Redux/Service/template.master.service";
import axios from "axios"; import axios from "axios";
const IMGURL = import.meta.env.VITE_IMG_TEMPLATES const IMGURL = import.meta.env.VITE_IMG_TEMPLATES
@@ -30,13 +30,14 @@ function EditTemplateModel({ id, localData, refetch }: { id: number, localData:
const [subTitle, setSubTitle] = useState(""); const [subTitle, setSubTitle] = useState("");
const [userType, setUserType] = useState<number | "">(""); const [userType, setUserType] = useState<number | "">("");
const [images, setImages] = useState<(File | string)[]>([]); const [images, setImages] = useState<(File | string)[]>([]);
const [loading, setLoading] = useState(false);
// const [objectURLs, setObjectURLs] = useState<string[]>([]); // Store object URLs separately // const [objectURLs, setObjectURLs] = useState<string[]>([]); // Store object URLs separately
// const [updateTemplateMaster] = useUpdateTemplateMasterMutation() // const [updateTemplateMaster] = useUpdateTemplateMasterMutation()
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [selectedTemplate, setSelectedTemplate] = useState<Template | null>(null); // const [selectedTemplate, setSelectedTemplate] = useState<Template | null>(null);
const token = localStorage.getItem("token"); const token = localStorage.getItem("token");
console.log(selectedTemplate); console.log(images);
const handleImageChange = async (event: React.ChangeEvent<HTMLInputElement>) => { const handleImageChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.files) { if (event.target.files) {
@@ -50,14 +51,17 @@ function EditTemplateModel({ id, localData, refetch }: { id: number, localData:
return; return;
} }
setImages((prevImages) => [...prevImages, file]); // setImages((prevImages) => [...prevImages, file]);
if (file) {
setImages([file])
}
} }
}; };
const handleOpenModal = () => { const handleOpenModal = () => {
const template = localData?.find((item: any) => item.id === id); const template = localData?.find((item: any) => item.id === id);
if (template) { if (template) {
setSelectedTemplate(template); // setSelectedTemplate(template);
setTitle(template.post_template_translate.length > 0 ? template.post_template_translate[0].title : ""); 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 : ""); setSubTitle(template.post_template_translate.length > 0 ? template.post_template_translate[0].sub_title : "");
setUserType(template.principle_type_xid?.toString() || ""); setUserType(template.principle_type_xid?.toString() || "");
@@ -90,9 +94,9 @@ function EditTemplateModel({ id, localData, refetch }: { id: number, localData:
return; return;
} }
const newImages = images.filter((image) => image instanceof File); // const newImages = images.filter((image) => image instanceof File);
if (newImages.length === 0) { if (images.length === 0) {
toaster.create({ toaster.create({
title: "Error", title: "Error",
description: "Please upload at least one image.", description: "Please upload at least one image.",
@@ -101,14 +105,18 @@ function EditTemplateModel({ id, localData, refetch }: { id: number, localData:
return; return;
} }
setLoading(true);
const formData = new FormData(); const formData = new FormData();
formData.append("id", `${id}`); formData.append("id", `${id}`);
formData.append("principle_type_xid", `${userType}`); formData.append("principle_type_xid", `${userType}`);
formData.append("title", title); formData.append("title", title);
formData.append("sub_title", subTitle); formData.append("sub_title", subTitle);
newImages.forEach((image, index) => { images.forEach((image, index) => {
formData.append(`image_name[${index}]`, image, image.name); if (image instanceof File) {
formData.append(`image_name[${index}]`, image, image.name);
}
}); });
try { try {
@@ -123,12 +131,14 @@ function EditTemplateModel({ id, localData, refetch }: { id: number, localData:
}); });
} }
setIsOpen(false); setIsOpen(false);
setLoading(false);
refetch() refetch()
} catch (error) { } catch (error: any) {
console.error("Error updating template:", error); console.error("Error updating template:", error);
setLoading(false);
toaster.create({ toaster.create({
title: "Error", title: "Error",
description: "Failed to update template. Please try again.", description: `${error.response?.data?.message || "Please try again later."}`,
type: "error", type: "error",
}); });
} }
@@ -294,7 +304,7 @@ function EditTemplateModel({ id, localData, refetch }: { id: number, localData:
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={loading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -3,7 +3,7 @@ import { Box, Field, Input, Stack, Text } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io" import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button" import { Button } from "../../../components/ui/button"
import { FiUpload } from "react-icons/fi"; import { FiUpload } from "react-icons/fi";
import { useState } from "react"; import { useEffect, useState } from "react";
// import { useCreateTemplatePostMutation } from "../../../Redux/Service/template.master.service"; // import { useCreateTemplatePostMutation } from "../../../Redux/Service/template.master.service";
import { Toaster, toaster } from "../../../components/ui/toaster" import { Toaster, toaster } from "../../../components/ui/toaster"
import axios from "axios"; import axios from "axios";
@@ -17,10 +17,21 @@ function TemplateAddModel({ refetch }: { refetch: VoidFunction }) {
const [images, setImages] = useState<(File | string)[]>([]); const [images, setImages] = useState<(File | string)[]>([]);
// const [createTemplatePost] = useCreateTemplatePostMutation() // const [createTemplatePost] = useCreateTemplatePostMutation()
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const token = localStorage.getItem("token"); const token = localStorage.getItem("token");
useEffect(() => {
if (!isOpen) {
setTitle("");
setSubTitle("");
setUserType("");
setImages([]);
}
}, [isOpen]);
if (!token) { if (!token) {
console.error("No token found in localStorage!"); console.error("No token found in localStorage!");
return; return null;
} }
const handleOpenModal = () => { const handleOpenModal = () => {
@@ -40,7 +51,10 @@ function TemplateAddModel({ refetch }: { refetch: VoidFunction }) {
return; return;
} }
setImages((prevImages) => [...prevImages, file]); // setImages((prevImages) => [...prevImages, file]);
if(file){
setImages([file])
}
} }
}; };
@@ -72,6 +86,7 @@ function TemplateAddModel({ refetch }: { refetch: VoidFunction }) {
// image_name: images.filter((img) => typeof img === "string"), // Send only Base64 strings // image_name: images.filter((img) => typeof img === "string"), // Send only Base64 strings
// }; // };
setIsLoading(true);
const formData = new FormData(); const formData = new FormData();
formData.append("principle_type_xid", `${userType}`); formData.append("principle_type_xid", `${userType}`);
@@ -106,13 +121,19 @@ function TemplateAddModel({ refetch }: { refetch: VoidFunction }) {
setUserType(""); setUserType("");
setImages([]); setImages([]);
setIsOpen(false) setIsOpen(false)
} catch (error) { setIsLoading(false);
} catch (error: any) {
console.error("Error creating template:", error); console.error("Error creating template:", error);
// alert("Failed to create template"); // alert("Failed to create template");
toaster.create({
title: "Error",
description: `${error.response?.data?.message || "Please try again later."}`,
type: "error",
});
} }
}; };
// console.log("Token stored:", window.localStorage.getItem("token")); // console.log("Token stored:", window.localStorage.getItem("token"))
return ( return (
@@ -226,7 +247,7 @@ function TemplateAddModel({ refetch }: { refetch: VoidFunction }) {
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -9,6 +9,8 @@ import EditTemplateModel from "./EditTemplateModel";
import { Template, useGetTemplateMasterQuery, useTemplateMasterToggleMutation } from "../../../Redux/Service/template.master.service"; import { Template, useGetTemplateMasterQuery, useTemplateMasterToggleMutation } from "../../../Redux/Service/template.master.service";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import SearchComponent from "../../../components/SearchComponent"; 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 const APIURL = import.meta.env.VITE_IMG_TEMPLATES
@@ -17,6 +19,7 @@ const APIURL = import.meta.env.VITE_IMG_TEMPLATES
const tableHeadRow = [ const tableHeadRow = [
"Sr. No", "Sr. No",
"Title", "Title",
"User Type",
"Images", "Images",
"Action" "Action"
]; ];
@@ -46,7 +49,7 @@ const tableHeadRow = [
const TemplateMaster = () => { const TemplateMaster = () => {
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const { data, refetch } = useGetTemplateMasterQuery(currentPage) const { data, refetch, isFetching, isError } = useGetTemplateMasterQuery(currentPage)
const [localData, setLocalData] = useState<any[]>([]); const [localData, setLocalData] = useState<any[]>([]);
const [templateMasterToggle] = useTemplateMasterToggleMutation(); const [templateMasterToggle] = useTemplateMasterToggleMutation();
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
@@ -71,6 +74,12 @@ const TemplateMaster = () => {
); );
try { try {
await templateMasterToggle({ id: agencyId, is_active: newStatus }).unwrap(); await templateMasterToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
await delay(500);
refetch() refetch()
} catch (error) { } catch (error) {
console.error("Error updating privacy policy:", error); console.error("Error updating privacy policy:", error);
@@ -79,6 +88,11 @@ const TemplateMaster = () => {
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
) )
); );
toaster.create({
title: "Error",
description: "Please try again later",
type: "error",
});
} }
}; };
@@ -86,37 +100,45 @@ const TemplateMaster = () => {
agency.post_template_translate[0].title.toLowerCase().includes(searchTerm.toLowerCase()) agency.post_template_translate[0].title.toLowerCase().includes(searchTerm.toLowerCase())
); );
const managepost = filteredData?.map((agency: Template, index: number) => ({ const activeCount = filteredData?.filter((a: any) => a.is_active === 1).length ?? 0;
'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",
"Images": (
// <Image w={50} src={img} />
<HStack key={agency.id}>
{agency.post_template_image.map((img) => (
<Image rounded={'lg'} w={100} h={50} src={`${APIURL}${img.image_name}`} />
))}
{/* <Image rounded={'lg'} w={100} h={50} src={Templateimg} /> */} const managepost = filteredData?.map((agency: Template, index: number) => {
</HStack> const isOnlyActive = activeCount === 1 && Number(agency.is_active) === 1;
),
"Action": ( return {
<HStack justifyContent="center"> 'id': agency.id,
<EditTemplateModel id={agency.id} localData={localData} refetch={refetch} /> "Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
<Box> "Title": agency.post_template_translate.length > 0
<Switch ? agency.post_template_translate[0].title
colorPalette={'teal'} : "N/A",
size={"xs"} "User Type": agency.principle_type_xid === 2 ? 'Recruiter' : 'Job Seeker',
onChange={() => handleToggle(agency.id.toString(), Number(agency.is_active ?? 0))} "Images": (
checked={Boolean(Number(agency.is_active))} // <Image w={50} src={img} />
/> <HStack>
</Box> {agency.post_template_image.map((img) => (
</HStack> <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 ( return (
@@ -172,8 +194,11 @@ const TemplateMaster = () => {
total: data?.data.total || 0 total: data?.data.total || 0
}} }}
onPageChange={handlePageChange} onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/> />
</Box> </Box>
<Toaster />
</MainFrame> </MainFrame>
) )
} }

View File

@@ -24,7 +24,7 @@ import { useUpdateWorkSpaceMutation } from "../../../Redux/Service/workspace.mod
function EditWorkModel({ localData, refetch }: {localData: any, refetch: VoidFunction}) { function EditWorkModel({ localData, refetch }: {localData: any, refetch: VoidFunction}) {
const [title, setTitle] = useState(localData?.en_name); const [title, setTitle] = useState(localData?.en_name);
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [updateWorkSpace] = useUpdateWorkSpaceMutation() const [updateWorkSpace, { isLoading }] = useUpdateWorkSpaceMutation()
console.log("localData", localData) console.log("localData", localData)
const handleOpenModal = () => { const handleOpenModal = () => {
@@ -104,7 +104,7 @@ function EditWorkModel({ localData, refetch }: {localData: any, refetch: VoidFun
</Stack> </Stack>
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -2,14 +2,14 @@ import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHead
import { Field, Input, Stack, Text } from "@chakra-ui/react" import { Field, Input, Stack, Text } from "@chakra-ui/react"
import { IoMdAdd } from "react-icons/io" import { IoMdAdd } from "react-icons/io"
import { Button } from "../../../components/ui/button" import { Button } from "../../../components/ui/button"
import { useState } from "react"; import { useEffect, useState } from "react";
import { useCreateWorkspacePostMutation } from "../../../Redux/Service/workspace.mode"; import { useCreateWorkspacePostMutation } from "../../../Redux/Service/workspace.mode";
import { Toaster, toaster } from "../../../components/ui/toaster"; import { Toaster, toaster } from "../../../components/ui/toaster";
function WorkAddModel({ refetch }: { refetch: VoidFunction }) { function WorkAddModel({ refetch }: { refetch: VoidFunction }) {
const [title, setTitle] = useState('') const [title, setTitle] = useState('')
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [createWorkspacePost] = useCreateWorkspacePostMutation() const [createWorkspacePost, { isLoading }] = useCreateWorkspacePostMutation()
const handleOpenModal = () => { const handleOpenModal = () => {
setIsOpen(true); setIsOpen(true);
@@ -40,6 +40,12 @@ function WorkAddModel({ refetch }: { refetch: VoidFunction }) {
} }
}; };
useEffect(() => {
if (!isOpen) {
setTitle("");
}
}, [isOpen]);
return ( return (
<DialogRoot placement="center" open={isOpen}> <DialogRoot placement="center" open={isOpen}>
@@ -88,7 +94,7 @@ function WorkAddModel({ refetch }: { refetch: VoidFunction }) {
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>

View File

@@ -37,7 +37,7 @@ const tableHeadRow = [
const WorkspaceMode = () => { const WorkspaceMode = () => {
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const { data, refetch } = useGetWorkSpaceModeQuery(currentPage) const { data, refetch, isError, isFetching } = useGetWorkSpaceModeQuery(currentPage)
const [localData, setLocalData] = useState<any[]>([]); const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
const [workspaceToggle] = useWorkspaceToggleMutation() const [workspaceToggle] = useWorkspaceToggleMutation()
@@ -63,12 +63,17 @@ const WorkspaceMode = () => {
); );
try { try {
await workspaceToggle({ id: agencyId, is_active: newStatus }).unwrap(); await workspaceToggle({ id: agencyId, is_active: newStatus }).unwrap();
toaster.create({
title: "Success",
description: "Status updated successfully",
type: "success",
});
refetch() refetch()
} catch (error) { } catch (error) {
console.error("Error updating privacy policy:", error); console.error("Error updating privacy policy:", error);
toaster.create({ toaster.create({
title: "Error", title: "Error",
description: "Someting went wrong.", description: "Please try again later.",
type: "error", type: "error",
}); });
setLocalData((prevData) => setLocalData((prevData) =>
@@ -88,7 +93,9 @@ const WorkspaceMode = () => {
const managepost = filteredData?.map((agency: any, index: number) => ({ const managepost = filteredData?.map((agency: any, index: number) => ({
'id': agency.id, 'id': agency.id,
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1, "Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
"Title": agency.en_name, "Title": agency.en_name.length > 12
? agency.en_name.slice(0, 12) + '...'
: agency.en_name,
"is_active": agency.is_active, "is_active": agency.is_active,
"Action": ( "Action": (
<HStack justifyContent="center"> <HStack justifyContent="center">
@@ -131,7 +138,7 @@ const WorkspaceMode = () => {
}} }}
/> />
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */} {/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
<WorkAddModel refetch={refetch}/> <WorkAddModel refetch={refetch} />
</HStack> </HStack>
</HStack> </HStack>
<DataTable <DataTable
@@ -145,6 +152,8 @@ const WorkspaceMode = () => {
total: data?.data.total || 0 total: data?.data.total || 0
}} }}
onPageChange={handlePageChange} onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/> />
</Box> </Box>
<Toaster /> <Toaster />

View File

@@ -1,11 +1,11 @@
import { DialogCloseTrigger, Field, IconButton, Input, Stack, Text } from "@chakra-ui/react"; import { DialogCloseTrigger, Field, IconButton, Input, Stack, Text } from "@chakra-ui/react";
import { Button } from "../../components/ui/button"; import { Button } from "../../components/ui/button";
import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"; import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle } from "../../components/ui/dialog";
// import EnterPassword from "./EnterPassword"; // import EnterPassword from "./EnterPassword";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { toaster } from "../../components/ui/toaster"; import { toaster, Toaster } from "../../components/ui/toaster";
import { useNewPasswordSetMutation } from "../../Redux/Service/profile.password"; import { useNewPasswordSetMutation } from "../../Redux/Service/profile.password";
import { LuEye, LuEyeOff } from "react-icons/lu"; import { LuEye, LuEyeOff } from "react-icons/lu";
import { InputGroup } from "../../components/ui/input-group"; import { InputGroup } from "../../components/ui/input-group";
@@ -114,11 +114,11 @@ function Changepassword({ onClose, isOpen }: EnterPasswordProps) {
onOpenChange={(open) => !open && onClose()} onOpenChange={(open) => !open && onClose()}
> >
<DialogTrigger asChild> {/* <DialogTrigger asChild>
<Button bg="#02A0A0" size={'2xs'} color={"#fff"} px={2} > <Button bg="#02A0A0" size={'2xs'} color={"#fff"} px={2} >
Change Password Change Password
</Button> </Button>
</DialogTrigger> </DialogTrigger> */}
<DialogContent <DialogContent
bg={"#fff"} bg={"#fff"}
@@ -203,7 +203,7 @@ function Changepassword({ onClose, isOpen }: EnterPasswordProps) {
pl={1} pl={1}
fontSize="12px" fontSize="12px"
height="30px" height="30px"
type= {showNewPassword ? "password" : "Text"} type={showNewPassword ? "text" : "password"}
border={errors.confirm_password ? "1px solid red" : "1px solid grey"} border={errors.confirm_password ? "1px solid red" : "1px solid grey"}
{...register("confirm_password", { {...register("confirm_password", {
required: "Please confirm your password", required: "Please confirm your password",
@@ -240,6 +240,7 @@ function Changepassword({ onClose, isOpen }: EnterPasswordProps) {
<DialogCloseTrigger color="black" /> <DialogCloseTrigger color="black" />
</DialogContent> </DialogContent>
</DialogRoot > </DialogRoot >
<Toaster />
</> </>
) )
} }

View File

@@ -6,9 +6,78 @@ import { Field } from "../../components/ui/field";
// import Changepassword from "./ChangePassword"; // import Changepassword from "./ChangePassword";
import EnterPassword from "./EnterPassword"; import EnterPassword from "./EnterPassword";
import { useGetProfileQuery } from "../../Redux/Service/profile.password"; 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
const Profile = () => { const Profile = () => {
const { data } = useGetProfileQuery() 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); console.log('PROFILE DATA:', data?.data);
return ( return (
@@ -20,10 +89,11 @@ const Profile = () => {
<HStack shadow={'md'} rounded={'lg'} justifyContent={'space-between'} alignItems={'flex-end'} w={'100%'} px={3} py={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}> <VStack w={'100%'} alignItems={'flex-start'} gap={0}>
<Box mb={2} position="relative" width="fit-content" <Box mb={2} position="relative" width="fit-content"
cursor="pointer" onClick={() => alert("Avatar clicked!")}> cursor="pointer" onClick={handleClick}>
<Avatar.Root size={"2xl"} style={{ display: "inline-block", width: "auto" }}> <Avatar.Root size={"2xl"} style={{ display: "flex", width: "50px", height: '50px', justifyContent: 'center' }}>
<Avatar.Fallback /> <Avatar.Fallback />
<Avatar.Image src="https://i.pinimg.com/736x/d6/cd/0f/d6cd0ffd4634b0763d3958a7325ce26e.jpg" /> {/* <Avatar.Image src="https://i.pinimg.com/736x/d6/cd/0f/d6cd0ffd4634b0763d3958a7325ce26e.jpg" /> */}
{avatarSrc && <Avatar.Image src={`${PROFILEIMGURL}${avatarSrc}`} />}
</Avatar.Root> </Avatar.Root>
<Box <Box
position="absolute" position="absolute"
@@ -33,6 +103,13 @@ const Profile = () => {
> >
<FaCamera color="#ccc" size={16} /> <FaCamera color="#ccc" size={16} />
</Box> </Box>
<input
type="file"
accept="image/*"
ref={fileInputRef}
style={{ display: "none" }}
onChange={handleFileChange}
/>
</Box> </Box>
<Text color={"black"} as={'span'} fontSize={'sm'} fontWeight={"bold"}>{`${data?.data?.first_name.charAt(0).toUpperCase()}${data?.data.first_name.slice(1)}`} <Text color={"black"} as={'span'} fontSize={'sm'} fontWeight={"bold"}>{`${data?.data?.first_name.charAt(0).toUpperCase()}${data?.data.first_name.slice(1)}`}
</Text> </Text>
@@ -63,7 +140,7 @@ const Profile = () => {
</VStack> </VStack>
</HStack> </HStack>
<Toaster />
</MainFrame > </MainFrame >
) )
} }

View File

@@ -123,7 +123,7 @@ const SetNewPassword = () => {
height={"fit-content"} height={"fit-content"}
mr={2} mr={2}
> >
{showOldPassword ? <LuEye /> : <LuEyeOff />} {showOldPassword ? <LuEyeOff /> : <LuEye />}
</IconButton> </IconButton>
} }
> >
@@ -158,7 +158,7 @@ const SetNewPassword = () => {
color={"#000"} color={"#000"}
mr={2} mr={2}
> >
{showNewPassword ? <LuEye /> : <LuEyeOff />} {showNewPassword ? <LuEyeOff /> : <LuEye />}
</IconButton> </IconButton>
} }
> >

View File

@@ -12,26 +12,54 @@ import {
import { Field, Grid, Heading, Input, Stack, Text } from "@chakra-ui/react"; import { Field, Grid, Heading, Input, Stack, Text } from "@chakra-ui/react";
import { IoMdAdd } from "react-icons/io"; import { IoMdAdd } from "react-icons/io";
import { Checkbox } from "../../components/ui/checkbox"; import { Checkbox } from "../../components/ui/checkbox";
import { useCreateSubAdminPostMutation } from "../../Redux/Service/manage.subadmin.service"; import { PermissionResponse, useCreateSubAdminPostMutation } from "../../Redux/Service/manage.subadmin.service";
import { toaster } from "../../components/ui/toaster"; import { toaster, Toaster } from "../../components/ui/toaster";
import { useState } from "react"; import { useEffect, useState } from "react";
function AddModel({ refetch }: { refetch: VoidFunction }) { function AddModel({ refetch, allPermissions }: { refetch: VoidFunction, allPermissions?: PermissionResponse }) {
const [createSubAdminPost] = useCreateSubAdminPostMutation(); const [createSubAdminPost, { isLoading }] = useCreateSubAdminPostMutation();
// State fields // State fields
const [firstName, setFirstName] = useState(""); const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState(""); const [lastName, setLastName] = useState("");
const [userName, setUserName] = useState(""); // const [userName, setUserName] = useState("");
const [dateOfBirth, setDateOfBirth] = useState(""); const [dateOfBirth, setDateOfBirth] = useState("");
const [gender, setGender] = useState(""); const [gender, setGender] = useState("");
const [ setIsOpen] = useState(false); const [email, setEmail] = useState("");
const [phonenumber, setPhonenumber] = useState("");
const [permissions, setPermission] = useState<number[]>([]);
const [isOpen, setIsOpen] = useState(false);
// const [ setIsOpen] = useState(false);
const handleOpenModal = () => {
setIsOpen(true);
};
const handleCheckboxToggle = (permissionId: number) => {
setPermission((prevData) =>
prevData.includes(permissionId)
? prevData.filter((id) => id !== permissionId)
: [...prevData, permissionId]
);
};
useEffect(() => {
if (!isOpen) {
setFirstName("");
setLastName("");
// setUserName("");
setDateOfBirth("");
setGender("");
setEmail("");
setPhonenumber("");
setPermission([]);
}
}, [isOpen]);
const handleSubmit = async () => { const handleSubmit = async () => {
if ( if (
!firstName.trim() || !firstName.trim() ||
!lastName.trim() || !lastName.trim() ||
!userName.trim() ||
!dateOfBirth.trim() || !dateOfBirth.trim() ||
!gender.trim() !gender.trim()
) { ) {
@@ -43,17 +71,35 @@ function AddModel({ refetch }: { refetch: VoidFunction }) {
return; return;
} }
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
toaster.create({
title: "Invalid Email",
description: "Please enter a valid email address",
type: "error",
});
return;
}
if (phonenumber.length !== 10) {
toaster.create({
title: "Invalid Phone Number",
description: "Phone number must be exactly 10 digits",
type: "error",
});
return;
}
const payload = { const payload = {
principal_type_xid: 4, // user_name: userName,
principal_source_xid: 1,
user_name: userName,
first_name: firstName, first_name: firstName,
last_name: lastName, last_name: lastName,
date_of_birth: dateOfBirth, date_of_birth: dateOfBirth,
gender: gender, gender: gender,
email_address: "example@yopmail.com", // Hardcoded email_address: email,
phone_number: "9876543210", // Hardcoded phone_number: phonenumber,
created_by: 1, permission: permissions.filter((id) => typeof id === "number"),
// created_by: 1,
}; };
try { try {
@@ -65,27 +111,33 @@ function AddModel({ refetch }: { refetch: VoidFunction }) {
type: "success", type: "success",
}); });
refetch(); refetch();
setIsOpen(false);
setFirstName(""); setFirstName("");
setLastName(""); setLastName("");
setUserName(""); // setUserName("");
setDateOfBirth(""); setDateOfBirth("");
setGender(""); setGender("");
setIsOpen(false);
} }
} catch (error) { } catch (error:any) {
console.error("Error creating sub-admin:", error); console.error("Error creating sub-admin:", error);
toaster.create({ toaster.create({
title: "Error", title: "Error",
description: "Failed to create sub-admin", description: error ? error.data.message : "Failed to create sub-admin",
type: "error", type: "error",
}); });
} }
}; };
return ( return (
<DialogRoot placement="center"> <DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogTrigger asChild> <DialogTrigger asChild>
<Button rounded={"md"} px={4} py={2} size={"xs"} bg={"#02A0A0"}>
<Button
rounded={"md"}
px={4} py={2}
size={"xs"}
bg={"#02A0A0"}
onClick={handleOpenModal}>
<IoMdAdd /> Add <IoMdAdd /> Add
</Button> </Button>
</DialogTrigger> </DialogTrigger>
@@ -138,7 +190,7 @@ function AddModel({ refetch }: { refetch: VoidFunction }) {
onChange={(e) => setLastName(e.target.value)} onChange={(e) => setLastName(e.target.value)}
/> />
<Field.Label color="black" pt={1} fontSize="12px"> {/* <Field.Label color="black" pt={1} fontSize="12px">
Username Username
</Field.Label> </Field.Label>
<Input <Input
@@ -151,7 +203,7 @@ function AddModel({ refetch }: { refetch: VoidFunction }) {
height="30px" height="30px"
value={userName} value={userName}
onChange={(e) => setUserName(e.target.value)} onChange={(e) => setUserName(e.target.value)}
/> /> */}
<Field.Label color="black" pt={1} fontSize="12px"> <Field.Label color="black" pt={1} fontSize="12px">
DOB DOB
@@ -184,30 +236,63 @@ function AddModel({ refetch }: { refetch: VoidFunction }) {
onChange={(e) => setGender(e.target.value)} 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"}> <Heading mt={5} color={"#000"} fontSize={"sm"}>
Permissions Permissions
</Heading> </Heading>
</Field.Root> </Field.Root>
<Grid templateColumns="repeat(2, 1fr)" gap={4}> <Grid templateColumns="repeat(2, 1fr)" gap={4}>
{[ {Array.isArray(allPermissions?.data?.permission)
"Dashboard", ? allPermissions.data.permission.map((permission: any) => (
"Manage contact us", <Checkbox
"manage User", size="sm"
"Manage CMS", color="black"
"Manage Post", key={permission.id}
"Manage Reports", checked={permissions.includes(permission.id)}
"manage Sub-Admin", onChange={() => handleCheckboxToggle(permission.id)}
"My profile", >
"Manage Jobs", <Text fontSize={12}>{permission.app_resource_title}</Text>
"manage feedbacks", </Checkbox>
"Manage community", ))
"Notification", : <Text fontSize={12} color="gray.500">Loading permissions...</Text>
].map((permission) => ( }
<Checkbox size="sm" color="black" key={permission}>
<Text fontSize={12}>{permission}</Text>
</Checkbox>
))}
</Grid> </Grid>
</Stack> </Stack>
</DialogBody> </DialogBody>
@@ -219,13 +304,14 @@ function AddModel({ refetch }: { refetch: VoidFunction }) {
bg="#02A0A0" bg="#02A0A0"
color={"#fff"} color={"#fff"}
onClick={handleSubmit} onClick={handleSubmit}
disabled={isLoading}
> >
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
<DialogCloseTrigger color="black" />
</DialogContent> </DialogContent>
<Toaster />
</DialogRoot> </DialogRoot>
); );
} }

View File

@@ -1,7 +1,7 @@
import { Field, Grid, Heading, Input, Stack, Text } from "@chakra-ui/react"; import { Field, Grid, Heading, Input, Stack, Text } from "@chakra-ui/react";
// import { TbEdit } from "react-icons/tb"; // import { TbEdit } from "react-icons/tb";
import { Button } from "./ui/button"; import { Button } from "../../components/ui/button";
import { Checkbox } from "./ui/checkbox"; import { Checkbox } from "../../components/ui/checkbox";
import { import {
DialogBody, DialogBody,
DialogCloseTrigger, DialogCloseTrigger,
@@ -11,25 +11,23 @@ import {
DialogRoot, DialogRoot,
DialogTitle, DialogTitle,
DialogTrigger, DialogTrigger,
} from "./ui/dialog"; } from "../../components/ui/dialog";
import Edit from "./ActionIcons/Edit"; import Edit from "../../components/ActionIcons/Edit";
import { useLazyViewSubAdminQuery, useUpdateSubAdminMutation } from "../Redux/Service/manage.subadmin.service"; import { PermissionResponse, useLazyViewSubAdminQuery, useUpdateSubAdminMutation } from "../../Redux/Service/manage.subadmin.service";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { toaster } from "./ui/toaster"; import { Toaster, toaster } from "../../components/ui/toaster";
const resourceIdToLabel: { [key: number]: string } = { const resourceIdToLabel: { [key: number]: string } = {
1: 'Dashboard', 1: 'Dashboard',
2: 'Manage contact us', 2: 'Manage User',
3: 'Manage User', 3: 'Manage Post',
4: 'Manage CMS', 4: 'Manage Subadmin',
5: 'Manage Post', 5: 'Manage Jobs',
6: 'Manage Reports', 6: 'Manage Groups',
7: 'Manage Sub-Admin', 7: 'Manage Contact Us',
8: 'My profile', 8: 'Manage CMS',
9: 'Manage Jobs', 9: 'My Profile',
10: 'Manage feedbacks', 10: 'Master Module',
11: 'Manage community',
12: 'Notification',
}; };
@@ -37,11 +35,15 @@ interface ResourceActionLink {
id: number; id: number;
app_resource_xid: number; app_resource_xid: number;
is_active: boolean; is_active: boolean;
app_resource: {
id: number,
app_resource_title: string
}
} }
function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) { function EditSubAdmin({ id, refetch, allPermissions }: { id: number, refetch: VoidFunction, allPermissions?: PermissionResponse }) {
const [trigger, { data }] = useLazyViewSubAdminQuery(); const [trigger, { data }] = useLazyViewSubAdminQuery();
const [updateSubAdmin] = useUpdateSubAdminMutation() const [updateSubAdmin, {isLoading}] = useUpdateSubAdminMutation()
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [editData, setEditData] = useState<{ const [editData, setEditData] = useState<{
id: string; id: string;
@@ -62,8 +64,23 @@ function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
}) })
useEffect(() => { useEffect(() => {
if (data?.data && data.data.length > 0) { if (data?.data?.length && allPermissions?.data?.permission?.length) {
const subAdmin = data.data[0]; // Extract the first item from the array 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 // Map the API response to editData
setEditData({ setEditData({
@@ -73,10 +90,10 @@ function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
last_name: subAdmin.last_name, last_name: subAdmin.last_name,
date_of_birth: formatDateOfBirth(subAdmin.date_of_birth), date_of_birth: formatDateOfBirth(subAdmin.date_of_birth),
gender: subAdmin.gender, gender: subAdmin.gender,
permission: subAdmin.get_resource_action_link, permission: mergedPermissions,
}); });
} }
}, [data]); }, [data, allPermissions]);
const formatDateOfBirth = (dob: string): string => { const formatDateOfBirth = (dob: string): string => {
// Convert the date to the desired format with slashes // Convert the date to the desired format with slashes
@@ -99,7 +116,7 @@ function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
setEditData((prevData) => ({ setEditData((prevData) => ({
...prevData, ...prevData,
permission: prevData.permission.map((permission) => permission: prevData.permission.map((permission) =>
permission.id === permissionId permission.app_resource_xid === permissionId
? { ...permission, is_active: !permission.is_active } ? { ...permission, is_active: !permission.is_active }
: permission : permission
), ),
@@ -113,12 +130,14 @@ function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
const payload = { const payload = {
id: Number(editData.id), id: Number(editData.id),
unique_id: editData.unique_id, // unique_id: editData.unique_id,
first_name: editData.first_name, first_name: editData.first_name,
last_name: editData.last_name, last_name: editData.last_name,
date_of_birth: editData.date_of_birth, date_of_birth: editData.date_of_birth,
gender: editData.gender, gender: editData.gender,
permission: editData.permission permission: editData.permission
.filter((p) => p.is_active)
.map((p) => p.app_resource_xid),
}; };
try { try {
@@ -171,7 +190,7 @@ function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
<DialogBody bg="white"> <DialogBody bg="white">
<Stack py={3}> <Stack py={3}>
<Field.Root> <Field.Root>
<Field.Label color="black" pt={1} fontSize="12px"> {/* <Field.Label color="black" pt={1} fontSize="12px">
ID ID
</Field.Label> </Field.Label>
<Input <Input
@@ -184,7 +203,7 @@ function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
height="30px" height="30px"
value={editData.unique_id} value={editData.unique_id}
onChange={(e) => setEditData({ ...editData, unique_id: e.target.value })} onChange={(e) => setEditData({ ...editData, unique_id: e.target.value })}
/> /> */}
<Field.Label color="black" pt={1} fontSize="12px"> <Field.Label color="black" pt={1} fontSize="12px">
First Name First Name
@@ -248,44 +267,6 @@ function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
Permissions Permissions
</Heading> </Heading>
</Field.Root> </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> */}
<Grid templateColumns="repeat(2, 1fr)" gap={4}> <Grid templateColumns="repeat(2, 1fr)" gap={4}>
{editData.permission.map((permission) => { {editData.permission.map((permission) => {
const label = resourceIdToLabel[permission.app_resource_xid]; const label = resourceIdToLabel[permission.app_resource_xid];
@@ -295,7 +276,7 @@ function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
size="sm" size="sm"
color="black" color="black"
checked={permission.is_active} checked={permission.is_active}
onChange={() => handleCheckboxToggle(permission.id)} onChange={() => handleCheckboxToggle(permission.app_resource_xid)}
cursor={'pointer'} cursor={'pointer'}
> >
<Text fontSize={12}>{label}</Text> <Text fontSize={12}>{label}</Text>
@@ -306,12 +287,13 @@ function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
</Stack> </Stack>
</DialogBody> </DialogBody>
<DialogFooter display="flex" justifyContent="center" pt={"2"}> <DialogFooter display="flex" justifyContent="center" pt={"2"}>
<Button size={"xs"} w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit}> <Button size={"xs"} w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
Save Save
</Button> </Button>
</DialogFooter> </DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} /> <DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent> </DialogContent>
<Toaster />
</DialogRoot> </DialogRoot>
); );
} }

View File

@@ -1,24 +1,26 @@
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react" import { Box, HStack, Image, Text } from "@chakra-ui/react"
import MainFrame from "../../components/MainFrame" import MainFrame from "../../components/MainFrame"
import { InputGroup } from "../../components/ui/input-group" // import { InputGroup } from "../../components/ui/input-group"
import { LuSearch } from "react-icons/lu" // import { LuSearch } from "react-icons/lu"
import DataTable from "../../components/DataTable" import DataTable from "../../components/DataTable"
import AlertDailog from "../../components/AlertDailog"; import AlertDailog from "../../components/AlertDailog";
// import { RiDeleteBin5Line } from "react-icons/ri"; // import { RiDeleteBin5Line } from "react-icons/ri";
import AddModel from "./AddModel" import AddModel from "./AddModel"
import EditSubAdmin from "../../components/EditSubAdmin" import EditSubAdmin from "./EditSubAdmin"
import ViewSubAdmin from "./ViewSubAdmin" import ViewSubAdmin from "./ViewSubAdmin"
import Delete from "../../components/ActionIcons/Delete" import Delete from "../../components/ActionIcons/Delete"
import { useDeleteSubAdminPostMutation, useGetSubAdminQuery } from "../../Redux/Service/manage.subadmin.service" import { PermissionResponse, useDeleteSubAdminPostMutation, useGetPermissionQuery, useGetSubAdminQuery } from "../../Redux/Service/manage.subadmin.service"
import { useEffect, useState } from "react" import { useEffect, useState } from "react"
import { toaster } from "../../components/ui/toaster" import { Toaster, toaster } from "../../components/ui/toaster"
import { useDebounce } from "../../components/Hooks/useDebounce"
import SearchComponent from "../../components/SearchComponent"
// table data // table data
const tableHeadRow = [ const tableHeadRow = [
"Sr. No", "Sr. No",
"Id", "Emp ID",
"First Name", "First Name",
"last Name", "last Name",
"DOB", "DOB",
@@ -55,37 +57,52 @@ const tableHeadRow = [
// ]; // ];
const SubAdmin = () => { const SubAdmin = () => {
const { data, refetch } = useGetSubAdminQuery() const [currentPage, setCurrentPage] = useState(1);
// const { data, refetch } = useGetSubAdminQuery()
const { data: permissions } = useGetPermissionQuery()
const [localData, setLocalData] = useState<any[]>([]); const [localData, setLocalData] = useState<any[]>([]);
const [allPermissions, setAllPermissions] = useState<PermissionResponse>();
const [deleteModal, setDeleteModal] = useState(false) const [deleteModal, setDeleteModal] = useState(false)
const [deleteSubAdminPost] = useDeleteSubAdminPostMutation() const [deleteSubAdminPost] = useDeleteSubAdminPostMutation()
const [searchTerm, setSearchTerm] = useState("");
console.log("============================",data); const debouncedSearchTerm = useDebounce(searchTerm, 500);
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
const { data, refetch, isError, isFetching } = useGetSubAdminQuery(queryArgs);
useEffect(() => { useEffect(() => {
if (data?.data.data) { if (data?.data.data) {
setLocalData(data?.data.data); setLocalData(data?.data.data);
setAllPermissions(permissions);
} }
}, [data]); }, [data, permissions]);
console.log("============================", allPermissions);
console.log('localData', localData); console.log('localData', localData);
const handleDeleteFaq = async (faqId: number) => { const handlePageChange = (page: number) => {
setCurrentPage(page);
};
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
const handleDeleteAdmin = async (faqId: number) => {
try { try {
const response = await deleteSubAdminPost(faqId).unwrap(); const response = await deleteSubAdminPost(faqId).unwrap();
if (response.success) { if (response.success) {
toaster.create({ toaster.create({
title: "Success", title: "Success",
description: "FAQ deleted successfully", description: "Sub Admin deleted successfully",
type: "success", type: "success",
}); });
refetch() refetch()
console.log("FAQ deleted successfully:", response); console.log("Sub Admin deleted successfully:", response);
} }
// Optionally, refetch data or update state after deletion // Optionally, refetch data or update state after deletion
} catch (error) { } catch (error) {
console.error("Error deleting FAQ:", error); console.error("Error deleting Sub Admin:", error);
toaster.create({ toaster.create({
title: "Error", title: "Error",
description: "Something went wrong", description: "Something went wrong",
@@ -102,10 +119,18 @@ const SubAdmin = () => {
}); });
}; };
const managepost = localData?.map((agency: any, index: number) => ({ 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, 'id': agency.id,
"Sr. No": index + 1, "Sr. No": index + 1,
"Id": agency.unique_id, "Emp ID": agency.unique_id,
"First Name": agency.first_name, "First Name": agency.first_name,
"last Name": agency.last_name, "last Name": agency.last_name,
"DOB": formatDateOfBirth(agency.date_of_birth), "DOB": formatDateOfBirth(agency.date_of_birth),
@@ -114,20 +139,20 @@ const SubAdmin = () => {
"Action": ( "Action": (
<HStack justifyContent="center"> <HStack justifyContent="center">
{/* <EditDetails rowData={{ id: agency.id, question: agency.question, answer: agency.answer }} refetch={refetch} /> */} {/* <EditDetails rowData={{ id: agency.id, question: agency.question, answer: agency.answer }} refetch={refetch} /> */}
<ViewSubAdmin id={agency.id}/> <ViewSubAdmin id={agency.id} />
<EditSubAdmin id={agency.id} refetch={refetch} /> <EditSubAdmin id={agency.id} refetch={refetch} allPermissions={permissions} />
<AlertDailog <AlertDailog
isOpen={deleteModal} isOpen={deleteModal}
AltertTiggerIcon={() => <Delete onClick={() => setDeleteModal(prev => !prev)} />} AltertTiggerIcon={() => <Delete onClick={() => setDeleteModal(prev => !prev)} />}
alertText="Delete FAQ" alertText="Delete sub admin"
alertIcon={<Image src={"DeleteIcon"} h={"39px"} />} alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
alertCaption="are you sure you want to delete ?" alertCaption="are you sure you want to delete ?"
onClose={() => setDeleteModal(false)} onClose={() => setDeleteModal(false)}
onConfirm={() => { onConfirm={() => {
// console.log("User deleted:", index + 1); // console.log("User deleted:", index + 1);
setDeleteModal(false); setDeleteModal(false);
handleDeleteFaq(agency.id) handleDeleteAdmin(agency.id)
}} }}
/> />
</HStack> </HStack>
@@ -150,38 +175,31 @@ const SubAdmin = () => {
</Text> </Text>
<HStack> <HStack>
<InputGroup <SearchComponent
startElement={ value={searchTerm}
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} /> onChange={handleSearchChange}
} />
color={"#000"}
>
<Input
p={3}
w={300}
bg={"#fff"}
colorPalette={"cyan"}
_focus={{ border: "1px solid #02A0A0" }}
rounded={"md"}
size={"xs"}
fontSize={"sm"}
placeholder="Search..."
bgColor={'#EEEEEE'}
ps={8}
/>
</InputGroup>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */} {/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
<AddModel /> <AddModel refetch={refetch} allPermissions={permissions} />
</HStack> </HStack>
</HStack> </HStack>
<DataTable <DataTable
sortableColumns={["Name", "Registration Date "]} sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow} tableHeadRow={tableHeadRow}
data={managepost} data={managepost}
// paginationData={data?.data} paginationData={{
// refetch={refetch} 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> </MainFrame> </Box>
<Toaster />
</MainFrame>
) )
} }
export default SubAdmin export default SubAdmin

View File

@@ -22,9 +22,9 @@ import { Checkbox } from "../../components/ui/checkbox";
// import { FaRegEdit } from "react-icons/fa"; // import { FaRegEdit } from "react-icons/fa";
import View from "../../components/ActionIcons/View"; import View from "../../components/ActionIcons/View";
import { Button } from "../../components/ui/button"; import { Button } from "../../components/ui/button";
import { useLazyViewSubAdminQuery } from "../../Redux/Service/manage.subadmin.service"; import {useLazyViewSubAdminQuery } from "../../Redux/Service/manage.subadmin.service";
function ViewSubAdmin({ id }: { id: number }) { function ViewSubAdmin({ id, }: { id: number}) {
const [trigger, { data }] = useLazyViewSubAdminQuery(); const [trigger, { data }] = useLazyViewSubAdminQuery();
const handleView = () => { const handleView = () => {
@@ -64,6 +64,7 @@ function ViewSubAdmin({ id }: { id: number }) {
overflowX="hidden" overflowX="hidden"
p={3} // Reduced padding p={3} // Reduced padding
bgSize={"md"} bgSize={"md"}
key={data.id}
> >
<DialogHeader bg="white"> <DialogHeader bg="white">
<DialogTitle alignSelf="center" color="black" fontSize="14px"> <DialogTitle alignSelf="center" color="black" fontSize="14px">
@@ -149,8 +150,8 @@ function ViewSubAdmin({ id }: { id: number }) {
</Field.Root> </Field.Root>
<Grid templateColumns="repeat(2, 1fr)" gap={4}> <Grid templateColumns="repeat(2, 1fr)" gap={4}>
{data.get_resource_action_link.map((check: any) => ( {data.get_resource_action_link.map((check: any) => (
<Checkbox size={"sm"} color={"black"} checked={check.is_active}> <Checkbox size={"sm"} color={"black"} checked={check.is_active} key={check.id}>
<Text fontSize={12}>{check.app_resource_xid}</Text> <Text fontSize={12}>{check?.app_resource.app_resource_title}</Text>
</Checkbox> </Checkbox>
// <> // <>
// <Checkbox size={"sm"} color={"black"}> // <Checkbox size={"sm"} color={"black"}>

View File

@@ -70,8 +70,18 @@ export const agencyMasterModule = createApi({
}), }),
}), }),
getAgencyMaster: builder.query<AgencyResponse, number>({ // getAgencyMaster: builder.query<AgencyResponse, number>({
query: (page = 1) => `/agency-master?page=${page}` // 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({ agencyMasterToggle: builder.mutation({

View File

@@ -65,8 +65,18 @@ export const countryMaster = createApi({
}), }),
}), }),
// 🔹 GET: Fetch all posts // 🔹 GET: Fetch all posts
getCountryMaster: builder.query<ApiResponse, number>({ // getCountryMaster: builder.query<ApiResponse, number>({
query: (page = 1) => `/country-list?page=${page}`, // 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>({ getCountryMasterEdit: builder.query<CountryEdit, number>({

View File

@@ -0,0 +1,77 @@
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

@@ -64,8 +64,18 @@ export const departmentMaster = createApi({
}), }),
}), }),
// 🔹 GET: Fetch all posts // 🔹 GET: Fetch all posts
getDepartmentMaster: builder.query<ApiResponse, number>({ // getDepartmentMaster: builder.query<ApiResponse, number>({
query: (page = 1) => `/department-master-list?page=${page}`, // 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>({ getDepartmentMasterDropDown: builder.query<DropDown, void>({

View File

@@ -61,8 +61,18 @@ export const industryMaster = createApi({
}), }),
}), }),
// 🔹 GET: Fetch all posts // 🔹 GET: Fetch all posts
getIndustryMaster: builder.query<IndustryMasterResponse, number>({ // getIndustryMaster: builder.query<IndustryMasterResponse, number>({
query: (page = 1) => `/industry-master-list?page=${page}`, // 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({ updateIndustryMaster: builder.mutation({

View File

@@ -51,8 +51,18 @@ export const jobStatus = createApi({
}), }),
}), }),
// 🔹 GET: Fetch all posts // 🔹 GET: Fetch all posts
getJobStatus: builder.query<ApiResponse, number>({ // getJobStatus: builder.query<ApiResponse, number>({
query: (page = 1) => `/job-status-list?page=${page}`, // 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({ updateJobStatus: builder.mutation({

View File

@@ -71,9 +71,9 @@ export const jobType = createApi({
}), }),
}), }),
templateMasterToggle: builder.mutation({ jobTypeToggle: builder.mutation({
query: ({ id, is_active }) => ({ query: ({ id, is_active }) => ({
url: `/template-status`, url: `/job-type-status`,
method: "POST", method: "POST",
body: { id, is_active }, body: { id, is_active },
}), }),
@@ -86,5 +86,5 @@ export const {
useGetJobTypeQuery, useGetJobTypeQuery,
useCreateJobTypePostMutation, useCreateJobTypePostMutation,
useUpdateJobTypeMutation, useUpdateJobTypeMutation,
useTemplateMasterToggleMutation, useJobTypeToggleMutation,
} = jobType; } = jobType;

View File

@@ -21,13 +21,25 @@ export const manageContactUs = createApi({
endpoints: (builder) => ({ endpoints: (builder) => ({
getContact: builder.query<ApiResponse, void>({ getContact: builder.query<ApiResponse, { page?: number; search?: string }>({
query: () => "/contact-us", 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"], providesTags: ["Contact"],
}), }),
pendingRequest: builder.mutation({
query: (body) => ({
url: `/contact-us-response`,
method: "POST",
body,
}),
invalidatesTags: ["Contact"],
}),
}), }),
}); });
export const { useGetContactQuery } = manageContactUs; export const { useGetContactQuery, usePendingRequestMutation } = manageContactUs;

View File

@@ -66,17 +66,40 @@ export type PostJobStatus = {
title: string title: string
}; };
export type WorkSpace = {
id: number;
en_name: string;
};
export const manageJobs = createApi({ export const manageJobs = createApi({
reducerPath: "manageJobs", reducerPath: "manageJobs",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({ endpoints: (builder) => ({
getManageJobs: builder.query<ApiResponse, number>({ // getManageJobs: builder.query<ApiResponse, number>({
query: (page = 1) => `/manage-jobs-list?page=${page}`, // query: (page = 1) => `/manage-jobs-list?page=${page}`,
// }),
getManageJobs: 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 `/manage-jobs-list?${params.toString()}`;
},
}),
updateJobs: builder.mutation({
query: (updatedData) => ({
url: "/manage-jobs-update",
method: "POST",
body: updatedData,
}),
}), }),
viewJobs: builder.query<ApiResponse, number>({ viewJobs: builder.query<ApiResponse, number>({
query: (id) => `/manage-jobs-list/${id}`, query: () => `/manage-jobs-list`,
}), }),
deleteJobsPost: builder.mutation<{ status: string; message: string }, { id: number }>({ deleteJobsPost: builder.mutation<{ status: string; message: string }, { id: number }>({
@@ -87,10 +110,38 @@ export const manageJobs = createApi({
}), }),
}), }),
// Modes
getWorkspaceModes: builder.query({
query: () => `/manage-jobs-get-workspace`,
}),
getIndustry: builder.query({
query: () => `/manage-jobs-get-industry`,
}),
getDepartment: builder.query({
query: () => `/manage-jobs-get-department`,
}),
getCountry: builder.query({
query: () => `/manage-jobs-get-country`,
}),
getManageJobType: builder.query({
query: () => `/job-type`,
}),
}), }),
}); });
export const { useGetManageJobsQuery,useLazyViewJobsQuery,useDeleteJobsPostMutation } = manageJobs; export const {
useGetManageJobsQuery,
useLazyViewJobsQuery,
useDeleteJobsPostMutation,
useUpdateJobsMutation,
useGetWorkspaceModesQuery,
useGetIndustryQuery,
useGetDepartmentQuery,
useGetCountryQuery,
useGetManageJobTypeQuery
} = manageJobs;

View File

@@ -40,6 +40,25 @@ interface ApiResponse {
data: PaginatedData; data: PaginatedData;
} }
export type Permission = {
id: number;
app_resource_title: string;
is_active: boolean;
created_by: string | null;
modified_by: string | null;
deleted_at: string | null;
created_at: string;
updated_at: string;
};
export type PermissionResponse = {
status: string;
status_code: number;
message: string;
data: {
permission: Permission[];
};
};
// export type SubAdminPost = { // export type SubAdminPost = {
// id: number; // id: number;
// first_name: string, // first_name: string,
@@ -60,6 +79,10 @@ interface ResourceActionLink {
deleted_at: string | null; deleted_at: string | null;
created_at: string; created_at: string;
updated_at: string; updated_at: string;
app_resource: {
id: number;
app_resource_title: string
}
} }
interface SubAdmin { interface SubAdmin {
@@ -80,16 +103,14 @@ interface SubAdminView {
} }
interface CreateSubAdminPayload { interface CreateSubAdminPayload {
principal_type_xid: number; // user_name: string;
principal_source_xid: number;
user_name: string;
first_name: string; first_name: string;
last_name: string; last_name: string;
date_of_birth: string; date_of_birth: string;
gender: string; gender: string;
email_address: string; email_address: string;
phone_number: string; phone_number: string;
created_by: number; // created_by: number;
} }
interface CreateSubAdminResponse { interface CreateSubAdminResponse {
@@ -113,8 +134,17 @@ export const manageSubAdmin = createApi({
}), }),
}), }),
getSubAdmin: builder.query<ApiResponse, void>({ getSubAdmin: builder.query<ApiResponse, { page?: number; search?: string }>({
query: () => `/sub-admin`, query: ({ page, search }) => {
const params = new URLSearchParams();
if (page) params.append("page", page.toString());
if (search) params.append("search", search);
return `/sub-admin?${params.toString()}`
}
}),
getPermission: builder.query<PermissionResponse, void>({
query: () => `/resources`,
}), }),
viewSubAdmin: builder.query<SubAdminView, number>({ viewSubAdmin: builder.query<SubAdminView, number>({
@@ -151,8 +181,9 @@ export const manageSubAdmin = createApi({
deleteSubAdminPost: builder.mutation<{ success: boolean }, number>({ deleteSubAdminPost: builder.mutation<{ success: boolean }, number>({
query: (id) => ({ query: (id) => ({
url: `/faq-delete/${id}`, url: `/sub-admin-delete`,
method: "DELETE", method: "POST",
body: { id },
}), }),
}), }),
}), }),
@@ -160,6 +191,7 @@ export const manageSubAdmin = createApi({
export const { export const {
useGetSubAdminQuery, useGetSubAdminQuery,
useGetPermissionQuery,
useLazyViewSubAdminQuery, useLazyViewSubAdminQuery,
useUpdateSubAdminMutation, useUpdateSubAdminMutation,
useDeleteSubAdminPostMutation, useDeleteSubAdminPostMutation,

View File

@@ -10,11 +10,19 @@ export interface UserData {
gender: string; gender: string;
date_of_birth: string; date_of_birth: string;
is_active: boolean; is_active: boolean;
principal_type:{ principal_type: {
id: number; id: number;
principal_type_title: string; principal_type_title: string;
}, },
principle_language_links:[] principle_language_linkss: {
id: number;
language_xid: number;
iam_principal_xid: number;
language: {
id: number,
language_name: string;
}
}
} }
interface ApiResponse { interface ApiResponse {
@@ -55,9 +63,9 @@ export const registerUser = createApi({
reducerPath: "registerUser", reducerPath: "registerUser",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({ endpoints: (builder) => ({
createCountryPost: builder.mutation<PostCountry, Partial<PostCountry>>({ createUser: builder.mutation<PostCountry, Partial<PostCountry>>({
query: (data) => ({ query: (data) => ({
url: "/country-add", url: "/manage-user-store",
method: "POST", method: "POST",
body: data, body: data,
}), }),
@@ -67,13 +75,13 @@ export const registerUser = createApi({
query: (page = 1) => `/manage-user-list?page=${page}`, query: (page = 1) => `/manage-user-list?page=${page}`,
}), }),
getCountryMasterEdit: builder.query<CountryEdit, number>({ getDeactivateUser: builder.query<ApiResponse, number>({
query: (id) => `/country-edit/${id}`, query: (page = 1) => `/manage-user-deactivate-list?page=${page}`,
}), }),
updateCountry: builder.mutation({ updateUser: builder.mutation({
query: (updatedData) => ({ query: (updatedData) => ({
url: "/country-update", url: "/manage-user-update",
method: "POST", method: "POST",
body: updatedData, body: updatedData,
}), }),
@@ -87,22 +95,31 @@ export const registerUser = createApi({
}), }),
}), }),
// deleteFaqPost: builder.mutation<{ status: string; message: string }, { id: number }>({ userDeactivateToggle: builder.mutation({
// query: ({ id }) => ({ query: ({ id, is_active }) => ({
// url: `/faq-delete`, url: `/manage-user-deactivate-status`,
// method: "POST", method: "POST",
// body: { id }, body: { id, is_active },
// }), }),
// }), }),
deleteUser: builder.mutation({
query: ({ id }) => ({
url: `/manage-user-delete`,
method: "POST",
body: { id },
}),
}),
}), }),
}); });
export const { export const {
useGetManageUserQuery, useGetManageUserQuery,
useGetCountryMasterEditQuery, useCreateUserMutation,
useCreateCountryPostMutation, useUpdateUserMutation,
useUpdateCountryMutation,
useUserToggleMutation, useUserToggleMutation,
// useDeleteFaqPostMutation useGetDeactivateUserQuery,
useUserDeactivateToggleMutation,
useDeleteUserMutation
} = registerUser; } = registerUser;

View File

@@ -1,26 +1,37 @@
import { createApi } from "@reduxjs/toolkit/query"; import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQueryWithReauth } from "./apiSlice"; import { baseQueryWithReauth } from "./apiSlice";
export const myProfile = createApi({ export const myProfile = createApi({
reducerPath: "myProfile", reducerPath: "myProfile",
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
endpoints: (builder) => ({ endpoints: (builder) => ({
getPosts: builder.query<Post[], void>({ query: () => "/posts" }), // getPosts: builder.query<Post[], void>({ query: () => "/profile-image-edit" }),
updateImage: builder.mutation({
query: (formData: FormData) => {
const token = localStorage.getItem("token");
return {
url: "/profile-image-edit",
method: "POST",
body: formData,
headers: {
"access-token": `${token}`,
},
};
},
}),
}), }),
}); });
export const { } = myProfile; export const {
useUpdateImageMutation,
export type Post = { } = myProfile;
id: number;
title: string;
body: string;
};

View File

@@ -27,6 +27,7 @@ interface PaginationData {
export interface Template { export interface Template {
id: number; id: number;
is_active: boolean; is_active: boolean;
principle_type_xid: number;
post_template_translate: PostTemplateTranslate[]; post_template_translate: PostTemplateTranslate[];
post_template_image: PostTemplateImage[]; post_template_image: PostTemplateImage[];
} }

View File

@@ -50,7 +50,7 @@ export const workspaceMode = createApi({
endpoints: (builder) => ({ endpoints: (builder) => ({
createWorkspacePost: builder.mutation<PostDepartment, Partial<PostDepartment>>({ createWorkspacePost: builder.mutation<PostDepartment, Partial<PostDepartment>>({
query: (data) => ({ query: (data) => ({
url: "/department-master-store", url: "/workspace-create",
method: "POST", method: "POST",
body: data, body: data,
}), }),

View File

@@ -23,6 +23,7 @@ import { workspaceMode } from "./Service/workspace.mode";
import { jobStatus } from "./Service/job.status"; import { jobStatus } from "./Service/job.status";
import { managePosts } from "./Service/manage.post.service"; import { managePosts } from "./Service/manage.post.service";
import { registerUser } from "./Service/manage.user"; import { registerUser } from "./Service/manage.user";
import { dashBoard } from "./Service/dashBoard";
export const store = configureStore({ export const store = configureStore({
reducer: { reducer: {
@@ -49,6 +50,7 @@ export const store = configureStore({
[jobStatus.reducerPath]: jobStatus.reducer, [jobStatus.reducerPath]: jobStatus.reducer,
[managePosts.reducerPath]: managePosts.reducer, [managePosts.reducerPath]: managePosts.reducer,
[registerUser.reducerPath]: registerUser.reducer, [registerUser.reducerPath]: registerUser.reducer,
[dashBoard.reducerPath]: dashBoard.reducer,
auth: authReducer, auth: authReducer,
}, },
middleware: (getDefaultMiddleware) => middleware: (getDefaultMiddleware) =>
@@ -76,6 +78,7 @@ export const store = configureStore({
jobStatus.middleware, jobStatus.middleware,
managePosts.middleware, managePosts.middleware,
registerUser.middleware, registerUser.middleware,
dashBoard.middleware,
), ),
}); });

View File

@@ -1,5 +1,5 @@
import { LuBriefcaseBusiness} from "react-icons/lu"; import { LuBriefcaseBusiness } from "react-icons/lu";
import { MdHeadsetMic, MdOutlineDashboard} from "react-icons/md"; import { MdHeadsetMic, MdOutlineDashboard } from "react-icons/md";
import { GoDotFill } from "react-icons/go"; import { GoDotFill } from "react-icons/go";
import { HiOutlinePencilSquare } from "react-icons/hi2"; import { HiOutlinePencilSquare } from "react-icons/hi2";
import { BiUser, BiUserPin } from "react-icons/bi"; import { BiUser, BiUserPin } from "react-icons/bi";
@@ -9,145 +9,155 @@ import { AiOutlineFileText } from "react-icons/ai";
export const nav = [ export const nav = [
{ {
title: "Dashboard", title: "Dashboard",
path: "/", path: "/",
Icon: MdOutlineDashboard, Icon: MdOutlineDashboard,
type:'single' type: 'single',
}, resourceTitle: 'Dashboard'
{ },
title: "Manage Users", {
initPath: "/manage-users", title: "Manage Users",
Icon: BiUserPin, initPath: "/manage-users",
type:'multiple', Icon: BiUserPin,
children: [ type: 'multiple',
{ resourceTitle: 'Manage User',
title: "Register Users", children: [
path: "/manage-users/register-users", {
Icon: GoDotFill, title: "Register Users",
}, path: "/manage-users/register-users",
{ Icon: GoDotFill,
title: "Deactivated Accounts", },
path: "/manage-users/deactivated-accounts", {
Icon: GoDotFill, title: "Deactivated Accounts",
}, path: "/manage-users/deactivated-accounts",
], Icon: GoDotFill,
}, },
{ ],
title: "Manage Post", },
path: "/manage-post", {
Icon: HiOutlinePencilSquare, title: "Manage Post",
type:'single' path: "/manage-post",
}, Icon: HiOutlinePencilSquare,
{ type: 'single',
title: "Manage Sub-Admin", resourceTitle: 'Manage Post'
path: "/sub-admin", },
Icon: BiUser, {
type:'single' title: "Manage Sub-Admin",
}, path: "/sub-admin",
{ Icon: BiUser,
title: "Manage Jobs", type: 'single',
path: "/manage-jobs", resourceTitle: 'Manage Subadmin'
Icon: LuBriefcaseBusiness, },
type:'single' {
}, title: "Manage Jobs",
{ path: "/manage-jobs",
title: "Manage Groups", Icon: LuBriefcaseBusiness,
path: "/manage-groups", type: 'single',
Icon: PiUsersThree, resourceTitle: 'Manage Jobs'
type:'single' },
}, {
{ title: "Manage Groups",
title: "Manage Contact Us", path: "/manage-groups",
path: "/manage-contact", Icon: PiUsersThree,
Icon: MdHeadsetMic , type: 'single',
type:'single' resourceTitle: 'Manage Groups'
}, },
{ {
title: "Manage CMS", title: "Manage Contact Us",
initPath: "/manage-cms", path: "/manage-contact",
Icon: AiOutlineFileText, Icon: MdHeadsetMic,
type:'multiple', type: 'single',
children: [ resourceTitle: 'Manage Contact Us'
{ },
title: "FAQs", {
path: "/manage-cms/faq", title: "Manage CMS",
Icon: GoDotFill, initPath: "/manage-cms",
}, Icon: AiOutlineFileText,
{ type: 'multiple',
title: "About Us", resourceTitle: 'Manage CMS',
path: "/manage-cms/about-us", children: [
Icon: GoDotFill, {
}, title: "FAQs",
{ path: "/manage-cms/faq",
title: "Privacy Policy", Icon: GoDotFill,
path: "/manage-cms/privacy-policy", },
Icon: GoDotFill, {
}, title: "About Us",
{ path: "/manage-cms/about-us",
title: "Terms And Conditions", Icon: GoDotFill,
path: "/manage-cms/terms-conditions", },
Icon: GoDotFill, {
}, title: "Privacy Policy",
// { path: "/manage-cms/privacy-policy",
// title: "Privacy", Icon: GoDotFill,
// path: "/manage-cms/privacy", },
// Icon: GoDotFill, {
// }, title: "Terms And Conditions",
], path: "/manage-cms/terms-conditions",
}, Icon: GoDotFill,
{ },
title: "My Profile", // {
path: "/profile", // title: "Privacy",
Icon: BsPersonBadge, // path: "/manage-cms/privacy",
type:'single' // Icon: GoDotFill,
}, // },
{ ],
title: "Master Module", },
initPath: "/master-module", {
Icon: BsBoxes, title: "My Profile",
type:'multiple', path: "/profile",
children: [ Icon: BsPersonBadge,
{ type: 'single',
title: "Agency Master", resourceTitle: 'My Profile'
path: "/master-module/agency-master", },
Icon: GoDotFill, {
}, title: "Master Module",
{ initPath: "/master-module",
title: "Template Master", Icon: BsBoxes,
path: "/master-module/template-master", type: 'multiple',
Icon: GoDotFill, resourceTitle: 'Master Module',
}, children: [
{ {
title: "Job Type", title: "Agency Master",
path: "/master-module/job-type", path: "/master-module/agency-master",
Icon: GoDotFill, Icon: GoDotFill,
}, },
{ {
title: "Workspace Mode", title: "Template Master",
path: "/master-module/workspace-mode", path: "/master-module/template-master",
Icon: GoDotFill, Icon: GoDotFill,
}, },
{ {
title: "Country", title: "Job Type",
path: "/master-module/country", path: "/master-module/job-type",
Icon: GoDotFill, Icon: GoDotFill,
}, },
{ {
title: "Job Status", title: "Workspace Mode",
path: "/master-module/job-status", path: "/master-module/workspace-mode",
Icon: GoDotFill, Icon: GoDotFill,
}, },
{ {
title: "Industry Master", title: "Country",
path: "/master-module/industry-master", path: "/master-module/country",
Icon: GoDotFill, Icon: GoDotFill,
}, },
{ {
title: "Department Master", title: "Job Status",
path: "/master-module/department-master", path: "/master-module/job-status",
Icon: GoDotFill, Icon: GoDotFill,
}, },
], {
}, title: "Industry Master",
]; path: "/master-module/industry-master",
Icon: GoDotFill,
},
{
title: "Department Master",
path: "/master-module/department-master",
Icon: GoDotFill,
},
],
},
];

View File

@@ -11,13 +11,29 @@ import { FaUser } from "react-icons/fa";
// ✅ Register required components // ✅ Register required components
ChartJS.register(ArcElement, Tooltip, Legend); ChartJS.register(ArcElement, Tooltip, Legend);
const SemiDoughnutChart = () => { const SemiDoughnutChart = ({ totalUser }: { totalUser: any }) => {
const dataSource = totalUser ?? {}
const recruiterCount =
dataSource.past24hourRecruiterCount ??
dataSource.totalRecruiterCount ??
dataSource.newRecuiterCount ??
0;
const customerCount =
dataSource.past24hourCustomercount ??
dataSource.totalCustomerCount ??
dataSource.newCustomerCount ??
0;
// 📊 Chart Data // 📊 Chart Data
const data = { const data = {
labels: ["Recruiter", "Customer"], labels: ["Recruiter", "Customer"],
datasets: [ datasets: [
{ {
data: [2554, 2800], // Values data: [recruiterCount, customerCount], // Values
backgroundColor: ["#E0E0E0", "#3D5AFE"], // Grey and Blue backgroundColor: ["#E0E0E0", "#3D5AFE"], // Grey and Blue
borderWidth: 0, // No border borderWidth: 0, // No border
cutout: "90%", // Makes it a doughnut shape cutout: "90%", // Makes it a doughnut shape
@@ -50,9 +66,9 @@ const SemiDoughnutChart = () => {
fontSize: "20px", fontSize: "20px",
fontWeight: "bold", fontWeight: "bold",
color: "#3D5AFE", color: "#3D5AFE",
backgroundColor:'#ECEAF8', backgroundColor: '#ECEAF8',
padding:'15px', padding: '15px',
borderRadius:'50%' borderRadius: '50%'
}} }}
> >
<FaUser /> <FaUser />

View File

@@ -25,6 +25,8 @@ interface TableProps {
total: number; total: number;
}; };
onPageChange?: (page: number) => void; onPageChange?: (page: number) => void;
isLoading?: boolean;
isError?: boolean;
} }
const DataTable: React.FC<TableProps> = ({ const DataTable: React.FC<TableProps> = ({
@@ -33,6 +35,8 @@ const DataTable: React.FC<TableProps> = ({
sortableColumns = [], sortableColumns = [],
paginationData, paginationData,
onPageChange, onPageChange,
isLoading,
isError
}: TableProps) => { }: TableProps) => {
const { current_page = 1, last_page = 1 } = paginationData || {}; const { current_page = 1, last_page = 1 } = paginationData || {};
const [sortConfig, setSortConfig] = useState<{ const [sortConfig, setSortConfig] = useState<{
@@ -103,47 +107,65 @@ const DataTable: React.FC<TableProps> = ({
))} ))}
</Table.Row> </Table.Row>
</Table.Header> </Table.Header>
{data?.length === 0 ? ( {isLoading ? (
<Box> <Box textAlign={"center"} py={20} position="absolute" w="84%">
<Box textAlign={"center"} py={20} position={'absolute'} w={'84%'}> <Text fontSize={"18px"} fontWeight={500} mt={2}>
<Image src={EmptyFile} alt="No data" maxW="65px" mx="auto" /> Loading...
<Text fontSize={"18px"} fontWeight={500} mt={2}> </Text>
We do not have any records </Box>
</Text> ) : isError ? (
</Box> <Box textAlign={"center"} py={20} position="absolute" w="84%">
<Image src={EmptyFile} alt="No data" maxW="65px" mx="auto" />
<Text fontSize={"18px"} fontWeight={500} mt={2}>
No records found theyll appear here if available.
</Text>
</Box> </Box>
) : ( ) : (
<Table.Body h={"100%"}> <Table.Body h="100%">
{data.length === 0 && (
<Box textAlign={"center"} py={20} position="absolute" w="84%">
<Image src={EmptyFile} alt="No data" maxW="65px" mx="auto" />
<Text fontSize={"18px"} fontWeight={500} mt={2}>
No records found theyll appear here if available.
</Text>
</Box>
)}
{data.map((item: any, index) => ( {data.map((item: any, index) => (
<Table.Row <Table.Row
key={index} key={index}
bg={index % 2 === 0 ? "#fff" : "#007F3310"} bg={index % 2 === 0 ? "#fff" : "#007F3310"}
> >
{tableHeadRow.map((heading, colIndex) => ( {tableHeadRow.map((heading, colIndex) => {
<Table.Cell const cellContent = item[heading];
px={4} const words = typeof cellContent === 'string'
p={2} ? cellContent.split(" ")
key={`${index}-${colIndex}`} : cellContent?.toString().split(" ") || [];
fontSize={"xs"}
fontWeight={500} const truncated = words.length > 15
border={"none"} ? `${words.slice(0, 15).join(" ")}...`
> : cellContent;
{(() => {
const words = return (
item[heading]?.toString().split(" ") || []; <Table.Cell
return words.length > 5 px={4}
? `${words.slice(0, 5).join(" ")}...` p={2}
: item[heading]; key={`${index}-${colIndex}`}
})()} fontSize="xs"
</Table.Cell> fontWeight={500}
))} border="none"
>
{truncated}
</Table.Cell>
);
})}
</Table.Row> </Table.Row>
))} ))}
</Table.Body> </Table.Body>
)} )}
</Table.Root> </Table.Root>
</Table.ScrollArea> </Table.ScrollArea>
{last_page > 1 && ( {last_page > 1 && !isLoading && !isError && (
<PaginationRoot <PaginationRoot
count={paginationData?.total ?? 0} count={paginationData?.total ?? 0}
pageSize={paginationData?.per_page ?? 0} pageSize={paginationData?.per_page ?? 0}

View File

@@ -0,0 +1,16 @@
// hooks/useDebounce.ts
import { useEffect, useState } from "react";
export function useDebounce<T>(value: T, delay = 500): T {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebounced(value);
}, delay);
return () => clearTimeout(handler); // cleanup on unmount or value change
}, [value, delay]);
return debounced;
}

3
src/components/Utils.ts Normal file
View File

@@ -0,0 +1,3 @@
export const delay = (ms: number) => new Promise(res => setTimeout(res, ms));

View File

@@ -44,7 +44,7 @@ export const DialogCloseTrigger = React.forwardRef<
{...props} {...props}
asChild asChild
> >
<CloseButton size="sm" ref={ref}> <CloseButton size="sm" ref={ref} _hover={{ color: "gray.200" }}>
{props.children} {props.children}
</CloseButton> </CloseButton>
</ChakraDialog.CloseTrigger> </ChakraDialog.CloseTrigger>

View File

@@ -184,3 +184,22 @@ input:focus-visible {
.css-1ilznyv { .css-1ilznyv {
border: none; border: none;
} }
.custom-checkbox {
width: 16px;
height: 16px;
border: 2px solid black;
background-color: white;
appearance: none;
cursor: pointer;
position: relative;
}
.custom-checkbox:checked::after {
content: "✔";
color: black;
font-size: 16px;
position: absolute;
top: -2px;
left: 0px;
}