Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22e609194d | ||
|
|
900bf48de2 | ||
|
|
9f07032251 | ||
|
|
d81e55d51c | ||
|
|
c37c799b79 | ||
|
|
e8342aed66 |
24
.env
24
.env
@@ -1,23 +1,5 @@
|
|||||||
# VITE_API_URL='https://ssa.betadelivery.com/apia/v1'
|
VITE_API_URL='https://ssa.betadelivery.com/apia/v1'
|
||||||
# # VITE_API_URL='http://192.16.50.44/seo-backend/apia/v1'
|
# VITE_API_URL='http://192.16.50.44/seo-backend/apia/v1'
|
||||||
# VITE_USER_NAME="Admin"
|
|
||||||
# VITE_PASSWORD="71%@L%es^bUX94`J9XT*@bh,._WWM{$%^^&&"
|
|
||||||
# VITE_APP_NAME=MyViteApp
|
|
||||||
# VITE_IMG_TEMPLATES='https://ssa.betadelivery.com/storage/app/public/uploads/post_templates/'
|
|
||||||
# VITE_API_URL='https://ssa.betadelivery.com/testing/apia/v1'
|
|
||||||
# VITE_API_URL='https://ssa.betadelivery.com/apia/v1'
|
|
||||||
# VITE_USER_NAME="Admin"
|
|
||||||
# VITE_PASSWORD="71%@L%es^bUX94`J9XT*@bh,._WWM{$%^^&&"
|
|
||||||
# # VITE_PASSWORD="71%@L%es^bUX94`J9XT*%4&^%tUU^%Q^ffgt"
|
|
||||||
# VITE_APP_NAME=MyViteApp
|
|
||||||
# VITE_IMG_TEMPLATES='https://ssa.betadelivery.com/testing/storage/app/public/uploads/post_templates/'
|
|
||||||
# VITE_MAIN_URL='https://ssa.betadelivery.com/testing'
|
|
||||||
# VITE_POST_IMG=`${VITE_MAIN_URL}/storage/app/public/uploads/post/`
|
|
||||||
VITE_API_URL='https://ssa.betadelivery.com/testing/apia/v1'
|
|
||||||
VITE_USER_NAME="Admin"
|
VITE_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_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/`
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
VITE_API_URL='https://ssa.betadelivery.com/testing/apia/v1'
|
|
||||||
VITE_USER_NAME="Admin"
|
|
||||||
VITE_PASSWORD="71%@L%es^bUX94`J9XT*@bh,._WWM{$%^^&&"
|
|
||||||
VITE_APP_NAME=MyViteApp
|
|
||||||
VITE_IMG_TEMPLATES='https://ssa.betadelivery.com/storage/app/public/uploads/post_templates/'
|
|
||||||
VITE_MAIN_URL='https://ssa.betadelivery.com/testing'
|
|
||||||
VITE_POST_IMG=`${VITE_MAIN_URL}/storage/app/public/uploads/post/`
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -22,4 +22,3 @@ dist-ssr
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
*.env
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ define(['./workbox-54d0af47'], (function (workbox) { 'use strict';
|
|||||||
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
||||||
}, {
|
}, {
|
||||||
"url": "index.html",
|
"url": "index.html",
|
||||||
"revision": "0.73grfmd27h8"
|
"revision": "0.ahcfbbr0fl8"
|
||||||
}], {});
|
}], {});
|
||||||
workbox.cleanupOutdatedCaches();
|
workbox.cleanupOutdatedCaches();
|
||||||
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
||||||
|
|||||||
26
index.html
26
index.html
@@ -1,17 +1,13 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
<head>
|
||||||
<head>
|
<meta charset="UTF-8" />
|
||||||
<meta charset="UTF-8" name="referrer" content="strict-origin-when-cross-origin" />
|
<link rel="icon" type="image/svg+xml" href="/src/assets/favicon.png" />
|
||||||
<!-- <link rel="icon" type="image/png+xml" href="/src/assets/favicon.png" /> -->
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
<title>SEO Admin</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
</head>
|
||||||
<title>SEO Admin</title>
|
<body>
|
||||||
</head>
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
<body>
|
</body>
|
||||||
<div id="root"></div>
|
</html>
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|||||||
4790
package-lock.json
generated
4790
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -30,7 +30,7 @@
|
|||||||
"vite-plugin-pwa": "^0.21.1"
|
"vite-plugin-pwa": "^0.21.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@chakra-ui/cli": "^2.4.1",
|
"@chakra-ui/cli": "^3.2.3",
|
||||||
"@eslint/js": "^9.17.0",
|
"@eslint/js": "^9.17.0",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/react": "^18.3.18",
|
"@types/react": "^18.3.18",
|
||||||
|
|||||||
55
src/App.tsx
55
src/App.tsx
@@ -4,15 +4,12 @@ import GlobalStateContext from "./Contexts/GlobalStateContext";
|
|||||||
import DefaultLayout from "./Layouts/DefaultLayout";
|
import DefaultLayout from "./Layouts/DefaultLayout";
|
||||||
import Login from "./Pages/Login";
|
import Login from "./Pages/Login";
|
||||||
import { RouteLink } from "./Routes/Routes";
|
import { RouteLink } from "./Routes/Routes";
|
||||||
import ForgotPassword from "./Pages/ForgotPassword";
|
|
||||||
import VerifyEnterOTP from "./Pages/VerifyEnterOTP";
|
|
||||||
import SetNewPassword from "./Pages/SetNewPassword";
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const context = useContext(GlobalStateContext);
|
const context = useContext(GlobalStateContext);
|
||||||
if (!context) throw new Error("App must be used within a GlobalStateProvider");
|
if (!context) throw new Error("App must be used within a GlobalStateProvider");
|
||||||
|
|
||||||
const { isAuthenticate, setIsAuthenticate } = context;
|
const { isAuthenticate, setIsAuthenticate } = context;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const token = localStorage.getItem("token");
|
const token = localStorage.getItem("token");
|
||||||
@@ -21,19 +18,16 @@ function App() {
|
|||||||
|
|
||||||
console.log("Auth Status:", isAuthenticate);
|
console.log("Auth Status:", isAuthenticate);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
<Routes>
|
<Routes>
|
||||||
{/* Redirect logged-in users away from login */}
|
{/* Redirect logged-in users away from login */}
|
||||||
<Route path="/login" element={isAuthenticate && localStorage.getItem("token") ? <Navigate to="/" /> : <Login />} />
|
<Route path="/login" element={isAuthenticate && localStorage.getItem("token") ? <Navigate to="/" /> : <Login />} />
|
||||||
<Route path="/forgot-password" element={<ForgotPassword />} />
|
|
||||||
<Route path="/forgot-password/verify-otp" element={<VerifyEnterOTP />} />
|
|
||||||
<Route path="/forgot-password/reset-password" element={<SetNewPassword />} />
|
|
||||||
|
|
||||||
{/* Protected Routes */}
|
{/* Protected Routes */}
|
||||||
<Route
|
<Route
|
||||||
path="/*"
|
path="/*"
|
||||||
element={isAuthenticate && localStorage.getItem("token") ? (
|
element={isAuthenticate && localStorage.getItem("token") ? (
|
||||||
<DefaultLayout>
|
<DefaultLayout>
|
||||||
<Routes>
|
<Routes>
|
||||||
{RouteLink.map(({ path, Component }, index) => (
|
{RouteLink.map(({ path, Component }, index) => (
|
||||||
@@ -42,24 +36,15 @@ function App() {
|
|||||||
</Routes>
|
</Routes>
|
||||||
</DefaultLayout>
|
</DefaultLayout>
|
||||||
) : (
|
) : (
|
||||||
<Routes>
|
<Navigate to="/login" />
|
||||||
{/* Allow only forgot password flows */}
|
)}
|
||||||
<Route path="/forgot-password" element={<ForgotPassword />} />
|
/>
|
||||||
<Route path="/forgot-password/verify" element={<VerifyEnterOTP />} /> {/* ✅ Add this line */}
|
|
||||||
<Route path="/forgot-password/verify-otp" element={<VerifyEnterOTP />} />
|
|
||||||
<Route path="/forgot-password/reset-password" element={<SetNewPassword />} />
|
|
||||||
|
|
||||||
{/* Default to login */}
|
|
||||||
<Route path="*" element={<Navigate to="/login" />} />
|
|
||||||
</Routes>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Catch-all route to prevent unauthorized access */}
|
{/* Catch-all route to prevent unauthorized access */}
|
||||||
<Route path="*" element={<Navigate to="/login" />} />
|
<Route path="*" element={<Navigate to="/login" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ 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);
|
||||||
|
|||||||
@@ -6,10 +6,6 @@ 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) : [];
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -19,8 +15,6 @@ const GlobalStateProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
setIsAuthenticate,
|
setIsAuthenticate,
|
||||||
isBarLoading,
|
isBarLoading,
|
||||||
setIsBarLoading, // ✅ Fixed typo
|
setIsBarLoading, // ✅ Fixed typo
|
||||||
userAccess,
|
|
||||||
setUserAccess
|
|
||||||
}}>
|
}}>
|
||||||
{children}
|
{children}
|
||||||
</GlobalStateContext.Provider>
|
</GlobalStateContext.Provider>
|
||||||
|
|||||||
@@ -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';
|
||||||
@@ -12,12 +12,9 @@ import { useDispatch } from "react-redux";
|
|||||||
import GlobalStateContext from "../Contexts/GlobalStateContext";
|
import GlobalStateContext from "../Contexts/GlobalStateContext";
|
||||||
import { useLogOutMutation } from "../Redux/Service/apiSlice";
|
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";
|
|
||||||
|
|
||||||
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 dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
@@ -27,25 +24,21 @@ 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, userAccess } = context;
|
const { setIsAuthenticate, isBarLoading } = 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 () => {
|
||||||
try {
|
try {
|
||||||
// ✅ Call mutation and wait for the response
|
// ✅ Call mutation and wait for the response
|
||||||
const res = await logOutAdmin().unwrap();
|
const res = await logOutAdmin().unwrap();
|
||||||
console.log("Logout Success:", res);
|
console.log("Logout Success:", res);
|
||||||
|
|
||||||
// ✅ Clear local storage & update authentication state
|
// ✅ Clear local storage & update authentication state
|
||||||
dispatch(logout());
|
dispatch(logout());
|
||||||
localStorage.removeItem("token");
|
localStorage.removeItem("token");
|
||||||
setIsAuthenticate(false);
|
setIsAuthenticate(false);
|
||||||
// ✅ Redirect to login page
|
// ✅ Redirect to login page
|
||||||
navigate("/login");
|
navigate("/login");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -55,43 +48,43 @@ const DefaultLayout: FC<{ children: React.ReactNode }> = ({ children }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<VStack gap={0} w="100%" h="100vh" bg="#F2F2F2">
|
<VStack gap={0} w="100%" h="100vh" bg="#F2F2F2">
|
||||||
<ProgressBar isLoading={isBarLoading} />
|
<ProgressBar isLoading={isBarLoading} />
|
||||||
<HStack overflow={'hidden'} position={'relative'} bg="#F2F2F2" backgroundPosition="center" backgroundRepeat="repeat" backgroundSize="cover" gap={0} w="100%" h="calc(100% - 4px)" p={0}>
|
<HStack overflow={'hidden'} position={'relative'} bg="#F2F2F2" backgroundPosition="center" backgroundRepeat="repeat" backgroundSize="cover" gap={0} w="100%" h="calc(100% - 4px)" p={0}>
|
||||||
|
|
||||||
<VStack pt={0} zIndex={1} gap={0} rounded={'lg'} h="100%" w="15%" overflow={'auto'} >
|
<VStack pt={0} zIndex={1} gap={0} rounded={'lg'} h="100%" w="15%" overflow={'auto'} >
|
||||||
<HStack w={'100%'} p={3} h={'7%'} justifyContent={'center'}>
|
<HStack w={'100%'} p={3} h={'7%'} justifyContent={'center'}>
|
||||||
<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}>
|
||||||
{filteredNav?.map(({ title, path, Icon, type, children, initPath }, index) => type === 'single' ?
|
{nav?.map(({ title, path, Icon, type, children, initPath }, index) => type === 'single' ?
|
||||||
<NavLink className="link" key={index} to={path || ''} style={{ cursor: 'pointer', borderRadius: '8px', padding: '6px', width: '100%', display: 'flex', alignItems: 'center', gap: 6, border: '1px solid #ffffff', backgroundColor: '#fff', color: '#000', boxShadow: 'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px' }} ><Icon style={{ fontSize: '20px' }} /> <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}>
|
||||||
<AccordionItemTrigger className="Oxygen" color={'#fff'} onClick={() => navigate(path || '')} gap={0} style={{ cursor: 'pointer', borderRadius: '8px', padding: '5px', width: '100%', display: 'flex', alignItems: 'center', border: '1px solid #ffffff', backgroundColor: '#fff', color: '#000', fontSize: '14px', }}> <Text fontSize={'xs'} gap={1} display={'flex'} alignItems={'center'} ><Icon style={{ fontSize: '20px' }} />{title}</Text></AccordionItemTrigger>
|
<AccordionItemTrigger className="Oxygen" color={'#fff'} onClick={() => navigate(path)} gap={0} style={{ cursor: 'pointer', borderRadius: '8px', padding: '5px', width: '100%', display: 'flex', alignItems: 'center', border: '1px solid #ffffff', backgroundColor:'#fff',color:'#000', fontSize: '14px', }}> <Text fontSize={'xs'} gap={1} display={'flex'} alignItems={'center'} ><Icon style={{ fontSize: '20px' }} />{title}</Text></AccordionItemTrigger>
|
||||||
{children?.map(({ title, path, Icon }, index) => <AccordionItemContent className={`linkChild Oxygen ${location?.pathname === path && 'activeChild'}`} key={index} onClick={() => navigate(path)} style={{ marginTop: 6, cursor: 'pointer', borderRadius: '8px', padding: '6px', width: '100%', display: 'flex', alignItems: 'center', gap: 6, border: '1px solid #ffffff', backgroundColor: '#fff', color: '#919198' }} ><Icon style={{ fontSize: '20px' }} /> <Text fontSize={'xs'} w={'100%'}>{title}</Text></AccordionItemContent>)}
|
{children?.map(({ title, path, Icon }, index) => <AccordionItemContent className={`linkChild Oxygen ${location?.pathname === path && 'activeChild'}`} key={index} onClick={()=>navigate(path)} style={{ marginTop: 6, cursor: 'pointer', borderRadius: '8px', padding: '6px', width: '100%', display: 'flex', alignItems: 'center', gap: 6, border: '1px solid #ffffff', backgroundColor:'#fff',color:'#919198' }} ><Icon style={{ fontSize: '20px' }} /> <Text fontSize={'xs'} w={'100%'}>{title}</Text></AccordionItemContent>)}
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
</AccordionRoot>)}
|
</AccordionRoot>)}
|
||||||
</VStack>
|
|
||||||
<VStack w={'100%'} p={3} pt={0}>
|
|
||||||
<HStack onClick={handleLogout} className="link" style={{ cursor: 'pointer', borderRadius: '8px', padding: '6px', width: '100%', display: 'flex', alignItems: 'center', gap: 6, border: '1px solid #ffffff', backgroundColor: '#fff', color: '#000', boxShadow: 'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px' }} ><LuLogOut style={{ fontSize: '20px' }} /> <Text fontSize={'xs'} w={'100%'}>Logout</Text></HStack>
|
|
||||||
</VStack>
|
|
||||||
</VStack>
|
</VStack>
|
||||||
<VStack gap={0} h="100%" w="85%" >
|
<VStack w={'100%'} p={3} pt={0}>
|
||||||
|
<HStack onClick={handleLogout} className="link" style={{ cursor: 'pointer', borderRadius: '8px', padding: '6px', width: '100%', display: 'flex', alignItems: 'center', gap: 6, border: '1px solid #ffffff', backgroundColor:'#fff', color:'#000', boxShadow:'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'}} ><LuLogOut style={{ fontSize: '20px' }} /> <Text fontSize={'xs'} w={'100%'}>Logout</Text></HStack>
|
||||||
<HStack h={'11%'} w={'100%'} justifyContent={'flex-end'} pe={3} gap={6}>
|
|
||||||
|
|
||||||
{/* <NavLink to={'/manage-notification'}><RiNotificationLine color="#013e3e" cursor={'pointer'} style={{ fontSize: '22px' }} /></NavLink> */}
|
|
||||||
<HStack cursor={'pointer'} onClick={() => navigate('/profile')} >
|
|
||||||
<Avatar size={'sm'} src={`${PROFILEIMGURL}${data?.data.profile_photo}`} />
|
|
||||||
<VStack color={'#013e3e'} gap={0} alignItems={'flex-start'}>
|
|
||||||
<Text fontSize={'sm'} fontWeight={'bold'}>{data?.data?.first_name ? `${data?.data?.first_name.charAt(0).toUpperCase()}${data?.data.first_name.slice(1)}` : ''}</Text>
|
|
||||||
<Text fontSize={'xs'} >{data?.data?.phone_number ? data?.data?.phone_number : ''}</Text>
|
|
||||||
</VStack>
|
|
||||||
</HStack>
|
|
||||||
</HStack>
|
|
||||||
{children}
|
|
||||||
</VStack>
|
</VStack>
|
||||||
</HStack>
|
</VStack>
|
||||||
|
<VStack gap={0} h="100%" w="85%" >
|
||||||
|
|
||||||
|
<HStack h={'11%'} w={'100%'} justifyContent={'flex-end'} pe={3} gap={6}>
|
||||||
|
|
||||||
|
<NavLink to={'/manage-notification'}><RiNotificationLine color="#013e3e" cursor={'pointer'} style={{ fontSize: '22px' }} /></NavLink>
|
||||||
|
<HStack cursor={'pointer'} onClick={() => navigate('/profile')} >
|
||||||
|
<Avatar size={'sm'} src="https://i.pinimg.com/736x/d6/cd/0f/d6cd0ffd4634b0763d3958a7325ce26e.jpg" />
|
||||||
|
<VStack color={'#013e3e'} gap={0} alignItems={'flex-start'}>
|
||||||
|
<Text fontSize={'sm'} fontWeight={'bold'}>Ritesh Pandey</Text>
|
||||||
|
<Text fontSize={'xs'} >ritesh.pandey@wdimails.com</Text>
|
||||||
|
</VStack>
|
||||||
|
</HStack>
|
||||||
|
</HStack>
|
||||||
|
{children}
|
||||||
|
</VStack>
|
||||||
|
</HStack>
|
||||||
</VStack>
|
</VStack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,68 +1,61 @@
|
|||||||
import {
|
import { Box, HStack, Image, Input, Stack, Text } from "@chakra-ui/react";
|
||||||
Box,
|
import React, { useState, useEffect } from "react";
|
||||||
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 = ({ agencyList }: { agencyList: AgencyList }) => {
|
const AgencyName: React.FC = () => {
|
||||||
// const [todos, setTodos] = useState<Todo[]>([]);
|
const [todos, setTodos] = useState<Todo[]>([]);
|
||||||
// const [input, setInput] = useState<string>("");
|
const [input, setInput] = useState<string>("");
|
||||||
|
|
||||||
|
|
||||||
|
const getCurrentTime = () => {
|
||||||
|
const now = new Date();
|
||||||
|
return now.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// const getCurrentTime = () => {
|
const addTodo = () => {
|
||||||
// const now = new Date();
|
if (input.trim() === "") return;
|
||||||
// return now.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
setTodos([...todos, { id: Date.now(), text: input, completed: false, timestamp: getCurrentTime() }]);
|
||||||
// };
|
setInput("");
|
||||||
|
};
|
||||||
|
|
||||||
// const addTodo = () => {
|
|
||||||
// if (input.trim() === "") return;
|
|
||||||
// setTodos([...todos, { id: Date.now(), text: input, completed: false, timestamp: getCurrentTime() }]);
|
|
||||||
// setInput("");
|
|
||||||
// };
|
|
||||||
|
|
||||||
// Delete a task
|
// 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}>
|
||||||
Agency List
|
Add Agency Name
|
||||||
</Text>
|
</Text>
|
||||||
{/* <Button
|
<Button
|
||||||
bg={"#fff"}
|
bg={"#fff"}
|
||||||
color={"#222222CC"}
|
color={"#222222CC"}
|
||||||
px={3}
|
px={3}
|
||||||
@@ -71,18 +64,9 @@ const AgencyName = ({ agencyList }: { agencyList: AgencyList }) => {
|
|||||||
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)}
|
||||||
@@ -92,14 +76,14 @@ const AgencyName = ({ agencyList }: { agencyList: AgencyList }) => {
|
|||||||
w={"100%"}
|
w={"100%"}
|
||||||
p={2}
|
p={2}
|
||||||
mb={4}
|
mb={4}
|
||||||
/> */}
|
/>
|
||||||
{agencyList?.data.map((todo) => (
|
{todos.map((todo) => (
|
||||||
<HStack key={todo.id} backgroundColor={"#fff"} rounded={5} mb={3} p={4} justifyContent={'space-between'} alignItems={'inherit'}>
|
<HStack key={todo.id} backgroundColor={"#fff"} rounded={5} mb={3} p={4} justifyContent={'space-between'} alignItems={'inherit'}>
|
||||||
<Text fontSize={'sm'} color={'#222222bd'} fontWeight={400}>{todo.name}</Text>
|
<Text fontSize={'sm'} color={'#222222bd'} fontWeight={400}>{todo.text}</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)}
|
||||||
@@ -109,7 +93,7 @@ const AgencyName = ({ agencyList }: { agencyList: AgencyList }) => {
|
|||||||
>
|
>
|
||||||
<Image w={"16px"} src={delateIcon} />
|
<Image w={"16px"} src={delateIcon} />
|
||||||
</Box>
|
</Box>
|
||||||
</Stack> */}
|
</Stack>
|
||||||
</HStack>
|
</HStack>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -26,31 +26,9 @@ 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 { Spinner } from "../../components/Sipnner/Spinner";
|
||||||
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" },
|
||||||
@@ -60,35 +38,40 @@ 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.",
|
||||||
// },
|
},
|
||||||
// ];
|
{
|
||||||
|
value: "5",
|
||||||
|
title: "How to create new account?",
|
||||||
|
text: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since. Lorem Ipsum has been the industry's standard dummy text ever since.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainFrame>
|
<MainFrame>
|
||||||
<Box display={"flex"} p={"20px"} pe={'20px'} gap={5}>
|
<Box display={"flex"} p={"20px"} pt={'8px'} 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 : {totalUsers?.data?.totalUserCount ?? 0}
|
Total Users
|
||||||
</Heading>
|
</Heading>
|
||||||
<Tabs.Root
|
<Tabs.Root
|
||||||
size={"sm"}
|
size={"sm"}
|
||||||
@@ -97,8 +80,6 @@ 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>
|
||||||
@@ -114,7 +95,7 @@ const Dashboard = () => {
|
|||||||
</Tabs.List>
|
</Tabs.List>
|
||||||
</Tabs.Root>
|
</Tabs.Root>
|
||||||
<Box>
|
<Box>
|
||||||
{totalUser && <SemiDoughnutChart totalUser={totalUser} />}
|
<SemiDoughnutChart />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
@@ -126,17 +107,17 @@ const Dashboard = () => {
|
|||||||
>
|
>
|
||||||
<Status.Root colorPalette="blue">
|
<Status.Root colorPalette="blue">
|
||||||
<Status.Indicator />
|
<Status.Indicator />
|
||||||
Recruiter <Text fontWeight={500}>{totalUser?.past24hourRecruiterCount ?? totalUser?.totalRecruiterCount ?? totalUser?.newRecuiterCount }</Text>
|
Recruiter <Text fontWeight={500}>2554</Text>
|
||||||
</Status.Root>
|
</Status.Root>
|
||||||
<Status.Root colorPalette="blue">
|
<Status.Root colorPalette="blue">
|
||||||
<Status.Indicator />
|
<Status.Indicator />
|
||||||
Customer <Text fontWeight={500}>{totalUser?.past24hourCustomercount ?? totalUser?.totalCustomerCount ?? totalUser?.newCustomerCount}</Text>
|
Customer <Text fontWeight={500}>1224</Text>
|
||||||
</Status.Root>
|
</Status.Root>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
<Box
|
||||||
p={"20px"}
|
p={"20px"}
|
||||||
w={"49%"}
|
w={"50%"}
|
||||||
rounded={'lg'}
|
rounded={'lg'}
|
||||||
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
|
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
|
||||||
>
|
>
|
||||||
@@ -168,7 +149,7 @@ const Dashboard = () => {
|
|||||||
</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"} overflowY={'scroll'} height={'292px'}>
|
<Box w={"50%"} rounded={'lg'} bg={"#f2f2f2"} h={400} p={"10px"} overflow={'auto'}>
|
||||||
<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
|
||||||
@@ -178,15 +159,14 @@ const Dashboard = () => {
|
|||||||
fontSize={"12px"}
|
fontSize={"12px"}
|
||||||
h={"28px"}
|
h={"28px"}
|
||||||
>
|
>
|
||||||
<Link to="/manage-cms/faq">View ALL</Link>
|
View ALL
|
||||||
</Button>
|
</Button>
|
||||||
</HStack>
|
</HStack>
|
||||||
<AccordionRoot collapsible defaultValue={["b"]}>
|
<AccordionRoot collapsible defaultValue={["b"]}>
|
||||||
{faqList?.data.map((item) => (
|
{accItems.map((item, index) => (
|
||||||
<AccordionItem
|
<AccordionItem
|
||||||
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"}
|
||||||
@@ -194,19 +174,20 @@ const Dashboard = () => {
|
|||||||
borderBottom={0}
|
borderBottom={0}
|
||||||
>
|
>
|
||||||
<AccordionItemTrigger fontSize={"sm"} >
|
<AccordionItemTrigger fontSize={"sm"} >
|
||||||
{item.question}
|
{item.title}
|
||||||
</AccordionItemTrigger>
|
</AccordionItemTrigger>
|
||||||
<AccordionItemContent fontSize={"xs"} color={'#222222CC'} pt={2}>
|
<AccordionItemContent fontSize={"xs"} color={'#222222CC'} pt={2}>
|
||||||
{item.answer}
|
{item.text}
|
||||||
</AccordionItemContent>
|
</AccordionItemContent>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
))}
|
))}
|
||||||
</AccordionRoot>
|
</AccordionRoot>
|
||||||
</Box>
|
</Box>
|
||||||
<Box w={"50%"} rounded={'lg'} bg={"#f2f2f2"} alignItems={'flex-start'} overflowY={'scroll'} height={'292px'}>
|
<Box w={"50%"} rounded={'lg'} bg={"#f2f2f2"} h={400} overflow={'auto'}>
|
||||||
{agencyList && <AgencyName agencyList={agencyList}/>}
|
<AgencyName />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
</MainFrame>
|
</MainFrame>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,171 +0,0 @@
|
|||||||
import {
|
|
||||||
Box,
|
|
||||||
Center,
|
|
||||||
HStack,
|
|
||||||
Image,
|
|
||||||
Input,
|
|
||||||
Text,
|
|
||||||
VStack,
|
|
||||||
} from "@chakra-ui/react";
|
|
||||||
import axios from "axios";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { useForm } from "react-hook-form";
|
|
||||||
// import { useDispatch } from "react-redux";
|
|
||||||
import logo from "../assets/logo.svg";
|
|
||||||
import { Button } from "../components/ui/button";
|
|
||||||
import { Field } from "../components/ui/field";
|
|
||||||
import { toaster, Toaster } from "../components/ui/toaster";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
|
|
||||||
interface FormValues {
|
|
||||||
mobileNumber: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ForgotPassword = () => {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
|
||||||
const {
|
|
||||||
register,
|
|
||||||
handleSubmit,
|
|
||||||
formState: { errors },
|
|
||||||
} = useForm<FormValues>();
|
|
||||||
|
|
||||||
const onSubmit = handleSubmit(async (data) => {
|
|
||||||
const username = import.meta.env.VITE_USER_NAME || ""; // Replace with actual username
|
|
||||||
const password = import.meta.env.VITE_PASSWORD || ""; // Replace with actual password
|
|
||||||
const basicAuth = `${username}:${password}`; // Encode to Base64
|
|
||||||
|
|
||||||
setIsLoading(true);
|
|
||||||
try {
|
|
||||||
const res = await axios.post(
|
|
||||||
`${import.meta.env.VITE_API_URL}/send-otp`,
|
|
||||||
{
|
|
||||||
mobile_number: Number(data.mobileNumber),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Basic ${basicAuth}`,
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (res.status === 200) {
|
|
||||||
navigate(`/forgot-password/verify?phone=${data.mobileNumber}`)
|
|
||||||
} else {
|
|
||||||
// alert(res.data.message || "Something went wrong");
|
|
||||||
toaster.create({
|
|
||||||
// title: error?.response?.data?.message,
|
|
||||||
title: res.data.message || "Something went wrong",
|
|
||||||
type: "error",
|
|
||||||
})
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
console.log("============", res);
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log('error', error);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
toaster.create({
|
|
||||||
// title: error?.response?.data?.message,
|
|
||||||
title: "Something Went Wrong",
|
|
||||||
type: "info",
|
|
||||||
})
|
|
||||||
// console.log("Login failed", error?.response?.data?.message);
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
|
|
||||||
<VStack appearance={'light'} w={"100%"} h={"100vh"} bg={"#ffffff"}>
|
|
||||||
<HStack
|
|
||||||
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
|
|
||||||
w={"100%"}
|
|
||||||
ps={8}
|
|
||||||
h={"7%"}
|
|
||||||
justifyContent={"flex-start"}
|
|
||||||
>
|
|
||||||
<Image w={50} src={logo} />
|
|
||||||
</HStack>
|
|
||||||
|
|
||||||
<HStack w={"100%"} h={"93%"} p={8} gap={8}>
|
|
||||||
<Center
|
|
||||||
display={{ base: "none", md: "flex" }}
|
|
||||||
bg={"#02A0A033"}
|
|
||||||
w={"50%"}
|
|
||||||
h={"100%"}
|
|
||||||
rounded={"3xl"}
|
|
||||||
>
|
|
||||||
<Image w={250} src={logo} />
|
|
||||||
</Center>
|
|
||||||
|
|
||||||
<Box
|
|
||||||
as={"form"}
|
|
||||||
onSubmit={onSubmit}
|
|
||||||
p={{ base: 4, md: 16 }}
|
|
||||||
w={{ base: "100%", md: "50%" }}
|
|
||||||
h={"100%"}
|
|
||||||
>
|
|
||||||
<VStack gap={2} w={"100%"}>
|
|
||||||
<Text
|
|
||||||
w={"100%"}
|
|
||||||
textAlign={"center"}
|
|
||||||
fontSize={"24px"}
|
|
||||||
fontWeight={"normal"}
|
|
||||||
color={"#313039"}
|
|
||||||
>
|
|
||||||
Forgot Password
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Box mt={6} gap={4} w={"full"}>
|
|
||||||
<Field
|
|
||||||
color={"#313039"}
|
|
||||||
label={"Enter Mobile Number"}
|
|
||||||
w={"100%"}
|
|
||||||
invalid={!!errors.mobileNumber}
|
|
||||||
errorText={errors.mobileNumber?.message}
|
|
||||||
mb={4}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
type="number"
|
|
||||||
ps={3}
|
|
||||||
maxLength={10}
|
|
||||||
{...register("mobileNumber", {
|
|
||||||
required: "Please enter a 10 digit mobile number",
|
|
||||||
pattern: {
|
|
||||||
value: /^[0-9]{10}$/,
|
|
||||||
message: "Mobile number must be exactly 10 digits"
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
placeholder="Enter Mobile Number"
|
|
||||||
onInput={(e) => {
|
|
||||||
const target = e.target as HTMLInputElement;
|
|
||||||
target.value = target.value.replace(/\D/g, "").slice(0, 10);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
<Button
|
|
||||||
loading={isLoading}
|
|
||||||
mt={4}
|
|
||||||
size={"sm"}
|
|
||||||
bg={"#02A0A0"}
|
|
||||||
rounded={"md"}
|
|
||||||
w={"100%"}
|
|
||||||
color={"#ffffff"}
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
Send OTP
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</VStack>
|
|
||||||
</Box>
|
|
||||||
<Toaster />
|
|
||||||
</HStack>
|
|
||||||
</VStack>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ForgotPassword;
|
|
||||||
@@ -18,8 +18,8 @@ import { Button } from "../components/ui/button";
|
|||||||
import { Field } from "../components/ui/field";
|
import { Field } from "../components/ui/field";
|
||||||
import { toaster, Toaster } from "../components/ui/toaster";
|
import { toaster, Toaster } from "../components/ui/toaster";
|
||||||
import { PasswordInput } from "../components/ui/password-input";
|
import { PasswordInput } from "../components/ui/password-input";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
// import ForgetPassword from "./ForgetPassword";
|
import ForgetPassword from "./ForgetPassword";
|
||||||
|
|
||||||
interface FormValues {
|
interface FormValues {
|
||||||
mobileNumber: number;
|
mobileNumber: number;
|
||||||
@@ -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, setUserAccess } = context;
|
const { setIsAuthenticate } = 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 || "";
|
const username = import.meta.env.VITE_USER_NAME || ""; // Replace with actual username
|
||||||
const password = import.meta.env.VITE_PASSWORD || "";
|
const password = import.meta.env.VITE_PASSWORD || ""; // Replace with actual password
|
||||||
const basicAuth = `${username}:${password}`;
|
const basicAuth = `${username} : ${password}`; // Encode to Base64
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await axios.post(
|
const res = await axios.post(
|
||||||
@@ -62,36 +62,35 @@ const Login = () => {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
console.log("============",res);
|
||||||
|
|
||||||
|
|
||||||
const loginData = res.data?.data;
|
if (res.data) {
|
||||||
const { principal_type_xid, role_permission } = loginData;
|
setIsAuthenticate(true);
|
||||||
|
console.log("====================================");
|
||||||
const isAdmin = principal_type_xid === 1;
|
console.log(res.data?.data);
|
||||||
|
console.log("====================================");
|
||||||
const allowedTitles = isAdmin
|
navigate("/dashboard");
|
||||||
? ['*']
|
dispatch(setToken(String(res.data?.data["access-token"])));
|
||||||
: role_permission?.get_resource_action_link
|
} else {
|
||||||
?.filter((link: unknown) => (link as any).is_active)
|
console.log("====================================");
|
||||||
.map((link: unknown) => (link as any).app_resource.app_resource_title) ?? [];
|
console.log(res);
|
||||||
|
console.log("====================================");
|
||||||
setIsAuthenticate(true);
|
}
|
||||||
setUserAccess(allowedTitles);
|
} catch (error) {
|
||||||
dispatch(setToken(String(loginData["access-token"])));
|
console.log('error', error);
|
||||||
sessionStorage.setItem('userAccess', JSON.stringify(allowedTitles));
|
|
||||||
navigate("/dashboard");
|
if (error) {
|
||||||
setIsLoading(false);
|
toaster.create({
|
||||||
|
// title: error?.response?.data?.message,
|
||||||
} catch (error: any) {
|
title: "Something Went Wrong",
|
||||||
console.log('error', error?.response?.data?.message);
|
type: "info",
|
||||||
toaster.create({
|
})
|
||||||
title: "Error",
|
// console.log("Login failed", error?.response?.data?.message);
|
||||||
description: error?.response?.data?.message || "Login failed",
|
setIsLoading(false);
|
||||||
type: "error",
|
}
|
||||||
});
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// console.log("User Access in Context:", userAccess);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
@@ -182,15 +181,7 @@ const Login = () => {
|
|||||||
Login
|
Login
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{/* <ForgetPassword /> */}
|
<ForgetPassword />
|
||||||
<Box textAlign={"center"} mt={4}>
|
|
||||||
<Link
|
|
||||||
to={'/forgot-password'}
|
|
||||||
style={{ color: "black", fontSize: "16px" }}
|
|
||||||
>
|
|
||||||
Forgot Password
|
|
||||||
</Link>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
</Box>
|
||||||
</VStack>
|
</VStack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -1,132 +1,68 @@
|
|||||||
// import { Badge, HStack, Text, VStack } from "@chakra-ui/react";
|
import { Box, HStack, Skeleton, Text } from "@chakra-ui/react";
|
||||||
// import MainFrame from "../../../components/MainFrame"
|
import MainFrame from "../../../components/MainFrame"
|
||||||
// import { useGetAboutUsQuery } from "../../../Redux/Service/manage.aboutus.service";
|
import AboutUsAddModel from "../../ManageCMS/AboutUs/AboutUsAddModel";
|
||||||
// import { Spinner } from "../../../components/Sipnner/Spinner";
|
|
||||||
// import GlobalStateContext from "../../../Contexts/GlobalStateContext";
|
|
||||||
// import { useContext, useEffect } from "react";
|
|
||||||
// import AboutUsAddModel from "./AboutUsAddModel";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// const AboutUs = () => {
|
|
||||||
|
|
||||||
// const { data, isLoading, isFetching } = useGetAboutUsQuery();
|
|
||||||
|
|
||||||
// // const content = data?.data
|
|
||||||
// console.log('====================================');
|
|
||||||
// console.log(data);
|
|
||||||
// console.log('====================================');
|
|
||||||
|
|
||||||
// const context = useContext(GlobalStateContext);
|
|
||||||
// if (!context) throw new Error('App must be used within a GlobalStateProvider');
|
|
||||||
|
|
||||||
// const { setIsBarLoading } = context;
|
|
||||||
// useEffect(() => {
|
|
||||||
// setIsBarLoading(isFetching)
|
|
||||||
// }, [data])
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <MainFrame transperant={true}>
|
|
||||||
// <VStack gap={4} pb={4} pt={0}>
|
|
||||||
// {isLoading || isFetching ?
|
|
||||||
// <Spinner /> : data?.data?.map(({ id, content, about_language }) => <VStack bg={'#fff'}
|
|
||||||
// boxShadow={'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'} rounded={'lg'} p={3} key={id}>
|
|
||||||
// <HStack
|
|
||||||
// w={"100%"}
|
|
||||||
// justifyContent={"space-between"}
|
|
||||||
|
|
||||||
// py={0}
|
|
||||||
// px={0}
|
|
||||||
// >
|
|
||||||
// <Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
|
||||||
// About Us <Badge variant={'surface'} colorPalette="cyan" ms={2} size={'sm'} fontSize={'xs'} px={2}>🎓 {about_language?.language_name}</Badge>
|
|
||||||
// </Text>
|
|
||||||
|
|
||||||
// {/* <AboutUsAddModel /> */}
|
|
||||||
// <AboutUsAddModel/>
|
|
||||||
// </HStack>
|
|
||||||
// <Text
|
|
||||||
// as="p"
|
|
||||||
// fontSize="sm"
|
|
||||||
// fontWeight={400}
|
|
||||||
// color="#1D1D1D"
|
|
||||||
// >
|
|
||||||
// {content}
|
|
||||||
// </Text>
|
|
||||||
|
|
||||||
// </VStack>)}
|
|
||||||
// </VStack>
|
|
||||||
// </MainFrame>
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// export default AboutUs
|
|
||||||
|
|
||||||
import { Badge, HStack, Stack, Text, VStack } from "@chakra-ui/react";
|
|
||||||
import MainFrame from "../../../components/MainFrame";
|
|
||||||
import { useGetAboutUsQuery } from "../../../Redux/Service/manage.aboutus.service";
|
import { useGetAboutUsQuery } from "../../../Redux/Service/manage.aboutus.service";
|
||||||
import { Spinner } from "../../../components/Sipnner/Spinner";
|
|
||||||
import GlobalStateContext from "../../../Contexts/GlobalStateContext";
|
|
||||||
import { useContext, useEffect } from "react";
|
|
||||||
import AboutUsAddModel from "./AboutUsAddModel";
|
|
||||||
|
|
||||||
const AboutUs = () => {
|
const AboutUs = () => {
|
||||||
const { data, isLoading, isFetching } = useGetAboutUsQuery();
|
|
||||||
|
|
||||||
console.log("Fetched About Us Data:", data);
|
const { data, isLoading } = useGetAboutUsQuery();
|
||||||
|
|
||||||
const context = useContext(GlobalStateContext);
|
const content = data?.data?.[0]?.content
|
||||||
if (!context) throw new Error("App must be used within a GlobalStateProvider");
|
console.log('====================================');
|
||||||
|
// console.log(response);
|
||||||
|
console.log('====================================');
|
||||||
|
|
||||||
const { setIsBarLoading } = context;
|
|
||||||
useEffect(() => {
|
|
||||||
setIsBarLoading(isFetching);
|
|
||||||
}, [isFetching, setIsBarLoading]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainFrame transperant={true}>
|
|
||||||
<VStack gap={4} pb={4} pt={0}>
|
|
||||||
<Stack bg={"#fff"} w={"100%"} mt={2} p={4} borderRadius={4}><Text color={"black"} textAlign={"left"} fontWeight={"600"} > About Us
|
|
||||||
</Text></Stack>
|
|
||||||
|
|
||||||
{isLoading || isFetching ? (
|
<MainFrame>
|
||||||
<Spinner />
|
<Box pb={4}>
|
||||||
|
<HStack
|
||||||
|
w={"100%"}
|
||||||
|
justifyContent={"space-between"}
|
||||||
|
mb={4}
|
||||||
|
py={0}
|
||||||
|
px={3}
|
||||||
|
>
|
||||||
|
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
||||||
|
AboutUs
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<HStack>
|
||||||
|
|
||||||
|
<AboutUsAddModel />
|
||||||
|
</HStack>
|
||||||
|
</HStack>
|
||||||
|
{/* Show Skeleton until content is available */}
|
||||||
|
{isLoading || !content ? (
|
||||||
|
<Box px={3} w="85%">
|
||||||
|
<Skeleton height="20px" mb="10px" />
|
||||||
|
<Skeleton height="20px" mb="10px" />
|
||||||
|
<Skeleton height="20px" mb="10px" />
|
||||||
|
<Skeleton height="20px" mb="10px" width="75%" />
|
||||||
|
<Skeleton height="20px" mb="15px" width="90%" />
|
||||||
|
<Skeleton height="20px" mb="10px" />
|
||||||
|
<Skeleton height="20px" mb="10px" width="85%" />
|
||||||
|
<Skeleton height="20px" mb="10px" />
|
||||||
|
<Skeleton height="20px" width="70%" />
|
||||||
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
data?.data?.map(({ id, content, about_language }) => (
|
<Text
|
||||||
<VStack
|
as="p"
|
||||||
bg={"#fff"}
|
fontSize="sm"
|
||||||
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
|
fontWeight={400}
|
||||||
rounded={"lg"}
|
color="#1D1D1D"
|
||||||
p={3}
|
px={3}
|
||||||
key={id}
|
w="85%"
|
||||||
>
|
mb="15px"
|
||||||
|
>
|
||||||
<HStack w={"100%"} justifyContent={"space-between"} py={0} px={0}>
|
{content}
|
||||||
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
</Text>
|
||||||
<Badge
|
|
||||||
variant={"surface"}
|
|
||||||
colorPalette="cyan"
|
|
||||||
ms={2}
|
|
||||||
size={"sm"}
|
|
||||||
fontSize={"xs"}
|
|
||||||
px={2}
|
|
||||||
>
|
|
||||||
🎓 {about_language?.language_name}
|
|
||||||
</Badge>
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
{/* Pass Data to AboutUsAddModel */}
|
|
||||||
<AboutUsAddModel aboutUsData={{ id, content, about_language }} />
|
|
||||||
</HStack>
|
|
||||||
<Text as="p" fontSize="sm" fontWeight={400} color="#1D1D1D">
|
|
||||||
{/* {content} */}
|
|
||||||
<div dangerouslySetInnerHTML={{ __html: content }} />
|
|
||||||
</Text>
|
|
||||||
</VStack>
|
|
||||||
))
|
|
||||||
)}
|
)}
|
||||||
</VStack>
|
</Box>
|
||||||
</MainFrame>
|
</MainFrame>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
export default AboutUs
|
||||||
export default AboutUs;
|
|
||||||
@@ -1,152 +1,119 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
import { FaRegEdit } from "react-icons/fa";
|
import { FaRegEdit } from "react-icons/fa";
|
||||||
import {
|
import {
|
||||||
DialogBody,
|
DialogBody,
|
||||||
DialogCloseTrigger,
|
DialogCloseTrigger,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogRoot,
|
DialogRoot,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "../../../components/ui/dialog";
|
} from "../../../components/ui/dialog";
|
||||||
import { Field, Stack, Text } from "@chakra-ui/react";
|
import { Field, Stack, Text, Textarea } from "@chakra-ui/react";
|
||||||
import { Button } from "../../../components/ui/button";
|
import { Button } from "../../../components/ui/button";
|
||||||
import ReactQuill from "react-quill";
|
|
||||||
import "react-quill/dist/quill.snow.css"; // Import the styles
|
|
||||||
import { useState } from "react";
|
|
||||||
import { useUpdateAboutUsMutation } from "../../../Redux/Service/manage.aboutus.service";
|
import { useUpdateAboutUsMutation } from "../../../Redux/Service/manage.aboutus.service";
|
||||||
import { useForm, Controller } from "react-hook-form"; // Import React Hook Form
|
|
||||||
import { toaster, Toaster } from "../../../components/ui/toaster";
|
|
||||||
|
|
||||||
function AboutUsAddModel({ aboutUsData }: { aboutUsData: any }) {
|
function AboutUsAddModel() {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [content, setContent] = useState(""); // State for the textarea input
|
||||||
|
const [updateAboutUs, { isLoading }] = useUpdateAboutUsMutation(); // Mutation for updating About Us
|
||||||
|
// const toast = useToast(); // Toast for feedback
|
||||||
|
|
||||||
// RTK Query Mutation Hook
|
// Handle form submission
|
||||||
const [updateAboutUs, { isLoading }] = useUpdateAboutUsMutation();
|
const handleSubmit = async (e: any) => {
|
||||||
|
e.preventDefault(); // Prevent default form submission
|
||||||
|
|
||||||
// React Hook Form
|
try {
|
||||||
const {
|
// Call the updateAboutUs mutation
|
||||||
control,
|
const res = await updateAboutUs({ id: 2, updatedData: content }).unwrap();
|
||||||
handleSubmit,
|
console.log(res);
|
||||||
reset,
|
|
||||||
setValue,
|
|
||||||
} = useForm({
|
|
||||||
defaultValues: {
|
|
||||||
content: "",
|
|
||||||
languageCode: "",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Function to handle edit click (pre-fill the editor)
|
// Show success toast
|
||||||
const handleEditClick = (data: any) => {
|
// toast({
|
||||||
setValue("content", data.content); // Pre-fill the content field
|
// title: "Success",
|
||||||
setValue("languageCode", data.about_language.language_code); // Pre-fill the language code
|
// description: "About Us content updated successfully",
|
||||||
setIsOpen(true); // Open dialog
|
// status: "success",
|
||||||
};
|
// duration: 5000,
|
||||||
|
// isClosable: true,
|
||||||
|
// });
|
||||||
|
|
||||||
// Function to handle update submission
|
// Clear the input field after successful submission
|
||||||
const onSubmit = async (formData: any) => {
|
setContent("");
|
||||||
if (!formData.content.trim()) return; // Prevent empty updates
|
} catch (error) {
|
||||||
|
// Show error toast
|
||||||
|
// toast({
|
||||||
|
// title: "Error",
|
||||||
|
// description: "Failed to update About Us content",
|
||||||
|
// status: "error",
|
||||||
|
// duration: 5000,
|
||||||
|
// isClosable: true,
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
return (
|
||||||
await updateAboutUs({
|
<DialogRoot placement="center">
|
||||||
id: aboutUsData.id,
|
<DialogTrigger asChild>
|
||||||
content: formData.content,
|
<Button bgColor="#EEEEEE" pl={3} pr={3} size="xs" color="#000">
|
||||||
language_code: formData.languageCode,
|
<FaRegEdit color="#000" style={{ height: "14px", width: "14px" }} />
|
||||||
}).unwrap();
|
<Text color="#000" mt={1}>
|
||||||
setIsOpen(false); // Close dialog on success
|
Edit
|
||||||
reset(); // Reset the form
|
</Text>
|
||||||
} catch (error: any) {
|
</Button>
|
||||||
console.error("Update failed:", error);
|
</DialogTrigger>
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: `${error.data.message || "Failed to update"}`,
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
<DialogContent
|
||||||
<>
|
bg="#fff"
|
||||||
<DialogRoot placement="center" open={isOpen}>
|
w={{ base: "90%", md: "400px" }}
|
||||||
<DialogTrigger asChild>
|
height="auto"
|
||||||
<Button
|
p={3}
|
||||||
bgColor="#EEEEEE"
|
>
|
||||||
pl={3}
|
<DialogHeader bg="white">
|
||||||
pr={3}
|
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
||||||
size="xs"
|
Edit
|
||||||
color="#000"
|
</DialogTitle>
|
||||||
onClick={() => handleEditClick(aboutUsData)} // Set content before opening modal
|
</DialogHeader>
|
||||||
>
|
|
||||||
<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}>
|
<DialogBody bg="white">
|
||||||
<DialogHeader bg="white">
|
<Stack py={3}>
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
<Field.Root>
|
||||||
Edit About Us
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
</DialogTitle>
|
AboutUs
|
||||||
</DialogHeader>
|
</Field.Label>
|
||||||
|
<Textarea
|
||||||
|
placeholder="Enter About Us content"
|
||||||
|
bgColor="#EEEEEE"
|
||||||
|
color="black"
|
||||||
|
border="none"
|
||||||
|
p={2}
|
||||||
|
fontSize="12px"
|
||||||
|
height="140px" // Increased height for better usability
|
||||||
|
pt={1.5}
|
||||||
|
value={content} // Bind the state to the textarea
|
||||||
|
onChange={(e) => setContent(e.target.value)}
|
||||||
|
resize={'none'}
|
||||||
|
_focusVisible={{outline:'none'}}
|
||||||
|
/>
|
||||||
|
</Field.Root>
|
||||||
|
</Stack>
|
||||||
|
</DialogBody>
|
||||||
|
|
||||||
<DialogBody bg="white">
|
<DialogFooter display="flex" justifyContent="center" pt="2">
|
||||||
<Stack py={3} mb={8}>
|
<Button
|
||||||
<Field.Root>
|
w="100%"
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
bg="#02A0A0"
|
||||||
About Us Content
|
color="#fff"
|
||||||
</Field.Label>
|
onClick={handleSubmit} // Trigger handleSubmit on button click
|
||||||
{/* Use Controller to integrate ReactQuill with React Hook Form */}
|
// isLoading={isLoading} // Show loading state while the mutation is in progress
|
||||||
<Controller
|
>
|
||||||
name="content"
|
Save
|
||||||
control={control}
|
</Button>
|
||||||
render={({ field }) => (
|
</DialogFooter>
|
||||||
<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">
|
<DialogCloseTrigger color="black" />
|
||||||
<Button
|
</DialogContent>
|
||||||
w="100%"
|
</DialogRoot>
|
||||||
bg="#02A0A0"
|
);
|
||||||
color="#fff"
|
|
||||||
// isLoading={isLoading}
|
|
||||||
disabled={isLoading}
|
|
||||||
onClick={handleSubmit(onSubmit)} // Use handleSubmit to trigger form submission
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
|
||||||
</DialogContent>
|
|
||||||
</DialogRoot>
|
|
||||||
<Toaster />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AboutUsAddModel;
|
export default AboutUsAddModel;
|
||||||
|
|||||||
@@ -11,100 +11,24 @@ import {
|
|||||||
} from "../../../components/ui/dialog";
|
} from "../../../components/ui/dialog";
|
||||||
import { Field, Input, Stack, Textarea } from "@chakra-ui/react";
|
import { Field, Input, Stack, Textarea } from "@chakra-ui/react";
|
||||||
import Edit from "../../../components/ActionIcons/Edit";
|
import Edit from "../../../components/ActionIcons/Edit";
|
||||||
import { useUpdateFaqMutation } from "../../../Redux/Service/faqs.service";
|
function EditDetails() {
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { Toaster, toaster } from "../../../components/ui/toaster";
|
|
||||||
|
|
||||||
interface RowData {
|
|
||||||
id: number;
|
|
||||||
principal_type_xid: number;
|
|
||||||
question: string;
|
|
||||||
answer: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function EditDetails({ rowData, refetch }: {rowData: RowData, refetch: VoidFunction}) {
|
|
||||||
const [faqQuestion, setFaqQuestion] = useState(rowData?.question);
|
|
||||||
const [faqAnswer, setFaqAnswer] = useState(rowData?.answer);
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [updateFaq, { isLoading }] = useUpdateFaqMutation()
|
|
||||||
|
|
||||||
// console.log('ROWDATA', rowData);
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (rowData) {
|
|
||||||
setFaqQuestion(rowData.question);
|
|
||||||
setFaqAnswer(rowData.answer);
|
|
||||||
}
|
|
||||||
}, [rowData]);
|
|
||||||
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
setIsOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (!faqQuestion.trim() || !faqAnswer.trim()) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Input fields cannot be empty",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
id: rowData?.id,
|
|
||||||
question: faqQuestion,
|
|
||||||
answer: faqAnswer,
|
|
||||||
principal_type_xid: rowData?.principal_type_xid,
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await updateFaq(payload).unwrap();
|
|
||||||
if (response?.status === "success") {
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "FAQ updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
refetch()
|
|
||||||
setIsOpen(false);
|
|
||||||
} else {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Failed to update FAQ",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
// alert("Failed to update template");
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Something went wrong",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
|
<Edit />
|
||||||
<Button bg="transparent" color={"black"} h={"18px"} onClick={handleOpenModal}><Edit /></Button>
|
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<DialogContent
|
<DialogContent
|
||||||
bg={"#fff"}
|
bg={"#fff"}
|
||||||
|
// w={{ lg: "60%", md: "230px" }}
|
||||||
w={{ base: "90%", md: "400px" }}
|
w={{ base: "90%", md: "400px" }}
|
||||||
height={"auto"}
|
height={"auto"}
|
||||||
p={3}
|
p={3} // Reduced padding
|
||||||
|
bgSize={"md"}
|
||||||
>
|
>
|
||||||
<DialogHeader bg="white">
|
<DialogHeader bg="white">
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
||||||
Edit Details (ID: {rowData?.id})
|
Edit Details
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
@@ -112,18 +36,16 @@ function EditDetails({ rowData, refetch }: {rowData: RowData, refetch: VoidFunct
|
|||||||
<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">
|
||||||
Question
|
Questions
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Question"
|
placeholder="Questions"
|
||||||
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={faqQuestion}
|
|
||||||
onChange={(e) => setFaqQuestion(e.target.value)}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
@@ -134,26 +56,22 @@ function EditDetails({ rowData, refetch }: {rowData: RowData, refetch: VoidFunct
|
|||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
p={2}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="auto"
|
height="30px"
|
||||||
pt={1.5}
|
pt={1.5}
|
||||||
value={faqAnswer}
|
|
||||||
onChange={(e) => setFaqAnswer(e.target.value)}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
</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} disabled={isLoading}>
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<Toaster />
|
|
||||||
</DialogRoot>
|
</DialogRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,206 +1,53 @@
|
|||||||
import { Box, HStack, Image, Spinner, Text } from "@chakra-ui/react";
|
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
|
||||||
import MainFrame from "../../../components/MainFrame"
|
import MainFrame from "../../../components/MainFrame"
|
||||||
import EditDetails from "./EditDetails";
|
import EditDetails from "./EditDetails";
|
||||||
// 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 { Switch } from "../../../components/ui/switch";
|
import { Switch } from "../../../components/ui/switch";
|
||||||
import FaqAddModel from "./FaqAddModel";
|
import FaqAddModel from "./FaqAddModel";
|
||||||
import Delete from "../../../components/ActionIcons/Delete";
|
import Delete from "../../../components/ActionIcons/Delete";
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { FaqData, useDeleteFaqPostMutation, useFaqToggleMutation, useGetFaqQuery } from "../../../Redux/Service/faqs.service";
|
|
||||||
import SearchComponent from "../../../components/SearchComponent";
|
|
||||||
import NoData from "../../../components/NoData";
|
|
||||||
import { Toaster, toaster } from "../../../components/ui/toaster";
|
|
||||||
|
|
||||||
|
|
||||||
// table data
|
// table data
|
||||||
|
|
||||||
const tableHeadRow = [
|
const tableHeadRow = [
|
||||||
"Sr. No",
|
"Sr. No",
|
||||||
'Category',
|
|
||||||
"Question",
|
"Question",
|
||||||
"Answer",
|
"Answer",
|
||||||
"Action",
|
"Action",
|
||||||
];
|
];
|
||||||
|
|
||||||
// const managepost: any[] = [
|
const managepost: any[] = [
|
||||||
// ...Array.from({ length: 12 }, (_, i) => ({
|
...Array.from({ length: 12 }, (_, i) => ({
|
||||||
// "Sr. No": i + 1,
|
"Sr. No": i + 1,
|
||||||
// "Question": "Lorem Ipsum",
|
"Question": "Lorem Ipsum",
|
||||||
// "Answer": "Lorem Ipsum",
|
"Answer": "Lorem Ipsum",
|
||||||
// "Action": (
|
"Action": (
|
||||||
// <HStack justifyContent="center">
|
<HStack justifyContent="center">
|
||||||
// <Box>
|
<Box>
|
||||||
// <Switch colorPalette={'teal'} size={"xs"} />
|
<Switch colorPalette={'teal'} size={"xs"}/>
|
||||||
// </Box>
|
</Box>
|
||||||
// {/* <EditDetails /> */}
|
<EditDetails />
|
||||||
// <EditDetails id={(i + 1).toString()} question="Lorem Ipsum" answer="Lorem Ipsum" />
|
<AlertDailog
|
||||||
|
AltertTiggerIcon={() => <Delete />}
|
||||||
// <AlertDailog
|
alertText="Delete Users"
|
||||||
// AltertTiggerIcon={() => <Delete />}
|
alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
|
||||||
// alertText="Delete Users"
|
alertCaption="are you sure you want to delete ?"
|
||||||
// alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
|
onConfirm={() => {
|
||||||
// alertCaption="are you sure you want to delete ?"
|
console.log("User deleted:", i + 1);
|
||||||
// onConfirm={() => {
|
}}
|
||||||
// console.log("User deleted:", i + 1);
|
/>
|
||||||
// }}
|
</HStack>
|
||||||
// />
|
),
|
||||||
// </HStack>
|
})),
|
||||||
// ),
|
];
|
||||||
// })),
|
|
||||||
// ];
|
|
||||||
|
|
||||||
const FAQ = () => {
|
const FAQ = () => {
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
const { data, refetch, isLoading, isFetching, isError } = useGetFaqQuery(currentPage)
|
|
||||||
const [localData, setLocalData] = useState<any[]>([]);
|
|
||||||
const [faqToggle] = useFaqToggleMutation()
|
|
||||||
const [deleteFaqPost] = useDeleteFaqPostMutation()
|
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const [deleteModal, setDeleteModal] = useState(false)
|
|
||||||
const [selectedFaqId, setSelectedFaqId] = useState<number | null>(null);
|
|
||||||
|
|
||||||
console.log('DATA', data?.data.data);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data) {
|
|
||||||
setLocalData(data?.data.data);
|
|
||||||
}
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
setCurrentPage(page);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const handleToggle = async (agencyId: number, currentStatus: string) => {
|
|
||||||
const newStatus = currentStatus === '1' ? '0' : '1';
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await faqToggle({ id: agencyId, is_active: newStatus }).unwrap();
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Status updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
setTimeout(() => {
|
|
||||||
refetch();
|
|
||||||
}, 500);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating privacy policy:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Someting went wrong.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteFaq = async (faqId: number) => {
|
|
||||||
try {
|
|
||||||
const response = await deleteFaqPost({ id: faqId }).unwrap();
|
|
||||||
if (response?.status === "success") {
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "FAQ deleted successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
refetch()
|
|
||||||
console.log("FAQ deleted successfully:", response);
|
|
||||||
}
|
|
||||||
// Optionally, refetch data or update state after deletion
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error deleting FAQ:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Something went wrong",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const filteredData = localData?.filter((agency) =>
|
|
||||||
agency.translations.some((translation: any) => {
|
|
||||||
const searchLower = searchTerm.toLowerCase();
|
|
||||||
const questionMatch = translation.question?.toLowerCase().includes(searchLower);
|
|
||||||
const answerMatch = translation.answer?.toLowerCase().includes(searchLower);
|
|
||||||
return questionMatch || answerMatch;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log("filteredData", filteredData);
|
|
||||||
|
|
||||||
|
|
||||||
const managepost = filteredData?.flatMap((agency: FaqData, index: number) =>
|
|
||||||
agency.translations.map((translation: any) => ({
|
|
||||||
'id': translation.id,
|
|
||||||
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
|
|
||||||
"Question": translation.question,
|
|
||||||
"Answer": translation.answer,
|
|
||||||
'Category': agency.principal_type_xid === 2 ? "Recruiter" : "Job Seeker",
|
|
||||||
|
|
||||||
"Action": (
|
|
||||||
<HStack justifyContent="center">
|
|
||||||
<EditDetails rowData={{ id: agency.id, question: translation.question, answer: translation.answer, principal_type_xid: agency.principal_type_xid }} refetch={refetch} />
|
|
||||||
|
|
||||||
<AlertDailog
|
|
||||||
isOpen={deleteModal}
|
|
||||||
AltertTiggerIcon={() => <Delete onClick={() => {
|
|
||||||
setSelectedFaqId(agency.id);
|
|
||||||
setDeleteModal(true)
|
|
||||||
}} />}
|
|
||||||
alertText="Delete FAQ"
|
|
||||||
alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
|
|
||||||
alertCaption="are you sure you want to delete ?"
|
|
||||||
onClose={() => setDeleteModal(false)}
|
|
||||||
onConfirm={() => {
|
|
||||||
// console.log("Deleting FAQ with ID:", selectedFaqId); // Correct ID
|
|
||||||
if (selectedFaqId) {
|
|
||||||
setDeleteModal(false);
|
|
||||||
handleDeleteFaq(selectedFaqId);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Box>
|
|
||||||
<Switch
|
|
||||||
colorPalette={'teal'}
|
|
||||||
size={"xs"}
|
|
||||||
onChange={() => handleToggle(Number(agency.id), agency.is_active.toString())}
|
|
||||||
checked={Boolean(Number(agency.is_active))}
|
|
||||||
key={`switch-${agency.id}`}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</HStack>
|
|
||||||
),
|
|
||||||
})))
|
|
||||||
|
|
||||||
if (isFetching) {
|
|
||||||
return (
|
|
||||||
<HStack
|
|
||||||
w={"100%"}
|
|
||||||
justifyContent={"center"}
|
|
||||||
mb={4}
|
|
||||||
py={0}
|
|
||||||
px={3}
|
|
||||||
>
|
|
||||||
<Spinner color={'teal'} />
|
|
||||||
</HStack>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<MainFrame>
|
<MainFrame>
|
||||||
<Box>
|
<Box>
|
||||||
<HStack
|
<HStack
|
||||||
@@ -211,37 +58,40 @@ const FAQ = () => {
|
|||||||
px={3}
|
px={3}
|
||||||
>
|
>
|
||||||
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
||||||
FAQs
|
FAQs
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<HStack >
|
<HStack >
|
||||||
<SearchComponent
|
<InputGroup
|
||||||
value={searchTerm}
|
startElement={
|
||||||
onChange={setSearchTerm}
|
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
|
||||||
/>
|
}
|
||||||
|
color={"#000"}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
p={3}
|
||||||
|
w={300}
|
||||||
|
bg={"#fff"}
|
||||||
|
colorPalette={"blue"}
|
||||||
|
_focus={{ border: "1px solid #02A0A0" }}
|
||||||
|
rounded={"md"}
|
||||||
|
size={"xs"}
|
||||||
|
fontSize={"2sm"}
|
||||||
|
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> */}
|
||||||
<FaqAddModel refetch={refetch} />
|
<FaqAddModel />
|
||||||
</HStack>
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
{isFetching && <Spinner />}
|
<DataTable
|
||||||
{!isLoading && !data?.data ? (
|
sortableColumns={["Name", "Registration Date "]}
|
||||||
<NoData message={'No data found'} text={'Please add new data'} />
|
|
||||||
) : (<DataTable
|
|
||||||
sortableColumns={["Name"]}
|
|
||||||
tableHeadRow={tableHeadRow}
|
tableHeadRow={tableHeadRow}
|
||||||
data={managepost}
|
data={managepost}
|
||||||
paginationData={{
|
/>
|
||||||
current_page: data?.data.current_page || 1,
|
</Box>
|
||||||
last_page: data?.data.last_page || 1,
|
|
||||||
per_page: data?.data.per_page || 10,
|
|
||||||
total: data?.data.total || 0
|
|
||||||
}}
|
|
||||||
onPageChange={handlePageChange}
|
|
||||||
isLoading={isFetching}
|
|
||||||
isError={isError}
|
|
||||||
/>)}
|
|
||||||
</Box>
|
|
||||||
<Toaster />
|
|
||||||
</MainFrame>
|
</MainFrame>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,77 +8,15 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "../../../components/ui/dialog";
|
} from "../../../components/ui/dialog";
|
||||||
import { Box, Field, Input, Stack, Text, Textarea } from "@chakra-ui/react";
|
import { Field, Input, Stack, Text, Textarea } 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 { Toaster, toaster } from "../../../components/ui/toaster";
|
|
||||||
import { useCreateFaqPostMutation } from "../../../Redux/Service/faqs.service";
|
|
||||||
|
|
||||||
function FaqAddModel({ refetch }: { refetch: VoidFunction }) {
|
|
||||||
const [faqQuestion, setFaqQuestion] = useState('');
|
|
||||||
const [faqAnswer, setFaqAnswer] = useState('');
|
|
||||||
const [userType, setUserType] = useState("");
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [createFaqPost, { isLoading }] = useCreateFaqPostMutation()
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
setIsOpen(true); // Open modal when clicking "Add"
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (userType === "" || isNaN(Number(userType))) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Please select a valid user type.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!faqQuestion.trim() || !faqAnswer.trim()) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Please fill in all required fields",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
principal_type_xid: Number(userType),
|
|
||||||
language_code: 'en',
|
|
||||||
question: faqQuestion,
|
|
||||||
answer: faqAnswer
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await createFaqPost(payload).unwrap();
|
|
||||||
if (response) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "FAQ updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
refetch()
|
|
||||||
setIsOpen(false);
|
|
||||||
} else {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Failed to update FAQ",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
// alert("Failed to update template");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
function FaqAddModel() {
|
||||||
return (
|
return (
|
||||||
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
|
<Button px={5} size={"xs"} bg={"#02A0A0"}>
|
||||||
<IoMdAdd /> <Text>Add</Text>
|
<IoMdAdd /> <Text>Add</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
@@ -95,33 +33,10 @@ function FaqAddModel({ refetch }: { refetch: VoidFunction }) {
|
|||||||
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
||||||
Add
|
Add
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<DialogBody bg="white">
|
<DialogBody bg="white">
|
||||||
<Stack py={3}>
|
<Stack py={3}>
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Select User Type</Field.Label>
|
|
||||||
<Box bgColor="#EEEEEE" borderRadius="md" p={1} w={'100%'}>
|
|
||||||
<select
|
|
||||||
style={{
|
|
||||||
width: "100%",
|
|
||||||
background: "transparent",
|
|
||||||
color: "black",
|
|
||||||
border: "none",
|
|
||||||
fontSize: "12px",
|
|
||||||
height: "30px",
|
|
||||||
outline: "none",
|
|
||||||
}}
|
|
||||||
value={userType}
|
|
||||||
onChange={(e) => setUserType(e.target.value)}
|
|
||||||
>
|
|
||||||
<option value="" disabled>Select User Type</option>
|
|
||||||
<option value="2">Recruiter</option>
|
|
||||||
<option value="3">Jobseeker</option>
|
|
||||||
</select>
|
|
||||||
</Box>
|
|
||||||
</Field.Root>
|
|
||||||
|
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
Questions
|
Questions
|
||||||
@@ -133,10 +48,8 @@ function FaqAddModel({ refetch }: { refetch: VoidFunction }) {
|
|||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
_focusVisible={{ outline: 'none' }}
|
_focusVisible={{outline:'none'}}
|
||||||
size={'sm'}
|
size={'sm'}
|
||||||
value={faqQuestion}
|
|
||||||
onChange={(e) => setFaqQuestion(e.target.value)}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
@@ -151,22 +64,19 @@ function FaqAddModel({ refetch }: { refetch: VoidFunction }) {
|
|||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="120px"
|
height="120px"
|
||||||
resize={'none'}
|
resize={'none'}
|
||||||
_focusVisible={{ outline: 'none' }}
|
_focusVisible={{outline:'none'}}
|
||||||
value={faqAnswer}
|
|
||||||
onChange={(e) => setFaqAnswer(e.target.value)}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
</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} disabled={isLoading}>
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<Toaster />
|
|
||||||
</DialogRoot>
|
</DialogRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Badge, HStack, Stack, Text, VStack } from "@chakra-ui/react";
|
import { Badge, HStack, Text, VStack } from "@chakra-ui/react";
|
||||||
import { useGetPrivacyPolicyQuery } from "../../../Redux/Service/privacy.policy.service";
|
import { useGetPrivacyPolicyQuery } from "../../../Redux/Service/privacy.policy.service";
|
||||||
import MainFrame from "../../../components/MainFrame";
|
import MainFrame from "../../../components/MainFrame";
|
||||||
import { Spinner } from "../../../components/Sipnner/Spinner";
|
import { Spinner } from "../../../components/Sipnner/Spinner";
|
||||||
@@ -6,77 +6,50 @@ import PrivacyPolicyAddModel from "./PrivacyPolicyAddModel";
|
|||||||
import GlobalStateContext from "../../../Contexts/GlobalStateContext";
|
import GlobalStateContext from "../../../Contexts/GlobalStateContext";
|
||||||
import { useContext, useEffect } from "react";
|
import { useContext, useEffect } from "react";
|
||||||
|
|
||||||
const PrivacyPolicy = () => {
|
|
||||||
const { data, isLoading, isFetching, refetch } = useGetPrivacyPolicyQuery();
|
|
||||||
|
|
||||||
console.log("PRIVACY", data?.data);
|
const PrivacyPolicy = () => {
|
||||||
|
const { data, isLoading, isFetching } = useGetPrivacyPolicyQuery();
|
||||||
|
|
||||||
const context = useContext(GlobalStateContext);
|
const context = useContext(GlobalStateContext);
|
||||||
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 { setIsBarLoading } = context;
|
const { setIsBarLoading } = context;
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsBarLoading(isFetching);
|
setIsBarLoading(isFetching)
|
||||||
}, [data]);
|
}, [data])
|
||||||
|
|
||||||
console.log("Privacy Policy Data:", data?.data);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainFrame transperant={true}>
|
<MainFrame transperant={true}>
|
||||||
<Stack bg={"#fff"} w={"100%"} p={4} borderRadius={4} mb={4}>
|
<VStack gap={4} pb={4} pt={0}>
|
||||||
<Text color={"black"} textAlign={"left"} fontWeight={"600"}>
|
{isLoading || isFetching ?
|
||||||
Privacy Policy
|
<Spinner /> : data?.data?.map(({ id, content, privacy_language }) => <VStack bg={'#fff'}
|
||||||
</Text>
|
boxShadow={'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'} rounded={'lg'} p={3} key={id}>
|
||||||
</Stack>
|
<HStack
|
||||||
<VStack gap={4} pb={4} pt={0}>
|
w={"100%"}
|
||||||
{isLoading || isFetching ? (
|
justifyContent={"space-between"}
|
||||||
<Spinner />
|
|
||||||
) : (
|
|
||||||
data?.data?.map(({ id, content, privacy_language }) => (
|
|
||||||
<VStack
|
|
||||||
bg={"#fff"}
|
|
||||||
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
|
|
||||||
rounded={"lg"}
|
|
||||||
p={3}
|
|
||||||
key={id}
|
|
||||||
>
|
|
||||||
<HStack w={"100%"} justifyContent={"space-between"} py={0} px={0}>
|
|
||||||
<Text
|
|
||||||
as={"span"}
|
|
||||||
fontSize={"sm"}
|
|
||||||
fontWeight={500}
|
|
||||||
color={"#000"}
|
|
||||||
>
|
|
||||||
<Badge
|
|
||||||
variant={"surface"}
|
|
||||||
colorPalette="cyan"
|
|
||||||
size={"sm"}
|
|
||||||
fontSize={"xs"}
|
|
||||||
px={2}
|
|
||||||
>
|
|
||||||
🎓 {privacy_language?.language_name}
|
|
||||||
</Badge>
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<PrivacyPolicyAddModel
|
py={0}
|
||||||
policyData={{ id, content, privacy_language }}
|
px={0}
|
||||||
refetch={refetch}
|
>
|
||||||
/>
|
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
||||||
</HStack>
|
Privacy Policy <Badge variant={'surface'} colorPalette="cyan" ms={2} size={'sm'} fontSize={'xs'} px={2}>🎓 {privacy_language?.language_name}</Badge>
|
||||||
<Text
|
</Text>
|
||||||
as="p"
|
|
||||||
fontSize="sm"
|
<PrivacyPolicyAddModel />
|
||||||
fontWeight={400}
|
</HStack>
|
||||||
color="#1D1D1D"
|
<Text
|
||||||
dangerouslySetInnerHTML={{ __html: content }}
|
as="p"
|
||||||
/>
|
fontSize="sm"
|
||||||
</VStack>
|
fontWeight={400}
|
||||||
))
|
color="#1D1D1D"
|
||||||
)}
|
>
|
||||||
|
{content}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
</VStack>)}
|
||||||
</VStack>
|
</VStack>
|
||||||
</MainFrame>
|
</MainFrame>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PrivacyPolicy;
|
export default PrivacyPolicy;
|
||||||
@@ -4,92 +4,46 @@ import {
|
|||||||
DialogCloseTrigger,
|
DialogCloseTrigger,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
DialogRoot,
|
DialogRoot,
|
||||||
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "../../../components/ui/dialog";
|
} from "../../../components/ui/dialog";
|
||||||
import { Box, Field, Stack, Text } from "@chakra-ui/react";
|
import { Field, Stack, Text, Textarea } from "@chakra-ui/react";
|
||||||
import { Button } from "../../../components/ui/button";
|
import { Button } from "../../../components/ui/button";
|
||||||
import { useUpdatePrivacyPolicyMutation } from "../../../Redux/Service/privacy.policy.service";
|
|
||||||
import { Controller, useForm } from "react-hook-form";
|
|
||||||
import { useState } from "react";
|
|
||||||
import ReactQuill from "react-quill";
|
|
||||||
|
|
||||||
function PrivacyPolicyAddModel({ policyData, refetch }: { policyData: any, refetch: VoidFunction }) {
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [updatePrivacyPolicy, { isLoading }] = useUpdatePrivacyPolicyMutation()
|
|
||||||
const {
|
|
||||||
control,
|
|
||||||
handleSubmit,
|
|
||||||
reset,
|
|
||||||
setValue,
|
|
||||||
} = useForm({
|
|
||||||
defaultValues: {
|
|
||||||
content: "",
|
|
||||||
languageCode: "",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('POLICY', policyData);
|
|
||||||
|
|
||||||
const handleEditClick = (data: any) => {
|
|
||||||
setValue("content", data.content); // Pre-fill the content field
|
|
||||||
setValue("languageCode", data.privacy_language.language_code); // Pre-fill the language code
|
|
||||||
setIsOpen(true); // Open dialog
|
|
||||||
};
|
|
||||||
|
|
||||||
const onSubmit = async (formData: any) => {
|
|
||||||
if (!formData.content.trim()) return; // Prevent empty updates
|
|
||||||
|
|
||||||
try {
|
|
||||||
await updatePrivacyPolicy({
|
|
||||||
id: policyData.id,
|
|
||||||
content: formData.content,
|
|
||||||
language_code: formData.languageCode,
|
|
||||||
}).unwrap();
|
|
||||||
setIsOpen(false); // Close dialog on success
|
|
||||||
reset(); // Reset the form
|
|
||||||
refetch()
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Update failed:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
function PrivacyPolicyAddModel() {
|
||||||
return (
|
return (
|
||||||
<DialogRoot placement="center" open={isOpen}>
|
<DialogRoot placement="center">
|
||||||
<Box key={policyData.id}>
|
<DialogTrigger asChild>
|
||||||
<DialogTrigger asChild>
|
{/* <Button bg={"transparent"} size="sm">
|
||||||
<Button
|
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
||||||
bgColor={"#EEEEEE"}
|
</Button> */}
|
||||||
pl={3} pr={3}
|
<Button bgColor={"#EEEEEE"} pl={3} pr={3} size={"xs"} color={"#000"}>
|
||||||
size={"xs"}
|
{" "}
|
||||||
color={"#000"}
|
<FaRegEdit
|
||||||
onClick={() => handleEditClick(policyData)}
|
color="#000"
|
||||||
>
|
style={{ height: "14px", width: "14px" }}
|
||||||
{" "}
|
/>{" "}
|
||||||
<FaRegEdit
|
<Text color={"#000"} mt={1}>
|
||||||
color="#000"
|
Edit
|
||||||
style={{ height: "14px", width: "14px" }}
|
</Text>
|
||||||
/>{" "}
|
</Button>
|
||||||
<Text color={"#000"} mt={1}>
|
</DialogTrigger>
|
||||||
Edit
|
|
||||||
</Text>
|
|
||||||
</Button>
|
|
||||||
</DialogTrigger>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<DialogContent
|
<DialogContent
|
||||||
bg={"#fff"}
|
bg={"#fff"}
|
||||||
minW={'600px'}
|
// w={{ lg: "60%", md: "230px" }}
|
||||||
// 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">
|
<DialogHeader bg="white">
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
||||||
Edit
|
Edit
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
</DialogHeader> */}
|
</DialogHeader>
|
||||||
|
|
||||||
<DialogBody bg="white">
|
<DialogBody bg="white">
|
||||||
<Stack py={3}>
|
<Stack py={3}>
|
||||||
@@ -97,7 +51,7 @@ function PrivacyPolicyAddModel({ policyData, refetch }: { policyData: any, refet
|
|||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
PrivacyPolicy
|
PrivacyPolicy
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
{/* <Textarea
|
<Textarea
|
||||||
placeholder=""
|
placeholder=""
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
@@ -105,46 +59,19 @@ function PrivacyPolicyAddModel({ policyData, refetch }: { policyData: any, refet
|
|||||||
p={2}
|
p={2}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height={'140px'}
|
height={'140px'}
|
||||||
_focusVisible={{ outline: 'none' }}
|
_focusVisible={{outline:'none'}}
|
||||||
resize={'none'}
|
resize={'none'}
|
||||||
/> */}
|
|
||||||
<Controller
|
|
||||||
name="content"
|
|
||||||
control={control}
|
|
||||||
render={({ field }) => (
|
|
||||||
<ReactQuill
|
|
||||||
value={field.value}
|
|
||||||
onChange={field.onChange}
|
|
||||||
placeholder="Enter About Us content"
|
|
||||||
modules={{
|
|
||||||
toolbar: [
|
|
||||||
[{ 'header': [1, 2, false] }],
|
|
||||||
['bold', 'italic', 'underline', 'strike'],
|
|
||||||
['link', 'image'],
|
|
||||||
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
|
|
||||||
['clean']
|
|
||||||
],
|
|
||||||
}}
|
|
||||||
formats={[
|
|
||||||
'header',
|
|
||||||
'bold', 'italic', 'underline', 'strike',
|
|
||||||
'list', 'bullet',
|
|
||||||
'link', 'image'
|
|
||||||
]}
|
|
||||||
style={{ color: "black", border: "none", fontSize: "12px", height: "220px", width: "100%",marginBottom:'20px' }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
</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)} disabled={isLoading}>
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</DialogRoot>
|
</DialogRoot>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import { Box, Skeleton } from '@chakra-ui/react'
|
import { Box, Skeleton } from '@chakra-ui/react'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
const PrivacyPolicySkeleton = () => {
|
const PrivacyPolicySkeleton = () => {
|
||||||
return (
|
return (
|
||||||
<Box px={3} pb={3} w="90%">
|
<Box px={3} pb={3} w="90%">
|
||||||
<Skeleton height="20px" mb="10px" width="90%" />
|
<Skeleton height="20px" mb="10px" width="90%" />
|
||||||
<Skeleton height="20px" mb="15px" width="90%" />
|
<Skeleton height="20px" mb="15px" width="90%" />
|
||||||
<Skeleton height="20px" mb="10px" width="90%" />
|
<Skeleton height="20px" mb="10px" width="90%" />
|
||||||
<Skeleton height="20px" mb="10px" width="80%" />
|
<Skeleton height="20px" mb="10px" width="80%" />
|
||||||
<Skeleton height="20px" width="60%" />
|
<Skeleton height="20px" width="60%" />
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { Box, Skeleton } from '@chakra-ui/react'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const TermAndConditionSkeleton = () => {
|
||||||
|
return (
|
||||||
|
<Box px={3} pb={3} w="90%">
|
||||||
|
<Skeleton height="20px" mb="10px" width="90%" />
|
||||||
|
<Skeleton height="20px" mb="15px" width="90%" />
|
||||||
|
<Skeleton height="20px" mb="10px" width="90%" />
|
||||||
|
<Skeleton height="20px" mb="10px" width="80%" />
|
||||||
|
<Skeleton height="20px" width="60%" />
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TermAndConditionSkeleton
|
||||||
@@ -1,67 +1,58 @@
|
|||||||
import { Badge, HStack, Spinner, Stack, Text, VStack } from "@chakra-ui/react";
|
import { Badge, HStack, Text, VStack } from "@chakra-ui/react";
|
||||||
import MainFrame from "../../../components/MainFrame";
|
import MainFrame from "../../../components/MainFrame"
|
||||||
import TermsAndConditionsAddModel from "./TermsAndConditionsAddModel";
|
import TermsAndConditionsAddModel from "./TermsAndConditionsAddModel";
|
||||||
import { useGetTermsQuery } from "../../../Redux/Service/terms.and.condition.service";
|
import {useGetTermsAndConditionQuery} from "../../../Redux/Service/terms.and.condition.service"
|
||||||
|
import { useContext, useEffect } from "react";
|
||||||
|
import GlobalStateContext from "../../../Contexts/GlobalStateContext";
|
||||||
|
import { Spinner } from "../../../components/Sipnner/Spinner";
|
||||||
|
|
||||||
|
|
||||||
const TermsAndConditions = () => {
|
const TermsAndConditions = () => {
|
||||||
const { data, refetch, isLoading, isFetching } = useGetTermsQuery();
|
|
||||||
|
// Fetch data using RTK Query with type annotations
|
||||||
|
const { data, isLoading, isFetching } = useGetTermsAndConditionQuery();
|
||||||
|
|
||||||
console.log(data);
|
const context = useContext(GlobalStateContext);
|
||||||
|
if (!context) throw new Error('App must be used within a GlobalStateProvider');
|
||||||
|
|
||||||
|
const { setIsBarLoading } = context;
|
||||||
|
useEffect(() => {
|
||||||
|
setIsBarLoading(isFetching)
|
||||||
|
}, [data])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainFrame transperant={true}>
|
|
||||||
<VStack gap={4} pb={4} pt={0}>
|
|
||||||
<Stack bg={"#fff"} w={"100%"} mt={2} p={4} borderRadius={4}>
|
|
||||||
<Text color={"black"} textAlign={"left"} fontWeight={"600"}>
|
|
||||||
Terms and Conditions
|
|
||||||
</Text>
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
{isLoading || isFetching ? (
|
<MainFrame transperant={true}>
|
||||||
<Spinner />
|
|
||||||
) : (
|
<VStack gap={4} pb={4} pt={0}>
|
||||||
data?.data?.map(({ id, content, terms_cond_language }) => (
|
{isLoading || isFetching ?
|
||||||
<VStack
|
<Spinner /> : data?.data?.map(({ id, content, terms_cond_language }) => <VStack bg={'#fff'}
|
||||||
bg={"#fff"}
|
boxShadow={'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'} rounded={'lg'} p={3} key={id}>
|
||||||
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
|
<HStack
|
||||||
rounded={"lg"}
|
w={"100%"}
|
||||||
p={3}
|
justifyContent={"space-between"}
|
||||||
key={id}
|
|
||||||
|
py={0}
|
||||||
|
px={0}
|
||||||
>
|
>
|
||||||
<HStack w={"100%"} justifyContent={"space-between"} py={0} px={0}>
|
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
||||||
<Text
|
Terms And Conditions<Badge variant={'surface'} colorPalette="cyan" ms={2} size={'sm'} fontSize={'xs'} px={2}>🎓 {terms_cond_language?.language_name}</Badge>
|
||||||
as={"span"}
|
|
||||||
fontSize={"sm"}
|
|
||||||
fontWeight={500}
|
|
||||||
color={"#000"}
|
|
||||||
>
|
|
||||||
<Badge
|
|
||||||
variant={"surface"}
|
|
||||||
colorPalette="cyan"
|
|
||||||
ms={2}
|
|
||||||
size={"sm"}
|
|
||||||
fontSize={"xs"}
|
|
||||||
px={2}
|
|
||||||
>
|
|
||||||
🎓 {terms_cond_language?.language_name}
|
|
||||||
</Badge>
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
{/* Pass Data to AboutUsAddModel */}
|
|
||||||
<TermsAndConditionsAddModel
|
|
||||||
termsData={{ id, content, terms_cond_language }}
|
|
||||||
refetch={refetch}
|
|
||||||
/>
|
|
||||||
</HStack>
|
|
||||||
<Text as="p" fontSize="sm" fontWeight={400} color="#1D1D1D">
|
|
||||||
{/* {content} */}
|
|
||||||
<div dangerouslySetInnerHTML={{ __html: content }} />
|
|
||||||
</Text>
|
</Text>
|
||||||
</VStack>
|
|
||||||
))
|
<TermsAndConditionsAddModel />
|
||||||
)}
|
</HStack>
|
||||||
|
<Text
|
||||||
|
as="p"
|
||||||
|
fontSize="sm"
|
||||||
|
fontWeight={400}
|
||||||
|
color="#1D1D1D"
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
</VStack>)}
|
||||||
</VStack>
|
</VStack>
|
||||||
</MainFrame>
|
</MainFrame>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
export default TermsAndConditions;
|
export default TermsAndConditions
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
import { FaRegEdit } from "react-icons/fa";
|
import { FaRegEdit } from "react-icons/fa";
|
||||||
import {
|
import {
|
||||||
DialogBody,
|
DialogBody,
|
||||||
@@ -11,59 +12,40 @@ import {
|
|||||||
} from "../../../components/ui/dialog";
|
} from "../../../components/ui/dialog";
|
||||||
import { Field, Stack, Text } from "@chakra-ui/react";
|
import { Field, Stack, Text } from "@chakra-ui/react";
|
||||||
import { Button } from "../../../components/ui/button";
|
import { Button } from "../../../components/ui/button";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
|
||||||
import ReactQuill from "react-quill";
|
import ReactQuill from "react-quill";
|
||||||
import { useState } from "react";
|
import "react-quill/dist/quill.snow.css"; // Import the styles
|
||||||
import { useUpdateTermsMutation } from "../../../Redux/Service/terms.and.condition.service";
|
|
||||||
|
|
||||||
function TermsAndConditionsAddModel({ termsData, refetch }: { termsData: any, refetch: VoidFunction }) {
|
function TermsAndConditionsAddModel() {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [value, setValue] = useState(""); // State to manage the rich text content
|
||||||
const [updateTerms, { isLoading }] = useUpdateTermsMutation()
|
|
||||||
const {
|
|
||||||
control,
|
|
||||||
handleSubmit,
|
|
||||||
reset,
|
|
||||||
setValue,
|
|
||||||
} = useForm({
|
|
||||||
defaultValues: {
|
|
||||||
content: "",
|
|
||||||
languageCode: "",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleEditClick = (data: any) => {
|
// Configuration for the Quill editor toolbar
|
||||||
setValue("content", data.content); // Pre-fill the content field
|
const modules = {
|
||||||
setValue("languageCode", data.terms_cond_language.language_code); // Pre-fill the language code
|
toolbar: [
|
||||||
setIsOpen(true); // Open dialog
|
[{ header: [1, 2, 3, 4, 5, 6, false] }],
|
||||||
|
["bold", "italic", "underline", "strike"],
|
||||||
|
[{ list: "ordered" }, { list: "bullet" }],
|
||||||
|
["link", "image"],
|
||||||
|
["clean"],
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = async (formData: any) => {
|
// Formats allowed in the Quill editor
|
||||||
if (!formData.content.trim()) return; // Prevent empty updates
|
const formats = [
|
||||||
|
"header",
|
||||||
try {
|
"bold",
|
||||||
await updateTerms({
|
"italic",
|
||||||
id: termsData.id,
|
"underline",
|
||||||
content: formData.content,
|
"strike",
|
||||||
language_code: formData.languageCode,
|
"list",
|
||||||
}).unwrap();
|
"bullet",
|
||||||
setIsOpen(false); // Close dialog on success
|
"link",
|
||||||
reset(); // Reset the form
|
"image",
|
||||||
refetch()
|
];
|
||||||
} catch (error) {
|
|
||||||
console.error("Update failed:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogRoot placement="center" open={isOpen}>
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button
|
<Button bgColor={"#EEEEEE"} pl={3} pr={3} size={"xs"} color={"#000"}>
|
||||||
bgColor={"#EEEEEE"}
|
|
||||||
pl={3} pr={3}
|
|
||||||
size={"xs"}
|
|
||||||
color={"#000"}
|
|
||||||
onClick={() => handleEditClick(termsData)}
|
|
||||||
>
|
|
||||||
{" "}
|
{" "}
|
||||||
<FaRegEdit
|
<FaRegEdit
|
||||||
color="#000"
|
color="#000"
|
||||||
@@ -74,12 +56,12 @@ function TermsAndConditionsAddModel({ termsData, refetch }: { termsData: any, re
|
|||||||
</Text>
|
</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<DialogContent
|
<DialogContent
|
||||||
bg={"#fff"}
|
bg={"#fff"}
|
||||||
maxW={'600px'}
|
w={{ base: "90%", md: "800px" }}
|
||||||
// w={{ base: "90%", md: "600px" }}
|
|
||||||
height={"auto"}
|
height={"auto"}
|
||||||
p={3} // Reduced padding
|
p={3}
|
||||||
bgSize={"md"}
|
bgSize={"md"}
|
||||||
>
|
>
|
||||||
<DialogHeader bg="white">
|
<DialogHeader bg="white">
|
||||||
@@ -94,57 +76,35 @@ function TermsAndConditionsAddModel({ termsData, refetch }: { termsData: any, re
|
|||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
TermsAndConditions
|
TermsAndConditions
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
{/* <Textarea
|
{/* Replace Textarea with ReactQuill */}
|
||||||
placeholder=""
|
<ReactQuill
|
||||||
bgColor="#EEEEEE"
|
theme="snow" // Theme style
|
||||||
color="black"
|
value={value}
|
||||||
border="none"
|
onChange={setValue}
|
||||||
p={2}
|
modules={modules}
|
||||||
fontSize="12px"
|
formats={formats}
|
||||||
height={'140px'}
|
style={{
|
||||||
_focusVisible={{outline:'none'}}
|
width:"100%",
|
||||||
resize={'none'}
|
color: "black",
|
||||||
/> */}
|
border: "none",
|
||||||
<Controller
|
fontSize: "12px",
|
||||||
name="content"
|
height: "140px",
|
||||||
control={control}
|
|
||||||
render={({ field }) => (
|
}}
|
||||||
<ReactQuill
|
|
||||||
value={field.value}
|
|
||||||
onChange={field.onChange}
|
|
||||||
placeholder="Enter About Us content"
|
|
||||||
modules={{
|
|
||||||
toolbar: [
|
|
||||||
[{ 'header': [1, 2, false] }],
|
|
||||||
['bold', 'italic', 'underline', 'strike'],
|
|
||||||
['link', 'image'],
|
|
||||||
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
|
|
||||||
['clean']
|
|
||||||
],
|
|
||||||
}}
|
|
||||||
formats={[
|
|
||||||
'header',
|
|
||||||
'bold', 'italic', 'underline', 'strike',
|
|
||||||
'list', 'bullet',
|
|
||||||
'link', 'image'
|
|
||||||
]}
|
|
||||||
style={{ color: "black", border: "none", fontSize: "12px", height: "220px", width: "100%",marginBottom:'20px' }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
</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)} disabled={isLoading}>
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</DialogRoot>
|
</DialogRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TermsAndConditionsAddModel;
|
export default TermsAndConditionsAddModel;
|
||||||
@@ -1,99 +1,38 @@
|
|||||||
import { Box, HStack, Text } from "@chakra-ui/react";
|
import { Box, HStack, Input, 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 { useEffect, useState } from "react";
|
|
||||||
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 ManageContact = () => {
|
const tableHeadRow = [
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
"Sr. No",
|
||||||
const [localData, setLocalData] = useState<any[]>([]);
|
"Email id",
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
"Name",
|
||||||
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
"Date",
|
||||||
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
|
"Action",
|
||||||
const { data, isLoading, isError, refetch, isFetching } = useGetContactQuery(queryArgs);
|
];
|
||||||
|
|
||||||
|
const managepost: any[] = [
|
||||||
useEffect(() => {
|
...Array.from({ length: 12 }, (_, i) => ({
|
||||||
if (data) {
|
"Sr. No": i + 1,
|
||||||
setLocalData((data as any)?.data?.data || []);
|
"Email id": "ABC@gmail.com",
|
||||||
}
|
"Name": "Pooja",
|
||||||
}, [data]);
|
"Date": "11/02/1989",
|
||||||
|
"Action": (
|
||||||
const handlePageChange = (page: number) => {
|
<HStack justifyContent="center">
|
||||||
setCurrentPage(page);
|
<PendingRequests />
|
||||||
};
|
|
||||||
|
|
||||||
const handleSearchChange = (value: string) => {
|
|
||||||
setSearchTerm(value);
|
|
||||||
setCurrentPage(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const filteredData = localData?.filter((agency) =>
|
|
||||||
agency?.first_name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
||||||
agency?.email.toLowerCase().includes(searchTerm.toLowerCase())
|
|
||||||
);
|
|
||||||
|
|
||||||
const formatDateOfBirth = (dob: string): string => {
|
|
||||||
return new Date(dob).toLocaleDateString("en-GB", {
|
|
||||||
day: "2-digit",
|
|
||||||
month: "2-digit",
|
|
||||||
year: "numeric",
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const managepost = filteredData?.map((agency: any, index: number) => ({
|
|
||||||
"Sr. No": index + 1, // Typically Sr. No starts from 1, not using id which might not be sequential
|
|
||||||
"Email id": agency?.email || "-",
|
|
||||||
Name: agency?.first_name || "-",
|
|
||||||
Date: formatDateOfBirth(agency?.created_at) || "-",
|
|
||||||
Action: (
|
|
||||||
<HStack justifyContent="center" cursor={agency.response_status === 0 ? 'pointer' : 'default'}>
|
|
||||||
{agency.response_status === 0 ? <PendingRequests data={agency} refetch={refetch} /> : 'Resolved'}
|
|
||||||
{/* <PendingRequests data={agency} refetch={refetch} /> */}
|
|
||||||
</HStack>
|
</HStack>
|
||||||
),
|
),
|
||||||
}));
|
})),
|
||||||
|
];
|
||||||
if (isLoading) {
|
|
||||||
return (
|
|
||||||
<MainFrame>
|
|
||||||
<Box
|
|
||||||
display="flex"
|
|
||||||
justifyContent="center"
|
|
||||||
alignItems="center"
|
|
||||||
height="100%"
|
|
||||||
>
|
|
||||||
<Spinner />
|
|
||||||
</Box>
|
|
||||||
</MainFrame>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isError) {
|
|
||||||
return (
|
|
||||||
<MainFrame>
|
|
||||||
<Box
|
|
||||||
display="flex"
|
|
||||||
justifyContent="center"
|
|
||||||
alignItems="center"
|
|
||||||
height="100%"
|
|
||||||
>
|
|
||||||
<Text>Error loading data</Text>
|
|
||||||
</Box>
|
|
||||||
</MainFrame>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const ManageContact = () => {
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<MainFrame>
|
<MainFrame>
|
||||||
<Box>
|
<Box>
|
||||||
<HStack
|
<HStack
|
||||||
@@ -104,33 +43,40 @@ const ManageContact = () => {
|
|||||||
px={3}
|
px={3}
|
||||||
>
|
>
|
||||||
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
||||||
Contact Requests
|
Contact Requests
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<HStack>
|
<HStack >
|
||||||
<SearchComponent
|
<InputGroup
|
||||||
value={searchTerm}
|
startElement={
|
||||||
onChange={handleSearchChange}
|
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
|
||||||
/>
|
}
|
||||||
|
color={"#000"}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
p={3}
|
||||||
|
w={300}
|
||||||
|
bg={"#fff"}
|
||||||
|
colorPalette={"blue"}
|
||||||
|
_focus={{ border: "1px solid #02A0A0" }}
|
||||||
|
rounded={"md"}
|
||||||
|
size={"xs"}
|
||||||
|
fontSize={"sm"}
|
||||||
|
placeholder="Search..."
|
||||||
|
bgColor={'#EEEEEE'}
|
||||||
|
ps={8}
|
||||||
|
/>
|
||||||
|
</InputGroup>
|
||||||
|
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
|
||||||
</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}
|
||||||
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>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
export default ManageContact
|
||||||
export default ManageContact;
|
|
||||||
@@ -10,160 +10,95 @@ 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";
|
||||||
import { usePendingRequestMutation } from "../../Redux/Service/manage.contactus.service";
|
function PendingRequests() {
|
||||||
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">
|
||||||
<DialogRoot placement="center" key={data.id} open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
<DialogTrigger asChild>
|
||||||
<DialogTrigger asChild>
|
<Badge fontSize={"xs"} px={2} bg={'#02a0a01f'}>
|
||||||
<Badge fontSize={"xs"} px={2} bg={'#02a0a01f'} onClick={handleOpenModal}>
|
Answer request
|
||||||
Answer request
|
</Badge>
|
||||||
</Badge>
|
</DialogTrigger>
|
||||||
</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">
|
<DialogHeader bg="white">
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
||||||
Pending Requests
|
Pending Requests
|
||||||
</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">
|
||||||
Request Type
|
Request Type
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Message"
|
placeholder="Message"
|
||||||
bgColor="#EEEEEE"
|
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"
|
color="black"
|
||||||
_hover={{ bgColor: "white" }}
|
border="none"
|
||||||
variant="outline"
|
pl={1}
|
||||||
borderRadius="sm"
|
fontSize="12px"
|
||||||
border="1px solid #02A0A0"
|
height="30px"
|
||||||
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" />
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
</DialogContent>
|
Solution
|
||||||
</DialogRoot>
|
</Field.Label>
|
||||||
<Toaster />
|
<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"}>
|
||||||
|
<Button
|
||||||
|
width={"48%"}
|
||||||
|
color="black"
|
||||||
|
_hover={{ bgColor: "white" }}
|
||||||
|
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" />
|
||||||
|
</DialogContent>
|
||||||
|
</DialogRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Button } from "../../components/ui/button"
|
import { Button } from "../../components/ui/button"
|
||||||
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
|
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
|
||||||
import { Field, Heading, Input, Stack, Text } from "@chakra-ui/react"
|
import { Avatar, Box, Field, Heading, Input, Stack, Text } from "@chakra-ui/react"
|
||||||
import { Switch } from "../../components/ui/switch";
|
import { Switch } from "../../components/ui/switch";
|
||||||
import { IoMdAdd } from "react-icons/io";
|
import { IoMdAdd } from "react-icons/io";
|
||||||
function AddGroup() {
|
function AddGroup() {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "../../components/ui/dialog";
|
} from "../../components/ui/dialog";
|
||||||
import { Avatar, Box, Field, Heading, Input, Span, Stack } from "@chakra-ui/react";
|
import { Avatar, Box, Field, Heading, Input, Stack } from "@chakra-ui/react";
|
||||||
import { Switch } from "../../components/ui/switch";
|
import { Switch } from "../../components/ui/switch";
|
||||||
import { AvatarGroup } from "../../components/ui/avatar";
|
import { AvatarGroup } from "../../components/ui/avatar";
|
||||||
import Edit from "../../components/ActionIcons/Edit";
|
import Edit from "../../components/ActionIcons/Edit";
|
||||||
@@ -17,7 +17,7 @@ function EditDetailGroups() {
|
|||||||
return (
|
return (
|
||||||
<DialogRoot placement="center">
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Span><Edit /></Span>
|
<Edit />
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<DialogContent
|
<DialogContent
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
import { Box, HStack,
|
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
|
||||||
// Image,
|
|
||||||
Input, 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 ViewManageGroup from "./ViewManageGroup";
|
import ViewManageGroup from "./ViewManageGroup";
|
||||||
import EditDetailGroups from "./EditDetailGroup";
|
import EditDetailGroups from "./EditDetailGroup";
|
||||||
import AddGroup from "./AddGroup";
|
import AddGroup from "./AddGroup";
|
||||||
// import Delete from "../../components/ActionIcons/Delete";
|
import Delete from "../../components/ActionIcons/Delete";
|
||||||
// import ViewSubAdmin from "./ViewSubAdmin"
|
// import ViewSubAdmin from "./ViewSubAdmin"
|
||||||
|
|
||||||
// table data
|
// table data
|
||||||
@@ -35,7 +33,7 @@ const managepost: any[] = [
|
|||||||
<HStack justifyContent="center">
|
<HStack justifyContent="center">
|
||||||
<ViewManageGroup />
|
<ViewManageGroup />
|
||||||
<EditDetailGroups />
|
<EditDetailGroups />
|
||||||
{/* <AlertDailog
|
<AlertDailog
|
||||||
AltertTiggerIcon={() => <Delete />}
|
AltertTiggerIcon={() => <Delete />}
|
||||||
alertText="Delete Users"
|
alertText="Delete Users"
|
||||||
alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
|
alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
|
||||||
@@ -43,14 +41,11 @@ const managepost: any[] = [
|
|||||||
onConfirm={() => {
|
onConfirm={() => {
|
||||||
console.log("User deleted:", i + 1);
|
console.log("User deleted:", i + 1);
|
||||||
}}
|
}}
|
||||||
/> */}
|
/>
|
||||||
</HStack>
|
</HStack>
|
||||||
),
|
),
|
||||||
})),
|
})),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const ManageGroups = () => {
|
const ManageGroups = () => {
|
||||||
return (
|
return (
|
||||||
<MainFrame>
|
<MainFrame>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "../../components/ui/dialog";
|
} from "../../components/ui/dialog";
|
||||||
import { Avatar, Box, Field, Heading, Input, Span, Stack } from "@chakra-ui/react";
|
import { Avatar, Box, Field, Heading, Input, Stack } from "@chakra-ui/react";
|
||||||
import { Switch } from "../../components/ui/switch";
|
import { Switch } from "../../components/ui/switch";
|
||||||
import { AvatarGroup } from "../../components/ui/avatar";
|
import { AvatarGroup } from "../../components/ui/avatar";
|
||||||
import View from "../../components/ActionIcons/View";
|
import View from "../../components/ActionIcons/View";
|
||||||
@@ -15,7 +15,7 @@ function ViewManageGroup() {
|
|||||||
return (
|
return (
|
||||||
<DialogRoot placement="center">
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Span><View /></Span>
|
<View />
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<DialogContent
|
<DialogContent
|
||||||
|
|||||||
@@ -1,32 +1,13 @@
|
|||||||
import {
|
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
|
||||||
Box,
|
import { LuSearch } from "react-icons/lu";
|
||||||
HStack,
|
import { RiDeleteBin5Line } from "react-icons/ri";
|
||||||
Image,
|
import AlertDailog from "../../components/AlertDailog";
|
||||||
// Image,
|
|
||||||
Text,
|
|
||||||
} from "@chakra-ui/react";
|
|
||||||
// import { LuSearch } from "react-icons/lu";
|
|
||||||
// import { RiDeleteBin5Line } from "react-icons/ri";
|
|
||||||
// import AlertDailog from "../../components/AlertDailog";
|
|
||||||
import DataTable from "../../components/DataTable";
|
import 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 {
|
|
||||||
useDeleteJobsPostMutation,
|
|
||||||
useGetManageJobsQuery,
|
|
||||||
} from "../../Redux/Service/manage.jobs.service";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { Spinner } from "../../components/Sipnner/Spinner";
|
|
||||||
import Delete from "../../components/ActionIcons/Delete";
|
import Delete from "../../components/ActionIcons/Delete";
|
||||||
import { Toaster, toaster } from "../../components/ui/toaster";
|
|
||||||
import AlertDailog from "../../components/AlertDailog";
|
|
||||||
import { useDebounce } from "../../components/Hooks/useDebounce";
|
|
||||||
import SearchComponent from "../../components/SearchComponent";
|
|
||||||
// import { useState } from "react";
|
|
||||||
// import { useGetManageJobsQuery } from "../../Redux/Service/manage.jobs.service";
|
|
||||||
// import Delete from "../../components/ActionIcons/Delete";
|
|
||||||
|
|
||||||
// table data
|
// table data
|
||||||
|
|
||||||
@@ -40,106 +21,33 @@ const tableHeadRow = [
|
|||||||
"Action",
|
"Action",
|
||||||
];
|
];
|
||||||
|
|
||||||
const ManageJobs = () => {
|
const managepost: any[] = [
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
...Array.from({ length: 12 }, (_, i) => ({
|
||||||
const [localData, setLocalData] = useState([]);
|
"Sr. No": i + 1,
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
"Job Title": "Freelance content writer",
|
||||||
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
"Workspace mode": "Onsite",
|
||||||
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
|
Category: "IT",
|
||||||
const { data, refetch, isLoading, isError, isFetching } = useGetManageJobsQuery(queryArgs);
|
"Sub-category": "Flutter dev",
|
||||||
const [deleteJobsPost] = useDeleteJobsPostMutation();
|
Salary: "3.5 LPA",
|
||||||
const [deleteModal, setDeleteModal] = useState(false);
|
|
||||||
const [selectedJobsId, setSelectedJobsId] = useState<number | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data) {
|
|
||||||
setLocalData((data as any)?.data?.data || []);
|
|
||||||
}
|
|
||||||
}, [data]);
|
|
||||||
// console.log(data?.data.data);
|
|
||||||
|
|
||||||
const handleSearchChange = (value: string) => {
|
|
||||||
setSearchTerm(value);
|
|
||||||
setCurrentPage(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
setCurrentPage(page);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteJobs = async (jobsId: number) => {
|
|
||||||
try {
|
|
||||||
const response = await deleteJobsPost({ id: jobsId }).unwrap();
|
|
||||||
if (response?.status === "success") {
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Jobs deleted successfully",
|
|
||||||
type: "Success",
|
|
||||||
});
|
|
||||||
refetch();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error deleting FAQ:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Something went wrong",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const managepost = localData?.map((agency: any, index: number) => ({
|
|
||||||
"Sr. No": index + 1,
|
|
||||||
"Job Title": agency?.job_title,
|
|
||||||
"Workspace mode": agency?.workspace?.en_name,
|
|
||||||
Category: agency?.industry?.en_name,
|
|
||||||
"Sub-category": agency?.department?.en_name,
|
|
||||||
Salary: agency?.ctc_amount,
|
|
||||||
Action: (
|
Action: (
|
||||||
<HStack justifyContent="center">
|
<HStack justifyContent="center">
|
||||||
<ViewManageJob data={agency} />
|
<ViewManageJob />
|
||||||
<ManageJobsAdd data={agency} refetch={refetch}/>
|
<ManageJobsAdd />
|
||||||
<AlertDailog
|
<AlertDailog
|
||||||
isOpen={deleteModal}
|
AltertTiggerIcon={() => <Delete />}
|
||||||
AltertTiggerIcon={() => (
|
alertText="Delete Users"
|
||||||
<Delete
|
|
||||||
onClick={() => {
|
|
||||||
setSelectedJobsId(agency.id);
|
|
||||||
setDeleteModal(true);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
alertText="Delete FAQ"
|
|
||||||
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)}
|
|
||||||
onConfirm={() => {
|
onConfirm={() => {
|
||||||
// console.log("Deleting FAQ with ID:", selectedFaqId); // Correct ID
|
console.log("User deleted:", i + 1);
|
||||||
if (selectedJobsId) {
|
|
||||||
setDeleteModal(false);
|
|
||||||
handleDeleteJobs(selectedJobsId);
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</HStack>
|
</HStack>
|
||||||
),
|
),
|
||||||
}));
|
})),
|
||||||
|
];
|
||||||
if (isLoading) {
|
|
||||||
return (
|
|
||||||
<MainFrame>
|
|
||||||
<Box
|
|
||||||
display="flex"
|
|
||||||
justifyContent="center"
|
|
||||||
alignItems="center"
|
|
||||||
height="100%"
|
|
||||||
>
|
|
||||||
<Spinner />
|
|
||||||
</Box>
|
|
||||||
</MainFrame>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const ManageJobs = () => {
|
||||||
return (
|
return (
|
||||||
<MainFrame>
|
<MainFrame>
|
||||||
<Box>
|
<Box>
|
||||||
@@ -155,10 +63,29 @@ const ManageJobs = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<HStack>
|
<HStack>
|
||||||
<SearchComponent
|
<InputGroup
|
||||||
value={searchTerm}
|
startElement={
|
||||||
onChange={handleSearchChange}
|
<LuSearch
|
||||||
/>
|
fontSize={"xs"}
|
||||||
|
style={{ position: "relative", left: "10px" }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
color={"#000"}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
p={3}
|
||||||
|
w={300}
|
||||||
|
bg={"#fff"}
|
||||||
|
colorPalette={"blue"}
|
||||||
|
_focus={{ border: "1px solid #02A0A0" }}
|
||||||
|
rounded={"md"}
|
||||||
|
size={"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>
|
||||||
@@ -166,18 +93,8 @@ 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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import {
|
import {
|
||||||
Field,
|
Field,
|
||||||
|
Icon,
|
||||||
Input,
|
Input,
|
||||||
Span,
|
SelectValueText,
|
||||||
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 {
|
||||||
@@ -16,156 +18,29 @@ import {
|
|||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} 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>
|
||||||
<Span><Edit /></Span>
|
<Edit />
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<DialogContent
|
<DialogContent
|
||||||
@@ -198,182 +73,50 @@ function ManageJobsAdd({ data, refetch }: { data: JobStatusData, refetch: () =>
|
|||||||
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>
|
||||||
<select
|
<Input
|
||||||
style={{
|
placeholder="Enter the Workspace Mode"
|
||||||
backgroundColor: "#EEEEEE",
|
bgColor="#EEEEEE"
|
||||||
color: "black",
|
color="black"
|
||||||
border: "none",
|
border="none"
|
||||||
height: "30px",
|
pl={1}
|
||||||
fontSize: "12px",
|
fontSize="12px"
|
||||||
padding: "4px",
|
height="30px"
|
||||||
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>
|
||||||
<select
|
<Input
|
||||||
style={{
|
placeholder="Enter the Category"
|
||||||
backgroundColor: "#EEEEEE",
|
bgColor="#EEEEEE"
|
||||||
color: "black",
|
color="black"
|
||||||
border: "none",
|
border="none"
|
||||||
height: "30px",
|
pl={1}
|
||||||
fontSize: "12px",
|
fontSize="12px"
|
||||||
padding: "4px",
|
height="30px"
|
||||||
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>
|
||||||
<select
|
<Input
|
||||||
style={{
|
placeholder="Enter the Sub-Category"
|
||||||
backgroundColor: "#EEEEEE",
|
bgColor="#EEEEEE"
|
||||||
color: "black",
|
color="black"
|
||||||
border: "none",
|
border="none"
|
||||||
height: "30px",
|
pl={1}
|
||||||
fontSize: "12px",
|
fontSize="12px"
|
||||||
padding: "4px",
|
height="30px"
|
||||||
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
|
||||||
@@ -386,13 +129,6 @@ function ManageJobsAdd({ data, refetch }: { data: JobStatusData, refetch: () =>
|
|||||||
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>
|
||||||
@@ -400,20 +136,13 @@ function ManageJobsAdd({ data, refetch }: { data: JobStatusData, refetch: () =>
|
|||||||
Experience
|
Experience
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Enter the Experience in years"
|
placeholder="Enter the Experience"
|
||||||
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>
|
||||||
@@ -428,34 +157,71 @@ function ManageJobsAdd({ data, refetch }: { data: JobStatusData, refetch: () =>
|
|||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
value={state.jobLocation}
|
|
||||||
onChange={(e) =>
|
|
||||||
dispatch({
|
|
||||||
type: "SET_JOB_LOCATION",
|
|
||||||
payload: e.target.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
<Field.Root>
|
{/* <Field.Label pt={1} color="black" fontSize="12px">Country Selection</Field.Label>
|
||||||
<Field.Label pt={1} color="black" fontSize="12px">
|
<Input placeholder="Enter the Country Selection" /> */}
|
||||||
Skills description
|
<SelectRoot collection={frameworks} size="sm" w={"100%"}>
|
||||||
</Field.Label>
|
<SelectLabel pt={1} color="black" fontSize="12px">
|
||||||
<Input
|
Country Selection
|
||||||
placeholder="Enter the Skills description"
|
</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.Label pt={1} color="black" fontSize="12px">
|
||||||
|
Skills required
|
||||||
|
</Field.Label>
|
||||||
|
<Input
|
||||||
|
placeholder="Enter the Skills Required"
|
||||||
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>
|
||||||
@@ -470,13 +236,6 @@ function ManageJobsAdd({ data, refetch }: { data: JobStatusData, refetch: () =>
|
|||||||
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>
|
||||||
@@ -488,16 +247,13 @@ function ManageJobsAdd({ data, refetch }: { data: JobStatusData, refetch: () =>
|
|||||||
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" ref={closeRef} />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<Toaster />
|
|
||||||
</DialogRoot>
|
</DialogRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +1,48 @@
|
|||||||
import {
|
import {
|
||||||
Field,
|
Field,
|
||||||
|
Icon,
|
||||||
Input,
|
Input,
|
||||||
|
SelectValueText,
|
||||||
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,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} 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 { JobStatusData, useLazyViewJobsQuery } from "../../Redux/Service/manage.jobs.service";
|
|
||||||
|
|
||||||
function ViewManageJob({ data }: { data: JobStatusData }) {
|
|
||||||
const [trigger] = useLazyViewJobsQuery();
|
|
||||||
|
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
const handleView = () => {
|
|
||||||
trigger(data.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
// const viewJobs = data;
|
|
||||||
|
|
||||||
console.log();
|
|
||||||
|
|
||||||
|
const frameworks = createListCollection({
|
||||||
|
items: [
|
||||||
|
{ label: "React.js", value: "react" },
|
||||||
|
{ label: "Vue.js", value: "vue" },
|
||||||
|
{ label: "Angular", value: "angular" },
|
||||||
|
{ label: "Svelte", value: "svelte" },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
function ViewManageJob() {
|
||||||
return (
|
return (
|
||||||
<DialogRoot placement="center">
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button
|
<View />
|
||||||
onClick={handleView}
|
|
||||||
bg={'transparent'}
|
|
||||||
color={"black"}
|
|
||||||
>
|
|
||||||
<View />
|
|
||||||
</Button>
|
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
{/* {viewJobs?.map((data: any) => ( */}
|
|
||||||
<DialogContent
|
<DialogContent
|
||||||
bg={"#fff"}
|
bg={"#fff"}
|
||||||
// w={{ lg: "60%", md: "230px" }}
|
// w={{ lg: "60%", md: "230px" }}
|
||||||
@@ -74,7 +73,6 @@ function ViewManageJob({ data }: { data: JobStatusData }) {
|
|||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
value={data?.job_title}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
@@ -89,7 +87,6 @@ function ViewManageJob({ data }: { data: JobStatusData }) {
|
|||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
value={data?.workspace?.en_name}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
@@ -104,7 +101,6 @@ function ViewManageJob({ data }: { data: JobStatusData }) {
|
|||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
value={data?.industry?.en_name}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
@@ -119,7 +115,6 @@ function ViewManageJob({ data }: { data: JobStatusData }) {
|
|||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
value={data?.department?.en_name}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
@@ -134,7 +129,6 @@ function ViewManageJob({ data }: { data: JobStatusData }) {
|
|||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
value={data?.ctc_amount}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
@@ -149,7 +143,6 @@ function ViewManageJob({ data }: { data: JobStatusData }) {
|
|||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
value={data?.experience}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
@@ -164,27 +157,11 @@ function ViewManageJob({ data }: { data: JobStatusData }) {
|
|||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
value={data?.job_location}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
|
{/* <Field.Label pt={1} color="black" fontSize="12px">Country Selection</Field.Label>
|
||||||
<Field.Root>
|
<Input placeholder="Enter the Country Selection" /> */}
|
||||||
<Field.Label pt={1} color="black" fontSize="12px">
|
<SelectRoot collection={frameworks} size="sm" w={"100%"}>
|
||||||
Country
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter the Country"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={data?.country.en_name}
|
|
||||||
/>
|
|
||||||
</Field.Root>
|
|
||||||
|
|
||||||
{/* <SelectRoot collection={frameworks} size="sm" w={"100%"}>
|
|
||||||
<SelectLabel pt={1} color="black" fontSize="12px">
|
<SelectLabel pt={1} color="black" fontSize="12px">
|
||||||
Country Selection
|
Country Selection
|
||||||
</SelectLabel>
|
</SelectLabel>
|
||||||
@@ -203,11 +180,7 @@ function ViewManageJob({ data }: { data: JobStatusData }) {
|
|||||||
fontSize={"12px"}
|
fontSize={"12px"}
|
||||||
/>
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent
|
<SelectContent position={"relative"} zIndex={"9999"} bg={"#fff"}>
|
||||||
position={"relative"}
|
|
||||||
zIndex={"9999"}
|
|
||||||
bg={"#fff"}
|
|
||||||
>
|
|
||||||
{frameworks.items.map((movie) => (
|
{frameworks.items.map((movie) => (
|
||||||
<SelectItem
|
<SelectItem
|
||||||
item={movie}
|
item={movie}
|
||||||
@@ -222,7 +195,7 @@ function ViewManageJob({ data }: { data: JobStatusData }) {
|
|||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</SelectRoot> */}
|
</SelectRoot>
|
||||||
|
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
<Field.Label pt={1} color="black" fontSize="12px">
|
<Field.Label pt={1} color="black" fontSize="12px">
|
||||||
@@ -236,7 +209,6 @@ function ViewManageJob({ data }: { data: JobStatusData }) {
|
|||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
value={data?.job_type?.en_name}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
@@ -251,7 +223,6 @@ function ViewManageJob({ data }: { data: JobStatusData }) {
|
|||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
value={data?.skill_description}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
@@ -266,10 +237,9 @@ function ViewManageJob({ data }: { data: JobStatusData }) {
|
|||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
value={data?.job_description}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
{/* <Field.Root>
|
<Field.Root>
|
||||||
<Field.Label pt={1} color="black" fontSize="12px">
|
<Field.Label pt={1} color="black" fontSize="12px">
|
||||||
Upload Image
|
Upload Image
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
@@ -282,10 +252,10 @@ function ViewManageJob({ data }: { data: JobStatusData }) {
|
|||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
/>
|
/>
|
||||||
</Field.Root> */}
|
</Field.Root>
|
||||||
</Stack>
|
</Stack>
|
||||||
</DialogBody>
|
</DialogBody>
|
||||||
{/* <DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
||||||
<Button
|
<Button
|
||||||
w="100%"
|
w="100%"
|
||||||
bg="#02A0A0"
|
bg="#02A0A0"
|
||||||
@@ -295,11 +265,10 @@ function ViewManageJob({ data }: { data: JobStatusData }) {
|
|||||||
>
|
>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter> */}
|
</DialogFooter>
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
{/* ))} */}
|
|
||||||
</DialogRoot>
|
</DialogRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,211 +1,65 @@
|
|||||||
import {
|
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
|
||||||
Box, HStack, Icon, Image,
|
|
||||||
// Span,
|
|
||||||
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 { Switch } from "../../components/ui/switch";
|
import { Switch } from "../../components/ui/switch";
|
||||||
// import img from "../../assets/waterfall.jpg";
|
import img from "../../assets/waterfall.jpg";
|
||||||
// import { RiDeleteBin5Line } from "react-icons/ri";
|
import { RiDeleteBin5Line } from "react-icons/ri";
|
||||||
import ViewDailog from "./ViewDailog";
|
import ViewDailog from "./ViewDailog";
|
||||||
import { useGetManagePostsQuery, usePostStatusToggleMutation } from "../../Redux/Service/manage.post.service";
|
import Delete from "../../components/ActionIcons/Delete";
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { Toaster, toaster } from "../../components/ui/toaster";
|
|
||||||
import { FaVideo } from "react-icons/fa";
|
|
||||||
import SearchComponent from "../../components/SearchComponent";
|
|
||||||
import { delay } from "../../components/Utils";
|
|
||||||
// import Delete from "../../components/ActionIcons/Delete";
|
|
||||||
// import ViewDailog from './ViewDailog'
|
// import ViewDailog from './ViewDailog'
|
||||||
|
|
||||||
const APIURL = import.meta.env.VITE_POST_IMG
|
// table data
|
||||||
|
|
||||||
const tableHeadRow = [
|
const tableHeadRow = [
|
||||||
"Sr. No",
|
"Sr. No",
|
||||||
"Images",
|
"Images",
|
||||||
"Description",
|
"Description",
|
||||||
"Publish Data",
|
"Publish Data",
|
||||||
// "Activate/Deactivate",
|
"Activate/Deactivate",
|
||||||
"Action",
|
"Action",
|
||||||
];
|
];
|
||||||
|
|
||||||
// const managepost: any[] = [
|
const managepost: any[] = [
|
||||||
// ...Array.from({ length: 12 }, (_, i) => ({
|
...Array.from({ length: 12 }, (_, i) => ({
|
||||||
// "Sr. No": i + 1,
|
"Sr. No": i + 1,
|
||||||
// Images: (
|
|
||||||
// // <Image w={50} src={img} />
|
|
||||||
// <Image rounded={"lg"} w={100} h={50} src={img} />
|
|
||||||
// ),
|
|
||||||
// Description: (
|
|
||||||
// <Text>
|
|
||||||
// {`Lorem ipsum dolor, sit amet consectetur adipisicing elit.}`.slice(
|
|
||||||
// 0,
|
|
||||||
// 30
|
|
||||||
// ) + "..."}
|
|
||||||
// </Text>
|
|
||||||
// ),
|
|
||||||
// "Publish Data": "12/01/2025",
|
|
||||||
// "Activate/Deactivate": (
|
|
||||||
// <Box w={"100%"}>
|
|
||||||
// <Switch size={"sm"} colorPalette={"teal"} />
|
|
||||||
// </Box>
|
|
||||||
// ),
|
|
||||||
// Action: (
|
|
||||||
// <HStack justifyContent="center">
|
|
||||||
// <ViewDailog />
|
|
||||||
// {/* <AlertDailog
|
|
||||||
// AltertTiggerIcon={() => <Span><Delete /> </Span>}
|
|
||||||
// alertText="Delete Users"
|
|
||||||
// alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
|
|
||||||
// alertCaption="are you sure you want to delete ?"
|
|
||||||
// onConfirm={() => {
|
|
||||||
// console.log("User deleted:", i + 1);
|
|
||||||
// }}
|
|
||||||
// /> */}
|
|
||||||
// </HStack>
|
|
||||||
// ),
|
|
||||||
// })),
|
|
||||||
// ];
|
|
||||||
|
|
||||||
const ManagePost = () => {
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
const { data, refetch, isFetching, isError } = useGetManagePostsQuery(currentPage)
|
|
||||||
const [localData, setLocalData] = useState<any[]>([]);
|
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const [postStatusToggle] = usePostStatusToggleMutation()
|
|
||||||
console.log('POSTS', data?.data.data);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data?.data?.data) {
|
|
||||||
setLocalData(data?.data.data);
|
|
||||||
}
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
setCurrentPage(page);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleToggle = async (agencyId: string, currentStatus: number) => {
|
|
||||||
const newStatus = currentStatus ? 0 : 1;
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
await postStatusToggle({ id: agencyId, is_active: newStatus }).unwrap();
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Status updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
await delay(500);
|
|
||||||
refetch()
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Someting went wrong.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function formatAPIDate(apiDateString: any) {
|
|
||||||
const date = new Date(apiDateString);
|
|
||||||
|
|
||||||
// Get month, day, and year
|
|
||||||
const month = date.getMonth() + 1; // Months are 0-indexed
|
|
||||||
const day = date.getDate();
|
|
||||||
const year = date.getFullYear();
|
|
||||||
|
|
||||||
// Pad with leading zeros if needed
|
|
||||||
const formattedMonth = month.toString().padStart(2, '0');
|
|
||||||
const formattedDay = day.toString().padStart(2, '0');
|
|
||||||
|
|
||||||
return `${formattedMonth}/${formattedDay}/${year}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const filteredData = localData?.filter((agency) => {
|
|
||||||
return (agency.post_content_translation.some((item: any) => {
|
|
||||||
const searchLower = searchTerm.toLowerCase();
|
|
||||||
const title = item.content?.toLowerCase().includes(searchLower);
|
|
||||||
return title;
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
|
|
||||||
const managepost = filteredData?.flatMap((agency: any, index: number) => (agency.post_content_translation.map((translation: any) => ({
|
|
||||||
'id': agency.id,
|
|
||||||
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
|
|
||||||
Images: (
|
Images: (
|
||||||
agency.images.length > 0 ?
|
// <Image w={50} src={img} />
|
||||||
agency.images[0].type === "image" ? (
|
<Image rounded={"lg"} w={100} h={50} src={img} />
|
||||||
<HStack>
|
|
||||||
<Image
|
|
||||||
rounded={"lg"}
|
|
||||||
w={100}
|
|
||||||
h={50}
|
|
||||||
src={`${APIURL}${agency.images[0].image_name}`}
|
|
||||||
/>
|
|
||||||
<Text fontSize="xs" color={'lightgray'}>
|
|
||||||
{`${Number(agency.images.length) > 1 ? '+' + (Number(agency.images.length) - 1) : ''}`}
|
|
||||||
</Text>
|
|
||||||
</HStack>
|
|
||||||
) : (
|
|
||||||
<HStack>
|
|
||||||
<Box
|
|
||||||
rounded={"lg"}
|
|
||||||
w={100}
|
|
||||||
h={50}
|
|
||||||
bg="gray.200"
|
|
||||||
display="flex"
|
|
||||||
alignItems="center"
|
|
||||||
justifyContent="center"
|
|
||||||
>
|
|
||||||
<Icon as={FaVideo} color="gray.500" />
|
|
||||||
</Box>
|
|
||||||
<Text fontSize="xs" color={'lightgray'}>
|
|
||||||
{`${Number(agency.images.length) > 1 ? '+' + (Number(agency.images.length) - 1) : ''}`}
|
|
||||||
</Text>
|
|
||||||
</HStack>
|
|
||||||
) : ''
|
|
||||||
// <Image rounded={"lg"} w={100} h={50} src={img} />
|
|
||||||
),
|
),
|
||||||
Description: (
|
Description: (
|
||||||
<Text>
|
<Text>
|
||||||
{translation?.content?.length > 30
|
{`Lorem ipsum dolor, sit amet consectetur adipisicing elit.}`.slice(
|
||||||
? `${translation.content.slice(0, 30)}...`
|
0,
|
||||||
: translation?.content}
|
30
|
||||||
|
) + "..."}
|
||||||
</Text>
|
</Text>
|
||||||
),
|
),
|
||||||
"Publish Data": formatAPIDate(agency.created_at),
|
"Publish Data": "12/01/2025",
|
||||||
"is_active": agency.is_active,
|
"Activate/Deactivate": (
|
||||||
"Action": (
|
<Box w={"100%"}>
|
||||||
|
<Switch size={"sm"} colorPalette={"teal"} />
|
||||||
|
</Box>
|
||||||
|
),
|
||||||
|
Action: (
|
||||||
<HStack justifyContent="center">
|
<HStack justifyContent="center">
|
||||||
{/* <ViewAgencyMaster agency={localData} id={agency.id} /> */}
|
<ViewDailog />
|
||||||
<ViewDailog localData={{ ...agency, translation }} refetch={refetch} />
|
<AlertDailog
|
||||||
<Box>
|
AltertTiggerIcon={() => <Delete />}
|
||||||
<Switch
|
alertText="Delete Users"
|
||||||
colorPalette={"teal"}
|
alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
|
||||||
size={"xs"}
|
alertCaption="are you sure you want to delete ?"
|
||||||
onChange={() => handleToggle(agency.id, Number(agency.is_active))}
|
onConfirm={() => {
|
||||||
checked={Boolean(Number(agency.is_active))}
|
console.log("User deleted:", i + 1);
|
||||||
/>
|
}}
|
||||||
</Box>
|
/>
|
||||||
</HStack>
|
</HStack>
|
||||||
),
|
),
|
||||||
}))));
|
})),
|
||||||
|
];
|
||||||
|
const ManagePost = () => {
|
||||||
return (
|
return (
|
||||||
<MainFrame>
|
<MainFrame>
|
||||||
<Box>
|
<Box>
|
||||||
@@ -221,32 +75,37 @@ const ManagePost = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<HStack>
|
<HStack>
|
||||||
<SearchComponent
|
<InputGroup
|
||||||
value={searchTerm}
|
startElement={
|
||||||
onChange={(value) => {
|
<LuSearch
|
||||||
setSearchTerm(value);
|
fontSize={"xs"}
|
||||||
// setCurrentPage(1);
|
style={{ position: "relative", left: "10px" }}
|
||||||
refetch()
|
/>
|
||||||
}}
|
}
|
||||||
/>
|
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}
|
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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
import { Field, HStack, Image, Input, Stack } from "@chakra-ui/react"
|
import { Field, Icon, Image, Input, Stack } from "@chakra-ui/react"
|
||||||
// import { TbEdit } from "react-icons/tb"
|
import { TbEdit } from "react-icons/tb"
|
||||||
// import img from "../../assets/waterfall.jpg"
|
import img from "../../assets/waterfall.jpg"
|
||||||
import { DialogBody, DialogCloseTrigger, DialogContent, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
|
import { DialogBody, DialogCloseTrigger, DialogContent, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
|
||||||
// import Edit from "../../components/ActionIcons/Edit"
|
import Edit from "../../components/ActionIcons/Edit"
|
||||||
import { LuEye } from "react-icons/lu"
|
|
||||||
|
|
||||||
const APIURL = import.meta.env.VITE_POST_IMG
|
function ViewDailog() {
|
||||||
|
|
||||||
function ViewDailog({ localData }: { localData: any, refetch: VoidFunction }) {
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<DialogRoot placement="center">
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
{/* <Span><Edit /></Span> */}
|
<Edit />
|
||||||
<LuEye fontSize={"xm"} cursor={'pointer'} />
|
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<DialogContent
|
<DialogContent
|
||||||
@@ -28,49 +25,17 @@ function ViewDailog({ localData }: { localData: any, 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">Title</Field.Label>
|
||||||
|
<Input placeholder="Enter the Title" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly />
|
||||||
|
|
||||||
|
<Field.Label color="black" pt={1} fontSize="12px">Subtitle</Field.Label>
|
||||||
|
<Input placeholder="Enter the Subtitle" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly />
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Description</Field.Label>
|
<Field.Label color="black" pt={1} fontSize="12px">Description</Field.Label>
|
||||||
<Input
|
<Input placeholder="Enter the Description" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly />
|
||||||
// placeholder="Enter the Title"
|
|
||||||
value={localData.translation.content}
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
readOnly
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* <Field.Label color="black" pt={1} fontSize="12px">Subtitle</Field.Label>
|
|
||||||
<Input placeholder="Enter the Subtitle" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly /> */}
|
|
||||||
|
|
||||||
{/* <Field.Label color="black" pt={1} fontSize="12px">Description</Field.Label>
|
|
||||||
<Input placeholder="Enter the Description" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" readOnly /> */}
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Image</Field.Label>
|
<Field.Label color="black" pt={1} fontSize="12px">Image</Field.Label>
|
||||||
<HStack w="fit-content" flexWrap={'wrap'}>
|
<Image src={img} w="100%" maxH="150px" objectFit="contain" />
|
||||||
{localData.images.map((img: any) => (
|
|
||||||
img.type === 'image' ? (
|
|
||||||
<Image
|
|
||||||
key={img.id}
|
|
||||||
src={`${APIURL}${img.image_name}`}
|
|
||||||
w="30%"
|
|
||||||
maxH="150px"
|
|
||||||
objectFit="contain"
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<video
|
|
||||||
key={img.id}
|
|
||||||
width="45%"
|
|
||||||
height="50"
|
|
||||||
controls
|
|
||||||
>
|
|
||||||
<source src={`${APIURL}${img.image_name}`} type="video/mp4" />
|
|
||||||
</video>
|
|
||||||
)
|
|
||||||
))}
|
|
||||||
</HStack>
|
|
||||||
|
|
||||||
{/* <Image src={img} w="100%" maxH="150px" objectFit="contain" /> */}
|
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
</Stack>
|
</Stack>
|
||||||
</DialogBody>
|
</DialogBody>
|
||||||
|
|||||||
@@ -1,129 +1,37 @@
|
|||||||
import { Box, HStack, Text } from "@chakra-ui/react";
|
import { Box, HStack, Input, Text } from "@chakra-ui/react";
|
||||||
import MainFrame from "../../../components/MainFrame";
|
import 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 { useEffect, useState } from "react";
|
|
||||||
import { Spinner } from "../../../components/Sipnner/Spinner";
|
|
||||||
import { useGetDeactivateUserQuery, useUserDeactivateToggleMutation } from "../../../Redux/Service/manage.user";
|
|
||||||
import SearchComponent from "../../../components/SearchComponent";
|
|
||||||
import { Toaster, toaster } from "../../../components/ui/toaster";
|
|
||||||
import { delay } from "../../../components/Utils";
|
|
||||||
|
|
||||||
const tableHeadRow = [
|
const tableHeadRow = [
|
||||||
"Sr. No",
|
"Sr. No",
|
||||||
"First Name",
|
"First Name",
|
||||||
"Last Name",
|
"Last Name",
|
||||||
"User Type",
|
"Company name",
|
||||||
"Activate/Deactivate",
|
"Activate/Deactivate",
|
||||||
];
|
];
|
||||||
|
|
||||||
const DeactivatedAccounts = () => {
|
const manageUser: any[] = [
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
...Array.from({ length: 12 }, (_, i) => ({
|
||||||
const { data, isLoading, refetch, isError, isFetching } = useGetDeactivateUserQuery(currentPage);
|
"Sr. No": i + 1,
|
||||||
const [localData, setLocalData] = useState<any[]>([]);
|
"First Name": "Ritesh",
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
"Last Name": "akanksha@gmail.com",
|
||||||
const [userDeactivateToggle] = useUserDeactivateToggleMutation()
|
"Company name": "9876543210",
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data) {
|
|
||||||
setLocalData((data as any)?.data?.data || []);
|
|
||||||
}
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
setCurrentPage(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
const filteredData = localData?.filter((agency) => {
|
|
||||||
const searchLower = searchTerm.toLowerCase();
|
|
||||||
const firstName = agency.first_name?.toLowerCase().includes(searchLower);
|
|
||||||
const lastName = agency.last_name?.toLowerCase().includes(searchLower);
|
|
||||||
// const email = agency.capital?.toLowerCase().includes(searchLower);
|
|
||||||
return firstName || lastName;
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleToggle = async (agencyId: number, currentStatus: string) => {
|
|
||||||
const newStatus = currentStatus === '1' ? '0' : '1';
|
|
||||||
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await userDeactivateToggle({ id: agencyId, is_active: newStatus }).unwrap();
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Status updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
await delay(500);
|
|
||||||
refetch()
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating privacy policy:", error);
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const manageUser = filteredData?.map((agency: any, index: number) => ({
|
|
||||||
"Sr. No": index + 1,
|
|
||||||
"First Name": agency?.first_name,
|
|
||||||
"Last Name": agency?.last_name,
|
|
||||||
"User Type": agency?.principal_type_xid === 3 ? "JobSeeker" : "Recruiter",
|
|
||||||
"Activate/Deactivate": (
|
"Activate/Deactivate": (
|
||||||
<Box display={"flex"} justifyContent={"center"}>
|
<Box display={'flex'} justifyContent={'center'}>
|
||||||
<Switch
|
<Switch size={'sm'} colorPalette={'teal'} />
|
||||||
size={"sm"}
|
|
||||||
colorPalette={"teal"}
|
|
||||||
checked={agency.is_active === true}
|
|
||||||
onChange={() => handleToggle(agency.id, agency.is_active ? "1" : "0")}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
),
|
),
|
||||||
}));
|
})),
|
||||||
|
];
|
||||||
if (isLoading) {
|
|
||||||
return (
|
|
||||||
<MainFrame>
|
|
||||||
<Box
|
|
||||||
display="flex"
|
|
||||||
justifyContent="center"
|
|
||||||
alignItems="center"
|
|
||||||
height="100%"
|
|
||||||
>
|
|
||||||
<Spinner />
|
|
||||||
</Box>
|
|
||||||
</MainFrame>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (isError) {
|
|
||||||
// return (
|
|
||||||
// <MainFrame>
|
|
||||||
// <Box
|
|
||||||
// display="flex"
|
|
||||||
// justifyContent="center"
|
|
||||||
// alignItems="center"
|
|
||||||
// height="100%"
|
|
||||||
// >
|
|
||||||
// <Text>Error loading data</Text>
|
|
||||||
// </Box>
|
|
||||||
// </MainFrame>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
const DeactivatedAccounts = () => {
|
||||||
return (
|
return (
|
||||||
<MainFrame>
|
<MainFrame>
|
||||||
<Box>
|
<Box>
|
||||||
<HStack
|
<HStack
|
||||||
w={"100%"}
|
w={"100%"}
|
||||||
justifyContent={"space-between"}
|
justifyContent={"space-between"}
|
||||||
mb={4}
|
mb={4}
|
||||||
@@ -131,36 +39,38 @@ const DeactivatedAccounts = () => {
|
|||||||
px={3}
|
px={3}
|
||||||
>
|
>
|
||||||
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
||||||
Deactivated User Accounts
|
Deactivated User Accounts
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<HStack>
|
<HStack>
|
||||||
<SearchComponent
|
<InputGroup
|
||||||
value={searchTerm}
|
startElement={
|
||||||
onChange={(value) => {
|
<LuSearch fontSize={"xs"} style={{position:'relative',left:'10px'}} />
|
||||||
setSearchTerm(value);
|
}
|
||||||
// setCurrentPage(1);
|
color={"#000"}
|
||||||
refetch()
|
>
|
||||||
}}
|
<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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Box, Field, Input, Stack } from "@chakra-ui/react";
|
import { Field, Input, Stack } from "@chakra-ui/react";
|
||||||
import {
|
import {
|
||||||
DialogActionTrigger,
|
DialogActionTrigger,
|
||||||
DialogBody,
|
DialogBody,
|
||||||
@@ -12,32 +12,8 @@ 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>
|
||||||
@@ -47,13 +23,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">
|
||||||
@@ -68,110 +44,42 @@ function AddRegisterUsers() {
|
|||||||
First Name
|
First Name
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
|
||||||
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"
|
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
|
||||||
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"
|
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
|
||||||
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"
|
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
|
||||||
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.Root>
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
<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"
|
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
|
||||||
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>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// import { MdOutlineRemoveRedEye } from "react-icons/md";
|
import { MdOutlineRemoveRedEye } from "react-icons/md";
|
||||||
import { Box, Field, HStack, Input, Stack } from "@chakra-ui/react";
|
import { Field, Icon, Input, Stack } from "@chakra-ui/react";
|
||||||
import {
|
import {
|
||||||
|
DialogActionTrigger,
|
||||||
DialogBody,
|
DialogBody,
|
||||||
DialogCloseTrigger,
|
DialogCloseTrigger,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -10,336 +11,88 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "../../../components/ui/dialog";
|
} from "../../../components/ui/dialog";
|
||||||
// import { BiEdit } from "react-icons/bi";
|
import { BiEdit } from "react-icons/bi";
|
||||||
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">
|
||||||
<DialogRoot placement="center" key={formData.id} open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
<DialogTrigger asChild>
|
||||||
<DialogTrigger asChild>
|
<Edit/>
|
||||||
{/* <Span>
|
</DialogTrigger>
|
||||||
<Edit />
|
|
||||||
</Span> */}
|
|
||||||
<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" border="none" pl={1} fontSize="12px" height="30px"
|
||||||
color="black"
|
/>
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
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" border="none" pl={1} fontSize="12px" height="30px"
|
||||||
color="black"
|
/>
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={formData.last_name}
|
|
||||||
onChange={(e) => setFormData({ ...formData, last_name: e.target.value })}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
Gender
|
Gender
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
|
||||||
color="black"
|
/>
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={formData.gender}
|
|
||||||
onChange={(e) => setFormData({ ...formData, gender: e.target.value })}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
DOB
|
DOB
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
|
||||||
color="black"
|
/>
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={formData.date_of_birth ? new Date(formData.date_of_birth).toLocaleDateString('en-GB').replace(/\//g, '-') : 'N/A'}
|
|
||||||
onChange={(e) => setFormData({ ...formData, date_of_birth: e.target.value })}
|
|
||||||
disabled={formData.principal_type_xid === 2 ? true : false}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
Mobile Number
|
OTP Verified
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
|
||||||
color="black"
|
/>
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={formData.phone_number || ''}
|
|
||||||
onChange={(e) => setFormData({ ...formData, phone_number: e.target.value })}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
Type Of User
|
Language
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
{/* <Input
|
<Input
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
|
||||||
color="black"
|
/>
|
||||||
border="none"
|
</Field.Root>
|
||||||
pl={1}
|
</Stack>
|
||||||
fontSize="12px"
|
</DialogBody>
|
||||||
height="30px"
|
<DialogFooter mt={5}>
|
||||||
value={formData.principal_type?.principal_type_title || 'N/A'}
|
<DialogActionTrigger asChild>
|
||||||
onChange={(e) => setFormData({ ...formData, principal_type: { ...formData.principal_type, principal_type_title: e.target.value } })}
|
<Button rounded={'md'} w={"100%"} size={'sm'} bg={'#02A0A0'}>Save</Button>
|
||||||
/> */}
|
</DialogActionTrigger>
|
||||||
|
</DialogFooter>
|
||||||
<Box>
|
<DialogCloseTrigger color="black" />
|
||||||
<select
|
</DialogContent>
|
||||||
style={{
|
</DialogRoot>
|
||||||
width: "100%",
|
|
||||||
background: "transparent",
|
|
||||||
color: "black",
|
|
||||||
border: "none",
|
|
||||||
fontSize: "12px",
|
|
||||||
height: "30px",
|
|
||||||
outline: "none",
|
|
||||||
}}
|
|
||||||
value={formData.principal_type_xid?.toString() || 'N/A'}
|
|
||||||
onChange={(e) => setFormData({ ...formData, principal_type_xid: Number(e.target.value) })}
|
|
||||||
>
|
|
||||||
{/* <option value="">Select User Type</option> */}
|
|
||||||
<option value="2">Recruiter</option>
|
|
||||||
<option value="3">Jobseeker</option>
|
|
||||||
</select>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
Default Language
|
|
||||||
</Field.Label>
|
|
||||||
{/* <Input
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={formData?.principle_language_linkss?.language_xid || 'N/A'}
|
|
||||||
onChange={(e) => setFormData({
|
|
||||||
...formData, principle_language_linkss: {
|
|
||||||
...formData?.principle_language_linkss, language_xid: e.target.value
|
|
||||||
.split(",")
|
|
||||||
.map(lang => lang.trim())
|
|
||||||
.filter(Boolean)
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
/> */}
|
|
||||||
|
|
||||||
<HStack>
|
|
||||||
<select
|
|
||||||
style={{
|
|
||||||
width: "100%",
|
|
||||||
background: "transparent",
|
|
||||||
color: "black",
|
|
||||||
border: "none",
|
|
||||||
fontSize: "12px",
|
|
||||||
height: "30px",
|
|
||||||
outline: "none",
|
|
||||||
}}
|
|
||||||
value={formData?.principle_language_linkss?.language_xid || ""}
|
|
||||||
onChange={(e) => {
|
|
||||||
const value = Number(e.target.value);
|
|
||||||
setFormData({
|
|
||||||
...formData,
|
|
||||||
principle_language_linkss: {
|
|
||||||
...formData?.principle_language_linkss,
|
|
||||||
language_xid: value,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<option value="1">English</option>
|
|
||||||
<option value="2">Hindi</option>
|
|
||||||
<option value="3">Marathi</option>
|
|
||||||
<option value="4">Telgu</option>
|
|
||||||
<option value="5">Tamil</option>
|
|
||||||
<option value="6">Bengali</option>
|
|
||||||
<option value="7">Odia</option>
|
|
||||||
</select>
|
|
||||||
</HStack>
|
|
||||||
</Field.Root>
|
|
||||||
</Stack>
|
|
||||||
</DialogBody>
|
|
||||||
<DialogFooter mt={5}>
|
|
||||||
<Button rounded={"md"} w={"100%"} size={"sm"} bg={"#02A0A0"} onClick={handleSubmit} disabled={isLoading}>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
<DialogCloseTrigger color="black" />
|
|
||||||
</DialogContent>
|
|
||||||
</DialogRoot >
|
|
||||||
<Toaster />
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,204 +1,62 @@
|
|||||||
import {
|
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
|
||||||
Box, HStack,
|
|
||||||
Image,
|
|
||||||
// Image,
|
|
||||||
Text,
|
|
||||||
} from "@chakra-ui/react";
|
|
||||||
import MainFrame from "../../../components/MainFrame";
|
import MainFrame from "../../../components/MainFrame";
|
||||||
// import AlertDailog from "../../../components/AlertDailog";
|
import AlertDailog from "../../../components/AlertDailog";
|
||||||
// import { RiDeleteBin5Line } from "react-icons/ri";
|
import { RiDeleteBin5Line } from "react-icons/ri";
|
||||||
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 { LuSearch } from "react-icons/lu";
|
||||||
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 { useDeleteUserMutation, useGetManageUserQuery, UserData, useUserToggleMutation } from "../../../Redux/Service/manage.user";
|
|
||||||
import SearchComponent from "../../../components/SearchComponent";
|
|
||||||
import AlertDailog from "../../../components/AlertDailog";
|
|
||||||
import { toaster } from "../../../components/ui/toaster";
|
|
||||||
import Delete from "../../../components/ActionIcons/Delete";
|
import Delete from "../../../components/ActionIcons/Delete";
|
||||||
import { delay } from "../../../components/Utils";
|
|
||||||
// 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",
|
||||||
"Default Language",
|
"Language",
|
||||||
"Active/Deactive",
|
"Activate/Deactivate",
|
||||||
"Action",
|
"Action",
|
||||||
];
|
];
|
||||||
|
|
||||||
// const registerUser: any[] = [
|
const registerUser: any[] = [
|
||||||
// ...Array.from({ length: 12 }, (_, i) => ({
|
...Array.from({ length: 12 }, (_, i) => ({
|
||||||
// "Sr. No": i + 1,
|
"Sr. No": i + 1,
|
||||||
// "First Name": "Ritesh",
|
"First Name": "Ritesh",
|
||||||
// "Mobile Number": "akanksha@gmail.com",
|
"Mobile Number": "akanksha@gmail.com",
|
||||||
// "Gender": "9876543210",
|
"Gender": "9876543210",
|
||||||
// "DOB": "Female",
|
"DOB": "Female",
|
||||||
// "Type Of User": "15-01-1990",
|
"Type Of User": "15-01-1990",
|
||||||
// "Language": "Mumbai",
|
"Language": "Mumbai",
|
||||||
// "Activate/Deactivate": (
|
"Activate/Deactivate": (
|
||||||
// <Box>
|
<Box>
|
||||||
// <Switch size={'sm'} colorPalette={'teal'} />
|
<Switch size={'sm'} colorPalette={'teal'} />
|
||||||
// </Box>
|
</Box>
|
||||||
// ),
|
),
|
||||||
// "Action": (
|
|
||||||
// <HStack justifyContent="center">
|
|
||||||
// <ViewRegisterUsers />
|
|
||||||
// <EditRegisterUsers />
|
|
||||||
// {/* <RiDeleteBin5Line style={{ cursor: "pointer" }} /> */}
|
|
||||||
// {/* <AlertDailog
|
|
||||||
// AltertTiggerIcon={() =><Delete /> } // Pass as function
|
|
||||||
// alertText="Delete Users"
|
|
||||||
// alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
|
|
||||||
// alertCaption="Are You Sure You Want To Delete This User ?"
|
|
||||||
// onConfirm={() => {
|
|
||||||
// console.log("User deleted:", i + 1);
|
|
||||||
// }}
|
|
||||||
// /> */}
|
|
||||||
// </HStack>
|
|
||||||
// ),
|
|
||||||
// })),
|
|
||||||
// ];
|
|
||||||
|
|
||||||
const RegisterUsers = () => {
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
const { data, refetch, isFetching, isError } = useGetManageUserQuery(currentPage)
|
|
||||||
const [localData, setLocalData] = useState<any[]>([]);
|
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const [userToggle] = useUserToggleMutation()
|
|
||||||
const [deleteFaqPost] = useDeleteUserMutation()
|
|
||||||
const [deleteModal, setDeleteModal] = useState(false)
|
|
||||||
const [selectedFaqId, setSelectedFaqId] = useState<number | null>(null);
|
|
||||||
|
|
||||||
console.log("Register Users Data", data?.data.data);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data) {
|
|
||||||
setLocalData(data?.data.data);
|
|
||||||
}
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
setCurrentPage(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
const filteredData = localData?.filter((agency) => {
|
|
||||||
const searchLower = searchTerm.toLowerCase();
|
|
||||||
const firstName = agency.first_name?.toLowerCase().includes(searchLower);
|
|
||||||
// const email = agency.capital?.toLowerCase().includes(searchLower);
|
|
||||||
return firstName;
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleToggle = async (agencyId: number, currentStatus: string) => {
|
|
||||||
const newStatus = currentStatus === '1' ? '0' : '1';
|
|
||||||
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await userToggle({ id: agencyId, is_active: newStatus }).unwrap();
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Status updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
await delay(500);
|
|
||||||
refetch()
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating privacy policy:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Someting went wrong.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleDeleteFaq = async (faqId: number) => {
|
|
||||||
try {
|
|
||||||
const response = await deleteFaqPost({ id: faqId }).unwrap();
|
|
||||||
if (response?.status === "success") {
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "User deleted successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
refetch()
|
|
||||||
console.log("User deleted successfully:", response);
|
|
||||||
}
|
|
||||||
// Optionally, refetch data or update state after deletion
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error deleting User:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Something went wrong",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const managepost = filteredData?.flatMap((agency: UserData, index: number) => ({
|
|
||||||
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
|
|
||||||
"First Name": agency.first_name,
|
|
||||||
"Last Name": agency.last_name,
|
|
||||||
"Mobile Number": agency.phone_number,
|
|
||||||
"Gender": agency.gender,
|
|
||||||
"DOB": agency.date_of_birth ? new Date(agency.date_of_birth).toLocaleDateString('en-GB').replace(/\//g, '-') : 'N/A',
|
|
||||||
"Type Of User": agency.principal_type?.principal_type_title || 'N/A',
|
|
||||||
"Default Language": agency?.principle_language_linkss?.language?.language_name,
|
|
||||||
"Active/Deactive": agency.is_active === true ? 'Active' : 'Inactive',
|
|
||||||
"Action": (
|
"Action": (
|
||||||
<HStack justifyContent="center">
|
<HStack justifyContent="center">
|
||||||
<EditRegisterUsers
|
<ViewRegisterUsers />
|
||||||
data={agency}
|
<EditRegisterUsers />
|
||||||
refetch={refetch}
|
{/* <RiDeleteBin5Line style={{ cursor: "pointer" }} /> */}
|
||||||
/>
|
|
||||||
<ViewRegisterUsers data={agency} />
|
|
||||||
<Box>
|
|
||||||
<Switch
|
|
||||||
colorPalette={'teal'}
|
|
||||||
size={"xs"}
|
|
||||||
checked={agency.is_active === true}
|
|
||||||
onChange={() => handleToggle(agency.id, agency.is_active ? '1' : '0')}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<AlertDailog
|
<AlertDailog
|
||||||
isOpen={deleteModal}
|
AltertTiggerIcon={() => <Delete />} // Pass as function
|
||||||
AltertTiggerIcon={() => <Delete onClick={() => {
|
alertText="Delete Users"
|
||||||
setSelectedFaqId(agency.id);
|
|
||||||
setDeleteModal(true)
|
|
||||||
}} />}
|
|
||||||
alertText="Do you want to delete user?"
|
|
||||||
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 This User ?"
|
||||||
onClose={() => setDeleteModal(false)}
|
|
||||||
onConfirm={() => {
|
onConfirm={() => {
|
||||||
// console.log("Deleting FAQ with ID:", selectedFaqId); // Correct ID
|
console.log("User deleted:", i + 1);
|
||||||
if (selectedFaqId) {
|
|
||||||
setDeleteModal(false);
|
|
||||||
handleDeleteFaq(selectedFaqId);
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</HStack>
|
</HStack>
|
||||||
),
|
),
|
||||||
}))
|
})),
|
||||||
|
];
|
||||||
|
|
||||||
|
const RegisterUsers = () => {
|
||||||
return (
|
return (
|
||||||
<MainFrame>
|
<MainFrame>
|
||||||
<Box>
|
<Box>
|
||||||
@@ -213,31 +71,34 @@ const RegisterUsers = () => {
|
|||||||
Register Users
|
Register Users
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<HStack>
|
<HStack>
|
||||||
<SearchComponent
|
<InputGroup
|
||||||
value={searchTerm}
|
startElement={
|
||||||
onChange={(value) => {
|
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
|
||||||
setSearchTerm(value);
|
}
|
||||||
// setCurrentPage(1);
|
color={"#000"}
|
||||||
refetch()
|
>
|
||||||
}}
|
<Input
|
||||||
/>
|
p={3}
|
||||||
{/* <AddRegisterUsers /> */}
|
w={300}
|
||||||
|
bg={"#fff"}
|
||||||
|
colorPalette={"blue"}
|
||||||
|
_focus={{ border: "1px solid #02A0A0" }}
|
||||||
|
rounded={"md"}
|
||||||
|
size={"xs"}
|
||||||
|
fontSize={"sm"}
|
||||||
|
placeholder="Search..."
|
||||||
|
bgColor={'#EEEEEE'}
|
||||||
|
ps={8}
|
||||||
|
/>
|
||||||
|
</InputGroup>
|
||||||
|
<AddRegisterUsers />
|
||||||
</HStack>
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
<DataTable
|
<DataTable
|
||||||
sortableColumns={["Name", "Registration Date "]}
|
sortableColumns={["Name", "Registration Date "]}
|
||||||
tableHeadRow={tableHeadRow}
|
tableHeadRow={tableHeadRow}
|
||||||
data={managepost}
|
data={registerUser}
|
||||||
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>
|
||||||
</MainFrame>
|
</MainFrame>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Field, Input, Span, Stack } from "@chakra-ui/react";
|
import { MdOutlineRemoveRedEye } from "react-icons/md";
|
||||||
import View from "../../../components/ActionIcons/View";
|
import { Field, Icon, Input, Stack } from "@chakra-ui/react";
|
||||||
import {
|
import {
|
||||||
DialogBody,
|
DialogBody,
|
||||||
DialogCloseTrigger,
|
DialogCloseTrigger,
|
||||||
@@ -9,23 +9,23 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "../../../components/ui/dialog";
|
} from "../../../components/ui/dialog";
|
||||||
import { UserData } from "../../../Redux/Service/manage.user";
|
import View from "../../../components/ActionIcons/View";
|
||||||
|
|
||||||
function ViewRegisterUsers({ data }: { data: UserData }) {
|
function ViewRegisterUsers() {
|
||||||
return (
|
return (
|
||||||
<DialogRoot placement="center">
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Span><View /></Span>
|
<View />
|
||||||
</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">
|
||||||
@@ -46,7 +46,6 @@ function ViewRegisterUsers({ data }: { data: UserData }) {
|
|||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
value={data?.first_name || ''}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
@@ -55,29 +54,38 @@ function ViewRegisterUsers({ data }: { data: UserData }) {
|
|||||||
<Input
|
<Input
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none" pl={1}
|
border="none"
|
||||||
fontSize="12px" height="30px"
|
pl={1}
|
||||||
value={data?.last_name || ''}
|
fontSize="12px"
|
||||||
|
height="30px"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<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"
|
||||||
value={data?.gender || ''}
|
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">
|
||||||
DOB
|
DOB
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px"
|
bgColor="#EEEEEE"
|
||||||
value={data?.date_of_birth ? new Date(data.date_of_birth).toLocaleDateString('en-GB').replace(/\//g, '-') : 'N/A'}
|
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">
|
||||||
Mobile Number
|
OTP Verified
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
@@ -86,11 +94,10 @@ function ViewRegisterUsers({ data }: { data: UserData }) {
|
|||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
value={data?.phone_number || ''}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
Type Of User
|
Language
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
@@ -99,15 +106,6 @@ function ViewRegisterUsers({ data }: { data: UserData }) {
|
|||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
value={data?.principal_type?.principal_type_title || 'N/A'}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<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={data?.principle_language_linkss?.language?.language_name || 'N/A'}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
import { Box, HStack, Text } from "@chakra-ui/react";
|
import { Box, HStack, Input, Text } from "@chakra-ui/react";
|
||||||
import MainFrame from "../../../components/MainFrame"
|
import MainFrame from "../../../components/MainFrame"
|
||||||
|
import { InputGroup } from "../../../components/ui/input-group";
|
||||||
|
import { LuSearch } from "react-icons/lu";
|
||||||
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 { useEffect, useState } from "react";
|
|
||||||
import SearchComponent from "../../../components/SearchComponent";
|
|
||||||
import { useDebounce } from "../../../components/Hooks/useDebounce";
|
|
||||||
import { toaster, Toaster } from "../../../components/ui/toaster";
|
|
||||||
import { delay } from "../../../components/Utils";
|
|
||||||
|
|
||||||
// table data
|
// table data
|
||||||
|
|
||||||
@@ -23,139 +20,33 @@ const tableHeadRow = [
|
|||||||
"Registered Office Address",
|
"Registered Office Address",
|
||||||
"Website/Domain",
|
"Website/Domain",
|
||||||
"GST no.",
|
"GST no.",
|
||||||
"Agency Status",
|
|
||||||
"Action"
|
"Action"
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// const managepost: any[] = [
|
const managepost: any[] = [
|
||||||
// ...Array.from({ length: 12 }, (_, i) => ({
|
...Array.from({ length: 12 }, (_, i) => ({
|
||||||
// "Sr. No": i + 1,
|
"Sr. No": i + 1,
|
||||||
// "Agency Name": "Lorem Ipsum",
|
"Agency Name": "Lorem Ipsum",
|
||||||
// "RC no.": "Lorem Ipsum",
|
"RC no.": "Lorem Ipsum",
|
||||||
// "State": "Lorem Ipsum",
|
"State": "Lorem Ipsum",
|
||||||
// "RC Status": "Active",
|
"RC Status": "Active",
|
||||||
// "Registered Office Address": "Lorem Ipsum",
|
"Registered Office Address": "Lorem Ipsum",
|
||||||
// "Website/Domain": "Lorem Ipsum",
|
"Website/Domain": "Lorem Ipsum",
|
||||||
// "GST no.": "Lorem Ipsum",
|
"GST no.": "Lorem Ipsum",
|
||||||
// "Action": (
|
"Action": (
|
||||||
// <HStack justifyContent="center">
|
<HStack justifyContent="center">
|
||||||
// <ViewAgencyMaster/>
|
<ViewAgencyMaster/>
|
||||||
// <EditAgencyMaster />
|
<EditAgencyMaster />
|
||||||
// <Box>
|
<Box>
|
||||||
// <Switch colorPalette={'teal'} size={"xs"}/>
|
<Switch colorPalette={'teal'} size={"xs"}/>
|
||||||
// </Box>
|
</Box>
|
||||||
// </HStack>
|
</HStack>
|
||||||
// ),
|
),
|
||||||
// })),
|
})),
|
||||||
// ];
|
];
|
||||||
|
|
||||||
const AgencyMaster = () => {
|
const AgencyMaster = () => {
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
const [agencyMasterToggle] = useAgencyMasterToggleMutation()
|
|
||||||
const [localData, setLocalData] = useState<any[]>([]);
|
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
|
||||||
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
|
|
||||||
const { data, refetch, isError, isFetching } = useGetAgencyMasterQuery(queryArgs)
|
|
||||||
|
|
||||||
const handleToggle = async (agencyId: string, currentStatus: number) => {
|
|
||||||
const newStatus = currentStatus ? 0 : 1;
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
await agencyMasterToggle({ id: agencyId, is_active: newStatus }).unwrap();
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Status updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
await delay(500);
|
|
||||||
refetch()
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating privacy policy:", error);
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Please try again later",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
setCurrentPage(page);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSearchChange = (value: string) => {
|
|
||||||
setSearchTerm(value);
|
|
||||||
setCurrentPage(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const filteredData = localData?.filter((agency) =>
|
|
||||||
agency?.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
||||||
agency?.rc_number.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
||||||
agency?.state.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
||||||
agency?.registered_office.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
||||||
agency?.domain_name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
||||||
agency?.gst_number.toLowerCase().includes(searchTerm.toLowerCase())
|
|
||||||
);
|
|
||||||
|
|
||||||
// const activeCount = filteredData?.filter((a: any) => a.is_active === 1).length ?? 0;
|
|
||||||
|
|
||||||
const managepost = filteredData?.map((agency: any, index: number) => {
|
|
||||||
// const isOnlyActive = activeCount === 1 && agency.is_active === 1;
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: agency.id,
|
|
||||||
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
|
|
||||||
"Agency Name": agency.name,
|
|
||||||
"RC no.": agency.rc_number,
|
|
||||||
"State": agency.state,
|
|
||||||
"RC Status": agency.rc_status,
|
|
||||||
"Registered Office Address": agency.registered_office,
|
|
||||||
"Website/Domain": agency.domain_name,
|
|
||||||
"GST no.": agency.gst_number,
|
|
||||||
"Agency Status": agency.is_domain_verified ? "Verified" : "Unverified",
|
|
||||||
"is_active": agency.is_active,
|
|
||||||
Action: (
|
|
||||||
<HStack justifyContent="center">
|
|
||||||
<ViewAgencyMaster agency={localData} id={agency.id} />
|
|
||||||
<EditAgencyMaster editData={agency} refetch={refetch} />
|
|
||||||
<Box>
|
|
||||||
<Switch
|
|
||||||
colorPalette={"teal"}
|
|
||||||
size={"xs"}
|
|
||||||
onChange={() => handleToggle(agency.id.toString(), Number(agency.is_active))}
|
|
||||||
checked={Boolean(Number(agency.is_active))}
|
|
||||||
// disabled={isOnlyActive}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</HStack>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data?.data?.data) {
|
|
||||||
setLocalData(data?.data?.data);
|
|
||||||
}
|
|
||||||
}, [data, localData, managepost]);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// console.log("Fetched data:", data);
|
|
||||||
// console.log("Local data:", localData);
|
|
||||||
// console.log("Managepost data:", managepost);
|
|
||||||
// }, [data, localData, managepost]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<MainFrame>
|
<MainFrame>
|
||||||
@@ -168,11 +59,11 @@ const AgencyMaster = () => {
|
|||||||
px={3}
|
px={3}
|
||||||
>
|
>
|
||||||
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
||||||
Agency Master
|
Agency Master
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<HStack >
|
<HStack >
|
||||||
{/* <InputGroup
|
<InputGroup
|
||||||
startElement={
|
startElement={
|
||||||
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
|
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
|
||||||
}
|
}
|
||||||
@@ -191,30 +82,17 @@ const AgencyMaster = () => {
|
|||||||
bgColor={'#EEEEEE'}
|
bgColor={'#EEEEEE'}
|
||||||
ps={8}
|
ps={8}
|
||||||
/>
|
/>
|
||||||
</InputGroup> */}
|
</InputGroup>
|
||||||
<SearchComponent
|
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
|
||||||
value={searchTerm}
|
<ViewAgencyAddModel />
|
||||||
onChange={handleSearchChange}
|
|
||||||
/>
|
|
||||||
{/* <ViewAgencyAddModel refetch={refetch} /> */}
|
|
||||||
</HStack>
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
<DataTable
|
<DataTable
|
||||||
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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,129 +9,14 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "../../../components/ui/dialog";
|
} from "../../../components/ui/dialog";
|
||||||
import { Field, Input, Stack } from "@chakra-ui/react";
|
import { Field, Icon, Input, Stack } from "@chakra-ui/react";
|
||||||
import Edit from "../../../components/ActionIcons/Edit";
|
import Edit from "../../../components/ActionIcons/Edit";
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { useUpdateAgencyMasterMutation } from "../../../Redux/Service/agency.master.module.service";
|
|
||||||
import { Toaster, toaster } from "../../../components/ui/toaster";
|
|
||||||
|
|
||||||
// interface Organization {
|
|
||||||
// id: number;
|
|
||||||
// raid?: string;
|
|
||||||
// name: string;
|
|
||||||
// auth_signatory?: string;
|
|
||||||
// state: string;
|
|
||||||
// district?: string;
|
|
||||||
// rc_number: number;
|
|
||||||
// contact_details?: string;
|
|
||||||
// registered_office: string;
|
|
||||||
// branch_office?: string;
|
|
||||||
// registered_email?: string;
|
|
||||||
// other_email?: string;
|
|
||||||
// registered_contact?: string;
|
|
||||||
// website?: string;
|
|
||||||
// domain_name: string;
|
|
||||||
// staff_domain_name?: string;
|
|
||||||
// gst_number: string;
|
|
||||||
// rc_status?: "Active" | "Inactive"; // Assuming it's a status with limited values
|
|
||||||
// }
|
|
||||||
|
|
||||||
type AgencyFormData = {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
state: string;
|
|
||||||
rc_number: string;
|
|
||||||
registered_office: string;
|
|
||||||
domain_name: string;
|
|
||||||
gst_number: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function EditAgencyMaster<T extends AgencyFormData>({ editData, refetch }: { editData: T, refetch: VoidFunction }) {
|
|
||||||
|
|
||||||
const [formData, setFormData] = useState(editData);
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [updateAgencyMaster, { isLoading }] = useUpdateAgencyMasterMutation()
|
|
||||||
|
|
||||||
console.log("Edit Data", editData);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setFormData(editData);
|
|
||||||
}, [editData]);
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
setIsOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const { name, value } = e.target;
|
|
||||||
setFormData((prev: any) => ({
|
|
||||||
...prev,
|
|
||||||
[name]: value,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
// console.log("Updated Data:", formData);
|
|
||||||
if (!formData.name.trim() ||
|
|
||||||
!formData.rc_number ||
|
|
||||||
!formData.state.trim() ||
|
|
||||||
!formData.registered_office.trim() ||
|
|
||||||
!formData.domain_name.trim() ||
|
|
||||||
!formData.gst_number.trim()) {
|
|
||||||
// console.log("Validation failed: Some fields are empty.");
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Input fields cannot be empty",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setIsOpen(false);
|
|
||||||
// Handle API call or further processing here
|
|
||||||
const payload = {
|
|
||||||
id: formData?.id,
|
|
||||||
name: formData?.name,
|
|
||||||
state: formData?.state,
|
|
||||||
rc_number: formData?.rc_number,
|
|
||||||
registered_office: formData?.registered_office,
|
|
||||||
domain_name: formData?.domain_name,
|
|
||||||
gst_number:formData?.gst_number,
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await updateAgencyMaster(payload).unwrap();
|
|
||||||
if (response?.status === "success") {
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Data updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
refetch()
|
|
||||||
setIsOpen(false);
|
|
||||||
} else {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Failed to update",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: `${error.data.message || "Failed to update"}`,
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
// alert("Failed to update template");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
function EditAgencyMaster() {
|
||||||
return (
|
return (
|
||||||
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button bg="transparent" color={"black"} h={"18px"} onClick={handleOpenModal}><Edit /></Button>
|
<Edit />
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<DialogContent
|
<DialogContent
|
||||||
@@ -157,105 +42,92 @@ function EditAgencyMaster<T extends AgencyFormData>({ editData, refetch }: { edi
|
|||||||
Agency name
|
Agency name
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
name="name"
|
value="Lorem Ipsum"
|
||||||
value={formData?.name}
|
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
RC No.
|
RC No.
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
name='rc_number'
|
value="Lorem Ipsum"
|
||||||
value={formData.rc_number}
|
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
State
|
State
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
name="state"
|
value="Lorem Ipsum"
|
||||||
value={formData.state}
|
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
Registered Office Address
|
Registered Office Address
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
name="registered_office"
|
value="Active"
|
||||||
value={formData.registered_office}
|
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
Website/Domain
|
Website/Domain
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
name="domain_name"
|
value="Lorem Ipsum"
|
||||||
value={formData.domain_name}
|
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
GST no.
|
GST no.
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
name="gst_number"
|
value="Lorem Ipsum"
|
||||||
value={formData.gst_number}
|
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* <Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
RC Status
|
Action
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
value={formData.rc_status}
|
value="Lorem Ipsum"
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
onChange={handleChange}
|
/>
|
||||||
/> */}
|
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
</Stack>
|
</Stack>
|
||||||
</DialogBody>
|
</DialogBody>
|
||||||
@@ -266,16 +138,13 @@ function EditAgencyMaster<T extends AgencyFormData>({ editData, refetch }: { edi
|
|||||||
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" onClick={() => setIsOpen(false)} />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<Toaster />
|
|
||||||
</DialogRoot>
|
</DialogRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,99 +2,30 @@ 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 { AgencyPost, useCreateAgencyMasterPostMutation } from "../../../Redux/Service/agency.master.module.service"
|
|
||||||
import { useState } from "react"
|
|
||||||
import { Toaster, toaster } from "../../../components/ui/toaster"
|
|
||||||
|
|
||||||
function ViewAgencyAddModel({ refetch }: { refetch: VoidFunction }) {
|
|
||||||
const [formData, setFormData] = useState<AgencyPost>({
|
|
||||||
name: "",
|
|
||||||
rc_number: "",
|
|
||||||
state: "",
|
|
||||||
registered_office: "",
|
|
||||||
domain_name: "",
|
|
||||||
gst_number: "",
|
|
||||||
});
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [createAgencyMasterPost] = useCreateAgencyMasterPostMutation()
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
setIsOpen(true); // Open modal when clicking "Add"
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const { name, value } = e.target;
|
|
||||||
setFormData((prev: any) => ({
|
|
||||||
...prev,
|
|
||||||
[name]: value,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
console.log("New Data:", formData);
|
|
||||||
const requiredFields: (keyof AgencyPost)[] = ["name", "rc_number", "state", "registered_office", "domain_name", "gst_number"];
|
|
||||||
const isEmptyField = requiredFields.some(field => !formData[field]?.trim());
|
|
||||||
|
|
||||||
if (isEmptyField) {
|
|
||||||
console.log("Validation failed: Some fields are empty.");
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "All required fields must be filled.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
name: formData.name
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await createAgencyMasterPost(payload).unwrap();
|
|
||||||
if (response) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Added successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
refetch()
|
|
||||||
setIsOpen(false);
|
|
||||||
} else {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Failed to add data.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Please try again later",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
function ViewAgencyAddModel() {
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
|
{/* <Button bg={"transparent"} size="sm">
|
||||||
<IoMdAdd /> <Text >Add</Text>
|
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
||||||
|
</Button> */}
|
||||||
|
<Button px={5} size={"xs"} bg={"#02A0A0"}>
|
||||||
|
<IoMdAdd /> <Text >Add</Text>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<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">Add</DialogTitle>
|
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
|
||||||
@@ -105,97 +36,38 @@ function ViewAgencyAddModel({ refetch }: { refetch: VoidFunction }) {
|
|||||||
|
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Agency Name</Field.Label>
|
<Field.Label color="black" pt={1} fontSize="12px">Agency Name</Field.Label>
|
||||||
<Input
|
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
name="name"
|
|
||||||
value={formData.name}
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">RC No.</Field.Label>
|
<Field.Label color="black" pt={1} fontSize="12px">RC No.</Field.Label>
|
||||||
<Input
|
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
name='rc_number'
|
|
||||||
value={formData.rc_number}
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">State</Field.Label>
|
<Field.Label color="black" pt={1} fontSize="12px">State</Field.Label>
|
||||||
<Input
|
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
name="state"
|
|
||||||
value={formData.state}
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Registered Office Address</Field.Label>
|
<Field.Label color="black" pt={1} fontSize="12px">Registered Office Address</Field.Label>
|
||||||
<Input
|
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
name="registered_office"
|
|
||||||
value={formData.registered_office}
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Website/Domain</Field.Label>
|
<Field.Label color="black" pt={1} fontSize="12px">Website/Domain</Field.Label>
|
||||||
<Input
|
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
name="domain_name"
|
|
||||||
value={formData.domain_name}
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">GST no.</Field.Label>
|
<Field.Label color="black" pt={1} fontSize="12px">GST no.</Field.Label>
|
||||||
<Input
|
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
name="gst_number"
|
|
||||||
value={formData.gst_number}
|
<Field.Label color="black" pt={1} fontSize="12px">Action</Field.Label>
|
||||||
bgColor="#EEEEEE"
|
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* <Field.Label color="black" pt={1} fontSize="12px">Action</Field.Label>
|
|
||||||
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" /> */}
|
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
</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"}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<Toaster />
|
|
||||||
</DialogRoot >
|
</DialogRoot >
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,24 +2,22 @@ import {
|
|||||||
DialogBody,
|
DialogBody,
|
||||||
DialogCloseTrigger,
|
DialogCloseTrigger,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
// DialogFooter,
|
DialogFooter,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogRoot,
|
DialogRoot,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "../../../components/ui/dialog";
|
} from "../../../components/ui/dialog";
|
||||||
import { Field, Input, Span, Stack } from "@chakra-ui/react";
|
import { Field, Icon, Input, Stack } from "@chakra-ui/react";
|
||||||
// import { MdOutlineRemoveRedEye } from "react-icons/md";
|
import { MdOutlineRemoveRedEye } from "react-icons/md";
|
||||||
// import { Button } from "../../../components/ui/button";
|
import { Button } from "../../../components/ui/button";
|
||||||
import View from "../../../components/ActionIcons/View";
|
import View from "../../../components/ActionIcons/View";
|
||||||
import { Agency } from "../../../Redux/Service/agency.master.module.service";
|
|
||||||
|
|
||||||
function ViewAgencyMaster({ agency, id }: { agency: Agency[], id:number }) {
|
|
||||||
|
|
||||||
|
function ViewAgencyMaster() {
|
||||||
return (
|
return (
|
||||||
<DialogRoot placement="center">
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Span><View /></Span>
|
<View />
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<DialogContent
|
<DialogContent
|
||||||
@@ -34,130 +32,107 @@ function ViewAgencyMaster({ agency, id }: { agency: Agency[], id:number }) {
|
|||||||
>
|
>
|
||||||
<DialogHeader bg="white">
|
<DialogHeader bg="white">
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
||||||
View
|
Add
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
{agency.map((data) => (
|
|
||||||
<DialogBody bg="white">
|
|
||||||
{data.id === id && <Stack py={3}>
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
Agency name
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
value={data.name}
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
disabled
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<DialogBody bg="white">
|
||||||
RC No.
|
<Stack py={3}>
|
||||||
</Field.Label>
|
<Field.Root>
|
||||||
<Input
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
value={data.rc_number}
|
Agency name
|
||||||
bgColor="#EEEEEE"
|
</Field.Label>
|
||||||
color="black"
|
<Input
|
||||||
border="none"
|
value="Lorem Ipsum"
|
||||||
pl={1}
|
bgColor="#EEEEEE"
|
||||||
fontSize="12px"
|
color="black"
|
||||||
height="30px"
|
border="none"
|
||||||
disabled
|
pl={1}
|
||||||
/>
|
fontSize="12px"
|
||||||
|
height="30px"
|
||||||
|
/>
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
State
|
RC No.
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
value={data.state}
|
value="Lorem Ipsum"
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
disabled
|
/>
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
RC Status
|
State
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
value={data.rc_status}
|
value="Lorem Ipsum"
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
disabled
|
/>
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
Registered Office Address
|
Registered Office Address
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
value={data.registered_office}
|
value="Active"
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
disabled
|
/>
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
Website/Domain
|
Website/Domain
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
value={data.domain_name}
|
value="Lorem Ipsum"
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
disabled
|
/>
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
GST no.
|
GST no.
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
value={data.gst_number}
|
value="Lorem Ipsum"
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
disabled
|
/>
|
||||||
/>
|
|
||||||
|
|
||||||
{/* <Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
Action
|
Action
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
value={data}
|
value="Lorem Ipsum"
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
disabled
|
/>
|
||||||
/> */}
|
</Field.Root>
|
||||||
</Field.Root>
|
</Stack>
|
||||||
</Stack>}
|
</DialogBody>
|
||||||
</DialogBody>
|
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
||||||
))}
|
|
||||||
|
|
||||||
{/* <DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
|
||||||
<Button
|
<Button
|
||||||
w="100%"
|
w="100%"
|
||||||
bg="#02A0A0"
|
bg="#02A0A0"
|
||||||
@@ -167,7 +142,7 @@ function ViewAgencyMaster({ agency, id }: { agency: Agency[], id:number }) {
|
|||||||
>
|
>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter> */}
|
</DialogFooter>
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
import { Box, HStack, Text } from "@chakra-ui/react";
|
import { Box, HStack, Input, Text } from "@chakra-ui/react";
|
||||||
import MainFrame from "../../../components/MainFrame"
|
import MainFrame from "../../../components/MainFrame"
|
||||||
|
import { InputGroup } from "../../../components/ui/input-group";
|
||||||
|
import { LuSearch } from "react-icons/lu";
|
||||||
import DataTable from "../../../components/DataTable";
|
import DataTable from "../../../components/DataTable";
|
||||||
import { Switch } from "../../../components/ui/switch";
|
import { Switch } from "../../../components/ui/switch";
|
||||||
import CountryAddModel from "./CountryAddModel";
|
import CountryAddModel from "./CountryAddModel";
|
||||||
import EditCountryModel from "./EditCountryModel";
|
import EditCountryModel from "./EditCountryModel";
|
||||||
import { CountryData, useCountryToggleMutation, useGetCountryMasterQuery } from "../../../Redux/Service/country.master";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import SearchComponent from "../../../components/SearchComponent";
|
|
||||||
import { useDebounce } from "../../../components/Hooks/useDebounce";
|
|
||||||
import { toaster, Toaster } from "../../../components/ui/toaster";
|
|
||||||
import { delay } from "../../../components/Utils";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -19,109 +15,25 @@ const tableHeadRow = [
|
|||||||
"Sr. No",
|
"Sr. No",
|
||||||
"Title",
|
"Title",
|
||||||
"Action"
|
"Action"
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// const managepost: any[] = [
|
const managepost: any[] = [
|
||||||
// ...Array.from({ length: 12 }, (_, i) => ({
|
...Array.from({ length: 12 }, (_, i) => ({
|
||||||
// "Sr. No": i + 1,
|
"Sr. No": i + 1,
|
||||||
// "Title": "Lorem Ipsum",
|
"Title": "Lorem Ipsum",
|
||||||
// "Action": (
|
|
||||||
// <HStack justifyContent="center">
|
|
||||||
// <EditCountryModel />
|
|
||||||
// <Box>
|
|
||||||
// <Switch colorPalette={'teal'} size={"xs"} />
|
|
||||||
// </Box>
|
|
||||||
// </HStack>
|
|
||||||
// ),
|
|
||||||
// })),
|
|
||||||
// ];
|
|
||||||
|
|
||||||
const Country = () => {
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
// const { data, refetch } = useGetCountryMasterQuery(currentPage)
|
|
||||||
const [countryToggle] = useCountryToggleMutation()
|
|
||||||
const [localData, setLocalData] = useState<any[]>([]);
|
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
|
||||||
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
|
|
||||||
const { data, refetch, isError, isFetching } = useGetCountryMasterQuery(queryArgs);
|
|
||||||
console.log("Country Data", data?.data.data)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data) {
|
|
||||||
setLocalData(data?.data.data);
|
|
||||||
}
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
setCurrentPage(page);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSearchChange = (value: string) => {
|
|
||||||
setSearchTerm(value);
|
|
||||||
setCurrentPage(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const filteredData = localData?.filter((agency) => {
|
|
||||||
const searchLower = searchTerm.toLowerCase();
|
|
||||||
const countryName = agency.en_name?.toLowerCase().includes(searchLower);
|
|
||||||
const capitalName = agency.capital?.toLowerCase().includes(searchLower);
|
|
||||||
return countryName || capitalName;
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleToggle = async (agencyId: number, currentStatus: string) => {
|
|
||||||
const newStatus = currentStatus === '1' ? '0' : '1';
|
|
||||||
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await countryToggle({ id: agencyId, is_active: newStatus }).unwrap();
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Status updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
await delay(500);
|
|
||||||
refetch()
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating privacy policy:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Please try again later.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const managepost = filteredData?.flatMap((agency: CountryData, index: number) => ({
|
|
||||||
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
|
|
||||||
"Title": agency.en_name,
|
|
||||||
"Action": (
|
"Action": (
|
||||||
<HStack justifyContent="center">
|
<HStack justifyContent="center">
|
||||||
<EditCountryModel rowData={{ id: agency.id, en_name: agency.en_name, country_code: agency.country_code, phonecode: agency.phonecode, capital: agency.capital, currency: agency.currency, currency_name: agency.currency_name, currency_symbol: agency.currency_symbol }} refetch={refetch} />
|
<EditCountryModel />
|
||||||
<Box>
|
<Box>
|
||||||
<Switch
|
<Switch colorPalette={'teal'} size={"xs"}/>
|
||||||
colorPalette={'teal'}
|
|
||||||
size={"xs"}
|
|
||||||
checked={agency.is_active === '1'}
|
|
||||||
onChange={() => handleToggle(agency.id, agency.is_active)}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
</HStack>
|
</HStack>
|
||||||
),
|
),
|
||||||
}))
|
})),
|
||||||
|
];
|
||||||
|
|
||||||
|
const Country = () => {
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<MainFrame>
|
<MainFrame>
|
||||||
@@ -134,11 +46,11 @@ const Country = () => {
|
|||||||
px={3}
|
px={3}
|
||||||
>
|
>
|
||||||
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
||||||
Country
|
Country
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<HStack >
|
<HStack >
|
||||||
{/* <InputGroup
|
<InputGroup
|
||||||
startElement={
|
startElement={
|
||||||
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
|
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
|
||||||
}
|
}
|
||||||
@@ -157,36 +69,17 @@ const Country = () => {
|
|||||||
bgColor={'#EEEEEE'}
|
bgColor={'#EEEEEE'}
|
||||||
ps={8}
|
ps={8}
|
||||||
/>
|
/>
|
||||||
</InputGroup> */}
|
</InputGroup>
|
||||||
<SearchComponent
|
|
||||||
value={searchTerm}
|
|
||||||
// onChange={(value) => {
|
|
||||||
// setSearchTerm(value);
|
|
||||||
// // setCurrentPage(1);
|
|
||||||
// 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 refetch={refetch} />
|
<CountryAddModel />
|
||||||
</HStack>
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
<DataTable
|
<DataTable
|
||||||
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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,217 +1,56 @@
|
|||||||
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
|
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
|
||||||
import { Field, Input, Stack, Text } from "@chakra-ui/react"
|
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
|
||||||
import { IoMdAdd } from "react-icons/io"
|
import { IoMdAdd } from "react-icons/io"
|
||||||
import { Button } from "../../../components/ui/button"
|
import { Button } from "../../../components/ui/button"
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { PostCountry, useCreateCountryPostMutation } from "../../../Redux/Service/country.master";
|
|
||||||
import { Toaster, toaster } from "../../../components/ui/toaster";
|
|
||||||
|
|
||||||
function CountryAddModel({refetch}: { refetch: VoidFunction }) {
|
|
||||||
const [createCountryPost, { isLoading }] = useCreateCountryPostMutation()
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [countryName, setCountryName] = useState<PostCountry>({
|
|
||||||
en_name: '',
|
|
||||||
country_code: '',
|
|
||||||
phonecode: '',
|
|
||||||
capital: '',
|
|
||||||
currency: '',
|
|
||||||
currency_name: '',
|
|
||||||
currency_symbol: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isOpen) {
|
|
||||||
setCountryName({
|
|
||||||
en_name: '',
|
|
||||||
country_code: '',
|
|
||||||
phonecode: '',
|
|
||||||
capital: '',
|
|
||||||
currency: '',
|
|
||||||
currency_name: '',
|
|
||||||
currency_symbol: '',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [isOpen]);
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
setIsOpen(true); // Open modal when clicking "Add"
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (countryName.en_name === "" || countryName.country_code === "" || countryName.phonecode === "" || countryName.capital === "" || countryName.currency === "" || countryName.currency_name === "" || countryName.currency_symbol === "") {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Input fields cannot be empty",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload: PostCountry = {
|
|
||||||
en_name: countryName.en_name,
|
|
||||||
country_code: countryName.country_code,
|
|
||||||
phonecode: countryName.phonecode,
|
|
||||||
capital: countryName.capital,
|
|
||||||
currency: countryName.currency,
|
|
||||||
currency_name: countryName.currency_name,
|
|
||||||
currency_symbol: countryName.currency_symbol,
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await createCountryPost(payload).unwrap();
|
|
||||||
if (response) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Country added successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
setIsOpen(false);
|
|
||||||
refetch();
|
|
||||||
} else {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Failed to add Country",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
// alert("Failed to update template");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
function CountryAddModel() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
{/* <Button bg={"transparent"} size="sm">
|
{/* <Button bg={"transparent"} size="sm">
|
||||||
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
||||||
</Button> */}
|
</Button> */}
|
||||||
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
|
<Button px={5} size={"xs"} bg={"#02A0A0"}>
|
||||||
<IoMdAdd /> <Text>Add</Text>
|
<IoMdAdd /> <Text>Add</Text>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</DialogTrigger>
|
||||||
|
|
||||||
|
<DialogContent
|
||||||
|
bg={"#fff"}
|
||||||
|
// w={{ lg: "60%", md: "230px" }}
|
||||||
|
w={{ base: '90%', md: '400px' }}
|
||||||
|
height={'auto'}
|
||||||
|
|
||||||
|
overflowX="hidden"
|
||||||
|
p={3} // Reduced padding
|
||||||
|
bgSize={'md'}
|
||||||
|
>
|
||||||
|
<DialogHeader bg="white" >
|
||||||
|
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
<DialogBody bg="white">
|
||||||
|
<Stack py={3}>
|
||||||
|
|
||||||
|
<Field.Root>
|
||||||
|
<Field.Label color="black" pt={1} fontSize="12px">Country</Field.Label>
|
||||||
|
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
|
</Field.Root>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
</DialogBody>
|
||||||
|
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
||||||
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
|
||||||
</DialogTrigger>
|
<DialogCloseTrigger color="black" />
|
||||||
|
</DialogContent>
|
||||||
<DialogContent
|
</DialogRoot >
|
||||||
bg={"#fff"}
|
|
||||||
// w={{ lg: "60%", md: "230px" }}
|
|
||||||
w={{ base: '90%', md: '400px' }}
|
|
||||||
height={'auto'}
|
|
||||||
|
|
||||||
overflowX="hidden"
|
|
||||||
p={3} // Reduced padding
|
|
||||||
bgSize={'md'}
|
|
||||||
>
|
|
||||||
<DialogHeader bg="white" >
|
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
|
|
||||||
</DialogHeader>
|
|
||||||
|
|
||||||
<DialogBody bg="white">
|
|
||||||
<Stack py={3}>
|
|
||||||
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Country</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter Country Name"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={countryName.en_name}
|
|
||||||
onChange={(e) => setCountryName({ ...countryName, en_name: e.target.value })}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Country Code</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Please enter country code ex: IN, US"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={countryName.country_code}
|
|
||||||
onChange={(e) => setCountryName({ ...countryName, country_code: e.target.value })}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Phone Code</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Please enter phone code ex: +91, +1"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={countryName.phonecode}
|
|
||||||
onChange={(e) => setCountryName({ ...countryName, phonecode: e.target.value })}
|
|
||||||
/>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Capital</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter Capital City"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={countryName.capital}
|
|
||||||
onChange={(e) => setCountryName({ ...countryName, capital: e.target.value })}
|
|
||||||
/>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Currency</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter Currency"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={countryName.currency}
|
|
||||||
onChange={(e) => setCountryName({ ...countryName, currency: e.target.value })}
|
|
||||||
/>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Currency name</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter Currency Name"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={countryName.currency_name}
|
|
||||||
onChange={(e) => setCountryName({ ...countryName, currency_name: e.target.value })}
|
|
||||||
/>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Currency Symbol</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter Currency Symbol"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={countryName.currency_symbol}
|
|
||||||
onChange={(e) => setCountryName({ ...countryName, currency_symbol: e.target.value })}
|
|
||||||
/>
|
|
||||||
</Field.Root>
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
</DialogBody>
|
|
||||||
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
|
||||||
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" />
|
|
||||||
</DialogContent>
|
|
||||||
</DialogRoot >
|
|
||||||
<Toaster />
|
|
||||||
</>
|
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,150 +11,56 @@ import {
|
|||||||
import { Field, Input, Stack } from "@chakra-ui/react";
|
import { Field, Input, Stack } from "@chakra-ui/react";
|
||||||
import { Button } from "../../../components/ui/button";
|
import { Button } from "../../../components/ui/button";
|
||||||
import Edit from "../../../components/ActionIcons/Edit";
|
import Edit from "../../../components/ActionIcons/Edit";
|
||||||
import { useUpdateCountryMutation } from "../../../Redux/Service/country.master";
|
|
||||||
import { Toaster, toaster } from "../../../components/ui/toaster";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
|
|
||||||
export interface EditCountryModelProps {
|
|
||||||
id?: number;
|
|
||||||
en_name?: string;
|
|
||||||
hi_name?: string;
|
|
||||||
mr_name?: string;
|
|
||||||
te_name?: string;
|
|
||||||
ta_name?: string;
|
|
||||||
bn_name?: string;
|
|
||||||
or_name?: string;
|
|
||||||
country_code?: string;
|
|
||||||
phonecode?: string;
|
|
||||||
capital?: string;
|
|
||||||
currency?: string;
|
|
||||||
currency_name?: string;
|
|
||||||
currency_symbol?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function EditCountryModel({ rowData, refetch }: { rowData: EditCountryModelProps, refetch: VoidFunction }) {
|
|
||||||
const [updateCountry, { isLoading }] = useUpdateCountryMutation()
|
|
||||||
const [editData, setEditData] = useState(rowData)
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if(rowData){
|
|
||||||
setEditData(rowData)
|
|
||||||
}
|
|
||||||
}, [rowData])
|
|
||||||
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
setIsOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (editData?.en_name === '') {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Input fields cannot be empty",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only en_name is editable, so we only need to send that in the payload.
|
|
||||||
const payload = {
|
|
||||||
id: rowData?.id,
|
|
||||||
en_name: editData?.en_name,
|
|
||||||
country_code: rowData?.country_code,
|
|
||||||
phonecode: rowData?.phonecode,
|
|
||||||
capital: rowData?.capital,
|
|
||||||
currency: rowData?.currency,
|
|
||||||
currency_name: rowData?.currency_name,
|
|
||||||
currency_symbol: rowData?.currency_symbol,
|
|
||||||
};
|
|
||||||
|
|
||||||
// console.log('payload', payload)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await updateCountry(payload).unwrap();
|
|
||||||
if (response?.status === "success") {
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Country updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
setIsOpen(false);
|
|
||||||
refetch()
|
|
||||||
} else {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Failed to update Country",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
// alert("Failed to update template");
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Something went wrong",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
function EditCountryModel() {
|
||||||
return (
|
return (
|
||||||
<>
|
<DialogRoot placement="center">
|
||||||
<DialogRoot placement="center" key={editData.id} open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
<DialogTrigger asChild>
|
||||||
<DialogTrigger asChild>
|
<Edit />
|
||||||
<Button bg="transparent" color={"black"} h={"18px"} onClick={handleOpenModal}><Edit /></Button>
|
</DialogTrigger>
|
||||||
</DialogTrigger>
|
|
||||||
|
|
||||||
<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={"auto"}
|
height={"auto"}
|
||||||
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">
|
||||||
Edit
|
Edit
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<DialogBody bg="white">
|
|
||||||
<Stack py={3}>
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
Country
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
value={editData.en_name}
|
|
||||||
onChange={(e) => setEditData({ ...editData, en_name: e.target.value })}
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
/>
|
|
||||||
</Field.Root>
|
|
||||||
</Stack>
|
|
||||||
</DialogBody>
|
|
||||||
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
|
||||||
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" />
|
<DialogBody bg="white">
|
||||||
</DialogContent>
|
<Stack py={3}>
|
||||||
</DialogRoot>
|
<Field.Root>
|
||||||
<Toaster />
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
</>
|
Country
|
||||||
|
</Field.Label>
|
||||||
|
<Input
|
||||||
|
value="Lorem Ipsum"
|
||||||
|
bgColor="#EEEEEE"
|
||||||
|
color="black"
|
||||||
|
border="none"
|
||||||
|
pl={1}
|
||||||
|
fontSize="12px"
|
||||||
|
height="30px"
|
||||||
|
/>
|
||||||
|
</Field.Root>
|
||||||
|
</Stack>
|
||||||
|
</DialogBody>
|
||||||
|
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
||||||
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
|
||||||
|
<DialogCloseTrigger color="black" />
|
||||||
|
</DialogContent>
|
||||||
|
</DialogRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,155 +0,0 @@
|
|||||||
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
|
|
||||||
import { Field, Input, Stack, Text } from "@chakra-ui/react"
|
|
||||||
import { IoMdAdd } from "react-icons/io"
|
|
||||||
import { Button } from "../../../components/ui/button"
|
|
||||||
import { useState } from "react";
|
|
||||||
import { toaster } from "../../../components/ui/toaster";
|
|
||||||
import { useCreateDepartmentPostMutation, useGetDepartmentMasterDropDownQuery } from "../../../Redux/Service/department.master";
|
|
||||||
|
|
||||||
function AddDepartmentMaster({ refetch }: { refetch: VoidFunction }) {
|
|
||||||
const [jobType, setJobType] = useState("");
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [createDepartmentPost, { isLoading }] = useCreateDepartmentPostMutation()
|
|
||||||
const { data } = useGetDepartmentMasterDropDownQuery()
|
|
||||||
const [selectdDep, setSelectdDep] = useState<any>({
|
|
||||||
id: '',
|
|
||||||
en_name: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
setIsOpen(true); // Open modal when clicking "Add"
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (!jobType.trim() || !selectdDep.id) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Title and Subtitle cannot be empty.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
en_name: jobType,
|
|
||||||
industry_masters_xid: selectdDep.id,
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
await createDepartmentPost(payload);
|
|
||||||
refetch()
|
|
||||||
setIsOpen(false);
|
|
||||||
setJobType("");
|
|
||||||
setSelectdDep({
|
|
||||||
id: '',
|
|
||||||
en_name: '',
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
alert("Failed to update template");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log("Selected Department", selectdDep);
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
|
|
||||||
<DialogRoot placement="center" open={isOpen}>
|
|
||||||
<DialogTrigger asChild>
|
|
||||||
{/* <Button bg={"transparent"} size="sm">
|
|
||||||
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
|
||||||
</Button> */}
|
|
||||||
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
|
|
||||||
<IoMdAdd /> <Text>Add</Text>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</DialogTrigger>
|
|
||||||
|
|
||||||
<DialogContent
|
|
||||||
bg={"#fff"}
|
|
||||||
// w={{ lg: "60%", md: "230px" }}
|
|
||||||
w={{ base: '90%', md: '400px' }}
|
|
||||||
height={'auto'}
|
|
||||||
|
|
||||||
overflowX="hidden"
|
|
||||||
p={3} // Reduced padding
|
|
||||||
bgSize={'md'}
|
|
||||||
>
|
|
||||||
<DialogHeader bg="white" >
|
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
|
|
||||||
</DialogHeader>
|
|
||||||
|
|
||||||
<DialogBody bg="white">
|
|
||||||
<Stack py={3}>
|
|
||||||
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
Select Industry
|
|
||||||
</Field.Label>
|
|
||||||
<select
|
|
||||||
value={selectdDep.id}
|
|
||||||
onChange={(e) => {
|
|
||||||
const selectedId = e.target.value;
|
|
||||||
const selectedIndustry = data?.data.find((item: any) => item.id.toString() === selectedId);
|
|
||||||
if (selectedIndustry) {
|
|
||||||
setSelectdDep({
|
|
||||||
id: selectedIndustry.id,
|
|
||||||
en_name: selectedIndustry.en_name,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#EEEEEE",
|
|
||||||
color: "black",
|
|
||||||
border: "none",
|
|
||||||
height: "30px",
|
|
||||||
fontSize: "12px",
|
|
||||||
padding: "4px",
|
|
||||||
borderRadius: "4px",
|
|
||||||
width: "100%",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<option value="" disabled>
|
|
||||||
Select department
|
|
||||||
</option>
|
|
||||||
{data?.data.map((item: any) => (
|
|
||||||
<option value={item.id} key={item.id}>
|
|
||||||
{item.en_name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</Field.Root>
|
|
||||||
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Department</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder=""
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={jobType}
|
|
||||||
onChange={(e) => setJobType(e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field.Root>
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
</DialogBody>
|
|
||||||
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
|
||||||
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
|
||||||
</DialogContent>
|
|
||||||
</DialogRoot >
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AddDepartmentMaster
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
import { Box, HStack, Text } from "@chakra-ui/react";
|
|
||||||
import MainFrame from "../../../components/MainFrame"
|
|
||||||
// import { InputGroup } from "../../../components/ui/input-group";
|
|
||||||
// import { LuSearch } from "react-icons/lu";
|
|
||||||
import DataTable from "../../../components/DataTable";
|
|
||||||
import { Switch } from "../../../components/ui/switch";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import SearchComponent from "../../../components/SearchComponent";
|
|
||||||
import { useDepartmentToggleMutation, useGetDepartmentMasterQuery } from "../../../Redux/Service/department.master";
|
|
||||||
import AddDepartmentMaster from "./AddDepartmentMaster";
|
|
||||||
import EditDepartmentMaster from "./EditDepartmentMaster";
|
|
||||||
import { useDebounce } from "../../../components/Hooks/useDebounce";
|
|
||||||
import { Toaster, toaster } from "../../../components/ui/toaster";
|
|
||||||
import { delay } from "../../../components/Utils";
|
|
||||||
|
|
||||||
|
|
||||||
// table data
|
|
||||||
|
|
||||||
const tableHeadRow = [
|
|
||||||
"Sr. No",
|
|
||||||
"Title",
|
|
||||||
"Action"
|
|
||||||
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const DepartmentMasterList = () => {
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
const [departmentToggle] = useDepartmentToggleMutation()
|
|
||||||
const [localData, setLocalData] = useState<any[]>([]);
|
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
|
||||||
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
|
|
||||||
const { data, refetch, isError, isFetching } = useGetDepartmentMasterQuery(queryArgs)
|
|
||||||
|
|
||||||
console.log("Department Data", data?.data.data)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data?.data?.data) {
|
|
||||||
setLocalData(data?.data.data);
|
|
||||||
}
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
const handleSearchChange = (value: string) => {
|
|
||||||
setSearchTerm(value);
|
|
||||||
setCurrentPage(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
setCurrentPage(page);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleToggle = async (agencyId: string, currentStatus: number) => {
|
|
||||||
const newStatus = currentStatus ? 0 : 1;
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
await departmentToggle({ id: agencyId, is_active: newStatus }).unwrap();
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Status updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
await delay(500);
|
|
||||||
refetch()
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating privacy policy:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Someting went wrong.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const filteredData = localData?.filter((agency) => {
|
|
||||||
const searchLower = searchTerm.toLowerCase();
|
|
||||||
const title = agency.en_name?.toLowerCase().includes(searchLower);
|
|
||||||
return title;
|
|
||||||
});
|
|
||||||
|
|
||||||
const managepost = filteredData?.map((agency: any, index: number) => ({
|
|
||||||
'id': agency.id,
|
|
||||||
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
|
|
||||||
"Title": agency.en_name,
|
|
||||||
"is_active": agency.is_active,
|
|
||||||
"Action": (
|
|
||||||
<HStack justifyContent="center">
|
|
||||||
{/* <ViewAgencyMaster agency={localData} id={agency.id} /> */}
|
|
||||||
<EditDepartmentMaster localData={agency} refetch={refetch} />
|
|
||||||
<Box>
|
|
||||||
<Switch
|
|
||||||
colorPalette={"teal"}
|
|
||||||
size={"xs"}
|
|
||||||
onChange={() => handleToggle(agency.id, Number(agency.is_active))}
|
|
||||||
checked={Boolean(Number(agency.is_active))}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</HStack>
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// console.log("Fetched data:", data);
|
|
||||||
// console.log("Local data:", localData);
|
|
||||||
// console.log("Managepost data:", managepost);
|
|
||||||
// }, [data, localData, managepost]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
|
|
||||||
<MainFrame>
|
|
||||||
<Box>
|
|
||||||
<HStack
|
|
||||||
w={"100%"}
|
|
||||||
justifyContent={"space-between"}
|
|
||||||
mb={4}
|
|
||||||
py={0}
|
|
||||||
px={3}
|
|
||||||
>
|
|
||||||
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
|
||||||
Department Master
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<HStack >
|
|
||||||
<SearchComponent
|
|
||||||
value={searchTerm}
|
|
||||||
onChange={handleSearchChange}
|
|
||||||
/>
|
|
||||||
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
|
|
||||||
{/* <ViewAgencyAddModel /> */}
|
|
||||||
<AddDepartmentMaster refetch={refetch} />
|
|
||||||
</HStack>
|
|
||||||
</HStack>
|
|
||||||
<DataTable
|
|
||||||
sortableColumns={["Name"]}
|
|
||||||
tableHeadRow={tableHeadRow}
|
|
||||||
data={managepost || []}
|
|
||||||
paginationData={{
|
|
||||||
current_page: data?.data.current_page || 1,
|
|
||||||
last_page: data?.data.last_page || 1,
|
|
||||||
per_page: data?.data.per_page || 10,
|
|
||||||
total: data?.data.total || 0
|
|
||||||
}}
|
|
||||||
onPageChange={handlePageChange}
|
|
||||||
isLoading={isFetching}
|
|
||||||
isError={isError}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Toaster />
|
|
||||||
</MainFrame>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default DepartmentMasterList
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
import {
|
|
||||||
DialogBody,
|
|
||||||
DialogCloseTrigger,
|
|
||||||
DialogContent,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogRoot,
|
|
||||||
DialogTitle,
|
|
||||||
DialogTrigger,
|
|
||||||
} from "../../../components/ui/dialog";
|
|
||||||
import { Box, Field, Input, Stack } from "@chakra-ui/react";
|
|
||||||
import { Button } from "../../../components/ui/button";
|
|
||||||
import Edit from "../../../components/ActionIcons/Edit";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { Toaster, toaster } from "../../../components/ui/toaster";
|
|
||||||
import { useGetDepartmentMasterDropDownQuery, useUpdateDepartmentMutation } from "../../../Redux/Service/department.master";
|
|
||||||
|
|
||||||
function EditDepartmentMaster({ localData, refetch }: { localData: any, refetch: VoidFunction }) {
|
|
||||||
const [jobtype, setJobType] = useState("");
|
|
||||||
const [updateDepartment, { isLoading }] = useUpdateDepartmentMutation()
|
|
||||||
const { data } = useGetDepartmentMasterDropDownQuery()
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [selectdDep, setSelectdDep] = useState<any>({
|
|
||||||
id: localData.industry_master.id,
|
|
||||||
en_name: localData.industry_master.en_name,
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
// const template = localData?.find((item: any) => item.id === id);
|
|
||||||
if (localData) {
|
|
||||||
setJobType(localData.en_name);
|
|
||||||
setSelectdDep({
|
|
||||||
id: localData.industry_master.id,
|
|
||||||
en_name: localData.industry_master.en_name,
|
|
||||||
})
|
|
||||||
setIsOpen(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (!jobtype.trim()) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Title and Subtitle cannot be empty.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
id: localData.id,
|
|
||||||
industry_masters_xid: selectdDep.id != null ? selectdDep.id : localData.industry_master.id,
|
|
||||||
en_name: jobtype
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
await updateDepartment(payload).unwrap();
|
|
||||||
refetch()
|
|
||||||
setIsOpen(false);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
alert("Failed to update template");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log("Dropdown Data", selectdDep);
|
|
||||||
console.log("Dep Data", localData)
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
|
||||||
<DialogTrigger asChild>
|
|
||||||
<Box bg={"transparent"} onClick={handleOpenModal}>
|
|
||||||
<Edit />
|
|
||||||
</Box>
|
|
||||||
</DialogTrigger>
|
|
||||||
|
|
||||||
<DialogContent
|
|
||||||
bg={"#fff"}
|
|
||||||
// w={{ lg: "60%", md: "230px" }}
|
|
||||||
w={{ base: "90%", md: "400px" }}
|
|
||||||
height={"auto"}
|
|
||||||
overflowX="hidden"
|
|
||||||
p={3} // Reduced padding
|
|
||||||
bgSize={"md"}
|
|
||||||
>
|
|
||||||
<DialogHeader bg="white">
|
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
|
||||||
Edit Title
|
|
||||||
</DialogTitle>
|
|
||||||
</DialogHeader>
|
|
||||||
|
|
||||||
<DialogBody bg="white">
|
|
||||||
<Stack py={3}>
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
Select Industry
|
|
||||||
</Field.Label>
|
|
||||||
<select
|
|
||||||
value={selectdDep.id}
|
|
||||||
onChange={(e) => {
|
|
||||||
const selected = data?.data.find((item: any) => item.id === Number(e.target.value));
|
|
||||||
if (selected) {
|
|
||||||
setSelectdDep({ id: selected.id, en_name: selected.en_name });
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#EEEEEE",
|
|
||||||
color: "black",
|
|
||||||
border: "none",
|
|
||||||
height: "30px",
|
|
||||||
fontSize: "12px",
|
|
||||||
padding: "4px",
|
|
||||||
borderRadius: "4px",
|
|
||||||
width: "100%",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<option value="" disabled>
|
|
||||||
Select department
|
|
||||||
</option>
|
|
||||||
{data?.data.map((item: any) => (
|
|
||||||
<option value={item.id} key={item.id}>
|
|
||||||
{item.en_name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</Field.Root>
|
|
||||||
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
Department
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
value={jobtype}
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
onChange={(e) => setJobType(e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field.Root>
|
|
||||||
</Stack>
|
|
||||||
</DialogBody>
|
|
||||||
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
|
||||||
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
|
||||||
</DialogContent>
|
|
||||||
<Toaster />
|
|
||||||
</DialogRoot>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default EditDepartmentMaster;
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
|
|
||||||
import { Field, Input, Stack, Text } from "@chakra-ui/react"
|
|
||||||
import { IoMdAdd } from "react-icons/io"
|
|
||||||
import { Button } from "../../../components/ui/button"
|
|
||||||
import { useState } from "react";
|
|
||||||
import { toaster } from "../../../components/ui/toaster";
|
|
||||||
import { useCreateIndustryMasterPostMutation } from "../../../Redux/Service/industry.master.service";
|
|
||||||
|
|
||||||
function AddIndustryMaster({ refetch }: { refetch: VoidFunction }) {
|
|
||||||
const [jobType, setJobType] = useState("");
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [createIndustryMasterPost, { isLoading }] = useCreateIndustryMasterPostMutation()
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
setIsOpen(true); // Open modal when clicking "Add"
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (!jobType.trim()) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Title and Subtitle cannot be empty.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
en_name: jobType,
|
|
||||||
categories_masters_xid:4
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
await createIndustryMasterPost(payload);
|
|
||||||
refetch()
|
|
||||||
setIsOpen(false);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
alert("Failed to update template");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
|
|
||||||
<DialogRoot placement="center" open={isOpen}>
|
|
||||||
<DialogTrigger asChild>
|
|
||||||
{/* <Button bg={"transparent"} size="sm">
|
|
||||||
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
|
||||||
</Button> */}
|
|
||||||
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
|
|
||||||
<IoMdAdd /> <Text>Add</Text>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</DialogTrigger>
|
|
||||||
|
|
||||||
<DialogContent
|
|
||||||
bg={"#fff"}
|
|
||||||
// w={{ lg: "60%", md: "230px" }}
|
|
||||||
w={{ base: '90%', md: '400px' }}
|
|
||||||
height={'auto'}
|
|
||||||
|
|
||||||
overflowX="hidden"
|
|
||||||
p={3} // Reduced padding
|
|
||||||
bgSize={'md'}
|
|
||||||
>
|
|
||||||
<DialogHeader bg="white" >
|
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
|
|
||||||
</DialogHeader>
|
|
||||||
|
|
||||||
<DialogBody bg="white">
|
|
||||||
<Stack py={3}>
|
|
||||||
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Job Type</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder=""
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={jobType}
|
|
||||||
onChange={(e) => setJobType(e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field.Root>
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
</DialogBody>
|
|
||||||
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
|
||||||
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
|
||||||
</DialogContent>
|
|
||||||
</DialogRoot >
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AddIndustryMaster
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
import {
|
|
||||||
DialogBody,
|
|
||||||
DialogCloseTrigger,
|
|
||||||
DialogContent,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogRoot,
|
|
||||||
DialogTitle,
|
|
||||||
DialogTrigger,
|
|
||||||
} from "../../../components/ui/dialog";
|
|
||||||
import { Box, Field, Input, Stack } from "@chakra-ui/react";
|
|
||||||
import { Button } from "../../../components/ui/button";
|
|
||||||
import Edit from "../../../components/ActionIcons/Edit";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { toaster } from "../../../components/ui/toaster";
|
|
||||||
import { useUpdateIndustryMasterMutation } from "../../../Redux/Service/industry.master.service";
|
|
||||||
|
|
||||||
function EditIndustryMaster({ id, localData, refetch, categories }: { id: number, localData: any, refetch: VoidFunction, categories: any }) {
|
|
||||||
const [jobtype, setJobType] = useState("");
|
|
||||||
const [updateIndustryMaster, { isLoading }] = useUpdateIndustryMasterMutation()
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
const template = localData?.find((item: any) => item.id === id);
|
|
||||||
if (template) {
|
|
||||||
setJobType(template.en_name);
|
|
||||||
setIsOpen(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (!jobtype.trim()) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Title and Subtitle cannot be empty.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
id: id,
|
|
||||||
en_name: jobtype,
|
|
||||||
categories_masters_xid: categories
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
await updateIndustryMaster(payload);
|
|
||||||
refetch()
|
|
||||||
setIsOpen(false);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
alert("Failed to update template");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
|
||||||
<DialogTrigger asChild>
|
|
||||||
<Box bg={"transparent"} onClick={handleOpenModal}>
|
|
||||||
<Edit />
|
|
||||||
</Box>
|
|
||||||
</DialogTrigger>
|
|
||||||
|
|
||||||
<DialogContent
|
|
||||||
bg={"#fff"}
|
|
||||||
// w={{ lg: "60%", md: "230px" }}
|
|
||||||
w={{ base: "90%", md: "400px" }}
|
|
||||||
height={"auto"}
|
|
||||||
overflowX="hidden"
|
|
||||||
p={3} // Reduced padding
|
|
||||||
bgSize={"md"}
|
|
||||||
>
|
|
||||||
<DialogHeader bg="white">
|
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
|
||||||
Edit
|
|
||||||
</DialogTitle>
|
|
||||||
</DialogHeader>
|
|
||||||
|
|
||||||
<DialogBody bg="white">
|
|
||||||
<Stack py={3}>
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
Job Type
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
value={jobtype}
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
onChange={(e) => setJobType(e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field.Root>
|
|
||||||
</Stack>
|
|
||||||
</DialogBody>
|
|
||||||
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
|
||||||
<Button w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
|
||||||
</DialogContent>
|
|
||||||
</DialogRoot>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default EditIndustryMaster;
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
import { Box, HStack, Text } from "@chakra-ui/react";
|
|
||||||
import MainFrame from "../../../components/MainFrame"
|
|
||||||
// import { InputGroup } from "../../../components/ui/input-group";
|
|
||||||
// import { LuSearch } from "react-icons/lu";
|
|
||||||
import DataTable from "../../../components/DataTable";
|
|
||||||
import { Switch } from "../../../components/ui/switch";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { useGetIndustryMasterQuery, useIndustryMasterToggleMutation } from "../../../Redux/Service/industry.master.service";
|
|
||||||
import EditIndustryMaster from "./EditIndustryMaster";
|
|
||||||
import AddIndustryMaster from "./AddIndustryMaster";
|
|
||||||
import SearchComponent from "../../../components/SearchComponent";
|
|
||||||
import { useDebounce } from "../../../components/Hooks/useDebounce";
|
|
||||||
import { Toaster, toaster } from "../../../components/ui/toaster";
|
|
||||||
import { delay } from "../../../components/Utils";
|
|
||||||
|
|
||||||
|
|
||||||
// table data
|
|
||||||
|
|
||||||
const tableHeadRow = [
|
|
||||||
"Sr. No",
|
|
||||||
"Title",
|
|
||||||
"Action"
|
|
||||||
|
|
||||||
];
|
|
||||||
|
|
||||||
// const managepost: any[] = [
|
|
||||||
// ...Array.from({ length: 12 }, (_, i) => ({
|
|
||||||
// "Sr. No": i + 1,
|
|
||||||
// "Agency Name": "Lorem Ipsum",
|
|
||||||
// "RC no.": "Lorem Ipsum",
|
|
||||||
// "State": "Lorem Ipsum",
|
|
||||||
// "RC Status": "Active",
|
|
||||||
// "Registered Office Address": "Lorem Ipsum",
|
|
||||||
// "Website/Domain": "Lorem Ipsum",
|
|
||||||
// "GST no.": "Lorem Ipsum",
|
|
||||||
// "Action": (
|
|
||||||
// <HStack justifyContent="center">
|
|
||||||
// <ViewAgencyMaster/>
|
|
||||||
// <EditAgencyMaster />
|
|
||||||
// <Box>
|
|
||||||
// <Switch colorPalette={'teal'} size={"xs"}/>
|
|
||||||
// </Box>
|
|
||||||
// </HStack>
|
|
||||||
// ),
|
|
||||||
// })),
|
|
||||||
// ];
|
|
||||||
|
|
||||||
const IndustryMasterList = () => {
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
const [industryMasterToggle] = useIndustryMasterToggleMutation()
|
|
||||||
const [localData, setLocalData] = useState<any[]>([]);
|
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
|
||||||
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
|
|
||||||
const { data, refetch, isError, isFetching } = useGetIndustryMasterQuery(queryArgs)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data?.data?.data) {
|
|
||||||
setLocalData(data?.data.data);
|
|
||||||
}
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
const handleSearchChange = (value: string) => {
|
|
||||||
setSearchTerm(value);
|
|
||||||
setCurrentPage(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
setCurrentPage(page);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleToggle = async (agencyId: string, currentStatus: number) => {
|
|
||||||
const newStatus = currentStatus ? 0 : 1;
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
await industryMasterToggle({ id: agencyId, is_active: newStatus }).unwrap();
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Status updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
await delay(500);
|
|
||||||
refetch()
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating privacy policy:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Someting went wrong.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const filteredData = localData?.filter((agency) => {
|
|
||||||
const searchLower = searchTerm.toLowerCase();
|
|
||||||
const title = agency.en_name?.toLowerCase().includes(searchLower);
|
|
||||||
return title;
|
|
||||||
});
|
|
||||||
|
|
||||||
const managepost = filteredData?.map((agency: any, index: number) => ({
|
|
||||||
'id': agency.id,
|
|
||||||
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
|
|
||||||
"Title": agency.en_name,
|
|
||||||
"is_active": agency.is_active,
|
|
||||||
"Action": (
|
|
||||||
<HStack justifyContent="center">
|
|
||||||
{/* <ViewAgencyMaster agency={localData} id={agency.id} /> */}
|
|
||||||
<EditIndustryMaster id={agency.id} localData={localData} refetch={refetch} categories={agency.categories_masters_xid} />
|
|
||||||
<Box>
|
|
||||||
<Switch
|
|
||||||
colorPalette={"teal"}
|
|
||||||
size={"xs"}
|
|
||||||
onChange={() => handleToggle(agency.id, Number(agency.is_active))}
|
|
||||||
checked={Boolean(Number(agency.is_active))}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</HStack>
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// console.log("Fetched data:", data);
|
|
||||||
// console.log("Local data:", localData);
|
|
||||||
// console.log("Managepost data:", managepost);
|
|
||||||
// }, [data, localData, managepost]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
|
|
||||||
<MainFrame>
|
|
||||||
<Box>
|
|
||||||
<HStack
|
|
||||||
w={"100%"}
|
|
||||||
justifyContent={"space-between"}
|
|
||||||
mb={4}
|
|
||||||
py={0}
|
|
||||||
px={3}
|
|
||||||
>
|
|
||||||
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
|
||||||
Industry Master
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<HStack >
|
|
||||||
<SearchComponent
|
|
||||||
value={searchTerm}
|
|
||||||
onChange={handleSearchChange}
|
|
||||||
/>
|
|
||||||
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
|
|
||||||
{/* <ViewAgencyAddModel /> */}
|
|
||||||
<AddIndustryMaster refetch={refetch} />
|
|
||||||
</HStack>
|
|
||||||
</HStack>
|
|
||||||
<DataTable
|
|
||||||
sortableColumns={["Name"]}
|
|
||||||
tableHeadRow={tableHeadRow}
|
|
||||||
data={managepost || []}
|
|
||||||
paginationData={{
|
|
||||||
current_page: data?.data.current_page || 1,
|
|
||||||
last_page: data?.data.last_page || 1,
|
|
||||||
per_page: data?.data.per_page || 10,
|
|
||||||
total: data?.data.total || 0
|
|
||||||
}}
|
|
||||||
onPageChange={handlePageChange}
|
|
||||||
isLoading={isFetching}
|
|
||||||
isError={isError}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Toaster />
|
|
||||||
</MainFrame>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default IndustryMasterList
|
|
||||||
@@ -1,69 +1,30 @@
|
|||||||
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
|
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
|
||||||
import { Box, Field, Input, Stack } from "@chakra-ui/react"
|
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
|
||||||
import { Button } from "../../../components/ui/button"
|
import { Button } from "../../../components/ui/button"
|
||||||
// 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 { useState } from "react";
|
|
||||||
import { useUpdateJobStatusMutation } from "../../../Redux/Service/job.status";
|
|
||||||
import { Toaster, toaster } from "../../../components/ui/toaster";
|
|
||||||
|
|
||||||
|
|
||||||
function EditJobStatusModel({ localData, refetch }: { localData: any, refetch: VoidFunction }) {
|
function EditJobStatusModel() {
|
||||||
const [updateJobStatus, { isLoading }] = useUpdateJobStatusMutation()
|
|
||||||
const [title, setTitle] = useState(localData.translation.title);
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
|
|
||||||
console.log(localData);
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
if (localData) {
|
|
||||||
setIsOpen(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (!title.trim()) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Title field cannot be empty.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
id: localData?.id,
|
|
||||||
title: title
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
await updateJobStatus(payload).unwrap();
|
|
||||||
refetch()
|
|
||||||
setIsOpen(false);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
alert("Failed to update template");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Box bg={"transparent"} onClick={handleOpenModal}>
|
<Edit />
|
||||||
<Edit />
|
|
||||||
</Box>
|
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<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={'auto'}
|
height={'auto'}
|
||||||
|
|
||||||
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">Edit</DialogTitle>
|
<DialogTitle alignSelf="center" color="black" fontSize="14px">Edit</DialogTitle>
|
||||||
@@ -74,30 +35,21 @@ function EditJobStatusModel({ localData, refetch }: { localData: any, refetch: V
|
|||||||
|
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Job Status</Field.Label>
|
<Field.Label color="black" pt={1} fontSize="12px">Job Status</Field.Label>
|
||||||
<Input
|
<Input value="Lorem Ipsum" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
value={title}
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
onChange={(e) => setTitle(e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
</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} disabled={isLoading}>
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<Toaster />
|
|
||||||
</DialogRoot >
|
</DialogRoot >
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
import { Box, HStack, Text } from "@chakra-ui/react";
|
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
|
||||||
import MainFrame from "../../../components/MainFrame"
|
import MainFrame from "../../../components/MainFrame"
|
||||||
|
import { InputGroup } from "../../../components/ui/input-group";
|
||||||
|
import { LuSearch } from "react-icons/lu";
|
||||||
import DataTable from "../../../components/DataTable";
|
import DataTable from "../../../components/DataTable";
|
||||||
import { Switch } from "../../../components/ui/switch";
|
import { Switch } from "../../../components/ui/switch";
|
||||||
import JobStatusAddModel from "./JobStatusAddModel";
|
import JobStatusAddModel from "./JobStatusAddModel";
|
||||||
import EditJobStatusModel from "./EditJobStatusModel";
|
import EditJobStatusModel from "./EditJobStatusModel";
|
||||||
import { useGetJobStatusQuery, useJobStatusToggleMutation } from "../../../Redux/Service/job.status";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import SearchComponent from "../../../components/SearchComponent";
|
|
||||||
import { toaster, Toaster } from "../../../components/ui/toaster";
|
|
||||||
import { useDebounce } from "../../../components/Hooks/useDebounce";
|
|
||||||
import { delay } from "../../../components/Utils";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -19,109 +15,25 @@ const tableHeadRow = [
|
|||||||
"Sr. No",
|
"Sr. No",
|
||||||
"Title",
|
"Title",
|
||||||
"Action"
|
"Action"
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// const managepost: any[] = [
|
const managepost: any[] = [
|
||||||
// ...Array.from({ length: 12 }, (_, i) => ({
|
...Array.from({ length: 12 }, (_, i) => ({
|
||||||
// "Sr. No": i + 1,
|
"Sr. No": i + 1,
|
||||||
// "Title": "Lorem Ipsum",
|
"Title": "Lorem Ipsum",
|
||||||
// "Action": (
|
|
||||||
// <HStack justifyContent="center">
|
|
||||||
// <EditJobStatusModel />
|
|
||||||
// <Box>
|
|
||||||
// <Switch colorPalette={'teal'} size={"xs"} />
|
|
||||||
// </Box>
|
|
||||||
// </HStack>
|
|
||||||
// ),
|
|
||||||
// })),
|
|
||||||
// ];
|
|
||||||
|
|
||||||
const JobStatus = () => {
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
|
||||||
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
|
|
||||||
const { data, refetch, isError, isFetching } = useGetJobStatusQuery(queryArgs)
|
|
||||||
const [localData, setLocalData] = useState<any[]>([]);
|
|
||||||
const [jobStatusToggle] = useJobStatusToggleMutation()
|
|
||||||
console.log(data?.data.data)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data?.data?.data) {
|
|
||||||
setLocalData(data?.data.data);
|
|
||||||
}
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
setCurrentPage(page);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSearchChange = (value: string) => {
|
|
||||||
setSearchTerm(value);
|
|
||||||
setCurrentPage(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleToggle = async (agencyId: string, currentStatus: number) => {
|
|
||||||
const newStatus = currentStatus ? 0 : 1;
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
await jobStatusToggle({ id: agencyId, is_active: newStatus }).unwrap();
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Status updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
await delay(500);
|
|
||||||
refetch()
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Someting went wrong.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const filteredData = localData?.filter((agency) => {
|
|
||||||
return (agency.job_status_translation.map((item: any) => {
|
|
||||||
const searchLower = searchTerm.toLowerCase();
|
|
||||||
const title = item.title?.toLowerCase().includes(searchLower);
|
|
||||||
return title;
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
|
|
||||||
const managepost = filteredData?.flatMap((agency: any, index: number) => (agency.job_status_translation.map((translation: any) => ({
|
|
||||||
'id': agency.id,
|
|
||||||
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
|
|
||||||
"Title": translation.title,
|
|
||||||
"is_active": agency.is_active,
|
|
||||||
"Action": (
|
"Action": (
|
||||||
<HStack justifyContent="center">
|
<HStack justifyContent="center">
|
||||||
{/* <ViewAgencyMaster agency={localData} id={agency.id} /> */}
|
<EditJobStatusModel />
|
||||||
<EditJobStatusModel localData={{ ...agency, translation }} refetch={refetch} />
|
|
||||||
<Box>
|
<Box>
|
||||||
<Switch
|
<Switch colorPalette={'teal'} size={"xs"}/>
|
||||||
colorPalette={"teal"}
|
|
||||||
size={"xs"}
|
|
||||||
onChange={() => handleToggle(agency.id, Number(agency.is_active))}
|
|
||||||
checked={Boolean(Number(agency.is_active))}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
</HStack>
|
</HStack>
|
||||||
),
|
),
|
||||||
}))));
|
})),
|
||||||
|
];
|
||||||
|
|
||||||
|
const JobStatus = () => {
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<MainFrame>
|
<MainFrame>
|
||||||
@@ -134,34 +46,40 @@ const JobStatus = () => {
|
|||||||
px={3}
|
px={3}
|
||||||
>
|
>
|
||||||
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
||||||
Job Status
|
Job Status
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<HStack >
|
<HStack >
|
||||||
<SearchComponent
|
<InputGroup
|
||||||
value={searchTerm}
|
startElement={
|
||||||
onChange={handleSearchChange}
|
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
|
||||||
/>
|
}
|
||||||
|
color={"#000"}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
p={3}
|
||||||
|
w={300}
|
||||||
|
bg={"#fff"}
|
||||||
|
colorPalette={"blue"}
|
||||||
|
_focus={{ border: "1px solid #02A0A0" }}
|
||||||
|
rounded={"md"}
|
||||||
|
size={"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> */}
|
||||||
<JobStatusAddModel refetch={refetch} />
|
<JobStatusAddModel />
|
||||||
</HStack>
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
<DataTable
|
<DataTable
|
||||||
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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,67 +1,32 @@
|
|||||||
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
|
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
|
||||||
import { Field, Input, Stack, Text } from "@chakra-ui/react"
|
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
|
||||||
import { IoMdAdd } from "react-icons/io"
|
import { IoMdAdd } from "react-icons/io"
|
||||||
import { Button } from "../../../components/ui/button"
|
import { Button } from "../../../components/ui/button"
|
||||||
import { useCreateJobStatusPostMutation } from "../../../Redux/Service/job.status"
|
|
||||||
import { toaster } from "../../../components/ui/toaster"
|
|
||||||
import { useState } from "react"
|
|
||||||
|
|
||||||
function JobStatusAddModel({ refetch }: { refetch: VoidFunction }) {
|
|
||||||
const [title, setTitle] = useState('')
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [createJobStatusPost, { isLoading }] = useCreateJobStatusPostMutation()
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
setIsOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (!title.trim()) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Title field cannot be empty.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
title: title,
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
await createJobStatusPost(payload).unwrap();
|
|
||||||
refetch()
|
|
||||||
setIsOpen(false);
|
|
||||||
setTitle('')
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
alert("Failed to update template");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
function JobStatusAddModel() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<DialogRoot placement="center" open={isOpen}>
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
{/* <Button bg={"transparent"} size="sm">
|
{/* <Button bg={"transparent"} size="sm">
|
||||||
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
||||||
</Button> */}
|
</Button> */}
|
||||||
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
|
<Button px={5} size={"xs"} bg={"#02A0A0"}>
|
||||||
<IoMdAdd /> <Text>Add</Text>
|
<IoMdAdd /> <Text>Add</Text>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<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={'auto'}
|
height={'auto'}
|
||||||
|
|
||||||
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">Add</DialogTitle>
|
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
|
||||||
@@ -72,28 +37,18 @@ function JobStatusAddModel({ refetch }: { refetch: VoidFunction }) {
|
|||||||
|
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Job Status</Field.Label>
|
<Field.Label color="black" pt={1} fontSize="12px">Job Status</Field.Label>
|
||||||
<Input
|
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
placeholder=""
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={title}
|
|
||||||
onChange={(e) => setTitle(e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
</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} disabled={isLoading}>
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</DialogRoot >
|
</DialogRoot >
|
||||||
|
|
||||||
|
|||||||
@@ -8,58 +8,15 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "../../../components/ui/dialog";
|
} from "../../../components/ui/dialog";
|
||||||
import { Box, Field, Input, Stack } from "@chakra-ui/react";
|
import { Field, Input, Stack } from "@chakra-ui/react";
|
||||||
import { Button } from "../../../components/ui/button";
|
import { Button } from "../../../components/ui/button";
|
||||||
import Edit from "../../../components/ActionIcons/Edit";
|
import Edit from "../../../components/ActionIcons/Edit";
|
||||||
import { useState } from "react";
|
|
||||||
import { useUpdateJobTypeMutation } from "../../../Redux/Service/job.type.service";
|
|
||||||
import { toaster } from "../../../components/ui/toaster";
|
|
||||||
|
|
||||||
function EditJobeModel({ id, localData, refetch }: { id: number, localData: any, refetch: VoidFunction }) {
|
|
||||||
const [jobtype, setJobType] = useState("");
|
|
||||||
const [updateJobType, { isLoading }] = useUpdateJobTypeMutation()
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
const template = localData?.find((item: any) => item.id === id);
|
|
||||||
if (template) {
|
|
||||||
setJobType(template.en_name);
|
|
||||||
setIsOpen(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (!jobtype.trim()) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Title and Subtitle cannot be empty.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
id: id,
|
|
||||||
en_name: jobtype,
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
await updateJobType(payload);
|
|
||||||
refetch()
|
|
||||||
setIsOpen(false);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
alert("Failed to update template");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
function EditJobeModel() {
|
||||||
return (
|
return (
|
||||||
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Box bg={"transparent"} onClick={handleOpenModal}>
|
<Edit />
|
||||||
<Edit />
|
|
||||||
</Box>
|
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<DialogContent
|
<DialogContent
|
||||||
@@ -84,25 +41,24 @@ function EditJobeModel({ id, localData, refetch }: { id: number, localData: any,
|
|||||||
Job Type
|
Job Type
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
value={jobtype}
|
value="Lorem Ipsum"
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
onChange={(e) => setJobType(e.target.value)}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
</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} disabled={isLoading}>
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</DialogRoot>
|
</DialogRoot>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,66 +1,32 @@
|
|||||||
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
|
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
|
||||||
import { Field, Input, Stack, Text } from "@chakra-ui/react"
|
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
|
||||||
import { IoMdAdd } from "react-icons/io"
|
import { IoMdAdd } from "react-icons/io"
|
||||||
import { Button } from "../../../components/ui/button"
|
import { Button } from "../../../components/ui/button"
|
||||||
import { useState } from "react";
|
|
||||||
import { useCreateJobTypePostMutation } from "../../../Redux/Service/job.type.service";
|
|
||||||
import { toaster } from "../../../components/ui/toaster";
|
|
||||||
|
|
||||||
function JobAddModel({ refetch }: { refetch: VoidFunction }) {
|
|
||||||
const [jobType, setJobType] = useState("");
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [createJobTypePost, { isLoading }] = useCreateJobTypePostMutation()
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
setIsOpen(true); // Open modal when clicking "Add"
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (!jobType.trim()) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Title and Subtitle cannot be empty.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
en_name: jobType,
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
await createJobTypePost(payload);
|
|
||||||
refetch()
|
|
||||||
setIsOpen(false);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
alert("Failed to update template");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
function JobAddModel() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<DialogRoot placement="center" open={isOpen}>
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
{/* <Button bg={"transparent"} size="sm">
|
{/* <Button bg={"transparent"} size="sm">
|
||||||
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
||||||
</Button> */}
|
</Button> */}
|
||||||
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
|
<Button px={5} size={"xs"} bg={"#02A0A0"}>
|
||||||
<IoMdAdd /> <Text>Add</Text>
|
<IoMdAdd /> <Text>Add</Text>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<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={'auto'}
|
height={'auto'}
|
||||||
|
|
||||||
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">Add</DialogTitle>
|
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
|
||||||
@@ -71,28 +37,18 @@ function JobAddModel({ refetch }: { refetch: VoidFunction }) {
|
|||||||
|
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Job Type</Field.Label>
|
<Field.Label color="black" pt={1} fontSize="12px">Job Type</Field.Label>
|
||||||
<Input
|
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
placeholder=""
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={jobType}
|
|
||||||
onChange={(e) => setJobType(e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
</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} disabled={isLoading}>
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</DialogRoot >
|
</DialogRoot >
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
import { Box, HStack, Text } from "@chakra-ui/react";
|
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
|
||||||
import MainFrame from "../../../components/MainFrame"
|
import 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 { 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, useJobTypeToggleMutation } from "../../../Redux/Service/job.type.service";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import SearchComponent from "../../../components/SearchComponent";
|
|
||||||
import { toaster, Toaster } from "../../../components/ui/toaster";
|
|
||||||
import { delay } from "../../../components/Utils";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -20,102 +15,25 @@ const tableHeadRow = [
|
|||||||
"Sr. No",
|
"Sr. No",
|
||||||
"Title",
|
"Title",
|
||||||
"Action"
|
"Action"
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// const managepost: any[] = [
|
const managepost: any[] = [
|
||||||
// ...Array.from({ length: 12 }, (_, i) => ({
|
...Array.from({ length: 12 }, (_, i) => ({
|
||||||
// "Sr. No": i + 1,
|
"Sr. No": i + 1,
|
||||||
// "Title": "Lorem Ipsum",
|
"Title": "Lorem Ipsum",
|
||||||
// "Action": (
|
|
||||||
// <HStack justifyContent="center">
|
|
||||||
// <EditJobeModel />
|
|
||||||
// <Box>
|
|
||||||
// <Switch colorPalette={'teal'} size={"xs"} />
|
|
||||||
// </Box>
|
|
||||||
// </HStack>
|
|
||||||
// ),
|
|
||||||
// })),
|
|
||||||
// ];
|
|
||||||
|
|
||||||
const JobType = () => {
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
const { data, refetch, isFetching, isError } = useGetJobTypeQuery(currentPage)
|
|
||||||
const [localData, setLocalData] = useState<any[]>([]);
|
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const [jobTypeToggle] = useJobTypeToggleMutation()
|
|
||||||
console.log('DATA', data?.data.data);
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data?.data?.data) {
|
|
||||||
setLocalData(data?.data.data);
|
|
||||||
}
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
setCurrentPage(page);
|
|
||||||
};
|
|
||||||
|
|
||||||
const filteredData = localData?.filter((agency) => {
|
|
||||||
const searchLower = searchTerm.toLowerCase();
|
|
||||||
const title = agency.en_name?.toLowerCase().includes(searchLower);
|
|
||||||
return title;
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleToggle = async (agencyId: string, currentStatus: number) => {
|
|
||||||
const newStatus = currentStatus ? 0 : 1;
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
await jobTypeToggle({ id: agencyId, is_active: newStatus }).unwrap();
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Status updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
await delay(500);
|
|
||||||
refetch()
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating privacy policy:", error);
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Please try again later",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const managepost = filteredData?.map((agency: JobTypeData, index: number) => ({
|
|
||||||
'id': (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
|
|
||||||
"Sr. No": index + 1,
|
|
||||||
"Title": agency.en_name,
|
|
||||||
|
|
||||||
"Action": (
|
"Action": (
|
||||||
<HStack justifyContent="center">
|
<HStack justifyContent="center">
|
||||||
<EditJobeModel id={agency.id} localData={localData} refetch={refetch} />
|
<EditJobeModel />
|
||||||
<Box>
|
<Box>
|
||||||
<Switch
|
<Switch colorPalette={'teal'} size={"xs"}/>
|
||||||
colorPalette={'teal'}
|
|
||||||
size={"xs"}
|
|
||||||
onChange={() => handleToggle(agency.id.toString(), Number(agency.is_active))}
|
|
||||||
checked={Boolean(Number(agency.is_active))}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
</HStack>
|
</HStack>
|
||||||
),
|
),
|
||||||
}));
|
})),
|
||||||
|
];
|
||||||
|
|
||||||
|
const JobType = () => {
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<MainFrame>
|
<MainFrame>
|
||||||
@@ -128,38 +46,40 @@ const JobType = () => {
|
|||||||
px={3}
|
px={3}
|
||||||
>
|
>
|
||||||
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
||||||
Job Type
|
Job Type
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<HStack >
|
<HStack >
|
||||||
<SearchComponent
|
<InputGroup
|
||||||
value={searchTerm}
|
startElement={
|
||||||
onChange={(value) => {
|
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
|
||||||
setSearchTerm(value);
|
}
|
||||||
// setCurrentPage(1);
|
color={"#000"}
|
||||||
refetch()
|
>
|
||||||
}}
|
<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> */}
|
||||||
<JobAddModel refetch={refetch} />
|
<JobAddModel />
|
||||||
</HStack>
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
<DataTable
|
<DataTable
|
||||||
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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,285 +6,115 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogRoot,
|
DialogRoot,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
} from "../../../components/ui/dialog";
|
} from "../../../components/ui/dialog";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Field,
|
Field,
|
||||||
|
IconButton,
|
||||||
Input,
|
Input,
|
||||||
Stack,
|
Stack,
|
||||||
|
Text,
|
||||||
|
Textarea,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
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 { 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 { Template } from "../../../Redux/Service/template.master.service";
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
const IMGURL = import.meta.env.VITE_IMG_TEMPLATES
|
function EditTemplateModel() {
|
||||||
const APIURL = import.meta.env.VITE_API_URL
|
const [images, setImages] = useState<string[]>([]);
|
||||||
|
|
||||||
function EditTemplateModel({ id, localData, refetch }: { id: number, localData: any, refetch: VoidFunction }) {
|
const handleImageChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const [title, setTitle] = useState("");
|
|
||||||
const [subTitle, setSubTitle] = useState("");
|
|
||||||
const [userType, setUserType] = useState<number | "">("");
|
|
||||||
const [images, setImages] = useState<(File | string)[]>([]);
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
// const [objectURLs, setObjectURLs] = useState<string[]>([]); // Store object URLs separately
|
|
||||||
// const [updateTemplateMaster] = useUpdateTemplateMasterMutation()
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
// const [selectedTemplate, setSelectedTemplate] = useState<Template | null>(null);
|
|
||||||
const token = localStorage.getItem("token");
|
|
||||||
|
|
||||||
console.log(images);
|
|
||||||
|
|
||||||
const handleImageChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
if (event.target.files) {
|
if (event.target.files) {
|
||||||
const file = event.target.files[0];
|
const selectedFiles = Array.from(event.target.files);
|
||||||
if (!["image/jpeg", "image/jpg", "image/png"].includes(file.type)) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Only JPEG, JPG, and PNG files are allowed.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// setImages((prevImages) => [...prevImages, file]);
|
const newImages = selectedFiles.map((file) => {
|
||||||
if (file) {
|
return URL.createObjectURL(file); // Convert to preview URL
|
||||||
setImages([file])
|
});
|
||||||
}
|
|
||||||
|
setImages((prevImages) => [...prevImages, ...newImages]); // Append new images
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
const template = localData?.find((item: any) => item.id === id);
|
|
||||||
if (template) {
|
|
||||||
// setSelectedTemplate(template);
|
|
||||||
setTitle(template.post_template_translate.length > 0 ? template.post_template_translate[0].title : "");
|
|
||||||
setSubTitle(template.post_template_translate.length > 0 ? template.post_template_translate[0].sub_title : "");
|
|
||||||
setUserType(template.principle_type_xid?.toString() || "");
|
|
||||||
|
|
||||||
// Convert image URLs to File objects if needed
|
|
||||||
const templateImages = template.post_template_image.map((img: any) => `${IMGURL}${img.image_name}`);
|
|
||||||
setImages(templateImages);
|
|
||||||
|
|
||||||
setIsOpen(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (!title.trim() || !subTitle.trim()) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Title and Subtitle cannot be empty.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userType === "" || isNaN(Number(userType))) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Please select a valid user type.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// const newImages = images.filter((image) => image instanceof File);
|
|
||||||
|
|
||||||
if (images.length === 0) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Please upload at least one image.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setLoading(true);
|
|
||||||
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append("id", `${id}`);
|
|
||||||
formData.append("principle_type_xid", `${userType}`);
|
|
||||||
formData.append("title", title);
|
|
||||||
formData.append("sub_title", subTitle);
|
|
||||||
|
|
||||||
images.forEach((image, index) => {
|
|
||||||
if (image instanceof File) {
|
|
||||||
formData.append(`image_name[${index}]`, image, image.name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
// await updateTemplateMaster(formData);
|
|
||||||
if (token) {
|
|
||||||
await axios.post(`${APIURL}/template-update`, formData, {
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'multipart/form-data',
|
|
||||||
'access-token': `${token}`,
|
|
||||||
},
|
|
||||||
// withCredentials: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setIsOpen(false);
|
|
||||||
setLoading(false);
|
|
||||||
refetch()
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
setLoading(false);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: `${error.response?.data?.message || "Please try again later."}`,
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// const handleSubmit = async () => {
|
|
||||||
// if (!title.trim() || !subTitle.trim()) {
|
|
||||||
// toaster.create({
|
|
||||||
// title: "Error",
|
|
||||||
// description: "Title and Subtitle cannot be empty.",
|
|
||||||
// type: "error",
|
|
||||||
// });
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (userType === "" || isNaN(Number(userType))) {
|
|
||||||
// toaster.create({
|
|
||||||
// title: "Error",
|
|
||||||
// description: "Please select a valid user type.",
|
|
||||||
// type: "error",
|
|
||||||
// });
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (images.length === 0) {
|
|
||||||
// toaster.create({
|
|
||||||
// title: "Error",
|
|
||||||
// description: "Please upload at least one image.",
|
|
||||||
// type: "error",
|
|
||||||
// });
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const existingImageUrls = images.filter((img) => typeof img === "string") as string[];
|
|
||||||
// const newBase64Images = images.filter((img) => typeof img === "string" && img.startsWith("data:image")) as string[];
|
|
||||||
|
|
||||||
// const payload = {
|
|
||||||
// id: id,
|
|
||||||
// principle_type_xid: userType,
|
|
||||||
// title,
|
|
||||||
// sub_title: subTitle,
|
|
||||||
// image_name: [...existingImageUrls, ...newBase64Images], // Send only Base64 strings
|
|
||||||
// };
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// await updateTemplateMaster(payload)
|
|
||||||
// setIsOpen(false)
|
|
||||||
// } catch (error) {
|
|
||||||
// console.error("Error creating template:", error);
|
|
||||||
// alert("Failed to create template");
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
<DialogRoot placement="center">
|
||||||
{/* <Button bg={"transparent"} size="sm">
|
<DialogTrigger asChild>
|
||||||
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
|
||||||
</Button> */}
|
|
||||||
<Box bg={"transparent"} onClick={handleOpenModal}>
|
|
||||||
<Edit />
|
<Edit />
|
||||||
</Box>
|
</DialogTrigger>
|
||||||
|
|
||||||
|
|
||||||
<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={'auto'}
|
height={"auto"}
|
||||||
|
|
||||||
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">Edit</DialogTitle>
|
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
||||||
|
Add
|
||||||
|
</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">Title</Field.Label>
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
|
Template Name
|
||||||
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Enter Title"
|
placeholder=""
|
||||||
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={title}
|
|
||||||
onChange={(e) => setTitle(e.target.value)}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
|
||||||
|
|
||||||
<Field.Root>
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Subtitle</Field.Label>
|
Images
|
||||||
<Input
|
</Field.Label>
|
||||||
placeholder="Enter subtitle"
|
<Box
|
||||||
|
display="flex"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="space-between"
|
||||||
|
px={3}
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
width="100%"
|
||||||
fontSize="12px"
|
height="50px"
|
||||||
height="30px"
|
cursor="pointer"
|
||||||
value={subTitle}
|
position="relative"
|
||||||
onChange={(e) => setSubTitle(e.target.value)}
|
>
|
||||||
/>
|
<Input
|
||||||
</Field.Root>
|
type="file"
|
||||||
|
accept="image/*"
|
||||||
<Field.Root>
|
opacity={0}
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Select User Type</Field.Label>
|
position="absolute"
|
||||||
<Box bgColor="#EEEEEE" borderRadius="md" p={1}>
|
bgColor="#EEEEEE"
|
||||||
<select
|
border="none"
|
||||||
style={{
|
pl={1}
|
||||||
width: "100%",
|
width="100%"
|
||||||
background: "transparent",
|
height="100%"
|
||||||
color: "black",
|
cursor="pointer"
|
||||||
border: "none",
|
onChange={handleImageChange}
|
||||||
fontSize: "12px",
|
/>
|
||||||
height: "30px",
|
|
||||||
outline: "none",
|
|
||||||
}}
|
|
||||||
value={userType}
|
|
||||||
onChange={(e) => setUserType(Number(e.target.value))}
|
|
||||||
>
|
|
||||||
<option value="">Select User Type</option>
|
|
||||||
<option value="2">Recruiter</option>
|
|
||||||
<option value="3">Jobseeker</option>
|
|
||||||
</select>
|
|
||||||
</Box>
|
|
||||||
</Field.Root>
|
|
||||||
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Images</Field.Label>
|
|
||||||
<Box display="flex" alignItems="center" justifyContent="space-between" px={3} bgColor="#EEEEEE" border="none" width="100%" height="50px" cursor="pointer" position="relative">
|
|
||||||
<Input type="file" accept="image/*" opacity={0} position="absolute" bgColor="#EEEEEE" border="none" pl={1} width="100%" height="100%" cursor="pointer" onChange={handleImageChange} />
|
|
||||||
<Box display="flex" gap={2} overflow="hidden">
|
<Box display="flex" gap={2} overflow="hidden">
|
||||||
{images.length > 0 ? (
|
{images.length > 0 ? (
|
||||||
images.map((img, index) => (
|
images.map((img, index) => (
|
||||||
<img
|
<img
|
||||||
key={index}
|
key={index}
|
||||||
src={img instanceof File ? URL.createObjectURL(img) : img}
|
src={img}
|
||||||
alt={`Uploaded ${index}`}
|
alt={`Uploaded ${index}`}
|
||||||
style={{ maxHeight: "40px", maxWidth: "70px", objectFit: "contain" }}
|
style={{
|
||||||
|
maxHeight: "40px",
|
||||||
|
maxWidth: "70px",
|
||||||
|
objectFit: "contain",
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
@@ -293,26 +123,20 @@ function EditTemplateModel({ id, localData, refetch }: { id: number, localData:
|
|||||||
</Box>
|
</Box>
|
||||||
<FiUpload color="#000" />
|
<FiUpload color="#000" />
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
|
||||||
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* <Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" /> */}
|
{/* <Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" /> */}
|
||||||
|
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
</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} disabled={loading}>
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<Toaster />
|
</DialogRoot>
|
||||||
</DialogRoot >
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,163 +1,50 @@
|
|||||||
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
|
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
|
||||||
import { Box, Field, Input, Stack, Text } from "@chakra-ui/react"
|
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
|
||||||
import { IoMdAdd } from "react-icons/io"
|
import { 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 { useEffect, useState } from "react";
|
import { useState } from "react";
|
||||||
// import { useCreateTemplatePostMutation } from "../../../Redux/Service/template.master.service";
|
|
||||||
import { Toaster, toaster } from "../../../components/ui/toaster"
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
const APIURL = import.meta.env.VITE_API_URL
|
|
||||||
|
|
||||||
function TemplateAddModel({ refetch }: { refetch: VoidFunction }) {
|
|
||||||
const [title, setTitle] = useState("");
|
|
||||||
const [subTitle, setSubTitle] = useState("");
|
|
||||||
const [userType, setUserType] = useState<number | "">("");
|
|
||||||
const [images, setImages] = useState<(File | string)[]>([]);
|
|
||||||
// const [createTemplatePost] = useCreateTemplatePostMutation()
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const token = localStorage.getItem("token");
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isOpen) {
|
|
||||||
setTitle("");
|
|
||||||
setSubTitle("");
|
|
||||||
setUserType("");
|
|
||||||
setImages([]);
|
|
||||||
}
|
|
||||||
}, [isOpen]);
|
|
||||||
|
|
||||||
if (!token) {
|
|
||||||
console.error("No token found in localStorage!");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
setIsOpen(true); // Open modal when clicking "Add"
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const handleImageChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
function TemplateAddModel() {
|
||||||
if (event.target.files) {
|
|
||||||
const file = event.target.files[0];
|
|
||||||
if (!["image/jpeg", "image/jpg", "image/png"].includes(file.type)) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Only JPEG, JPG, and PNG files are allowed.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// setImages((prevImages) => [...prevImages, file]);
|
const [images, setImages] = useState<string[]>([]);
|
||||||
if(file){
|
|
||||||
setImages([file])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
const handleImageChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const handleSubmit = async () => {
|
if (event.target.files) {
|
||||||
if (!title || !subTitle || images.length === 0) {
|
const selectedFiles = Array.from(event.target.files);
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
const newImages = selectedFiles.map((file) => {
|
||||||
description: "Please fill in all required fields and upload at least one image.",
|
return URL.createObjectURL(file); // Convert to preview URL
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userType === "" || isNaN(Number(userType))) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Please select a valid user type.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// const payload = {
|
|
||||||
// id: id,
|
|
||||||
// principle_type_xid: userType,
|
|
||||||
// title,
|
|
||||||
// sub_title: subTitle,
|
|
||||||
// image_name: images.filter((img) => typeof img === "string"), // Send only Base64 strings
|
|
||||||
// };
|
|
||||||
|
|
||||||
setIsLoading(true);
|
|
||||||
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append("principle_type_xid", `${userType}`);
|
|
||||||
formData.append("title", title);
|
|
||||||
formData.append("sub_title", subTitle);
|
|
||||||
|
|
||||||
images.forEach((image, index) => {
|
|
||||||
if (image instanceof File) {
|
|
||||||
formData.append(`image_name[${index}]`, image, image.name); // Ensure indexed naming
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (token) {
|
setImages((prevImages) => [...prevImages, ...newImages]); // Append new images
|
||||||
const payload = JSON.parse(atob(token.split(".")[1]));
|
}
|
||||||
console.log("Token Payload:", payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// await createTemplatePost(formData)
|
|
||||||
if (token) {
|
|
||||||
await axios.post(`${APIURL}/template-store`, formData, {
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'multipart/form-data',
|
|
||||||
'access-token': `${token}`,
|
|
||||||
},
|
|
||||||
// withCredentials: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
refetch();
|
|
||||||
setTitle("");
|
|
||||||
setSubTitle("");
|
|
||||||
setUserType("");
|
|
||||||
setImages([]);
|
|
||||||
setIsOpen(false)
|
|
||||||
setIsLoading(false);
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error("Error creating template:", error);
|
|
||||||
// alert("Failed to create template");
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: `${error.response?.data?.message || "Please try again later."}`,
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log("Token stored:", window.localStorage.getItem("token"))
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<DialogRoot placement="center" open={isOpen}>
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
{/* <Button bg={"transparent"} size="sm">
|
{/* <Button bg={"transparent"} size="sm">
|
||||||
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
||||||
</Button> */}
|
</Button> */}
|
||||||
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
|
<Button px={5} size={"xs"} bg={"#02A0A0"}>
|
||||||
<IoMdAdd /> <Text>Add</Text>
|
<IoMdAdd /> <Text>Add</Text>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<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={'auto'}
|
height={'auto'}
|
||||||
|
|
||||||
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">Add</DialogTitle>
|
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
|
||||||
@@ -167,79 +54,30 @@ function TemplateAddModel({ refetch }: { refetch: VoidFunction }) {
|
|||||||
<Stack py={3}>
|
<Stack py={3}>
|
||||||
|
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Title</Field.Label>
|
<Field.Label color="black" pt={1} fontSize="12px">Template Name</Field.Label>
|
||||||
<Input
|
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
placeholder="Enter Title"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={title}
|
|
||||||
onChange={(e) => setTitle(e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field.Root>
|
|
||||||
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Subtitle</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter subtitle"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={subTitle}
|
|
||||||
onChange={(e) => setSubTitle(e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field.Root>
|
|
||||||
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Select User Type</Field.Label>
|
|
||||||
<Box bgColor="#EEEEEE" borderRadius="md" p={1}>
|
|
||||||
<select
|
|
||||||
style={{
|
|
||||||
width: "100%",
|
|
||||||
background: "transparent",
|
|
||||||
color: "black",
|
|
||||||
border: "none",
|
|
||||||
fontSize: "12px",
|
|
||||||
height: "30px",
|
|
||||||
outline: "none",
|
|
||||||
}}
|
|
||||||
value={userType}
|
|
||||||
onChange={(e) => setUserType(Number(e.target.value))}
|
|
||||||
>
|
|
||||||
<option value="">Select User Type</option>
|
|
||||||
<option value="2">Recruiter</option>
|
|
||||||
<option value="3">Jobseeker</option>
|
|
||||||
</select>
|
|
||||||
</Box>
|
|
||||||
</Field.Root>
|
|
||||||
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Images</Field.Label>
|
<Field.Label color="black" pt={1} fontSize="12px">Images</Field.Label>
|
||||||
<Box display="flex" alignItems="center" justifyContent="space-between" px={3} bgColor="#EEEEEE" border="none" width="100%" height="50px" cursor="pointer" position="relative">
|
<Box display="flex" alignItems="center" justifyContent="space-between" px={3} bgColor="#EEEEEE" border="none" width="100%" height="50px" cursor="pointer" position="relative">
|
||||||
<Input type="file" accept="image/*" opacity={0} position="absolute" bgColor="#EEEEEE" border="none" pl={1} width="100%" height="100%" cursor="pointer" onChange={handleImageChange} />
|
<Input type="file" accept="image/*" opacity={0} position="absolute" bgColor="#EEEEEE" border="none" pl={1} width="100%" height="100%" cursor="pointer" onChange={handleImageChange}/>
|
||||||
<Box display="flex" gap={2} overflow="hidden">
|
<Box display="flex" gap={2} overflow="hidden">
|
||||||
{images.length > 0 ? (
|
{images.length > 0 ? (
|
||||||
images.map((img, index) => (
|
images.map((img, index) => (
|
||||||
<img
|
<img
|
||||||
key={index}
|
key={index}
|
||||||
src={img instanceof File ? URL.createObjectURL(img) : img}
|
src={img}
|
||||||
alt={`Uploaded ${index}`}
|
alt={`Uploaded ${index}`}
|
||||||
style={{ maxHeight: "40px", maxWidth: "70px", objectFit: "contain" }}
|
style={{ maxHeight: "40px", maxWidth: "70px", objectFit: "contain" }}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<Box width="70px" height="40px" /> // Placeholder to maintain layout
|
<Box width="70px" height="40px" /> // Placeholder to maintain layout
|
||||||
)}
|
)}
|
||||||
</Box>
|
|
||||||
<FiUpload color="#000" />
|
|
||||||
</Box>
|
</Box>
|
||||||
|
<FiUpload color="#000" />
|
||||||
|
</Box>
|
||||||
|
|
||||||
{/* <Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" /> */}
|
{/* <Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" /> */}
|
||||||
|
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
@@ -247,14 +85,13 @@ 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} disabled={isLoading}>
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<Toaster />
|
|
||||||
</DialogRoot >
|
</DialogRoot >
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,145 +1,52 @@
|
|||||||
import { Box, HStack, Image, Text } from "@chakra-ui/react";
|
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
|
||||||
import MainFrame from "../../../components/MainFrame"
|
import MainFrame from "../../../components/MainFrame"
|
||||||
|
import { InputGroup } from "../../../components/ui/input-group";
|
||||||
|
import { LuSearch } from "react-icons/lu";
|
||||||
import DataTable from "../../../components/DataTable";
|
import DataTable from "../../../components/DataTable";
|
||||||
import { Switch } from "../../../components/ui/switch";
|
import { Switch } from "../../../components/ui/switch";
|
||||||
// import img from "../../../assets/waterfall.jpg"
|
import img from "../../../assets/waterfall.jpg"
|
||||||
// import Templateimg from "../../../assets/Template_img.png"
|
import Templateimg from "../../../assets/Template_img.png"
|
||||||
import TemplateAddModel from "./TemplateAddModel";
|
import TemplateAddModel from "./TemplateAddModel";
|
||||||
import EditTemplateModel from "./EditTemplateModel";
|
import EditTemplateModel from "./EditTemplateModel";
|
||||||
import { Template, useGetTemplateMasterQuery, useTemplateMasterToggleMutation } from "../../../Redux/Service/template.master.service";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import SearchComponent from "../../../components/SearchComponent";
|
|
||||||
import { toaster, Toaster } from "../../../components/ui/toaster";
|
|
||||||
import { delay } from "../../../components/Utils";
|
|
||||||
|
|
||||||
const APIURL = import.meta.env.VITE_IMG_TEMPLATES
|
|
||||||
|
|
||||||
// table data
|
// table data
|
||||||
|
|
||||||
const tableHeadRow = [
|
const tableHeadRow = [
|
||||||
"Sr. No",
|
"Sr. No",
|
||||||
"Title",
|
"Title",
|
||||||
"User Type",
|
|
||||||
"Images",
|
"Images",
|
||||||
"Action"
|
"Action"
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// const managepost: any[] = [
|
const managepost: any[] = [
|
||||||
// ...Array.from({ length: 12 }, (_, i) => ({
|
...Array.from({ length: 12 }, (_, i) => ({
|
||||||
// "Sr. No": i + 1,
|
"Sr. No": i + 1,
|
||||||
// "Title": "Lorem Ipsum",
|
"Title": "Lorem Ipsum",
|
||||||
// "Images": (
|
"Images": (
|
||||||
// // <Image w={50} src={img} />
|
// <Image w={50} src={img} />
|
||||||
// <HStack >
|
<HStack >
|
||||||
// <Image rounded={'lg'} w={100} h={50} src={img} />
|
<Image rounded={'lg'} w={100} h={50} src={img} />
|
||||||
// <Image rounded={'lg'} w={100} h={50} src={Templateimg} />
|
<Image rounded={'lg'} w={100} h={50} src={Templateimg} />
|
||||||
// </HStack>
|
</HStack>
|
||||||
// ),
|
|
||||||
|
|
||||||
// "Action": (
|
|
||||||
// <HStack justifyContent="center">
|
),
|
||||||
// <EditTemplateModel />
|
|
||||||
// <Box>
|
"Action": (
|
||||||
// <Switch colorPalette={'teal'} size={"xs"} />
|
<HStack justifyContent="center">
|
||||||
// </Box>
|
<EditTemplateModel />
|
||||||
// </HStack>
|
<Box>
|
||||||
// ),
|
<Switch colorPalette={'teal'} size={"xs"}/>
|
||||||
// })),
|
</Box>
|
||||||
// ];
|
</HStack>
|
||||||
|
),
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
|
||||||
const TemplateMaster = () => {
|
const TemplateMaster = () => {
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
const { data, refetch, isFetching, isError } = useGetTemplateMasterQuery(currentPage)
|
|
||||||
const [localData, setLocalData] = useState<any[]>([]);
|
|
||||||
const [templateMasterToggle] = useTemplateMasterToggleMutation();
|
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
console.log('DATA', data?.data.data);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data?.data?.data) {
|
|
||||||
setLocalData(data?.data.data);
|
|
||||||
}
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
setCurrentPage(page);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleToggle = async (agencyId: string, currentStatus: number) => {
|
|
||||||
const newStatus = currentStatus ? 0 : 1;
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
await templateMasterToggle({ id: agencyId, is_active: newStatus }).unwrap();
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Status updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
await delay(500);
|
|
||||||
refetch()
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating privacy policy:", error);
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Please try again later",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const filteredData = localData?.filter((agency) =>
|
|
||||||
agency.post_template_translate[0].title.toLowerCase().includes(searchTerm.toLowerCase())
|
|
||||||
);
|
|
||||||
|
|
||||||
const activeCount = filteredData?.filter((a: any) => a.is_active === 1).length ?? 0;
|
|
||||||
|
|
||||||
const managepost = filteredData?.map((agency: Template, index: number) => {
|
|
||||||
const isOnlyActive = activeCount === 1 && Number(agency.is_active) === 1;
|
|
||||||
|
|
||||||
return {
|
|
||||||
'id': agency.id,
|
|
||||||
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
|
|
||||||
"Title": agency.post_template_translate.length > 0
|
|
||||||
? agency.post_template_translate[0].title
|
|
||||||
: "N/A",
|
|
||||||
"User Type": agency.principle_type_xid === 2 ? 'Recruiter' : 'Job Seeker',
|
|
||||||
"Images": (
|
|
||||||
// <Image w={50} src={img} />
|
|
||||||
<HStack>
|
|
||||||
{agency.post_template_image.map((img) => (
|
|
||||||
<Image key={img.id} rounded={'lg'} w={100} h={50} src={`${APIURL}${img.image_name}`} />
|
|
||||||
))}
|
|
||||||
|
|
||||||
{/* <Image rounded={'lg'} w={100} h={50} src={Templateimg} /> */}
|
|
||||||
</HStack>
|
|
||||||
),
|
|
||||||
|
|
||||||
"Action": (
|
|
||||||
<HStack justifyContent="center">
|
|
||||||
<EditTemplateModel id={agency.id} localData={localData} refetch={refetch} />
|
|
||||||
<Box>
|
|
||||||
<Switch
|
|
||||||
colorPalette={'teal'}
|
|
||||||
size={"xs"}
|
|
||||||
onChange={() => handleToggle(agency.id.toString(), Number(agency.is_active ?? 0))}
|
|
||||||
checked={Boolean(Number(agency.is_active))}
|
|
||||||
disabled={isOnlyActive}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</HStack>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<MainFrame>
|
<MainFrame>
|
||||||
@@ -152,11 +59,11 @@ const TemplateMaster = () => {
|
|||||||
px={3}
|
px={3}
|
||||||
>
|
>
|
||||||
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
||||||
Template Master
|
Template Master
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<HStack >
|
<HStack >
|
||||||
{/* <InputGroup
|
<InputGroup
|
||||||
startElement={
|
startElement={
|
||||||
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
|
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
|
||||||
}
|
}
|
||||||
@@ -175,30 +82,17 @@ const TemplateMaster = () => {
|
|||||||
bgColor={'#EEEEEE'}
|
bgColor={'#EEEEEE'}
|
||||||
ps={8}
|
ps={8}
|
||||||
/>
|
/>
|
||||||
</InputGroup> */}
|
</InputGroup>
|
||||||
<SearchComponent
|
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
|
||||||
value={searchTerm}
|
<TemplateAddModel />
|
||||||
onChange={setSearchTerm}
|
|
||||||
/>
|
|
||||||
<TemplateAddModel refetch={refetch} />
|
|
||||||
</HStack>
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
<DataTable
|
<DataTable
|
||||||
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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,62 +11,21 @@ import {
|
|||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Field,
|
Field,
|
||||||
|
IconButton,
|
||||||
Input,
|
Input,
|
||||||
Stack,
|
Stack,
|
||||||
|
Text,
|
||||||
|
Textarea,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { Button } from "../../../components/ui/button";
|
import { Button } from "../../../components/ui/button";
|
||||||
// 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 { useState } from "react";
|
|
||||||
import { toaster } from "../../../components/ui/toaster";
|
|
||||||
import { useUpdateWorkSpaceMutation } from "../../../Redux/Service/workspace.mode";
|
|
||||||
|
|
||||||
function EditWorkModel({ localData, refetch }: {localData: any, refetch: VoidFunction}) {
|
|
||||||
const [title, setTitle] = useState(localData?.en_name);
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [updateWorkSpace, { isLoading }] = useUpdateWorkSpaceMutation()
|
|
||||||
console.log("localData", localData)
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
// const template = localData?.find((item: any) => item.id === id);
|
|
||||||
if (localData) {
|
|
||||||
setIsOpen(true);
|
|
||||||
// setTitle(localData?.localData.en_name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (!title.trim()) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Title field cannot be empty.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
id: localData?.id,
|
|
||||||
en_name: title
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
await updateWorkSpace(payload).unwrap();
|
|
||||||
refetch()
|
|
||||||
setIsOpen(false);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
alert("Failed to update template");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
function EditWorkModel() {
|
||||||
return (
|
return (
|
||||||
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Box bg={"transparent"} onClick={handleOpenModal}>
|
<Edit />
|
||||||
<Edit />
|
|
||||||
</Box>
|
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<DialogContent
|
<DialogContent
|
||||||
@@ -91,20 +50,19 @@ function EditWorkModel({ localData, refetch }: {localData: any, refetch: VoidFun
|
|||||||
Workspace Mode
|
Workspace Mode
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
value={title}
|
value="Lorem Ipsum"
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
onChange={(e) => setTitle(e.target.value)}
|
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
</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} disabled={isLoading}>
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|||||||
@@ -1,73 +1,32 @@
|
|||||||
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
|
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../../components/ui/dialog"
|
||||||
import { Field, Input, Stack, Text } from "@chakra-ui/react"
|
import { Box, Field, IconButton, Input, Stack, Text, Textarea } from "@chakra-ui/react"
|
||||||
import { IoMdAdd } from "react-icons/io"
|
import { IoMdAdd } from "react-icons/io"
|
||||||
import { Button } from "../../../components/ui/button"
|
import { Button } from "../../../components/ui/button"
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { useCreateWorkspacePostMutation } from "../../../Redux/Service/workspace.mode";
|
|
||||||
import { Toaster, toaster } from "../../../components/ui/toaster";
|
|
||||||
|
|
||||||
function WorkAddModel({ refetch }: { refetch: VoidFunction }) {
|
|
||||||
const [title, setTitle] = useState('')
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [createWorkspacePost, { isLoading }] = useCreateWorkspacePostMutation()
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
setIsOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (!title.trim()) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Title field cannot be empty.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
en_name: title,
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
await createWorkspacePost(payload);
|
|
||||||
refetch()
|
|
||||||
setIsOpen(false);
|
|
||||||
setTitle('')
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
alert("Failed to update template");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isOpen) {
|
|
||||||
setTitle("");
|
|
||||||
}
|
|
||||||
}, [isOpen]);
|
|
||||||
|
|
||||||
|
function WorkAddModel() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<DialogRoot placement="center" open={isOpen}>
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
{/* <Button bg={"transparent"} size="sm">
|
{/* <Button bg={"transparent"} size="sm">
|
||||||
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
||||||
</Button> */}
|
</Button> */}
|
||||||
<Button px={5} size={"xs"} bg={"#02A0A0"} onClick={handleOpenModal}>
|
<Button px={5} size={"xs"} bg={"#02A0A0"}>
|
||||||
<IoMdAdd /> <Text>Add</Text>
|
<IoMdAdd /> <Text>Add</Text>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
<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={'auto'}
|
height={'auto'}
|
||||||
|
|
||||||
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">Add</DialogTitle>
|
<DialogTitle alignSelf="center" color="black" fontSize="14px">Add</DialogTitle>
|
||||||
@@ -78,30 +37,19 @@ function WorkAddModel({ refetch }: { refetch: VoidFunction }) {
|
|||||||
|
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Workspace Mode</Field.Label>
|
<Field.Label color="black" pt={1} fontSize="12px">Workspace Mode</Field.Label>
|
||||||
<Input
|
<Input placeholder="" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
placeholder=""
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={title}
|
|
||||||
onChange={(e) => setTitle(e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
</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} disabled={isLoading}>
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<Toaster />
|
|
||||||
</DialogRoot >
|
</DialogRoot >
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import { Box, HStack, Text } from "@chakra-ui/react";
|
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react";
|
||||||
import MainFrame from "../../../components/MainFrame"
|
import MainFrame from "../../../components/MainFrame"
|
||||||
|
import { InputGroup } from "../../../components/ui/input-group";
|
||||||
|
import { LuSearch } from "react-icons/lu";
|
||||||
import DataTable from "../../../components/DataTable";
|
import DataTable from "../../../components/DataTable";
|
||||||
import { Switch } from "../../../components/ui/switch";
|
import { Switch } from "../../../components/ui/switch";
|
||||||
import WorkAddModel from "./WorkAddModel";
|
import WorkAddModel from "./WorkAddModel";
|
||||||
import EditWorkModel from "./EditWorkModel";
|
import EditWorkModel from "./EditWorkModel";
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { useGetWorkSpaceModeQuery, useWorkspaceToggleMutation } from "../../../Redux/Service/workspace.mode";
|
|
||||||
import SearchComponent from "../../../components/SearchComponent";
|
|
||||||
import { Toaster, toaster } from "../../../components/ui/toaster";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -17,102 +15,25 @@ const tableHeadRow = [
|
|||||||
"Sr. No",
|
"Sr. No",
|
||||||
"Title",
|
"Title",
|
||||||
"Action"
|
"Action"
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// const managepost: any[] = [
|
const managepost: any[] = [
|
||||||
// ...Array.from({ length: 12 }, (_, i) => ({
|
...Array.from({ length: 12 }, (_, i) => ({
|
||||||
// "Sr. No": i + 1,
|
"Sr. No": i + 1,
|
||||||
// "Title": "Lorem Ipsum",
|
"Title": "Lorem Ipsum",
|
||||||
// "Action": (
|
|
||||||
// <HStack justifyContent="center">
|
|
||||||
// <EditWorkModel />
|
|
||||||
// <Box>
|
|
||||||
// <Switch colorPalette={'teal'} size={"xs"} />
|
|
||||||
// </Box>
|
|
||||||
// </HStack>
|
|
||||||
// ),
|
|
||||||
// })),
|
|
||||||
// ];
|
|
||||||
|
|
||||||
const WorkspaceMode = () => {
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
const { data, refetch, isError, isFetching } = useGetWorkSpaceModeQuery(currentPage)
|
|
||||||
const [localData, setLocalData] = useState<any[]>([]);
|
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const [workspaceToggle] = useWorkspaceToggleMutation()
|
|
||||||
|
|
||||||
console.log("Workspace Data", data?.data.data)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data?.data?.data) {
|
|
||||||
setLocalData(data?.data.data);
|
|
||||||
}
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
setCurrentPage(page);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleToggle = async (agencyId: string, currentStatus: number) => {
|
|
||||||
const newStatus = currentStatus ? 0 : 1;
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: newStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
await workspaceToggle({ id: agencyId, is_active: newStatus }).unwrap();
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Status updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
refetch()
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating privacy policy:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Please try again later.",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
setLocalData((prevData) =>
|
|
||||||
prevData.map((agency) =>
|
|
||||||
agency.id === agencyId ? { ...agency, is_active: currentStatus } : agency
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const filteredData = localData?.filter((agency) => {
|
|
||||||
const searchLower = searchTerm.toLowerCase();
|
|
||||||
const title = agency.en_name?.toLowerCase().includes(searchLower);
|
|
||||||
return title;
|
|
||||||
});
|
|
||||||
|
|
||||||
const managepost = filteredData?.map((agency: any, index: number) => ({
|
|
||||||
'id': agency.id,
|
|
||||||
"Sr. No": (currentPage - 1) * (data?.data.per_page ?? 0) + index + 1,
|
|
||||||
"Title": agency.en_name.length > 12
|
|
||||||
? agency.en_name.slice(0, 12) + '...'
|
|
||||||
: agency.en_name,
|
|
||||||
"is_active": agency.is_active,
|
|
||||||
"Action": (
|
"Action": (
|
||||||
<HStack justifyContent="center">
|
<HStack justifyContent="center">
|
||||||
{/* <ViewAgencyMaster agency={localData} id={agency.id} /> */}
|
<EditWorkModel />
|
||||||
<EditWorkModel localData={agency} refetch={refetch} />
|
|
||||||
<Box>
|
<Box>
|
||||||
<Switch
|
<Switch colorPalette={'teal'} size={"xs"}/>
|
||||||
colorPalette={"teal"}
|
|
||||||
size={"xs"}
|
|
||||||
onChange={() => handleToggle(agency.id, Number(agency.is_active))}
|
|
||||||
checked={Boolean(Number(agency.is_active))}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
</HStack>
|
</HStack>
|
||||||
),
|
),
|
||||||
}));
|
})),
|
||||||
|
];
|
||||||
|
|
||||||
|
const WorkspaceMode = () => {
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<MainFrame>
|
<MainFrame>
|
||||||
@@ -125,38 +46,40 @@ const WorkspaceMode = () => {
|
|||||||
px={3}
|
px={3}
|
||||||
>
|
>
|
||||||
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
<Text as={"span"} fontSize={"sm"} fontWeight={500} color={"#000"}>
|
||||||
Workspace Mode
|
Workspace Mode
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<HStack >
|
<HStack >
|
||||||
<SearchComponent
|
<InputGroup
|
||||||
value={searchTerm}
|
startElement={
|
||||||
onChange={(value) => {
|
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
|
||||||
setSearchTerm(value);
|
}
|
||||||
// setCurrentPage(1);
|
color={"#000"}
|
||||||
refetch()
|
>
|
||||||
}}
|
<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> */}
|
||||||
<WorkAddModel refetch={refetch} />
|
<WorkAddModel />
|
||||||
</HStack>
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
<DataTable
|
<DataTable
|
||||||
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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,247 +1,57 @@
|
|||||||
|
|
||||||
import { DialogCloseTrigger, Field, IconButton, Input, Stack, Text } from "@chakra-ui/react";
|
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
|
||||||
|
import { Field, Grid, Heading, Input, Stack, Text } from "@chakra-ui/react"
|
||||||
|
import { FaRegEdit } from "react-icons/fa";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle } from "../../components/ui/dialog";
|
import EnterPassword from "./EnterPassword";
|
||||||
// import EnterPassword from "./EnterPassword";
|
function Changepassword() {
|
||||||
import { useForm } from "react-hook-form";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { toaster, Toaster } from "../../components/ui/toaster";
|
|
||||||
import { useNewPasswordSetMutation } from "../../Redux/Service/profile.password";
|
|
||||||
import { LuEye, LuEyeOff } from "react-icons/lu";
|
|
||||||
import { InputGroup } from "../../components/ui/input-group";
|
|
||||||
|
|
||||||
type EnterPasswordProps = {
|
|
||||||
onClose: () => void;
|
|
||||||
isOpen: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
type FormData = {
|
|
||||||
new_password: string;
|
|
||||||
confirm_password: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
function Changepassword({ onClose, isOpen }: EnterPasswordProps) {
|
|
||||||
const [showOldPassword, setShowOldPassword] = useState(false);
|
|
||||||
const [showNewPassword, setShowNewPassword] = useState(false);
|
|
||||||
const [newPasswordSet] = useNewPasswordSetMutation()
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const {
|
|
||||||
register,
|
|
||||||
handleSubmit,
|
|
||||||
formState: { errors },
|
|
||||||
setError,
|
|
||||||
clearErrors,
|
|
||||||
watch,
|
|
||||||
reset,
|
|
||||||
} = useForm<FormData>({
|
|
||||||
defaultValues: {
|
|
||||||
new_password: '',
|
|
||||||
confirm_password: ''
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const newPassword = watch("new_password");
|
|
||||||
const confirmPassword = watch("confirm_password");
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (newPassword && confirmPassword && newPassword !== confirmPassword) {
|
|
||||||
setError("confirm_password", {
|
|
||||||
type: "manual",
|
|
||||||
message: "Passwords do not match"
|
|
||||||
});
|
|
||||||
} else if (confirmPassword) {
|
|
||||||
clearErrors("confirm_password");
|
|
||||||
}
|
|
||||||
}, [newPassword, confirmPassword, setError, clearErrors]);
|
|
||||||
|
|
||||||
|
|
||||||
const onSubmit = async (data: FormData) => {
|
|
||||||
|
|
||||||
if (data.new_password === '' || data.confirm_password === '') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.new_password !== data.confirm_password) {
|
|
||||||
setError("confirm_password", {
|
|
||||||
type: "manual",
|
|
||||||
message: "Passwords do not match"
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('ERROR', errors)
|
|
||||||
console.log('Change submitted:', data);
|
|
||||||
|
|
||||||
clearErrors("confirm_password");
|
|
||||||
|
|
||||||
setIsLoading(true);
|
|
||||||
const payload = {
|
|
||||||
new_password: data.new_password,
|
|
||||||
confirm_password: data.confirm_password
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await newPasswordSet(payload).unwrap()
|
|
||||||
|
|
||||||
if (res.status === 'success') {
|
|
||||||
toaster.create({
|
|
||||||
title: "Password changed Successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
onClose()
|
|
||||||
} else {
|
|
||||||
toaster.create({
|
|
||||||
title: res.data.message || "Invalid password",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
reset()
|
|
||||||
} catch (error: any) {
|
|
||||||
toaster.create({
|
|
||||||
title: error.data.message || "Something went wrong",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<DialogRoot
|
<DialogRoot placement="center">
|
||||||
placement="center"
|
<DialogTrigger asChild>
|
||||||
open={isOpen}
|
<Button bg="#02A0A0" color={"#fff"} p={4} fontSize={"12px"} mt={2}>
|
||||||
onOpenChange={(open) => !open && onClose()}
|
Change Password
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</DialogTrigger>
|
||||||
|
|
||||||
|
<DialogContent
|
||||||
|
bg={"#fff"}
|
||||||
|
// w={{ lg: "60%", md: "230px" }}
|
||||||
|
w={{ base: '90%', md: '400px' }}
|
||||||
|
|
||||||
|
// height={'80vh'}
|
||||||
|
// overflow={'scroll'}
|
||||||
|
p={2} // Reduced padding
|
||||||
|
bgSize={'md'}
|
||||||
>
|
>
|
||||||
|
<DialogHeader bg="white" pt={3} pb={2} >
|
||||||
|
<DialogTitle alignSelf="center" color="black" fontSize="18px" textAlign={"center"}>CHANGE PASSWORD</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
{/* <DialogTrigger asChild>
|
<DialogBody bg="white" pt={5}>
|
||||||
<Button bg="#02A0A0" size={'2xs'} color={"#fff"} px={2} >
|
<Stack p={2} >
|
||||||
Change Password
|
<Field.Root>
|
||||||
</Button>
|
<Field.Label color="black" pt={1} fontSize="12px">New password</Field.Label>
|
||||||
</DialogTrigger> */}
|
<Input color="black" pl={1} fontSize="12px" height="30px" type="password" border="1px solid grey" /></Field.Root>
|
||||||
|
<Field.Root>
|
||||||
|
<Field.Label color="black" pt={1} fontSize="12px">Confirm password</Field.Label>
|
||||||
|
<Input color="black" pl={1} fontSize="12px" height="30px" type="password" border="1px solid grey" /></Field.Root>
|
||||||
|
|
||||||
<DialogContent
|
</Stack>
|
||||||
bg={"#fff"}
|
</DialogBody>
|
||||||
w={{ base: '90%', md: '400px' }}
|
<DialogFooter display="flex" justifyContent="center" mt={2} p={2}
|
||||||
p={2}
|
|
||||||
bgSize={'md'}
|
|
||||||
>
|
>
|
||||||
<DialogHeader bg="white" pt={3} pb={2} >
|
{/* <Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="18px" textAlign={"center"}>CHANGE PASSWORD</DialogTitle>
|
Save
|
||||||
</DialogHeader>
|
</Button> */}
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<EnterPassword />
|
||||||
<DialogBody bg="white" pt={5}>
|
</DialogFooter>
|
||||||
<Stack p={2} >
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">New password</Field.Label>
|
|
||||||
<InputGroup
|
|
||||||
width={'100%'}
|
|
||||||
endElement={
|
|
||||||
<IconButton
|
|
||||||
aria-label={showOldPassword ? "Hide password" : "Show password"}
|
|
||||||
size="sm"
|
|
||||||
// variant="outline"
|
|
||||||
onClick={() => setShowOldPassword(!showOldPassword)}
|
|
||||||
_hover={{ bg: "transparent" }}
|
|
||||||
height={'fit-content'}
|
|
||||||
mr={2}
|
|
||||||
>
|
|
||||||
{showOldPassword ? <LuEye /> : <LuEyeOff />}
|
|
||||||
</IconButton>
|
|
||||||
}>
|
|
||||||
<Input
|
|
||||||
color="black"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
type={showOldPassword ? "text" : "password"}
|
|
||||||
border={errors.new_password ? "1px solid red" : "1px solid grey"}
|
|
||||||
{...register("new_password", {
|
|
||||||
required: "Password is required",
|
|
||||||
minLength: {
|
|
||||||
value: 8,
|
|
||||||
message: "Password must be at least 8 characters",
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</InputGroup>
|
|
||||||
{/* <IconButton
|
|
||||||
aria-label={showPassword ? "Hide password" : "Show password"}
|
|
||||||
size="sm"
|
|
||||||
variant="ghost"
|
|
||||||
onClick={() => setShowPassword(!showPassword)}
|
|
||||||
>
|
|
||||||
{showPassword ? <LuEye /> : <LuEyeOff />}
|
|
||||||
</IconButton> */}
|
|
||||||
|
|
||||||
{errors.new_password && (
|
{/* <DialogCloseTrigger color="black" /> */}
|
||||||
<Text color="red.500" fontSize="xs" mt={1}>
|
</DialogContent>
|
||||||
{errors.new_password.message}
|
</DialogRoot >
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</Field.Root>
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Confirm password</Field.Label>
|
|
||||||
<InputGroup
|
|
||||||
width={'100%'}
|
|
||||||
endElement={
|
|
||||||
<IconButton
|
|
||||||
aria-label={showNewPassword ? "Hide password" : "Show password"}
|
|
||||||
size="sm"
|
|
||||||
// variant="outline"
|
|
||||||
onClick={() => setShowNewPassword(!showNewPassword)}
|
|
||||||
_hover={{ bg: "transparent" }}
|
|
||||||
height={'fit-content'}
|
|
||||||
mr={2}
|
|
||||||
>
|
|
||||||
{showNewPassword ? <LuEye /> : <LuEyeOff />}
|
|
||||||
</IconButton>
|
|
||||||
}>
|
|
||||||
<Input
|
|
||||||
color="black"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
type={showNewPassword ? "text" : "password"}
|
|
||||||
border={errors.confirm_password ? "1px solid red" : "1px solid grey"}
|
|
||||||
{...register("confirm_password", {
|
|
||||||
required: "Please confirm your password",
|
|
||||||
validate: (value) =>
|
|
||||||
value === newPassword || "Passwords do not match",
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</InputGroup>
|
|
||||||
|
|
||||||
{errors.confirm_password && (
|
|
||||||
<Text color="red.500" fontSize="xs" mt={1}>
|
|
||||||
{errors.confirm_password.message}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Field.Root>
|
|
||||||
|
|
||||||
</Stack>
|
|
||||||
</DialogBody>
|
|
||||||
<DialogFooter display="flex" justifyContent="center" mt={2} p={2}
|
|
||||||
>
|
|
||||||
{/* <EnterPassword /> */}
|
|
||||||
<Button
|
|
||||||
loading={isLoading}
|
|
||||||
mt={6}
|
|
||||||
w="100%"
|
|
||||||
bg="#02A0A0"
|
|
||||||
color="white"
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
</form>
|
|
||||||
<DialogCloseTrigger color="black" />
|
|
||||||
</DialogContent>
|
|
||||||
</DialogRoot >
|
|
||||||
<Toaster />
|
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,87 +1,11 @@
|
|||||||
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle } from "../../components/ui/dialog"
|
import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
|
||||||
import { Box, Input, Stack, Text } from "@chakra-ui/react"
|
import { Box, Input, Stack, Text } from "@chakra-ui/react"
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
import { useEffect, useState } from "react";
|
import { useState } from "react";
|
||||||
// import { BiSolidEdit } from "react-icons/bi";
|
import { BiSolidEdit } from "react-icons/bi";
|
||||||
import { Toaster, toaster } from "../../components/ui/toaster";
|
|
||||||
import { useGetProfileQuery, useResendOtpMutation, useVerifyOTPMutation } from "../../Redux/Service/profile.password";
|
|
||||||
import { useForm } from "react-hook-form";
|
|
||||||
import Changepassword from "./ChangePassword";
|
|
||||||
|
|
||||||
type EnterOTPProps = {
|
function EnterOTP() {
|
||||||
onClose: () => void;
|
const [otp, setOtp] = useState<string[]>(["", "", "", ""]);
|
||||||
isOpen: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
type FormData = {
|
|
||||||
otp: string[];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function EnterOTP({ onClose, isOpen }: EnterOTPProps) {
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const [timer, setTimer] = useState(60);
|
|
||||||
const [isResendDisabled, setIsResendDisabled] = useState(true);
|
|
||||||
const [verifyOTP] = useVerifyOTPMutation()
|
|
||||||
const [otpSuccess, setOtpSuccess] = useState(false);
|
|
||||||
const [resendOtp] = useResendOtpMutation()
|
|
||||||
const { data } = useGetProfileQuery()
|
|
||||||
const id = data?.data.id
|
|
||||||
|
|
||||||
|
|
||||||
const {
|
|
||||||
register,
|
|
||||||
handleSubmit,
|
|
||||||
formState: { errors },
|
|
||||||
reset,
|
|
||||||
} = useForm<FormData>({
|
|
||||||
defaultValues: {
|
|
||||||
otp: ["", "", "", ""] // Initialize with empty strings for each digit
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let interval: NodeJS.Timeout;
|
|
||||||
|
|
||||||
if (timer > 0 && isResendDisabled) {
|
|
||||||
interval = setInterval(() => {
|
|
||||||
setTimer((prevTimer) => prevTimer - 1);
|
|
||||||
}, 1000);
|
|
||||||
} else if (timer === 0) {
|
|
||||||
setIsResendDisabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => clearInterval(interval);
|
|
||||||
}, [timer, isResendDisabled]);
|
|
||||||
|
|
||||||
const handleResendOTP = async () => {
|
|
||||||
setIsResendDisabled(true);
|
|
||||||
setTimer(60); // Reset timer to 1 minute
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
const res = await resendOtp({ mobile_number: Number(id) }).unwrap()
|
|
||||||
|
|
||||||
if (res.status === 200) {
|
|
||||||
toaster.create({
|
|
||||||
title: "OTP resent successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
toaster.create({
|
|
||||||
title: res.data.message || "Failed to resend OTP",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
setIsResendDisabled(false); // Enable button if failed
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
toaster.create({
|
|
||||||
title: error.response?.data?.message || "Failed to resend OTP",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
setIsResendDisabled(false); // Enable button if error
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle change for OTP inputs
|
// Handle change for OTP inputs
|
||||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>, index: number): void => {
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>, index: number): void => {
|
||||||
@@ -91,174 +15,94 @@ function EnterOTP({ onClose, isOpen }: EnterOTPProps) {
|
|||||||
if (/[^0-9]/.test(value)) return;
|
if (/[^0-9]/.test(value)) return;
|
||||||
|
|
||||||
// Update the OTP state with the new value
|
// Update the OTP state with the new value
|
||||||
// const newOtp = [...otp];
|
const newOtp = [...otp];
|
||||||
// newOtp[index] = value;
|
newOtp[index] = value;
|
||||||
// setOtp(newOtp);
|
setOtp(newOtp);
|
||||||
|
|
||||||
if (value && index < 3) {
|
|
||||||
const nextInput = document.getElementById(`otp-input-${index + 1}`) as HTMLInputElement;
|
|
||||||
if (nextInput) nextInput.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move focus to the next input automatically
|
// Move focus to the next input automatically
|
||||||
// if (value && index < otp.length - 1) {
|
if (value && index < otp.length - 1) {
|
||||||
// const nextInput = document.getElementById(`otp-input-${index + 1}`) as HTMLInputElement;
|
const nextInput = document.getElementById(`otp-input-${index + 1}`) as HTMLInputElement;
|
||||||
// if (nextInput) nextInput.focus();
|
if (nextInput) nextInput.focus();
|
||||||
// }
|
|
||||||
|
|
||||||
if (value === "" && index > 0) {
|
|
||||||
const prevInput = document.getElementById(`otp-input-${index - 1}`) as HTMLInputElement;
|
|
||||||
if (prevInput) prevInput.focus();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const onSubmit = async (data: FormData) => {
|
|
||||||
console.log('ERROR', errors)
|
|
||||||
if (data.otp.length !== 4) {
|
|
||||||
toaster.create({
|
|
||||||
title: "OTP must be 4 digits",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fullOtp = data.otp.join('');
|
|
||||||
console.log('OTP submitted:', fullOtp);
|
|
||||||
|
|
||||||
setIsLoading(true);
|
|
||||||
try {
|
|
||||||
const res = await verifyOTP({ otp: fullOtp }).unwrap()
|
|
||||||
|
|
||||||
if (res.status === 'success') {
|
|
||||||
toaster.create({
|
|
||||||
title: "OTP Verified Successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
setOtpSuccess(true);
|
|
||||||
reset();
|
|
||||||
} else {
|
|
||||||
toaster.create({
|
|
||||||
title: res.data.message || "Invalid OTP",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
reset()
|
|
||||||
} catch (error: any) {
|
|
||||||
toaster.create({
|
|
||||||
title: error.data?.message || "Something went wrong",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
setOtpSuccess(false);
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<DialogRoot placement="center"
|
|
||||||
open={isOpen}
|
|
||||||
onOpenChange={(open) => !open && onClose()}>
|
|
||||||
{/* <DialogTrigger asChild>
|
|
||||||
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
|
||||||
Submit
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</DialogTrigger> */}
|
<DialogRoot placement="center">
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
|
||||||
<DialogContent
|
</DialogTrigger>
|
||||||
bg={"#fff"}
|
|
||||||
// w={{ lg: "60%", md: "230px" }}
|
|
||||||
w={{ base: '90%', md: '400px' }}
|
|
||||||
|
|
||||||
// height={'80vh'}
|
<DialogContent
|
||||||
// overflow={'scroll'}
|
bg={"#fff"}
|
||||||
p={2} // Reduced padding
|
// w={{ lg: "60%", md: "230px" }}
|
||||||
bgSize={'md'}
|
w={{ base: '90%', md: '400px' }}
|
||||||
>
|
|
||||||
<DialogHeader bg="white" pt={3} alignSelf="center">
|
// height={'80vh'}
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="18px" textAlign={"center"}>ENTER OTP</DialogTitle>
|
// overflow={'scroll'}
|
||||||
</DialogHeader>
|
p={2} // Reduced padding
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
bgSize={'md'}
|
||||||
<DialogBody bg="white" pt={2}>
|
>
|
||||||
<Text color={"black"} textAlign={"center"}>OTP has been sent successfully</Text>
|
<DialogHeader bg="white" pt={3}>
|
||||||
{/* <Box display="flex" flexDirection="row" alignItems="center" justifyContent="center" p={3}>
|
<DialogTitle alignSelf="center" color="black" fontSize="18px" textAlign={"center"}>ENTER OTP</DialogTitle>
|
||||||
<BiSolidEdit color="black" />
|
</DialogHeader>
|
||||||
<Text color="black" textAlign="center" ml={2}>9619565889</Text>
|
|
||||||
</Box> */}
|
<DialogBody bg="white" pt={2}>
|
||||||
|
<Text color={"black"} textAlign={"center"}>OTP has been send to your E-mail Address</Text>
|
||||||
|
<Box display="flex" flexDirection="row" alignItems="center" justifyContent="center" p={3}>
|
||||||
|
<BiSolidEdit color="black" />
|
||||||
|
<Text color="black" textAlign="center" ml={2}>9619565889</Text>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
|
||||||
<Stack direction="row" justify="center" pt={2}>
|
<Stack direction="row" justify="center" pt={2}>
|
||||||
|
|
||||||
{/* 4 OTP Inputs */}
|
{/* 4 OTP Inputs */}
|
||||||
{Array.from({ length: 4 }).map((_, index) => (
|
{otp.map((digit, index) => (
|
||||||
<Input
|
<Input
|
||||||
key={index}
|
key={index}
|
||||||
id={`otp-input-${index}`}
|
id={`otp-input-${index}`}
|
||||||
maxW="50px"
|
value={digit}
|
||||||
color="black"
|
maxW="50px"
|
||||||
textAlign="center"
|
color={"black"}
|
||||||
fontSize="20px"
|
textAlign="center"
|
||||||
placeholder="0"
|
fontSize="20px"
|
||||||
border={errors.otp?.[index] ? "1px solid red" : "1px solid grey"}
|
placeholder="0"
|
||||||
maxLength={1}
|
border="1px solid grey"
|
||||||
{...register(`otp.${index}`, {
|
onChange={(e) => handleChange(e, index)}
|
||||||
required: "Digit required",
|
maxLength={1} // Only allows 1 character per input
|
||||||
pattern: {
|
/>
|
||||||
value: /^[0-9]$/,
|
))}
|
||||||
message: "Must be a single digit"
|
</Stack>
|
||||||
},
|
<Box textAlign="center">
|
||||||
onChange: (e) => handleChange(e, index)
|
<Text
|
||||||
})}
|
color="#4746F4"
|
||||||
/>
|
textDecoration="underline"
|
||||||
))}
|
fontWeight="bold"
|
||||||
</Stack>
|
mt={3}
|
||||||
<Box textAlign="center" mt={4}>
|
cursor="pointer"
|
||||||
{isResendDisabled ? (
|
display="inline-block"
|
||||||
<Text color="gray.500">
|
px={2} // Adds padding for better appearance
|
||||||
Resend OTP in {timer} seconds
|
|
||||||
</Text>
|
|
||||||
) : (
|
|
||||||
<Text
|
|
||||||
color="#4746F4"
|
|
||||||
textDecoration="underline"
|
|
||||||
fontWeight="bold"
|
|
||||||
cursor="pointer"
|
|
||||||
onClick={handleResendOTP}
|
|
||||||
>
|
|
||||||
Resend OTP
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
</DialogBody>
|
|
||||||
<DialogFooter display="flex" justifyContent="center" mt={2} p={2}
|
|
||||||
>
|
>
|
||||||
<Button
|
Resend OTP
|
||||||
loading={isLoading}
|
</Text>
|
||||||
mt={6}
|
</Box>
|
||||||
w="100%"
|
|
||||||
bg="#02A0A0"
|
</DialogBody>
|
||||||
color="white"
|
<DialogFooter display="flex" justifyContent="center" mt={2} p={2}
|
||||||
type="submit"
|
>
|
||||||
>
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
Verify OTP
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</form>
|
|
||||||
<DialogCloseTrigger color="black" />
|
{/* <DialogCloseTrigger color="black" /> */}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</DialogRoot >
|
</DialogRoot >
|
||||||
{otpSuccess && (<Changepassword
|
|
||||||
onClose={() => {
|
|
||||||
setOtpSuccess(false);
|
|
||||||
onClose()
|
|
||||||
}}
|
|
||||||
isOpen={otpSuccess}
|
|
||||||
/>)}
|
|
||||||
<Toaster />
|
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,127 +1,53 @@
|
|||||||
|
|
||||||
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
|
import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
|
||||||
import { Field, Input, Stack, Text } from "@chakra-ui/react"
|
import { Field, Input, Stack } from "@chakra-ui/react"
|
||||||
import { useForm } from "react-hook-form";
|
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
import EnterOTP from "./EnterOTP";
|
import EnterOTP from "./EnterOTP";
|
||||||
import { useProfilePasswordMutation } from "../../Redux/Service/profile.password";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { Toaster, toaster } from "../../components/ui/toaster";
|
|
||||||
|
|
||||||
type FormData = {
|
|
||||||
password: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
function EnterPassword() {
|
function EnterPassword() {
|
||||||
const [profilePassword] = useProfilePasswordMutation();
|
|
||||||
const [isSuccess, setIsSuccess] = useState(false);
|
|
||||||
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
||||||
|
|
||||||
const {
|
|
||||||
register,
|
|
||||||
handleSubmit,
|
|
||||||
formState: { errors },
|
|
||||||
reset,
|
|
||||||
} = useForm<FormData>();
|
|
||||||
|
|
||||||
const onSubmit = async (data: FormData) => {
|
|
||||||
if (!data.password) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await profilePassword({ password: data.password }).unwrap();
|
|
||||||
setIsSuccess(true);
|
|
||||||
reset();
|
|
||||||
setIsDialogOpen(false);
|
|
||||||
// Handle success (e.g., show a success message or redirect)
|
|
||||||
} catch (error: any) {
|
|
||||||
// Handle error (e.g., show an error message)
|
|
||||||
toaster.create({
|
|
||||||
title: error?.data.message || "Invalid password",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
console.error("Password change failed:", error.data.message);
|
|
||||||
setIsSuccess(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
|
|
||||||
<DialogRoot placement="center"
|
<DialogRoot placement="center">
|
||||||
open={isDialogOpen}
|
<DialogTrigger asChild>
|
||||||
onOpenChange={(details) => setIsDialogOpen(details.open)}
|
<Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</DialogTrigger>
|
||||||
|
|
||||||
|
<DialogContent
|
||||||
|
bg={"#fff"}
|
||||||
|
// w={{ lg: "60%", md: "230px" }}
|
||||||
|
w={{ base: '90%', md: '400px' }}
|
||||||
|
|
||||||
|
// height={'80vh'}
|
||||||
|
// overflow={'scroll'}
|
||||||
|
p={2} // Reduced padding
|
||||||
|
bgSize={'md'}
|
||||||
>
|
>
|
||||||
<DialogTrigger asChild>
|
<DialogHeader bg="white" pt={3} pb={2} >
|
||||||
<Button bg="#02A0A0" size={'2xs'} color={"#fff"} px={2} >
|
<DialogTitle alignSelf="center" color="black" fontSize="18px" textAlign={"center"}>ENTER PASSWORD</DialogTitle>
|
||||||
Change Password
|
</DialogHeader>
|
||||||
</Button>
|
|
||||||
|
|
||||||
</DialogTrigger>
|
<DialogBody bg="white" pt={5}>
|
||||||
<DialogContent
|
<Stack p={2} >
|
||||||
bg={"#fff"}
|
<Field.Root>
|
||||||
// w={{ lg: "60%", md: "230px" }}
|
<Field.Label color="black" pt={1} fontSize="12px">Password</Field.Label>
|
||||||
w={{ base: '90%', md: '400px' }}
|
<Input color="black" pl={1} fontSize="12px" height="30px" type="password" border="1px solid grey" /></Field.Root>
|
||||||
|
|
||||||
// height={'80vh'}
|
|
||||||
// overflow={'scroll'}
|
</Stack>
|
||||||
p={2} // Reduced padding
|
</DialogBody>
|
||||||
bgSize={'md'}
|
<DialogFooter display="flex" justifyContent="center" mt={2} p={2}
|
||||||
>
|
>
|
||||||
<DialogHeader bg="white" pt={3} pb={2} >
|
{/* <Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="18px" textAlign={"center"}>ENTER PASSWORD</DialogTitle>
|
|
||||||
</DialogHeader>
|
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
|
||||||
<DialogBody bg="white" pt={5}>
|
|
||||||
<Stack p={2} >
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">Password</Field.Label>
|
|
||||||
<Input
|
|
||||||
color="black"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
type="password"
|
|
||||||
border={errors.password ? "1px solid red" : "1px solid grey"}
|
|
||||||
{...register("password", {
|
|
||||||
required: "Password is required",
|
|
||||||
minLength: {
|
|
||||||
value: 8,
|
|
||||||
message: "Password must be at least 8 characters",
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
{errors.password && (
|
|
||||||
<Text color="red.500" fontSize="xs" mt={1}>
|
|
||||||
{errors.password.message}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Field.Root>
|
|
||||||
</Stack>
|
|
||||||
</DialogBody>
|
|
||||||
<DialogFooter display="flex" justifyContent="center" mt={2} p={2}
|
|
||||||
>
|
|
||||||
{/* <Button w="100%" bg="#02A0A0" color={"#fff"}>
|
|
||||||
Save
|
Save
|
||||||
</Button> */}
|
</Button> */}
|
||||||
<Button type="submit" w="100%" bg="#02A0A0" color={"#fff"}>
|
<EnterOTP />
|
||||||
Submit
|
</DialogFooter>
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" />
|
{/* <DialogCloseTrigger color="black" /> */}
|
||||||
</form>
|
</DialogContent>
|
||||||
</DialogContent>
|
</DialogRoot >
|
||||||
</DialogRoot >
|
|
||||||
{isSuccess && (<EnterOTP
|
|
||||||
onClose={() => {
|
|
||||||
setIsSuccess(false);
|
|
||||||
setIsDialogOpen(false);
|
|
||||||
}}
|
|
||||||
isOpen={isSuccess}
|
|
||||||
/>)
|
|
||||||
}
|
|
||||||
<Toaster />
|
|
||||||
</>
|
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,146 +1,57 @@
|
|||||||
import { Avatar, Box, HStack, Text, VStack } from "@chakra-ui/react";
|
import { Avatar, Box, Field, Input, SimpleGrid, Stack, Text } from "@chakra-ui/react";
|
||||||
import { FaCamera } from "react-icons/fa";
|
import { FaCamera } from "react-icons/fa";
|
||||||
import EditableInput from "../../components/EditableInput";
|
|
||||||
import MainFrame from "../../components/MainFrame";
|
import MainFrame from "../../components/MainFrame";
|
||||||
import { Field } from "../../components/ui/field";
|
import Changepassword from "./ChangePassword";
|
||||||
// import Changepassword from "./ChangePassword";
|
|
||||||
import EnterPassword from "./EnterPassword";
|
|
||||||
import { useGetProfileQuery } from "../../Redux/Service/profile.password";
|
|
||||||
// import { useUpdateImageMutation } from "../../Redux/Service/myprofie.service";
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
|
||||||
import { Toaster, toaster } from "../../components/ui/toaster";
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
const APIURL = import.meta.env.VITE_API_URL
|
|
||||||
const PROFILEIMGURL = import.meta.env.VITE_IMG_PROFILE
|
|
||||||
|
|
||||||
const Profile = () => {
|
const Profile = () => {
|
||||||
const { data, refetch } = useGetProfileQuery()
|
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
||||||
const [avatarSrc, setAvatarSrc] = useState<string>("");
|
|
||||||
// const [updateImage] = useUpdateImageMutation();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data?.data.profile_photo) {
|
|
||||||
setAvatarSrc(data.data.profile_photo);
|
|
||||||
}
|
|
||||||
}, [data?.data.profile_photo]);
|
|
||||||
|
|
||||||
|
|
||||||
const handleClick = () => {
|
|
||||||
fileInputRef.current?.click();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const file = e.target.files?.[0];
|
|
||||||
if (!file) return;
|
|
||||||
|
|
||||||
if (file.size > 2 * 1024 * 1024) {
|
|
||||||
alert("File size exceeds 2MB limit.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Preview the image
|
|
||||||
const previewUrl = URL.createObjectURL(file);
|
|
||||||
setAvatarSrc(previewUrl);
|
|
||||||
|
|
||||||
// Prepare FormData
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append("profile_photo", file, file.name);
|
|
||||||
|
|
||||||
const token = localStorage.getItem("token");
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (token) {
|
|
||||||
await axios.post(`${APIURL}/profile-image-edit`, formData, {
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'multipart/form-data',
|
|
||||||
'access-token': `${token}`,
|
|
||||||
},
|
|
||||||
// withCredentials: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
refetch();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating image:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Something went wrong",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
console.log('PROFILE DATA:', data?.data);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainFrame >
|
<MainFrame >
|
||||||
<HStack alignItems={'flex-start'} justifyContent={'center'} pt={0} h={'89vh'} w={'100%'} >
|
<Stack p={5}>
|
||||||
|
<Box position="relative" width="fit-content"
|
||||||
|
display="inline-block"
|
||||||
|
cursor="pointer" onClick={() => alert("Avatar clicked!")}>
|
||||||
|
<Avatar.Root size={"2xl"} style={{ display: "inline-block", width: "auto" }}>
|
||||||
|
<Avatar.Fallback />
|
||||||
|
<Avatar.Image src="https://bit.ly/sage-adebayo" />
|
||||||
|
</Avatar.Root>
|
||||||
|
<Box
|
||||||
|
position="absolute"
|
||||||
|
bottom="-2px"
|
||||||
|
left={"39px"}
|
||||||
|
p="2px"
|
||||||
|
>
|
||||||
|
<FaCamera color="black" size={16} />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Text color={"black"} fontWeight={"bold"}>{`Jackson Da`.slice(0, 10) + '...'}</Text>
|
||||||
|
<Text color="black" fontSize="12px">
|
||||||
|
Employee ID: <span>#1245679</span>
|
||||||
|
</Text>
|
||||||
|
<Box w={"70%"} mt={5}>
|
||||||
|
<SimpleGrid columns={{ base: 1, md: 2 }} columnGap={9} rowGap={4}>
|
||||||
|
<Field.Root>
|
||||||
|
<Field.Label color="black" pt={1} fontSize="12px">First Name</Field.Label>
|
||||||
|
<Input placeholder="Enter the First Name" color="black" border="1px solid grey" pl={1} fontSize="12px" height="30px" />
|
||||||
|
</Field.Root>
|
||||||
|
<Field.Root>
|
||||||
|
<Field.Label color="black" pt={1} fontSize="12px">last Name</Field.Label>
|
||||||
|
<Input placeholder="Enter the last Name" color="black" border="1px solid grey" pl={1} fontSize="12px" height="30px" />
|
||||||
|
</Field.Root>
|
||||||
|
<Field.Root>
|
||||||
|
<Field.Label color="black" pt={1} fontSize="12px" >Phone Number</Field.Label>
|
||||||
|
<Input placeholder="Enter the Phone Number" color="black" border="1px solid grey" pl={1} fontSize="12px" height="30px" />
|
||||||
|
</Field.Root>
|
||||||
|
</SimpleGrid>
|
||||||
|
<Text color={"black"} fontWeight={"bold"} fontSize={"14px"} mt={5}>Update password</Text>
|
||||||
|
{/* <Button bg="#02A0A0" color={"#fff"} p={4} fontSize={"12px"} mt={2}>
|
||||||
|
Change Password
|
||||||
|
</Button> */}
|
||||||
|
<Changepassword />
|
||||||
|
|
||||||
<VStack w={'50%'} p={3} rounded={'lg'} mb={3}>
|
</Box>
|
||||||
|
|
||||||
<HStack shadow={'md'} rounded={'lg'} justifyContent={'space-between'} alignItems={'flex-end'} w={'100%'} px={3} py={3} >
|
</Stack>
|
||||||
<VStack w={'100%'} alignItems={'flex-start'} gap={0}>
|
|
||||||
<Box mb={2} position="relative" width="fit-content"
|
|
||||||
cursor="pointer" onClick={handleClick}>
|
|
||||||
<Avatar.Root size={"2xl"} style={{ display: "flex", width: "50px", height: '50px', justifyContent: 'center' }}>
|
|
||||||
<Avatar.Fallback />
|
|
||||||
{/* <Avatar.Image src="https://i.pinimg.com/736x/d6/cd/0f/d6cd0ffd4634b0763d3958a7325ce26e.jpg" /> */}
|
|
||||||
{avatarSrc && <Avatar.Image src={`${PROFILEIMGURL}${avatarSrc}`} />}
|
|
||||||
</Avatar.Root>
|
|
||||||
<Box
|
|
||||||
position="absolute"
|
|
||||||
bottom="-2px"
|
|
||||||
left={"39px"}
|
|
||||||
p="2px"
|
|
||||||
>
|
|
||||||
<FaCamera color="#ccc" size={16} />
|
|
||||||
</Box>
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
accept="image/*"
|
|
||||||
ref={fileInputRef}
|
|
||||||
style={{ display: "none" }}
|
|
||||||
onChange={handleFileChange}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Text color={"black"} as={'span'} fontSize={'sm'} fontWeight={"bold"}>{`${data?.data?.first_name.charAt(0).toUpperCase()}${data?.data.first_name.slice(1)}`}
|
|
||||||
</Text>
|
|
||||||
{/* <Text color="black" as={'span'} fontSize={'xs'}>
|
|
||||||
Employee ID: <span>#1245679</span>
|
|
||||||
</Text> */}
|
|
||||||
</VStack>
|
|
||||||
|
|
||||||
<EnterPassword />
|
|
||||||
{/* <Changepassword /> */}
|
|
||||||
</HStack>
|
|
||||||
|
|
||||||
|
|
||||||
<VStack w={"100%"} >
|
|
||||||
<Field mt={4} label="First Name" fontSize="xs" required>
|
|
||||||
<EditableInput value={`${data?.data.first_name}`} placeholder="Enter first name" isDisabled />
|
|
||||||
</Field>
|
|
||||||
|
|
||||||
<Field mt={4} label="Last Name" fontSize="xs" required>
|
|
||||||
<EditableInput value={`${data?.data.last_name}`} placeholder="Enter last name" isDisabled />
|
|
||||||
</Field>
|
|
||||||
|
|
||||||
<Field mt={4} label="Mobile Number" fontSize="xs" required>
|
|
||||||
<EditableInput value={`${data?.data.phone_number}`} placeholder="Mobile Number" type='number' isDisabled />
|
|
||||||
</Field>
|
|
||||||
|
|
||||||
</VStack>
|
|
||||||
</VStack>
|
|
||||||
|
|
||||||
</HStack>
|
|
||||||
<Toaster />
|
|
||||||
</MainFrame >
|
</MainFrame >
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,197 +0,0 @@
|
|||||||
import {
|
|
||||||
Box,
|
|
||||||
Center,
|
|
||||||
HStack,
|
|
||||||
IconButton,
|
|
||||||
Image,
|
|
||||||
Input,
|
|
||||||
Stack,
|
|
||||||
Text,
|
|
||||||
VStack,
|
|
||||||
} from "@chakra-ui/react";
|
|
||||||
import axios from "axios";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import logo from "../assets/logo.svg";
|
|
||||||
import { Button } from "../components/ui/button";
|
|
||||||
import { toaster, Toaster } from "../components/ui/toaster";
|
|
||||||
import { InputGroup } from "../components/ui/input-group";
|
|
||||||
import { LuEye, LuEyeOff } from "react-icons/lu";
|
|
||||||
|
|
||||||
const SetNewPassword = () => {
|
|
||||||
const [password, setPassword] = useState("");
|
|
||||||
const [confirmPassword, setConfirmPassword] = useState("");
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const queryParams = new URLSearchParams(window.location.search);
|
|
||||||
const id = queryParams.get("id");
|
|
||||||
const [showOldPassword, setShowOldPassword] = useState(false);
|
|
||||||
const [showNewPassword, setShowNewPassword] = useState(false);
|
|
||||||
|
|
||||||
const handlePasswordSubmit = async () => {
|
|
||||||
// Validation
|
|
||||||
if (password.length < 8) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Password must be at least 8 characters long",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (password !== confirmPassword) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Passwords do not match",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsLoading(true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await axios.post(
|
|
||||||
`${import.meta.env.VITE_API_URL}/update-password`,
|
|
||||||
{
|
|
||||||
password: password,
|
|
||||||
confirm_password: confirmPassword,
|
|
||||||
id: Number(id),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (res.data.status === "success") {
|
|
||||||
toaster.create({
|
|
||||||
title: "Password updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
navigate("/login"); // Redirect to login page
|
|
||||||
} else {
|
|
||||||
toaster.create({
|
|
||||||
title: res.data.message || "Failed to update password",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
toaster.create({
|
|
||||||
title: error.response?.data?.message || "Something went wrong",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<VStack w="100%" h="100vh" bg="#ffffff">
|
|
||||||
<HStack
|
|
||||||
boxShadow="rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"
|
|
||||||
w="100%"
|
|
||||||
ps={8}
|
|
||||||
h="7%"
|
|
||||||
justifyContent="flex-start"
|
|
||||||
>
|
|
||||||
<Image w={50} src={logo} />
|
|
||||||
</HStack>
|
|
||||||
|
|
||||||
<Center w="100%" h="93%" p={8}>
|
|
||||||
<Box p={8} borderWidth={1} borderRadius="lg" boxShadow="lg" w={"400px"}>
|
|
||||||
<Text
|
|
||||||
fontSize="20px"
|
|
||||||
fontWeight="bold"
|
|
||||||
color="#313039"
|
|
||||||
marginBottom={"20px"}
|
|
||||||
>
|
|
||||||
Create a Password
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Stack>
|
|
||||||
<Box mb={3}>
|
|
||||||
<Text color="black" fontSize="12px" mb={2}>
|
|
||||||
New password
|
|
||||||
</Text>
|
|
||||||
<InputGroup
|
|
||||||
width={"100%"}
|
|
||||||
endElement={
|
|
||||||
<IconButton
|
|
||||||
aria-label={
|
|
||||||
showOldPassword ? "Hide password" : "Show password"
|
|
||||||
}
|
|
||||||
size="sm"
|
|
||||||
onClick={() => setShowOldPassword(!showOldPassword)}
|
|
||||||
// _hover={{ bg: "transparent" }}
|
|
||||||
bg={"transparent"}
|
|
||||||
color={"#000"}
|
|
||||||
height={"fit-content"}
|
|
||||||
mr={2}
|
|
||||||
>
|
|
||||||
{showOldPassword ? <LuEyeOff /> : <LuEye />}
|
|
||||||
</IconButton>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
color="black"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
type={showOldPassword ? "password" : "text"}
|
|
||||||
border="1px solid grey"
|
|
||||||
value={password}
|
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
|
||||||
size={"sm"}
|
|
||||||
/>
|
|
||||||
</InputGroup>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Box>
|
|
||||||
<Text color="black" mb={2} fontSize="12px">
|
|
||||||
Confirm password
|
|
||||||
</Text>
|
|
||||||
<InputGroup
|
|
||||||
width={"100%"}
|
|
||||||
endElement={
|
|
||||||
<IconButton
|
|
||||||
aria-label={
|
|
||||||
showNewPassword ? "Hide password" : "Show password"
|
|
||||||
}
|
|
||||||
size="sm"
|
|
||||||
// variant="outline"
|
|
||||||
onClick={() => setShowNewPassword(!showNewPassword)}
|
|
||||||
bg={"transparent"}
|
|
||||||
color={"#000"}
|
|
||||||
mr={2}
|
|
||||||
>
|
|
||||||
{showNewPassword ? <LuEyeOff /> : <LuEye />}
|
|
||||||
</IconButton>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
color="black"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
type={showNewPassword ? "password" : "text"}
|
|
||||||
border="1px solid grey"
|
|
||||||
value={confirmPassword}
|
|
||||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
||||||
size={"sm"}
|
|
||||||
/>
|
|
||||||
</InputGroup>
|
|
||||||
</Box>
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
loading={isLoading}
|
|
||||||
mt={6}
|
|
||||||
w="100%"
|
|
||||||
bg="#02A0A0"
|
|
||||||
color="white"
|
|
||||||
onClick={handlePasswordSubmit}
|
|
||||||
>
|
|
||||||
Confirm Password
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</Center>
|
|
||||||
|
|
||||||
<Toaster />
|
|
||||||
</VStack>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SetNewPassword;
|
|
||||||
@@ -1,319 +1,80 @@
|
|||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button"
|
||||||
import {
|
import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle, DialogTrigger } from "../../components/ui/dialog"
|
||||||
DialogBody,
|
import { Field, Grid, Heading, Input, Stack, Text } from "@chakra-ui/react"
|
||||||
DialogCloseTrigger,
|
import { IoMdAdd } from "react-icons/io"
|
||||||
DialogContent,
|
import { Checkbox } from "../../components/ui/checkbox"
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogRoot,
|
|
||||||
DialogTitle,
|
|
||||||
DialogTrigger,
|
|
||||||
} from "../../components/ui/dialog";
|
|
||||||
import { Field, Grid, Heading, Input, Stack, Text } from "@chakra-ui/react";
|
|
||||||
import { IoMdAdd } from "react-icons/io";
|
|
||||||
import { Checkbox } from "../../components/ui/checkbox";
|
|
||||||
import { PermissionResponse, useCreateSubAdminPostMutation } from "../../Redux/Service/manage.subadmin.service";
|
|
||||||
import { toaster, Toaster } from "../../components/ui/toaster";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
|
|
||||||
function AddModel({ refetch, allPermissions }: { refetch: VoidFunction, allPermissions?: PermissionResponse }) {
|
function AddModel() {
|
||||||
const [createSubAdminPost, { isLoading }] = useCreateSubAdminPostMutation();
|
return (
|
||||||
|
|
||||||
// State fields
|
<DialogRoot placement="center">
|
||||||
const [firstName, setFirstName] = useState("");
|
<DialogTrigger asChild>
|
||||||
const [lastName, setLastName] = useState("");
|
{/* <Button bg={"transparent"} size="sm">
|
||||||
// const [userName, setUserName] = useState("");
|
<MdOutlineRemoveRedEye style={{ cursor: "pointer", fontSize: "16px" }} />
|
||||||
const [dateOfBirth, setDateOfBirth] = useState("");
|
</Button> */}
|
||||||
const [gender, setGender] = useState("");
|
<Button rounded={'md'} px={4} py={2} size={"xs"} bg={"#02A0A0"}><IoMdAdd /> Add</Button>
|
||||||
const [email, setEmail] = useState("");
|
|
||||||
const [phonenumber, setPhonenumber] = useState("");
|
|
||||||
const [permissions, setPermission] = useState<number[]>([]);
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
// const [ setIsOpen] = useState(false);
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
</DialogTrigger>
|
||||||
setIsOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCheckboxToggle = (permissionId: number) => {
|
<DialogContent
|
||||||
setPermission((prevData) =>
|
bg={"#fff"}
|
||||||
prevData.includes(permissionId)
|
// w={{ lg: "60%", md: "230px" }}
|
||||||
? prevData.filter((id) => id !== permissionId)
|
w={{ base: '90%', md: '400px' }}
|
||||||
: [...prevData, permissionId]
|
height={'80vh'}
|
||||||
);
|
overflow={'scroll'}
|
||||||
};
|
overflowX="hidden"
|
||||||
|
p={3} // Reduced padding
|
||||||
|
bgSize={'md'}
|
||||||
|
>
|
||||||
|
<DialogHeader bg="white" >
|
||||||
|
<DialogTitle alignSelf="center" color="black" fontSize="14px"
|
||||||
|
>Add Sub Admin Account</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
useEffect(() => {
|
<DialogBody bg="white">
|
||||||
if (!isOpen) {
|
<Stack py={3} >
|
||||||
setFirstName("");
|
|
||||||
setLastName("");
|
|
||||||
// setUserName("");
|
|
||||||
setDateOfBirth("");
|
|
||||||
setGender("");
|
|
||||||
setEmail("");
|
|
||||||
setPhonenumber("");
|
|
||||||
setPermission([]);
|
|
||||||
}
|
|
||||||
}, [isOpen]);
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
<Field.Root>
|
||||||
if (
|
<Field.Label color="black" pt={1} fontSize="12px">First Name</Field.Label>
|
||||||
!firstName.trim() ||
|
<Input placeholder="Enter the First Name" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
!lastName.trim() ||
|
|
||||||
!dateOfBirth.trim() ||
|
|
||||||
!gender.trim()
|
|
||||||
) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Please fill in all required fields",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
<Field.Label color="black" pt={1} fontSize="12px">Last Name</Field.Label>
|
||||||
if (!emailRegex.test(email)) {
|
<Input placeholder="Enter the Last Name" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
toaster.create({
|
|
||||||
title: "Invalid Email",
|
|
||||||
description: "Please enter a valid email address",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (phonenumber.length !== 10) {
|
<Field.Label color="black" pt={1} fontSize="12px">DOB</Field.Label>
|
||||||
toaster.create({
|
<Input placeholder="Enter the DOB" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
title: "Invalid Phone Number",
|
|
||||||
description: "Phone number must be exactly 10 digits",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = {
|
<Field.Label color="black" pt={1} fontSize="12px">Gender</Field.Label>
|
||||||
// user_name: userName,
|
<Input placeholder="Enter the Gender" bgColor="#EEEEEE" color="black" border="none" pl={1} fontSize="12px" height="30px" />
|
||||||
first_name: firstName,
|
<Heading mt={5} color={'#000'} fontSize={'sm'}>Permissions</Heading>
|
||||||
last_name: lastName,
|
</Field.Root>
|
||||||
date_of_birth: dateOfBirth,
|
<Grid templateColumns="repeat(2, 1fr)" gap={4}>
|
||||||
gender: gender,
|
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>Dashboard</Text></Checkbox>
|
||||||
email_address: email,
|
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>Manage contact us</Text></Checkbox>
|
||||||
phone_number: phonenumber,
|
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>manage User</Text></Checkbox>
|
||||||
permission: permissions.filter((id) => typeof id === "number"),
|
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>Manage CMS</Text></Checkbox>
|
||||||
// created_by: 1,
|
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>Manage Post</Text></Checkbox>
|
||||||
};
|
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>Manage Reports</Text></Checkbox>
|
||||||
|
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>manage Sub-Admin</Text></Checkbox>
|
||||||
|
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>My profile</Text></Checkbox>
|
||||||
|
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>Manage Jobs</Text> </Checkbox>
|
||||||
|
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}> manage feedbacks</Text></Checkbox>
|
||||||
|
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}>Manage community</Text> </Checkbox>
|
||||||
|
<Checkbox size={'sm'} color={"black"} ><Text fontSize={12}> Notification</Text></Checkbox>
|
||||||
|
</Grid>
|
||||||
|
</Stack>
|
||||||
|
</DialogBody>
|
||||||
|
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
||||||
|
<Button size={'xs'} w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
|
||||||
try {
|
<DialogCloseTrigger color="black" />
|
||||||
const response = await createSubAdminPost(payload).unwrap();
|
</DialogContent>
|
||||||
if (response) {
|
</DialogRoot >
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Sub-admin created successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
refetch();
|
|
||||||
setFirstName("");
|
|
||||||
setLastName("");
|
|
||||||
// setUserName("");
|
|
||||||
setDateOfBirth("");
|
|
||||||
setGender("");
|
|
||||||
setIsOpen(false);
|
|
||||||
}
|
|
||||||
} catch (error:any) {
|
|
||||||
console.error("Error creating sub-admin:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: error ? error.data.message : "Failed to create sub-admin",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
)
|
||||||
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
|
||||||
<DialogTrigger asChild>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
rounded={"md"}
|
|
||||||
px={4} py={2}
|
|
||||||
size={"xs"}
|
|
||||||
bg={"#02A0A0"}
|
|
||||||
onClick={handleOpenModal}>
|
|
||||||
<IoMdAdd /> Add
|
|
||||||
</Button>
|
|
||||||
</DialogTrigger>
|
|
||||||
|
|
||||||
<DialogContent
|
|
||||||
bg={"#fff"}
|
|
||||||
w={{ base: "90%", md: "400px" }}
|
|
||||||
height={"80vh"}
|
|
||||||
overflow={"scroll"}
|
|
||||||
overflowX="hidden"
|
|
||||||
p={3}
|
|
||||||
bgSize={"md"}
|
|
||||||
>
|
|
||||||
<DialogHeader bg="white">
|
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
|
||||||
Add Sub Admin Account
|
|
||||||
</DialogTitle>
|
|
||||||
</DialogHeader>
|
|
||||||
|
|
||||||
<DialogBody bg="white">
|
|
||||||
<Stack py={3}>
|
|
||||||
<Field.Root>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
First Name
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter the First Name"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={firstName}
|
|
||||||
onChange={(e) => setFirstName(e.target.value)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
Last Name
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter the Last Name"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={lastName}
|
|
||||||
onChange={(e) => setLastName(e.target.value)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* <Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
Username
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter the Username"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={userName}
|
|
||||||
onChange={(e) => setUserName(e.target.value)}
|
|
||||||
/> */}
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
DOB
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter the DOB"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
type="date"
|
|
||||||
value={dateOfBirth}
|
|
||||||
onChange={(e) => setDateOfBirth(e.target.value)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
Gender
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter the Gender"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={gender}
|
|
||||||
onChange={(e) => setGender(e.target.value)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
Email Address
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter Email address"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
type="email"
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={email}
|
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
Phone Number
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter phone number"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
type="tel"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={phonenumber}
|
|
||||||
onChange={(e) => {
|
|
||||||
const value = e.target.value;
|
|
||||||
if (/^\d*$/.test(value)) { // Only allow digits
|
|
||||||
setPhonenumber(value);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Heading mt={5} color={"#000"} fontSize={"sm"}>
|
|
||||||
Permissions
|
|
||||||
</Heading>
|
|
||||||
</Field.Root>
|
|
||||||
|
|
||||||
<Grid templateColumns="repeat(2, 1fr)" gap={4}>
|
|
||||||
{Array.isArray(allPermissions?.data?.permission)
|
|
||||||
? allPermissions.data.permission.map((permission: any) => (
|
|
||||||
<Checkbox
|
|
||||||
size="sm"
|
|
||||||
color="black"
|
|
||||||
key={permission.id}
|
|
||||||
checked={permissions.includes(permission.id)}
|
|
||||||
onChange={() => handleCheckboxToggle(permission.id)}
|
|
||||||
>
|
|
||||||
<Text fontSize={12}>{permission.app_resource_title}</Text>
|
|
||||||
</Checkbox>
|
|
||||||
))
|
|
||||||
: <Text fontSize={12} color="gray.500">Loading permissions...</Text>
|
|
||||||
}
|
|
||||||
</Grid>
|
|
||||||
</Stack>
|
|
||||||
</DialogBody>
|
|
||||||
|
|
||||||
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
|
||||||
<Button
|
|
||||||
size={"xs"}
|
|
||||||
w="100%"
|
|
||||||
bg="#02A0A0"
|
|
||||||
color={"#fff"}
|
|
||||||
onClick={handleSubmit}
|
|
||||||
disabled={isLoading}
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
|
||||||
</DialogContent>
|
|
||||||
<Toaster />
|
|
||||||
</DialogRoot>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AddModel;
|
export default AddModel
|
||||||
@@ -1,301 +0,0 @@
|
|||||||
import { Field, Grid, Heading, Input, Stack, Text } from "@chakra-ui/react";
|
|
||||||
// import { TbEdit } from "react-icons/tb";
|
|
||||||
import { Button } from "../../components/ui/button";
|
|
||||||
import { Checkbox } from "../../components/ui/checkbox";
|
|
||||||
import {
|
|
||||||
DialogBody,
|
|
||||||
DialogCloseTrigger,
|
|
||||||
DialogContent,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogRoot,
|
|
||||||
DialogTitle,
|
|
||||||
DialogTrigger,
|
|
||||||
} from "../../components/ui/dialog";
|
|
||||||
import Edit from "../../components/ActionIcons/Edit";
|
|
||||||
import { PermissionResponse, useLazyViewSubAdminQuery, useUpdateSubAdminMutation } from "../../Redux/Service/manage.subadmin.service";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { Toaster, toaster } from "../../components/ui/toaster";
|
|
||||||
|
|
||||||
const resourceIdToLabel: { [key: number]: string } = {
|
|
||||||
1: 'Dashboard',
|
|
||||||
2: 'Manage User',
|
|
||||||
3: 'Manage Post',
|
|
||||||
4: 'Manage Subadmin',
|
|
||||||
5: 'Manage Jobs',
|
|
||||||
6: 'Manage Groups',
|
|
||||||
7: 'Manage Contact Us',
|
|
||||||
8: 'Manage CMS',
|
|
||||||
9: 'My Profile',
|
|
||||||
10: 'Master Module',
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
interface ResourceActionLink {
|
|
||||||
id: number;
|
|
||||||
app_resource_xid: number;
|
|
||||||
is_active: boolean;
|
|
||||||
app_resource: {
|
|
||||||
id: number,
|
|
||||||
app_resource_title: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function EditSubAdmin({ id, refetch, allPermissions }: { id: number, refetch: VoidFunction, allPermissions?: PermissionResponse }) {
|
|
||||||
const [trigger, { data }] = useLazyViewSubAdminQuery();
|
|
||||||
const [updateSubAdmin, {isLoading}] = useUpdateSubAdminMutation()
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [editData, setEditData] = useState<{
|
|
||||||
id: string;
|
|
||||||
unique_id?: string,
|
|
||||||
first_name: string;
|
|
||||||
last_name: string;
|
|
||||||
date_of_birth: string;
|
|
||||||
gender?: string,
|
|
||||||
permission: ResourceActionLink[];
|
|
||||||
}>({
|
|
||||||
id: '',
|
|
||||||
unique_id: '',
|
|
||||||
first_name: '',
|
|
||||||
last_name: '',
|
|
||||||
date_of_birth: '',
|
|
||||||
gender: '',
|
|
||||||
permission: [],
|
|
||||||
})
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data?.data?.length && allPermissions?.data?.permission?.length) {
|
|
||||||
const subAdmin = data.data[0];
|
|
||||||
|
|
||||||
const activePermissionIds = subAdmin.get_resource_action_link
|
|
||||||
.filter((perm: any) => perm.is_active)
|
|
||||||
.map((perm: any) => perm.app_resource_xid);
|
|
||||||
|
|
||||||
const mergedPermissions: ResourceActionLink[] = allPermissions.data.permission.map((perm) => ({
|
|
||||||
id: perm.id,
|
|
||||||
app_resource_xid: perm.id,
|
|
||||||
is_active: activePermissionIds.includes(perm.id),
|
|
||||||
app_resource: {
|
|
||||||
id: perm.id,
|
|
||||||
app_resource_title: perm.app_resource_title,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
// Map the API response to editData
|
|
||||||
setEditData({
|
|
||||||
id: subAdmin.id.toString(),
|
|
||||||
unique_id: subAdmin.unique_id,
|
|
||||||
first_name: subAdmin.first_name,
|
|
||||||
last_name: subAdmin.last_name,
|
|
||||||
date_of_birth: formatDateOfBirth(subAdmin.date_of_birth),
|
|
||||||
gender: subAdmin.gender,
|
|
||||||
permission: mergedPermissions,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [data, allPermissions]);
|
|
||||||
|
|
||||||
const formatDateOfBirth = (dob: string): string => {
|
|
||||||
// Convert the date to the desired format with slashes
|
|
||||||
const formattedDate = new Date(dob).toLocaleDateString("en-GB", {
|
|
||||||
day: "2-digit",
|
|
||||||
month: "2-digit",
|
|
||||||
year: "numeric",
|
|
||||||
});
|
|
||||||
|
|
||||||
// Replace slashes with hyphens
|
|
||||||
return formattedDate.replace(/\//g, '-');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOpenModal = () => {
|
|
||||||
trigger(id)
|
|
||||||
setIsOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCheckboxToggle = (permissionId: number) => {
|
|
||||||
setEditData((prevData) => ({
|
|
||||||
...prevData,
|
|
||||||
permission: prevData.permission.map((permission) =>
|
|
||||||
permission.app_resource_xid === permissionId
|
|
||||||
? { ...permission, is_active: !permission.is_active }
|
|
||||||
: permission
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
console.log('Updated Data:', editData);
|
|
||||||
// Call your API here with the updated editData
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
id: Number(editData.id),
|
|
||||||
// unique_id: editData.unique_id,
|
|
||||||
first_name: editData.first_name,
|
|
||||||
last_name: editData.last_name,
|
|
||||||
date_of_birth: editData.date_of_birth,
|
|
||||||
gender: editData.gender,
|
|
||||||
permission: editData.permission
|
|
||||||
.filter((p) => p.is_active)
|
|
||||||
.map((p) => p.app_resource_xid),
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await updateSubAdmin(payload).unwrap();
|
|
||||||
if (response?.status === "success") {
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "FAQ updated successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
refetch()
|
|
||||||
setIsOpen(false);
|
|
||||||
} else {
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Failed to update FAQ",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating template:", error);
|
|
||||||
// alert("Failed to update template");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
|
|
||||||
<DialogTrigger asChild>
|
|
||||||
{/* <FaRegEdit style={{ cursor: "pointer" }} color="#000" /> */}
|
|
||||||
|
|
||||||
<Button bg="transparent" color={"black"} h={"18px"} onClick={handleOpenModal}><Edit /></Button>
|
|
||||||
{/* <Button><FaRegEdit /></Button> */}
|
|
||||||
</DialogTrigger>
|
|
||||||
|
|
||||||
<DialogContent
|
|
||||||
bg={"#fff"}
|
|
||||||
w={{ base: "90%", md: "400px" }}
|
|
||||||
height={"80vh"}
|
|
||||||
overflow={"scroll"}
|
|
||||||
overflowX="hidden"
|
|
||||||
p={3} // Reduced padding
|
|
||||||
bgSize={"md"}
|
|
||||||
>
|
|
||||||
<DialogHeader bg="white">
|
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
|
||||||
Edit Sub Admin Account
|
|
||||||
</DialogTitle>
|
|
||||||
</DialogHeader>
|
|
||||||
|
|
||||||
<DialogBody bg="white">
|
|
||||||
<Stack py={3}>
|
|
||||||
<Field.Root>
|
|
||||||
{/* <Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
ID
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter the First Name"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={editData.unique_id}
|
|
||||||
onChange={(e) => setEditData({ ...editData, unique_id: e.target.value })}
|
|
||||||
/> */}
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
First Name
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter the First Name"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={editData.first_name}
|
|
||||||
onChange={(e) => setEditData({ ...editData, first_name: e.target.value })}
|
|
||||||
/>
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
Last Name
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter the Last Name"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={editData.last_name}
|
|
||||||
onChange={(e) => setEditData({ ...editData, last_name: e.target.value })}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
DOB
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter the DOB"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={editData.date_of_birth}
|
|
||||||
onChange={(e) => setEditData({ ...editData, date_of_birth: e.target.value })}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
|
||||||
Gender
|
|
||||||
</Field.Label>
|
|
||||||
<Input
|
|
||||||
placeholder="Enter the Gender"
|
|
||||||
bgColor="#EEEEEE"
|
|
||||||
color="black"
|
|
||||||
border="none"
|
|
||||||
pl={1}
|
|
||||||
fontSize="12px"
|
|
||||||
height="30px"
|
|
||||||
value={editData.gender}
|
|
||||||
onChange={(e) => setEditData({ ...editData, gender: e.target.value })}
|
|
||||||
/>
|
|
||||||
<Heading mt={5} color={"#000"} fontSize={"sm"}>
|
|
||||||
Permissions
|
|
||||||
</Heading>
|
|
||||||
</Field.Root>
|
|
||||||
<Grid templateColumns="repeat(2, 1fr)" gap={4}>
|
|
||||||
{editData.permission.map((permission) => {
|
|
||||||
const label = resourceIdToLabel[permission.app_resource_xid];
|
|
||||||
return (
|
|
||||||
<Checkbox
|
|
||||||
key={permission.id}
|
|
||||||
size="sm"
|
|
||||||
color="black"
|
|
||||||
checked={permission.is_active}
|
|
||||||
onChange={() => handleCheckboxToggle(permission.app_resource_xid)}
|
|
||||||
cursor={'pointer'}
|
|
||||||
>
|
|
||||||
<Text fontSize={12}>{label}</Text>
|
|
||||||
</Checkbox>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Grid>
|
|
||||||
</Stack>
|
|
||||||
</DialogBody>
|
|
||||||
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
|
||||||
<Button size={"xs"} w="100%" bg="#02A0A0" color={"#fff"} onClick={handleSubmit} disabled={isLoading}>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
|
|
||||||
</DialogContent>
|
|
||||||
<Toaster />
|
|
||||||
</DialogRoot>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default EditSubAdmin;
|
|
||||||
@@ -1,26 +1,21 @@
|
|||||||
import { Box, HStack, Image, Text } from "@chakra-ui/react"
|
import { Box, HStack, Image, Input, Text } from "@chakra-ui/react"
|
||||||
import MainFrame from "../../components/MainFrame"
|
import 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 "./EditSubAdmin"
|
import EditSubAdmin from "../../components/EditSubAdmin"
|
||||||
import ViewSubAdmin from "./ViewSubAdmin"
|
import ViewSubAdmin from "./ViewSubAdmin"
|
||||||
import Delete from "../../components/ActionIcons/Delete"
|
import Delete from "../../components/ActionIcons/Delete"
|
||||||
import { PermissionResponse, useDeleteSubAdminPostMutation, useGetPermissionQuery, useGetSubAdminQuery } from "../../Redux/Service/manage.subadmin.service"
|
|
||||||
import { useEffect, useState } from "react"
|
|
||||||
import { Toaster, toaster } from "../../components/ui/toaster"
|
|
||||||
import { useDebounce } from "../../components/Hooks/useDebounce"
|
|
||||||
import SearchComponent from "../../components/SearchComponent"
|
|
||||||
|
|
||||||
|
|
||||||
// table data
|
// table data
|
||||||
|
|
||||||
const tableHeadRow = [
|
const tableHeadRow = [
|
||||||
"Sr. No",
|
"Sr. No",
|
||||||
"Emp ID",
|
"Id",
|
||||||
"First Name",
|
"First Name",
|
||||||
"last Name",
|
"last Name",
|
||||||
"DOB",
|
"DOB",
|
||||||
@@ -28,137 +23,34 @@ const tableHeadRow = [
|
|||||||
"Action",
|
"Action",
|
||||||
];
|
];
|
||||||
|
|
||||||
// const managepost: any[] = [
|
const managepost: any[] = [
|
||||||
// ...Array.from({ length: 12 }, (_, i) => ({
|
...Array.from({ length: 12 }, (_, i) => ({
|
||||||
// "Sr. No": i + 1,
|
"Sr. No": i + 1,
|
||||||
// "Id": 12565,
|
"Id": 12565,
|
||||||
// "First Name": "Kamlesh",
|
"First Name": "Kamlesh",
|
||||||
// "last Name": "Pandey",
|
"last Name": "Pandey",
|
||||||
// "DOB": "12/01/1987",
|
"DOB": "12/01/1987",
|
||||||
// "Gender": "Male",
|
"Gender": "Male",
|
||||||
// "Action": (
|
|
||||||
// <HStack justifyContent="center">
|
|
||||||
|
|
||||||
// <ViewSubAdmin />
|
|
||||||
// <EditSubAdmin />
|
|
||||||
|
|
||||||
// <AlertDailog
|
|
||||||
// AltertTiggerIcon={() => <Delete />}
|
|
||||||
// alertText="Delete Users"
|
|
||||||
// alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
|
|
||||||
// alertCaption="are you sure you want to delete ?"
|
|
||||||
// onConfirm={() => {
|
|
||||||
// console.log("User deleted:", i + 1);
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// </HStack>
|
|
||||||
// ),
|
|
||||||
// })),
|
|
||||||
// ];
|
|
||||||
|
|
||||||
const SubAdmin = () => {
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
// const { data, refetch } = useGetSubAdminQuery()
|
|
||||||
const { data: permissions } = useGetPermissionQuery()
|
|
||||||
const [localData, setLocalData] = useState<any[]>([]);
|
|
||||||
const [allPermissions, setAllPermissions] = useState<PermissionResponse>();
|
|
||||||
const [deleteModal, setDeleteModal] = useState(false)
|
|
||||||
const [deleteSubAdminPost] = useDeleteSubAdminPostMutation()
|
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
|
||||||
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
|
|
||||||
const { data, refetch, isError, isFetching } = useGetSubAdminQuery(queryArgs);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data?.data.data) {
|
|
||||||
setLocalData(data?.data.data);
|
|
||||||
setAllPermissions(permissions);
|
|
||||||
}
|
|
||||||
}, [data, permissions]);
|
|
||||||
|
|
||||||
console.log("============================", allPermissions);
|
|
||||||
console.log('localData', localData);
|
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
setCurrentPage(page);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSearchChange = (value: string) => {
|
|
||||||
setSearchTerm(value);
|
|
||||||
setCurrentPage(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteAdmin = async (faqId: number) => {
|
|
||||||
try {
|
|
||||||
const response = await deleteSubAdminPost(faqId).unwrap();
|
|
||||||
if (response.success) {
|
|
||||||
toaster.create({
|
|
||||||
title: "Success",
|
|
||||||
description: "Sub Admin deleted successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
refetch()
|
|
||||||
console.log("Sub Admin deleted successfully:", response);
|
|
||||||
}
|
|
||||||
// Optionally, refetch data or update state after deletion
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error deleting Sub Admin:", error);
|
|
||||||
toaster.create({
|
|
||||||
title: "Error",
|
|
||||||
description: "Something went wrong",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const formatDateOfBirth = (dob: string): string => {
|
|
||||||
return new Date(dob).toLocaleDateString("en-GB", {
|
|
||||||
day: "2-digit",
|
|
||||||
month: "2-digit",
|
|
||||||
year: "numeric",
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const filteredData = localData?.filter((agency) => {
|
|
||||||
const searchLower = searchTerm.toLowerCase();
|
|
||||||
const userName = agency.user_name?.toLowerCase().includes(searchLower);
|
|
||||||
const firstName = agency.first_name?.toLowerCase().includes(searchLower);
|
|
||||||
const lastName = agency.last_name?.toLowerCase().includes(searchLower);
|
|
||||||
return userName || firstName || lastName;
|
|
||||||
});
|
|
||||||
|
|
||||||
const managepost = filteredData?.map((agency: any, index: number) => ({
|
|
||||||
'id': agency.id,
|
|
||||||
"Sr. No": index + 1,
|
|
||||||
"Emp ID": agency.unique_id,
|
|
||||||
"First Name": agency.first_name,
|
|
||||||
"last Name": agency.last_name,
|
|
||||||
"DOB": formatDateOfBirth(agency.date_of_birth),
|
|
||||||
"Gender": agency.gender,
|
|
||||||
|
|
||||||
"Action": (
|
"Action": (
|
||||||
<HStack justifyContent="center">
|
<HStack justifyContent="center">
|
||||||
{/* <EditDetails rowData={{ id: agency.id, question: agency.question, answer: agency.answer }} refetch={refetch} /> */}
|
|
||||||
<ViewSubAdmin id={agency.id} />
|
<ViewSubAdmin />
|
||||||
<EditSubAdmin id={agency.id} refetch={refetch} allPermissions={permissions} />
|
<EditSubAdmin />
|
||||||
|
|
||||||
<AlertDailog
|
<AlertDailog
|
||||||
isOpen={deleteModal}
|
AltertTiggerIcon={() => <Delete />}
|
||||||
AltertTiggerIcon={() => <Delete onClick={() => setDeleteModal(prev => !prev)} />}
|
alertText="Delete Users"
|
||||||
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)}
|
|
||||||
onConfirm={() => {
|
onConfirm={() => {
|
||||||
// console.log("User deleted:", index + 1);
|
console.log("User deleted:", i + 1);
|
||||||
setDeleteModal(false);
|
|
||||||
handleDeleteAdmin(agency.id)
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</HStack>
|
</HStack>
|
||||||
),
|
),
|
||||||
}));
|
})),
|
||||||
|
];
|
||||||
|
const SubAdmin = () => {
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<MainFrame >
|
<MainFrame >
|
||||||
@@ -175,31 +67,36 @@ const SubAdmin = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<HStack>
|
<HStack>
|
||||||
<SearchComponent
|
<InputGroup
|
||||||
value={searchTerm}
|
startElement={
|
||||||
onChange={handleSearchChange}
|
<LuSearch fontSize={"xs"} style={{ position: 'relative', left: '10px' }} />
|
||||||
/>
|
}
|
||||||
|
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 refetch={refetch} allPermissions={permissions} />
|
<AddModel />
|
||||||
</HStack>
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
<DataTable
|
<DataTable
|
||||||
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> </MainFrame>
|
||||||
<Toaster />
|
|
||||||
</MainFrame>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
export default SubAdmin
|
export default SubAdmin
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
import {
|
import {
|
||||||
DialogBody,
|
DialogBody,
|
||||||
DialogCloseTrigger,
|
DialogCloseTrigger,
|
||||||
@@ -13,204 +13,169 @@ import {
|
|||||||
Field,
|
Field,
|
||||||
Grid,
|
Grid,
|
||||||
Heading,
|
Heading,
|
||||||
|
Icon,
|
||||||
Input,
|
Input,
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { Checkbox } from "../../components/ui/checkbox";
|
import { Checkbox } from "../../components/ui/checkbox";
|
||||||
// import { MdOutlineRemoveRedEye } from "react-icons/md";
|
import { MdOutlineRemoveRedEye } from "react-icons/md";
|
||||||
// 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";
|
function ViewSubAdmin() {
|
||||||
import {useLazyViewSubAdminQuery } from "../../Redux/Service/manage.subadmin.service";
|
|
||||||
|
|
||||||
function ViewSubAdmin({ id, }: { id: number}) {
|
|
||||||
const [trigger, { data }] = useLazyViewSubAdminQuery();
|
|
||||||
|
|
||||||
const handleView = () => {
|
|
||||||
trigger(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
const viewSubAdmin = data?.data
|
|
||||||
|
|
||||||
const formatDateOfBirth = (dob: string): string => {
|
|
||||||
return new Date(dob).toLocaleDateString("en-GB", {
|
|
||||||
day: "2-digit",
|
|
||||||
month: "2-digit",
|
|
||||||
year: "numeric",
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('data', data?.data);
|
|
||||||
return (
|
return (
|
||||||
<DialogRoot placement="center">
|
<DialogRoot placement="center">
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button
|
<View />
|
||||||
onClick={handleView}
|
|
||||||
bg={'transparent'}
|
|
||||||
color={"black"}
|
|
||||||
>
|
|
||||||
<View />
|
|
||||||
</Button>
|
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|
||||||
{viewSubAdmin?.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"}
|
>
|
||||||
key={data.id}
|
<DialogHeader bg="white">
|
||||||
>
|
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
||||||
<DialogHeader bg="white">
|
View Sub Admin Account
|
||||||
<DialogTitle alignSelf="center" color="black" fontSize="14px">
|
</DialogTitle>
|
||||||
View Sub Admin Account
|
</DialogHeader>
|
||||||
</DialogTitle>
|
|
||||||
</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
|
||||||
value={data.first_name}
|
value="Priyanka"
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
readOnly
|
readOnly
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<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
|
||||||
value={data.last_name}
|
value="Joshi"
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
readOnly
|
readOnly
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
ID
|
ID
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
value={data.unique_id}
|
value="ID"
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
readOnly
|
readOnly
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
DOB
|
DOB
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
value={formatDateOfBirth(data.date_of_birth)}
|
value="11/02/1989"
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
readOnly
|
readOnly
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Field.Label color="black" pt={1} fontSize="12px">
|
<Field.Label color="black" pt={1} fontSize="12px">
|
||||||
Gender
|
Gender
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Input
|
<Input
|
||||||
value={data.gender}
|
value="Male"
|
||||||
bgColor="#EEEEEE"
|
bgColor="#EEEEEE"
|
||||||
color="black"
|
color="black"
|
||||||
border="none"
|
border="none"
|
||||||
pl={1}
|
pl={1}
|
||||||
fontSize="12px"
|
fontSize="12px"
|
||||||
height="30px"
|
height="30px"
|
||||||
readOnly
|
readOnly
|
||||||
/>
|
/>
|
||||||
<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}>
|
||||||
{data.get_resource_action_link.map((check: any) => (
|
<Checkbox size={"sm"} color={"black"}>
|
||||||
<Checkbox size={"sm"} color={"black"} checked={check.is_active} key={check.id}>
|
<Text fontSize={12}>Dashboard</Text>
|
||||||
<Text fontSize={12}>{check?.app_resource.app_resource_title}</Text>
|
</Checkbox>
|
||||||
</Checkbox>
|
<Checkbox size={"sm"} color={"black"}>
|
||||||
// <>
|
{" "}
|
||||||
// <Checkbox size={"sm"} color={"black"}>
|
<Text fontSize={12}>Manage contact us</Text>
|
||||||
// <Text fontSize={12}>Dashboard</Text>
|
</Checkbox>
|
||||||
// </Checkbox>
|
<Checkbox size={"sm"} color={"black"}>
|
||||||
// <Checkbox size={"sm"} color={"black"}>
|
{" "}
|
||||||
// {" "}
|
<Text fontSize={12}>manage User</Text>
|
||||||
// <Text fontSize={12}>Manage contact us</Text>
|
</Checkbox>
|
||||||
// </Checkbox>
|
<Checkbox size={"sm"} color={"black"}>
|
||||||
// <Checkbox size={"sm"} color={"black"}>
|
{" "}
|
||||||
// {" "}
|
<Text fontSize={12}>Manage CMS</Text>
|
||||||
// <Text fontSize={12}>manage User</Text>
|
</Checkbox>
|
||||||
// </Checkbox>
|
<Checkbox size={"sm"} color={"black"}>
|
||||||
// <Checkbox size={"sm"} color={"black"}>
|
{" "}
|
||||||
// {" "}
|
<Text fontSize={12}>Manage Post</Text>
|
||||||
// <Text fontSize={12}>Manage CMS</Text>
|
</Checkbox>
|
||||||
// </Checkbox>
|
<Checkbox size={"sm"} color={"black"}>
|
||||||
// <Checkbox size={"sm"} color={"black"}>
|
{" "}
|
||||||
// {" "}
|
<Text fontSize={12}>Manage Reports</Text>
|
||||||
// <Text fontSize={12}>Manage Post</Text>
|
</Checkbox>
|
||||||
// </Checkbox>
|
<Checkbox size={"sm"} color={"black"}>
|
||||||
// <Checkbox size={"sm"} color={"black"}>
|
{" "}
|
||||||
// {" "}
|
<Text fontSize={12}>manage Sub-Admin</Text>
|
||||||
// <Text fontSize={12}>Manage Reports</Text>
|
</Checkbox>
|
||||||
// </Checkbox>
|
<Checkbox size={"sm"} color={"black"}>
|
||||||
// <Checkbox size={"sm"} color={"black"}>
|
{" "}
|
||||||
// {" "}
|
<Text fontSize={12}>My profile</Text>
|
||||||
// <Text fontSize={12}>manage Sub-Admin</Text>
|
</Checkbox>
|
||||||
// </Checkbox>
|
<Checkbox size={"sm"} color={"black"}>
|
||||||
// <Checkbox size={"sm"} color={"black"}>
|
<Text fontSize={12}>Manage Jobs</Text>{" "}
|
||||||
// {" "}
|
</Checkbox>
|
||||||
// <Text fontSize={12}>My profile</Text>
|
<Checkbox size={"sm"} color={"black"}>
|
||||||
// </Checkbox>
|
<Text fontSize={12}> manage feedbacks</Text>
|
||||||
// <Checkbox size={"sm"} color={"black"}>
|
</Checkbox>
|
||||||
// <Text fontSize={12}>Manage Jobs</Text>{" "}
|
<Checkbox size={"sm"} color={"black"}>
|
||||||
// </Checkbox>
|
<Text fontSize={12}>Manage community</Text>{" "}
|
||||||
// <Checkbox size={"sm"} color={"black"}>
|
</Checkbox>
|
||||||
// <Text fontSize={12}> manage feedbacks</Text>
|
<Checkbox size={"sm"} color={"black"}>
|
||||||
// </Checkbox>
|
<Text fontSize={12}> Notification</Text>
|
||||||
// <Checkbox size={"sm"} color={"black"}>
|
</Checkbox>
|
||||||
// <Text fontSize={12}>Manage community</Text>{" "}
|
</Grid>
|
||||||
// </Checkbox>
|
</Stack>
|
||||||
// <Checkbox size={"sm"} color={"black"}>
|
</DialogBody>
|
||||||
// <Text fontSize={12}> Notification</Text>
|
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
||||||
// </Checkbox>
|
{/* <Button w="100%" bg="#02A0A0" color={"#fff"}>
|
||||||
// </>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
</Stack>
|
|
||||||
</DialogBody>
|
|
||||||
<DialogFooter display="flex" justifyContent="center" pt={"2"}>
|
|
||||||
{/* <Button w="100%" bg="#02A0A0" color={"#fff"}>
|
|
||||||
Save
|
Save
|
||||||
</Button> */}
|
</Button> */}
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|
||||||
<DialogCloseTrigger color="black" />
|
<DialogCloseTrigger color="black" />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
))}
|
|
||||||
</DialogRoot>
|
</DialogRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,219 +0,0 @@
|
|||||||
import {
|
|
||||||
Box,
|
|
||||||
Center,
|
|
||||||
HStack,
|
|
||||||
Image,
|
|
||||||
Input,
|
|
||||||
Text,
|
|
||||||
VStack,
|
|
||||||
} from "@chakra-ui/react";
|
|
||||||
import axios from "axios";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { useNavigate, useLocation } from "react-router-dom";
|
|
||||||
import logo from "../assets/logo.svg";
|
|
||||||
import { Button } from "../components/ui/button";
|
|
||||||
import { toaster, Toaster } from "../components/ui/toaster";
|
|
||||||
|
|
||||||
const VerifyOTP = () => {
|
|
||||||
const [otp, setOtp] = useState<string[]>(["", "", "", ""]);
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const [timer, setTimer] = useState(60);
|
|
||||||
const [isResendDisabled, setIsResendDisabled] = useState(true);
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const location = useLocation();
|
|
||||||
const queryParams = new URLSearchParams(location.search);
|
|
||||||
const phoneNumber = queryParams.get("phone");
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let interval: NodeJS.Timeout;
|
|
||||||
|
|
||||||
if (timer > 0 && isResendDisabled) {
|
|
||||||
interval = setInterval(() => {
|
|
||||||
setTimer((prevTimer) => prevTimer - 1);
|
|
||||||
}, 1000);
|
|
||||||
} else if (timer === 0) {
|
|
||||||
setIsResendDisabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => clearInterval(interval);
|
|
||||||
}, [timer, isResendDisabled]);
|
|
||||||
|
|
||||||
|
|
||||||
const handleResendOTP = async () => {
|
|
||||||
setIsResendDisabled(true);
|
|
||||||
setTimer(60); // Reset timer to 1 minute
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await axios.post(`${import.meta.env.VITE_API_URL}/send-otp`, {
|
|
||||||
mobile_number: phoneNumber,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.status === 200) {
|
|
||||||
toaster.create({
|
|
||||||
title: "OTP resent successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
toaster.create({
|
|
||||||
title: res.data.message || "Failed to resend OTP",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
setIsResendDisabled(false); // Enable button if failed
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
toaster.create({
|
|
||||||
title: error.response?.data?.message || "Failed to resend OTP",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
setIsResendDisabled(false); // Enable button if error
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>, index: number): void => {
|
|
||||||
const value = e.target.value;
|
|
||||||
|
|
||||||
// Prevent non-numeric input
|
|
||||||
if (/[^0-9]/.test(value)) return;
|
|
||||||
|
|
||||||
// Update the OTP state with the new value
|
|
||||||
const newOtp = [...otp];
|
|
||||||
newOtp[index] = value;
|
|
||||||
setOtp(newOtp);
|
|
||||||
|
|
||||||
// Move focus to the next input automatically
|
|
||||||
if (value && index < otp.length - 1) {
|
|
||||||
const nextInput = document.getElementById(`otp-input-${index + 1}`) as HTMLInputElement;
|
|
||||||
if (nextInput) nextInput.focus();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOtpSubmit = async () => {
|
|
||||||
if (otp.length !== 4) {
|
|
||||||
toaster.create({
|
|
||||||
title: "OTP must be 4 digits",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fullOtp = otp.join('');
|
|
||||||
|
|
||||||
setIsLoading(true);
|
|
||||||
try {
|
|
||||||
const res = await axios.post(`${import.meta.env.VITE_API_URL}/verify-otp`, {
|
|
||||||
mobile_number: phoneNumber,
|
|
||||||
otp: fullOtp,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.status === 200) {
|
|
||||||
toaster.create({
|
|
||||||
title: "OTP Verified Successfully",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
const userid = res.data.data.id;
|
|
||||||
navigate(`/forgot-password/reset-password?id=${userid}`);
|
|
||||||
} else {
|
|
||||||
toaster.create({
|
|
||||||
title: res.data.message || "Invalid OTP",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
toaster.create({
|
|
||||||
title: error.response?.data?.message || "Something went wrong",
|
|
||||||
type: "error",
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<VStack w="100%" h="100vh" bg="#ffffff">
|
|
||||||
<HStack
|
|
||||||
boxShadow="rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"
|
|
||||||
w="100%"
|
|
||||||
ps={8}
|
|
||||||
h="7%"
|
|
||||||
justifyContent="flex-start"
|
|
||||||
>
|
|
||||||
<Image w={50} src={logo} />
|
|
||||||
</HStack>
|
|
||||||
|
|
||||||
<Center w="100%" h="93%" p={8}>
|
|
||||||
<Box p={8} borderWidth={1} borderRadius="lg" boxShadow="lg">
|
|
||||||
<Text fontSize="24px" fontWeight="bold" color="#313039" textAlign="center">
|
|
||||||
Enter OTP
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Text fontSize="14px" color="gray.600" textAlign="center" mt={2}>
|
|
||||||
OTP sent to {phoneNumber}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<HStack gap={4} mt={6} justify="center">
|
|
||||||
{otp.map((digit, index) => (
|
|
||||||
<Input
|
|
||||||
key={index}
|
|
||||||
id={`otp-input-${index}`}
|
|
||||||
value={digit}
|
|
||||||
maxW="50px"
|
|
||||||
color={"black"}
|
|
||||||
textAlign="center"
|
|
||||||
fontSize="20px"
|
|
||||||
placeholder="0"
|
|
||||||
border="1px solid grey"
|
|
||||||
onChange={(e) => handleChange(e, index)}
|
|
||||||
maxLength={1} // Only allows 1 character per input
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</HStack>
|
|
||||||
{/* <Box textAlign="center">
|
|
||||||
<Text
|
|
||||||
color="#4746F4"
|
|
||||||
textDecoration="underline"
|
|
||||||
fontWeight="bold"
|
|
||||||
mt={3}
|
|
||||||
cursor="pointer"
|
|
||||||
display="inline-block"
|
|
||||||
px={2}
|
|
||||||
>
|
|
||||||
Resend OTP
|
|
||||||
</Text>
|
|
||||||
</Box> */}
|
|
||||||
<Box textAlign="center" mt={4}>
|
|
||||||
{isResendDisabled ? (
|
|
||||||
<Text color="gray.500">
|
|
||||||
Resend OTP in {timer} seconds
|
|
||||||
</Text>
|
|
||||||
) : (
|
|
||||||
<Text
|
|
||||||
color="#4746F4"
|
|
||||||
textDecoration="underline"
|
|
||||||
fontWeight="bold"
|
|
||||||
cursor="pointer"
|
|
||||||
onClick={handleResendOTP}
|
|
||||||
>
|
|
||||||
Resend OTP
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
loading={isLoading}
|
|
||||||
mt={6}
|
|
||||||
w="100%"
|
|
||||||
bg="#02A0A0"
|
|
||||||
color="white"
|
|
||||||
onClick={handleOtpSubmit}
|
|
||||||
>
|
|
||||||
Verify OTP
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</Center>
|
|
||||||
|
|
||||||
<Toaster />
|
|
||||||
</VStack>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default VerifyOTP;
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
|
||||||
|
|
||||||
export interface Agency {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
state: string;
|
|
||||||
rc_status: string;
|
|
||||||
rc_number: string;
|
|
||||||
domain_name: string;
|
|
||||||
gst_number: string;
|
|
||||||
is_active: boolean,
|
|
||||||
registered_office: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AgencyData {
|
|
||||||
current_page: number;
|
|
||||||
data: Agency[];
|
|
||||||
first_page_url: string;
|
|
||||||
from: number;
|
|
||||||
last_page: number;
|
|
||||||
last_page_url: string;
|
|
||||||
per_page: number;
|
|
||||||
total: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AgencyResponse {
|
|
||||||
status: "success" | "error";
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: AgencyData;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UpdatePrivacyPolicyPayload {
|
|
||||||
id: number,
|
|
||||||
is_active: boolean,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AgencyPost {
|
|
||||||
raid?: string;
|
|
||||||
name: string;
|
|
||||||
auth_signatory?: string;
|
|
||||||
state: string;
|
|
||||||
district?: string;
|
|
||||||
rc_number: string;
|
|
||||||
contact_details?: string;
|
|
||||||
registered_office: string;
|
|
||||||
branch_office?: string;
|
|
||||||
registered_email?: string;
|
|
||||||
other_email?: string;
|
|
||||||
registered_contact?: string;
|
|
||||||
website?: string;
|
|
||||||
domain_name: string;
|
|
||||||
staff_domain_name?: string;
|
|
||||||
gst_number: string;
|
|
||||||
rc_status?: "Active" | "Inactive"; // Assuming it's a status with limited values
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const agencyMasterModule = createApi({
|
|
||||||
reducerPath: "agencyMasterModule",
|
|
||||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
|
||||||
endpoints: (builder) => ({
|
|
||||||
|
|
||||||
createAgencyMasterPost: builder.mutation<AgencyPost, Partial<AgencyPost>>({
|
|
||||||
query: (data) => ({
|
|
||||||
url: "/agency-store",
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
// getAgencyMaster: builder.query<AgencyResponse, number>({
|
|
||||||
// query: (page = 1) => `/agency-master?page=${page}`
|
|
||||||
// }),
|
|
||||||
|
|
||||||
getAgencyMaster: builder.query<AgencyResponse, { page?: number; search?: string }>({
|
|
||||||
query: ({ page, search }) => {
|
|
||||||
const params = new URLSearchParams();
|
|
||||||
if (page) params.append("page", page.toString());
|
|
||||||
if (search) params.append("search", search);
|
|
||||||
|
|
||||||
return `/agency-master?${params.toString()}`;
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
agencyMasterToggle: builder.mutation({
|
|
||||||
query: ({ id, is_active }) => ({
|
|
||||||
url: `/agency-status`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id, is_active },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
updateAgencyMaster: builder.mutation({
|
|
||||||
query: (updatedData) => ({
|
|
||||||
url: "/agency-update",
|
|
||||||
method: "POST",
|
|
||||||
body: updatedData,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const {
|
|
||||||
useCreateAgencyMasterPostMutation,
|
|
||||||
useGetAgencyMasterQuery,
|
|
||||||
useAgencyMasterToggleMutation,
|
|
||||||
useUpdateAgencyMasterMutation,
|
|
||||||
} = agencyMasterModule;
|
|
||||||
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
|
||||||
|
|
||||||
export interface CountryData {
|
|
||||||
id: number;
|
|
||||||
en_name: string;
|
|
||||||
hi_name: string;
|
|
||||||
mr_name: string;
|
|
||||||
te_name: string;
|
|
||||||
ta_name: string;
|
|
||||||
bn_name: string;
|
|
||||||
or_name: string;
|
|
||||||
country_code: string;
|
|
||||||
phonecode: string;
|
|
||||||
capital: string;
|
|
||||||
currency: string;
|
|
||||||
currency_name: string;
|
|
||||||
currency_symbol: string;
|
|
||||||
is_active: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ApiResponse {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: {
|
|
||||||
current_page: number,
|
|
||||||
last_page: number,
|
|
||||||
total: number,
|
|
||||||
from: number,
|
|
||||||
per_page: number,
|
|
||||||
to: number,
|
|
||||||
data: CountryData[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CountryEdit {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: CountryData[];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export type PostCountry = {
|
|
||||||
en_name: string;
|
|
||||||
country_code: string;
|
|
||||||
phonecode: string;
|
|
||||||
capital: string;
|
|
||||||
currency: string;
|
|
||||||
currency_name: string;
|
|
||||||
currency_symbol: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export const countryMaster = createApi({
|
|
||||||
reducerPath: "countryMaster",
|
|
||||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
|
||||||
endpoints: (builder) => ({
|
|
||||||
createCountryPost: builder.mutation<PostCountry, Partial<PostCountry>>({
|
|
||||||
query: (data) => ({
|
|
||||||
url: "/country-add",
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
// 🔹 GET: Fetch all posts
|
|
||||||
// getCountryMaster: builder.query<ApiResponse, number>({
|
|
||||||
// query: (page = 1) => `/country-list?page=${page}`,
|
|
||||||
// }),
|
|
||||||
|
|
||||||
getCountryMaster: builder.query<ApiResponse, { page?: number; search?: string }>({
|
|
||||||
query: ({ page, search }) => {
|
|
||||||
const params = new URLSearchParams();
|
|
||||||
if (page) params.append("page", page.toString());
|
|
||||||
if (search) params.append("search", search);
|
|
||||||
|
|
||||||
return `/country-list?${params.toString()}`;
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
getCountryMasterEdit: builder.query<CountryEdit, number>({
|
|
||||||
query: (id) => `/country-edit/${id}`,
|
|
||||||
}),
|
|
||||||
|
|
||||||
updateCountry: builder.mutation({
|
|
||||||
query: (updatedData) => ({
|
|
||||||
url: "/country-update",
|
|
||||||
method: "POST",
|
|
||||||
body: updatedData,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
countryToggle: builder.mutation({
|
|
||||||
query: ({ id, is_active }) => ({
|
|
||||||
url: `/country-status`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id, is_active },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
// deleteFaqPost: builder.mutation<{ status: string; message: string }, { id: number }>({
|
|
||||||
// query: ({ id }) => ({
|
|
||||||
// url: `/faq-delete`,
|
|
||||||
// method: "POST",
|
|
||||||
// body: { id },
|
|
||||||
// }),
|
|
||||||
// }),
|
|
||||||
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const {
|
|
||||||
useGetCountryMasterQuery,
|
|
||||||
useGetCountryMasterEditQuery,
|
|
||||||
useCreateCountryPostMutation,
|
|
||||||
useUpdateCountryMutation,
|
|
||||||
useCountryToggleMutation,
|
|
||||||
// useDeleteFaqPostMutation
|
|
||||||
} = countryMaster;
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
|
||||||
|
|
||||||
export type TotalUser = {
|
|
||||||
data: {
|
|
||||||
totalRecruiterCount: number;
|
|
||||||
totalCustomerCount: string;
|
|
||||||
totalUserCount: string;
|
|
||||||
recruitersByMonth: Record<string, number>;
|
|
||||||
customersByMonth: Record<string, number>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PastUser = {
|
|
||||||
data: {
|
|
||||||
past24hourRecruiterCount: number;
|
|
||||||
past24hourCustomercount: number;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type NewUser = {
|
|
||||||
data: {
|
|
||||||
newRecuiterCount: number;
|
|
||||||
newCustomerCount: number;
|
|
||||||
newTotalUserCount: number;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AgencyList = {
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
created_at: string;
|
|
||||||
is_active: boolean
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type FaqList = {
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
id: number;
|
|
||||||
faqs_xid: number;
|
|
||||||
language_master_xid: number;
|
|
||||||
question: string;
|
|
||||||
answer: string;
|
|
||||||
is_active: boolean
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export const dashBoard = createApi({
|
|
||||||
reducerPath: "dashBoard",
|
|
||||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
|
||||||
endpoints: (builder) => ({
|
|
||||||
|
|
||||||
getTotalUser: builder.query<TotalUser, void>({ query: () => "/dashboard-total-user" }),
|
|
||||||
getPastUser: builder.query<PastUser, void>({ query: () => "/dashboard-past-user" }),
|
|
||||||
getNewUser: builder.query<NewUser, void>({ query: () => "/dashboard-new-user" }),
|
|
||||||
getAgencyList: builder.query<AgencyList, void>({ query: () => "/dashboard-agency-list" }),
|
|
||||||
getFaqList: builder.query<FaqList, void>({ query: () => "/dashboard-faq-list" }),
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const {
|
|
||||||
useGetTotalUserQuery,
|
|
||||||
useGetPastUserQuery,
|
|
||||||
useGetNewUserQuery,
|
|
||||||
useGetAgencyListQuery,
|
|
||||||
useGetFaqListQuery,
|
|
||||||
} = dashBoard;
|
|
||||||
@@ -1,30 +1,26 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react"; // add /react for auto-generated hooks
|
import { createApi } from "@reduxjs/toolkit/query";
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
import { baseQueryWithReauth } from "./apiSlice";
|
||||||
|
|
||||||
interface DeactivatedData {
|
|
||||||
id: number;
|
|
||||||
email: string;
|
|
||||||
first_name: string;
|
|
||||||
created_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ApiResponse {
|
|
||||||
data: {
|
|
||||||
data: DeactivatedData[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const deactivatedAccounts = createApi({
|
export const deactivatedAccounts = createApi({
|
||||||
reducerPath: "deactivatedAccounts",
|
reducerPath: "deactivatedAccounts",
|
||||||
baseQuery: baseQueryWithReauth,
|
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
||||||
tagTypes: ["Deactivated"],
|
endpoints: (builder) => ({
|
||||||
endpoints: (builder) => ({
|
|
||||||
getContact: builder.query<ApiResponse, void>({
|
|
||||||
query: () => "/manage-user-deactivate-list",
|
|
||||||
providesTags: ["Deactivated"],
|
getPosts: builder.query<Post[], void>({ query: () => "/posts" }),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}),
|
}),
|
||||||
}),
|
});
|
||||||
});
|
|
||||||
|
export const { } = deactivatedAccounts;
|
||||||
// ✅ Export the auto-generated hook
|
|
||||||
export const { useGetContactQuery } = deactivatedAccounts;
|
export type Post = {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
body: string;
|
||||||
|
};
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
|
||||||
|
|
||||||
export interface DepartmentData {
|
|
||||||
id: number;
|
|
||||||
industry_masters_xid: number;
|
|
||||||
en_name: string;
|
|
||||||
hi_name: string;
|
|
||||||
mr_name: string;
|
|
||||||
te_name: string;
|
|
||||||
ta_name: string;
|
|
||||||
bn_name: string;
|
|
||||||
or_name: string;
|
|
||||||
is_active: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ApiResponse {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: {
|
|
||||||
current_page: number,
|
|
||||||
last_page: number,
|
|
||||||
total: number,
|
|
||||||
from: number,
|
|
||||||
per_page: number,
|
|
||||||
to: number,
|
|
||||||
data: DepartmentData[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CountryEdit {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: DepartmentData[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DropDown{
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: {
|
|
||||||
id: number;
|
|
||||||
en_name: string;
|
|
||||||
}[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export type PostDepartment = {
|
|
||||||
en_name: string;
|
|
||||||
industry_masters_xid: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export const departmentMaster = createApi({
|
|
||||||
reducerPath: "departmentMaster",
|
|
||||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
|
||||||
endpoints: (builder) => ({
|
|
||||||
createDepartmentPost: builder.mutation<PostDepartment, Partial<PostDepartment>>({
|
|
||||||
query: (data) => ({
|
|
||||||
url: "/department-master-store",
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
// 🔹 GET: Fetch all posts
|
|
||||||
// getDepartmentMaster: builder.query<ApiResponse, number>({
|
|
||||||
// query: (page = 1) => `/department-master-list?page=${page}`,
|
|
||||||
// }),
|
|
||||||
|
|
||||||
getDepartmentMaster: builder.query<ApiResponse, { page?: number; search?: string }>({
|
|
||||||
query: ({ page, search }) => {
|
|
||||||
const params = new URLSearchParams();
|
|
||||||
if (page) params.append("page", page.toString());
|
|
||||||
if (search) params.append("search", search);
|
|
||||||
|
|
||||||
return `/department-master-list?${params.toString()}`;
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
getDepartmentMasterDropDown: builder.query<DropDown, void>({
|
|
||||||
query: () => `/industry-master-get-category`,
|
|
||||||
}),
|
|
||||||
|
|
||||||
updateDepartment: builder.mutation({
|
|
||||||
query: (updatedData) => ({
|
|
||||||
url: "/department-master-update",
|
|
||||||
method: "POST",
|
|
||||||
body: updatedData,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
departmentToggle: builder.mutation({
|
|
||||||
query: ({ id, is_active }) => ({
|
|
||||||
url: `/department-master-status`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id, is_active },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
// deleteFaqPost: builder.mutation<{ status: string; message: string }, { id: number }>({
|
|
||||||
// query: ({ id }) => ({
|
|
||||||
// url: `/faq-delete`,
|
|
||||||
// method: "POST",
|
|
||||||
// body: { id },
|
|
||||||
// }),
|
|
||||||
// }),
|
|
||||||
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const {
|
|
||||||
useGetDepartmentMasterQuery,
|
|
||||||
useGetDepartmentMasterDropDownQuery,
|
|
||||||
useCreateDepartmentPostMutation,
|
|
||||||
useUpdateDepartmentMutation,
|
|
||||||
useDepartmentToggleMutation,
|
|
||||||
// useDeleteFaqPostMutation
|
|
||||||
} = departmentMaster;
|
|
||||||
@@ -1,91 +1,26 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
import { createApi } from "@reduxjs/toolkit/query";
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
import { baseQueryWithReauth } from "./apiSlice";
|
||||||
|
|
||||||
export interface FaqData {
|
|
||||||
id: number;
|
|
||||||
principal_type_xid: number;
|
|
||||||
is_active: number;
|
|
||||||
translations:{
|
|
||||||
id: string,
|
|
||||||
faqs_xid: number,
|
|
||||||
language_master_xid: number,
|
|
||||||
question: string,
|
|
||||||
answer: string,
|
|
||||||
}[]
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ApiResponse {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: {
|
|
||||||
current_page: number,
|
|
||||||
last_page: number,
|
|
||||||
total: number,
|
|
||||||
from: number,
|
|
||||||
per_page: number,
|
|
||||||
to: number,
|
|
||||||
data: FaqData[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export type Post = {
|
|
||||||
principal_type_xid: number;
|
|
||||||
language_code: string;
|
|
||||||
question: string;
|
|
||||||
answer: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export const faqs = createApi({
|
export const faqs = createApi({
|
||||||
reducerPath: "faqs",
|
reducerPath: "faqs",
|
||||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
||||||
endpoints: (builder) => ({
|
endpoints: (builder) => ({
|
||||||
createFaqPost: builder.mutation<Post, Partial<Post>>({
|
|
||||||
query: (data) => ({
|
|
||||||
url: "/faq-store",
|
|
||||||
method: "POST",
|
getPosts: builder.query<Post[], void>({ query: () => "/posts" }),
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}),
|
}),
|
||||||
// 🔹 GET: Fetch all posts
|
});
|
||||||
getFaq: builder.query<ApiResponse, number>({
|
|
||||||
query: (page = 1) => `/faq-list?page=${page}`,
|
export const { } = faqs;
|
||||||
}),
|
|
||||||
|
export type Post = {
|
||||||
updateFaq: builder.mutation({
|
id: number;
|
||||||
query: (updatedData) => ({
|
title: string;
|
||||||
url: "/faq-update",
|
body: string;
|
||||||
method: "POST",
|
};
|
||||||
body: updatedData,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
faqToggle: builder.mutation({
|
|
||||||
query: ({ id, is_active }) => ({
|
|
||||||
url: `/faq-status`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id, is_active },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
|
|
||||||
deleteFaqPost: builder.mutation<{ status: string; message: string }, { id: number }>({
|
|
||||||
query: ({ id }) => ({
|
|
||||||
url: `/faq-delete`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const {
|
|
||||||
useGetFaqQuery,
|
|
||||||
useCreateFaqPostMutation,
|
|
||||||
useUpdateFaqMutation,
|
|
||||||
useFaqToggleMutation,
|
|
||||||
useDeleteFaqPostMutation
|
|
||||||
} = faqs;
|
|
||||||
36
src/Redux/Service/forget.password.service.ts
Normal file
36
src/Redux/Service/forget.password.service.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { createApi } from "@reduxjs/toolkit/query/react";
|
||||||
|
import { baseQueryWithReauth } from "./apiSlice";
|
||||||
|
|
||||||
|
export const forgetPassword = createApi({
|
||||||
|
reducerPath: "aboutUs",
|
||||||
|
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
||||||
|
endpoints: (builder) => ({
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 🔹 GET: Fetch all posts
|
||||||
|
getAboutUs: builder.query<AboutUs[], void>({
|
||||||
|
query: () => "/send-otp",
|
||||||
|
}),
|
||||||
|
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const {
|
||||||
|
useGetAboutUsQuery,
|
||||||
|
} = forgetPassword;
|
||||||
|
|
||||||
|
// Define Post type
|
||||||
|
export type Post = {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
body: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type AboutUs = {
|
||||||
|
id: number;
|
||||||
|
language_master_xid: number;
|
||||||
|
content: string;
|
||||||
|
is_active: boolean;
|
||||||
|
};
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
|
||||||
|
|
||||||
interface IndustryMasterResponse {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: PaginationData;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PaginationData {
|
|
||||||
current_page: number;
|
|
||||||
data: IndustryMaster[];
|
|
||||||
first_page_url: string;
|
|
||||||
from: number;
|
|
||||||
last_page: number;
|
|
||||||
last_page_url: string;
|
|
||||||
links: PaginationLink[];
|
|
||||||
next_page_url: string | null;
|
|
||||||
path: string;
|
|
||||||
per_page: number;
|
|
||||||
prev_page_url: string | null;
|
|
||||||
to: number;
|
|
||||||
total: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IndustryMaster {
|
|
||||||
id: number;
|
|
||||||
categories_masters_xid: number,
|
|
||||||
is_active: boolean;
|
|
||||||
en_name: string;
|
|
||||||
hi_name: string;
|
|
||||||
mr_name: string,
|
|
||||||
te_name: string,
|
|
||||||
ta_name: string,
|
|
||||||
bn_name: string,
|
|
||||||
or_name: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
interface PaginationLink {
|
|
||||||
url: string | null;
|
|
||||||
label: string;
|
|
||||||
active: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Post {
|
|
||||||
en_name: string,
|
|
||||||
categories_masters_xid: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export const industryMaster = createApi({
|
|
||||||
reducerPath: "industryMaster",
|
|
||||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
|
||||||
endpoints: (builder) => ({
|
|
||||||
createIndustryMasterPost: builder.mutation<Post, Partial<Post>>({
|
|
||||||
query: (data) => ({
|
|
||||||
url: "/industry-master-store",
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
// 🔹 GET: Fetch all posts
|
|
||||||
// getIndustryMaster: builder.query<IndustryMasterResponse, number>({
|
|
||||||
// query: (page = 1) => `/industry-master-list?page=${page}`,
|
|
||||||
// }),
|
|
||||||
|
|
||||||
getIndustryMaster: builder.query<IndustryMasterResponse, { page?: number; search?: string }>({
|
|
||||||
query: ({ page, search }) => {
|
|
||||||
const params = new URLSearchParams();
|
|
||||||
if (page) params.append("page", page.toString());
|
|
||||||
if (search) params.append("search", search);
|
|
||||||
|
|
||||||
return `/industry-master-list?${params.toString()}`;
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
updateIndustryMaster: builder.mutation({
|
|
||||||
query: (updatedData) => ({
|
|
||||||
url: "industry-master-update",
|
|
||||||
method: "POST",
|
|
||||||
body: updatedData,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
industryMasterToggle: builder.mutation({
|
|
||||||
query: ({ id, is_active }) => ({
|
|
||||||
url: `/industry-master-status`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id, is_active },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const {
|
|
||||||
useGetIndustryMasterQuery,
|
|
||||||
useCreateIndustryMasterPostMutation,
|
|
||||||
useUpdateIndustryMasterMutation,
|
|
||||||
useIndustryMasterToggleMutation,
|
|
||||||
} = industryMaster;
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
|
||||||
|
|
||||||
export interface JobStatusData {
|
|
||||||
id: number;
|
|
||||||
is_active: string;
|
|
||||||
job_status_translation:{
|
|
||||||
job_status_xid: number,
|
|
||||||
title:string,
|
|
||||||
language_xid:number
|
|
||||||
}[],
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ApiResponse {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: {
|
|
||||||
current_page: number,
|
|
||||||
last_page: number,
|
|
||||||
total: number,
|
|
||||||
from: number,
|
|
||||||
per_page: number,
|
|
||||||
to: number,
|
|
||||||
data: JobStatusData[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CountryEdit {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: JobStatusData[];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export type PostJobStatus = {
|
|
||||||
title: string
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export const jobStatus = createApi({
|
|
||||||
reducerPath: "jobStatus",
|
|
||||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
|
||||||
endpoints: (builder) => ({
|
|
||||||
createJobStatusPost: builder.mutation<PostJobStatus, Partial<PostJobStatus>>({
|
|
||||||
query: (data) => ({
|
|
||||||
url: "/job-status-store",
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
// 🔹 GET: Fetch all posts
|
|
||||||
// getJobStatus: builder.query<ApiResponse, number>({
|
|
||||||
// query: (page = 1) => `/job-status-list?page=${page}`,
|
|
||||||
// }),
|
|
||||||
|
|
||||||
getJobStatus: builder.query<ApiResponse, { page?: number; search?: string }>({
|
|
||||||
query: ({ page, search }) => {
|
|
||||||
const params = new URLSearchParams();
|
|
||||||
if (page) params.append("page", page.toString());
|
|
||||||
if (search) params.append("search", search);
|
|
||||||
|
|
||||||
return `/job-status-list?${params.toString()}`;
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
updateJobStatus: builder.mutation({
|
|
||||||
query: (updatedData) => ({
|
|
||||||
url: "/job-status-update",
|
|
||||||
method: "POST",
|
|
||||||
body: updatedData,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
jobStatusToggle: builder.mutation({
|
|
||||||
query: ({ id, is_active }) => ({
|
|
||||||
url: `/job-status-status`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id, is_active },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
// deleteFaqPost: builder.mutation<{ status: string; message: string }, { id: number }>({
|
|
||||||
// query: ({ id }) => ({
|
|
||||||
// url: `/faq-delete`,
|
|
||||||
// method: "POST",
|
|
||||||
// body: { id },
|
|
||||||
// }),
|
|
||||||
// }),
|
|
||||||
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const {
|
|
||||||
useGetJobStatusQuery,
|
|
||||||
useCreateJobStatusPostMutation,
|
|
||||||
useUpdateJobStatusMutation,
|
|
||||||
useJobStatusToggleMutation,
|
|
||||||
// useDeleteFaqPostMutation
|
|
||||||
} = jobStatus;
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
|
||||||
|
|
||||||
interface JobTypeResponse {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: PaginationData;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PaginationData {
|
|
||||||
current_page: number;
|
|
||||||
data: JobTypeData[];
|
|
||||||
first_page_url: string;
|
|
||||||
from: number;
|
|
||||||
last_page: number;
|
|
||||||
last_page_url: string;
|
|
||||||
links: PaginationLink[];
|
|
||||||
next_page_url: string | null;
|
|
||||||
path: string;
|
|
||||||
per_page: number;
|
|
||||||
prev_page_url: string | null;
|
|
||||||
to: number;
|
|
||||||
total: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface JobTypeData {
|
|
||||||
id: number;
|
|
||||||
is_active: boolean;
|
|
||||||
en_name: string;
|
|
||||||
hi_name: string;
|
|
||||||
mr_name:string,
|
|
||||||
te_name:string,
|
|
||||||
ta_name:string,
|
|
||||||
bn_name:string,
|
|
||||||
or_name:string,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
interface PaginationLink {
|
|
||||||
url: string | null;
|
|
||||||
label: string;
|
|
||||||
active: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Post {
|
|
||||||
en_name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const jobType = createApi({
|
|
||||||
reducerPath: "jobType",
|
|
||||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
|
||||||
endpoints: (builder) => ({
|
|
||||||
createJobTypePost: builder.mutation<Post, Partial<Post>>({
|
|
||||||
query: (data) => ({
|
|
||||||
url: "/job-type-add",
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
// 🔹 GET: Fetch all posts
|
|
||||||
getJobType: builder.query<JobTypeResponse, number>({
|
|
||||||
query: (page = 1) => `/job-type?page=${page}`,
|
|
||||||
}),
|
|
||||||
|
|
||||||
updateJobType: builder.mutation({
|
|
||||||
query: (updatedData) => ({
|
|
||||||
url: "job-type-update",
|
|
||||||
method: "POST",
|
|
||||||
body: updatedData,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
jobTypeToggle: builder.mutation({
|
|
||||||
query: ({ id, is_active }) => ({
|
|
||||||
url: `/job-type-status`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id, is_active },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const {
|
|
||||||
useGetJobTypeQuery,
|
|
||||||
useCreateJobTypePostMutation,
|
|
||||||
useUpdateJobTypeMutation,
|
|
||||||
useJobTypeToggleMutation,
|
|
||||||
} = jobType;
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
import { createApi } from "@reduxjs/toolkit/query/react";
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
import { baseQueryWithReauth } from "./apiSlice";
|
||||||
import { AboutUsResponse } from "../../Types/aboutUsType";
|
|
||||||
export const aboutUs = createApi({
|
export const aboutUs = createApi({
|
||||||
reducerPath: "aboutUs",
|
reducerPath: "aboutUs",
|
||||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
||||||
@@ -14,6 +14,9 @@ export const aboutUs = createApi({
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 🔹 GET: Fetch a single post by ID
|
// 🔹 GET: Fetch a single post by ID
|
||||||
getPostById: builder.query<Post, number>({
|
getPostById: builder.query<Post, number>({
|
||||||
query: (id) => `/posts/${id}`,
|
query: (id) => `/posts/${id}`,
|
||||||
@@ -27,22 +30,16 @@ export const aboutUs = createApi({
|
|||||||
body: data,
|
body: data,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// 🔹 PUT: Update an existing post
|
// 🔹 PUT: Update an existing post
|
||||||
// updateAboutUs: builder.mutation<UpdateAboutUsResponse, UpdateAboutUsRequest>({
|
updateAboutUs: builder.mutation<UpdateAboutUsResponse, UpdateAboutUsRequest>({
|
||||||
// query: ({ id, updatedData }) => ({
|
query: ({ id, updatedData }) => ({
|
||||||
// url: `/posts/${id}`,
|
url: `/posts/${id}`,
|
||||||
// method: "POST",
|
method: "POST",
|
||||||
// body: updatedData,
|
body: updatedData,
|
||||||
// }),
|
|
||||||
// }),
|
|
||||||
// 🔹 PUT: Update an About Us entry
|
|
||||||
updateAboutUs: builder.mutation({
|
|
||||||
query: (updatedData) => ({
|
|
||||||
url: "/about-us/update", // ✅ Updated URL
|
|
||||||
method: "POST",
|
|
||||||
body: updatedData,
|
|
||||||
}),
|
|
||||||
}),
|
}),
|
||||||
|
}),
|
||||||
|
|
||||||
// 🔹 DELETE: Remove a post by ID
|
// 🔹 DELETE: Remove a post by ID
|
||||||
deletePost: builder.mutation<{ success: boolean }, number>({
|
deletePost: builder.mutation<{ success: boolean }, number>({
|
||||||
query: (id) => ({
|
query: (id) => ({
|
||||||
@@ -56,6 +53,17 @@ export const aboutUs = createApi({
|
|||||||
export const {
|
export const {
|
||||||
useGetAboutUsQuery,
|
useGetAboutUsQuery,
|
||||||
useUpdateAboutUsMutation,
|
useUpdateAboutUsMutation,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useGetPostByIdQuery,
|
useGetPostByIdQuery,
|
||||||
useCreatePostMutation,
|
useCreatePostMutation,
|
||||||
useDeletePostMutation
|
useDeletePostMutation
|
||||||
@@ -70,12 +78,12 @@ export type Post = {
|
|||||||
|
|
||||||
|
|
||||||
export type UpdateAboutUsRequest={
|
export type UpdateAboutUsRequest={
|
||||||
id: number; updatedData: string,language_code:string
|
id: number; updatedData: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export type UpdateAboutUsResponse={
|
export type UpdateAboutUsResponse={
|
||||||
id: number; updatedData: string,language_code:string
|
id: number; updatedData: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -86,3 +94,10 @@ export type AboutUs = {
|
|||||||
is_active: boolean;
|
is_active: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// First define your interface
|
||||||
|
interface AboutUsResponse {
|
||||||
|
data: {
|
||||||
|
content: string;
|
||||||
|
// other fields...
|
||||||
|
}[];
|
||||||
|
}
|
||||||
@@ -1,45 +1,26 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
import { createApi } from "@reduxjs/toolkit/query";
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
import { baseQueryWithReauth } from "./apiSlice";
|
||||||
|
|
||||||
interface ContactData {
|
|
||||||
id: number;
|
|
||||||
email: string;
|
|
||||||
first_name: string;
|
|
||||||
created_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ApiResponse {
|
|
||||||
data: {
|
|
||||||
data: ContactData[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const manageContactUs = createApi({
|
export const manageContactUs = createApi({
|
||||||
reducerPath: "manageContactUs",
|
reducerPath: "manageContactUs",
|
||||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
||||||
tagTypes: ["Contact"],
|
endpoints: (builder) => ({
|
||||||
endpoints: (builder) => ({
|
|
||||||
|
|
||||||
|
|
||||||
getContact: builder.query<ApiResponse, { page?: number; search?: string }>({
|
getPosts: builder.query<Post[], void>({ query: () => "/posts" }),
|
||||||
query: ({ page, search }) => {
|
|
||||||
const params = new URLSearchParams();
|
|
||||||
if (page) params.append("page", page.toString());
|
|
||||||
if (search) params.append("search", search);
|
|
||||||
return `/contact-us?${params.toString()}`;
|
|
||||||
},
|
|
||||||
providesTags: ["Contact"],
|
|
||||||
}),
|
}),
|
||||||
|
});
|
||||||
pendingRequest: builder.mutation({
|
|
||||||
query: (body) => ({
|
export const { } = manageContactUs;
|
||||||
url: `/contact-us-response`,
|
|
||||||
method: "POST",
|
export type Post = {
|
||||||
body,
|
id: number;
|
||||||
}),
|
title: string;
|
||||||
invalidatesTags: ["Contact"],
|
body: string;
|
||||||
}),
|
};
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const { useGetContactQuery, usePendingRequestMutation } = manageContactUs;
|
|
||||||
@@ -1,147 +1,26 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
import { createApi } from "@reduxjs/toolkit/query";
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
import { baseQueryWithReauth } from "./apiSlice";
|
||||||
|
|
||||||
export interface JobStatusData {
|
|
||||||
id: number;
|
|
||||||
job_title: string;
|
|
||||||
workspace_mode_xid: number;
|
|
||||||
industry_xid: number;
|
|
||||||
department_xid: number;
|
|
||||||
company_name: string;
|
|
||||||
ctc_currency_symbol: string;
|
|
||||||
ctc_amount: string;
|
|
||||||
experience: string;
|
|
||||||
job_location: string;
|
|
||||||
country_xid: number;
|
|
||||||
job_type_xid: number;
|
|
||||||
skill_description: string;
|
|
||||||
job_description: string;
|
|
||||||
job_image: string | null;
|
|
||||||
industry: {
|
|
||||||
id: number;
|
|
||||||
en_name: string;
|
|
||||||
};
|
|
||||||
department: {
|
|
||||||
id: number;
|
|
||||||
en_name: string;
|
|
||||||
};
|
|
||||||
workspace: {
|
|
||||||
id: number;
|
|
||||||
en_name: string;
|
|
||||||
};
|
|
||||||
country: {
|
|
||||||
id: number;
|
|
||||||
en_name: string;
|
|
||||||
};
|
|
||||||
job_type: {
|
|
||||||
id: number;
|
|
||||||
en_name: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ApiResponse {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: {
|
|
||||||
current_page: number,
|
|
||||||
last_page: number,
|
|
||||||
total: number,
|
|
||||||
from: number,
|
|
||||||
per_page: number,
|
|
||||||
to: number,
|
|
||||||
data: JobStatusData[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CountryEdit {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: JobStatusData[];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export type PostJobStatus = {
|
|
||||||
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>({
|
|
||||||
// query: (page = 1) => `/manage-jobs-list?page=${page}`,
|
|
||||||
// }),
|
getPosts: builder.query<Post[], void>({ query: () => "/posts" }),
|
||||||
|
|
||||||
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) => ({
|
export const { } = manageJobs;
|
||||||
url: "/manage-jobs-update",
|
|
||||||
method: "POST",
|
export type Post = {
|
||||||
body: updatedData,
|
id: number;
|
||||||
}),
|
title: string;
|
||||||
}),
|
body: string;
|
||||||
|
};
|
||||||
viewJobs: builder.query<ApiResponse, number>({
|
|
||||||
query: () => `/manage-jobs-list`,
|
|
||||||
}),
|
|
||||||
|
|
||||||
deleteJobsPost: builder.mutation<{ status: string; message: string }, { id: number }>({
|
|
||||||
query: ({ id }) => ({
|
|
||||||
url: `/manage-jobs-delete`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
useUpdateJobsMutation,
|
|
||||||
useGetWorkspaceModesQuery,
|
|
||||||
useGetIndustryQuery,
|
|
||||||
useGetDepartmentQuery,
|
|
||||||
useGetCountryQuery,
|
|
||||||
useGetManageJobTypeQuery
|
|
||||||
} = manageJobs;
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
|
||||||
|
|
||||||
export interface JobStatusData {
|
|
||||||
id: number;
|
|
||||||
is_active: string;
|
|
||||||
created_at:string,
|
|
||||||
job_status_translation:{
|
|
||||||
job_status_xid: number,
|
|
||||||
title:string,
|
|
||||||
language_xid:number
|
|
||||||
}[],
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ApiResponse {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: {
|
|
||||||
current_page: number,
|
|
||||||
last_page: number,
|
|
||||||
total: number,
|
|
||||||
from: number,
|
|
||||||
per_page: number,
|
|
||||||
to: number,
|
|
||||||
data: JobStatusData[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CountryEdit {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: JobStatusData[];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export type PostJobStatus = {
|
|
||||||
title: string
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export const managePosts = createApi({
|
|
||||||
reducerPath: "managePosts",
|
|
||||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
|
||||||
endpoints: (builder) => ({
|
|
||||||
// createJobStatusPost: builder.mutation<PostJobStatus, Partial<PostJobStatus>>({
|
|
||||||
// query: (data) => ({
|
|
||||||
// url: "/job-status-store",
|
|
||||||
// method: "POST",
|
|
||||||
// body: data,
|
|
||||||
// }),
|
|
||||||
// }),
|
|
||||||
// 🔹 GET: Fetch all posts
|
|
||||||
getManagePosts: builder.query<ApiResponse, number>({
|
|
||||||
query: (page = 1) => `/manage-post-list?page=${page}`,
|
|
||||||
}),
|
|
||||||
|
|
||||||
postStatusToggle: builder.mutation({
|
|
||||||
query: ({ id, is_active }) => ({
|
|
||||||
url: `/manage-post-status`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id, is_active },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
// deleteFaqPost: builder.mutation<{ status: string; message: string }, { id: number }>({
|
|
||||||
// query: ({ id }) => ({
|
|
||||||
// url: `/faq-delete`,
|
|
||||||
// method: "POST",
|
|
||||||
// body: { id },
|
|
||||||
// }),
|
|
||||||
// }),
|
|
||||||
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const {
|
|
||||||
useGetManagePostsQuery,
|
|
||||||
usePostStatusToggleMutation,
|
|
||||||
// useDeleteFaqPostMutation
|
|
||||||
} = managePosts;
|
|
||||||
26
src/Redux/Service/manage.posts.service.ts
Normal file
26
src/Redux/Service/manage.posts.service.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { createApi } from "@reduxjs/toolkit/query";
|
||||||
|
import { baseQueryWithReauth } from "./apiSlice";
|
||||||
|
|
||||||
|
export const managePosts = createApi({
|
||||||
|
reducerPath: "managePosts",
|
||||||
|
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
||||||
|
endpoints: (builder) => ({
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
getPosts: builder.query<Post[], void>({ query: () => "/posts" }),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { } = managePosts;
|
||||||
|
|
||||||
|
export type Post = {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
body: string;
|
||||||
|
};
|
||||||
@@ -1,205 +1,26 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
import { createApi } from "@reduxjs/toolkit/query";
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
import { baseQueryWithReauth } from "./apiSlice";
|
||||||
|
|
||||||
interface PaginationLink {
|
|
||||||
url: string | null;
|
|
||||||
label: string;
|
|
||||||
active: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface UserData {
|
|
||||||
id: number;
|
|
||||||
unique_id: string;
|
|
||||||
user_name: string;
|
|
||||||
first_name: string;
|
|
||||||
last_name: string;
|
|
||||||
date_of_birth: string;
|
|
||||||
gender: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PaginatedData {
|
|
||||||
current_page: number;
|
|
||||||
data: UserData[];
|
|
||||||
first_page_url: string;
|
|
||||||
from: number;
|
|
||||||
last_page: number;
|
|
||||||
last_page_url: string;
|
|
||||||
links: PaginationLink[];
|
|
||||||
next_page_url: string | null;
|
|
||||||
path: string;
|
|
||||||
per_page: number;
|
|
||||||
prev_page_url: string | null;
|
|
||||||
to: number;
|
|
||||||
total: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ApiResponse {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
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 = {
|
|
||||||
// id: number;
|
|
||||||
// first_name: string,
|
|
||||||
// last_name: string,
|
|
||||||
// unique_id: string,
|
|
||||||
// date_of_birth: string,
|
|
||||||
// gender: string,
|
|
||||||
// }
|
|
||||||
|
|
||||||
interface ResourceActionLink {
|
|
||||||
id: number;
|
|
||||||
principal_xid: number;
|
|
||||||
role_xid: number;
|
|
||||||
app_resource_xid: number;
|
|
||||||
is_active: boolean;
|
|
||||||
created_by: number | null;
|
|
||||||
modified_by: number | null;
|
|
||||||
deleted_at: string | null;
|
|
||||||
created_at: string;
|
|
||||||
updated_at: string;
|
|
||||||
app_resource: {
|
|
||||||
id: number;
|
|
||||||
app_resource_title: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SubAdmin {
|
|
||||||
id: number;
|
|
||||||
first_name: string;
|
|
||||||
last_name: string;
|
|
||||||
unique_id: string;
|
|
||||||
date_of_birth: string;
|
|
||||||
gender: string;
|
|
||||||
get_resource_action_link: ResourceActionLink[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SubAdminView {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: SubAdmin[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CreateSubAdminPayload {
|
|
||||||
// user_name: string;
|
|
||||||
first_name: string;
|
|
||||||
last_name: string;
|
|
||||||
date_of_birth: string;
|
|
||||||
gender: string;
|
|
||||||
email_address: string;
|
|
||||||
phone_number: string;
|
|
||||||
// created_by: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CreateSubAdminResponse {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: UserData;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const manageSubAdmin = createApi({
|
export const manageSubAdmin = createApi({
|
||||||
reducerPath: "manageSubAdmin",
|
reducerPath: "manageSubAdmin",
|
||||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
||||||
tagTypes: ["SubAdmin"],
|
endpoints: (builder) => ({
|
||||||
endpoints: (builder) => ({
|
|
||||||
|
|
||||||
createFaqPost: builder.mutation<Post, Partial<Post>>({
|
|
||||||
query: (data) => ({
|
getPosts: builder.query<Post[], void>({ query: () => "/posts" }),
|
||||||
url: "/faq-store",
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
|
|
||||||
}),
|
}),
|
||||||
|
});
|
||||||
getSubAdmin: builder.query<ApiResponse, { page?: number; search?: string }>({
|
|
||||||
query: ({ page, search }) => {
|
export const { } = manageSubAdmin;
|
||||||
const params = new URLSearchParams();
|
|
||||||
if (page) params.append("page", page.toString());
|
export type Post = {
|
||||||
if (search) params.append("search", search);
|
id: number;
|
||||||
return `/sub-admin?${params.toString()}`
|
title: string;
|
||||||
}
|
body: string;
|
||||||
}),
|
};
|
||||||
|
|
||||||
getPermission: builder.query<PermissionResponse, void>({
|
|
||||||
query: () => `/resources`,
|
|
||||||
}),
|
|
||||||
|
|
||||||
viewSubAdmin: builder.query<SubAdminView, number>({
|
|
||||||
query: (id) => `/sub-admin-view/${id}`,
|
|
||||||
}),
|
|
||||||
|
|
||||||
updateSubAdmin: builder.mutation({
|
|
||||||
query: (updatedData) => ({
|
|
||||||
url: "/sub-admin-update",
|
|
||||||
method: "POST",
|
|
||||||
body: updatedData,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
createSubAdminPost: builder.mutation<
|
|
||||||
CreateSubAdminResponse,
|
|
||||||
CreateSubAdminPayload
|
|
||||||
>({
|
|
||||||
query: (data) => ({
|
|
||||||
url: "/sub-admin-create",
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
invalidatesTags: ["SubAdmin"], // Add this to invalidate cache
|
|
||||||
}),
|
|
||||||
|
|
||||||
faqToggle: builder.mutation({
|
|
||||||
query: ({ id, is_active }) => ({
|
|
||||||
url: `/faq-status`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id, is_active },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
deleteSubAdminPost: builder.mutation<{ success: boolean }, number>({
|
|
||||||
query: (id) => ({
|
|
||||||
url: `/sub-admin-delete`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const {
|
|
||||||
useGetSubAdminQuery,
|
|
||||||
useGetPermissionQuery,
|
|
||||||
useLazyViewSubAdminQuery,
|
|
||||||
useUpdateSubAdminMutation,
|
|
||||||
useDeleteSubAdminPostMutation,
|
|
||||||
useCreateSubAdminPostMutation,
|
|
||||||
} = manageSubAdmin;
|
|
||||||
|
|
||||||
export type Post = {
|
|
||||||
id: number;
|
|
||||||
title: string;
|
|
||||||
body: string;
|
|
||||||
};
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
|
||||||
|
|
||||||
export interface UserData {
|
|
||||||
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;
|
|
||||||
language_xid: number;
|
|
||||||
iam_principal_xid: number;
|
|
||||||
language: {
|
|
||||||
id: number,
|
|
||||||
language_name: string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ApiResponse {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: {
|
|
||||||
current_page: number,
|
|
||||||
last_page: number,
|
|
||||||
total: number,
|
|
||||||
from: number,
|
|
||||||
per_page: number,
|
|
||||||
to: number,
|
|
||||||
data: UserData[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CountryEdit {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: UserData[];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export type PostCountry = {
|
|
||||||
en_name: string;
|
|
||||||
country_code: string;
|
|
||||||
phonecode: string;
|
|
||||||
capital: string;
|
|
||||||
currency: string;
|
|
||||||
currency_name: string;
|
|
||||||
currency_symbol: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export const registerUser = createApi({
|
|
||||||
reducerPath: "registerUser",
|
|
||||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
|
||||||
endpoints: (builder) => ({
|
|
||||||
createUser: builder.mutation<PostCountry, Partial<PostCountry>>({
|
|
||||||
query: (data) => ({
|
|
||||||
url: "/manage-user-store",
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
// 🔹 GET: Fetch all posts
|
|
||||||
getManageUser: builder.query<ApiResponse, number>({
|
|
||||||
query: (page = 1) => `/manage-user-list?page=${page}`,
|
|
||||||
}),
|
|
||||||
|
|
||||||
getDeactivateUser: builder.query<ApiResponse, number>({
|
|
||||||
query: (page = 1) => `/manage-user-deactivate-list?page=${page}`,
|
|
||||||
}),
|
|
||||||
|
|
||||||
updateUser: builder.mutation({
|
|
||||||
query: (updatedData) => ({
|
|
||||||
url: "/manage-user-update",
|
|
||||||
method: "POST",
|
|
||||||
body: updatedData,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
userToggle: builder.mutation({
|
|
||||||
query: ({ id, is_active }) => ({
|
|
||||||
url: `/manage-user-status`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id, is_active },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
userDeactivateToggle: builder.mutation({
|
|
||||||
query: ({ id, is_active }) => ({
|
|
||||||
url: `/manage-user-deactivate-status`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id, is_active },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
deleteUser: builder.mutation({
|
|
||||||
query: ({ id }) => ({
|
|
||||||
url: `/manage-user-delete`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const {
|
|
||||||
useGetManageUserQuery,
|
|
||||||
useCreateUserMutation,
|
|
||||||
useUpdateUserMutation,
|
|
||||||
useUserToggleMutation,
|
|
||||||
useGetDeactivateUserQuery,
|
|
||||||
useUserDeactivateToggleMutation,
|
|
||||||
useDeleteUserMutation
|
|
||||||
} = registerUser;
|
|
||||||
26
src/Redux/Service/master.module.service.ts
Normal file
26
src/Redux/Service/master.module.service.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { createApi } from "@reduxjs/toolkit/query";
|
||||||
|
import { baseQueryWithReauth } from "./apiSlice";
|
||||||
|
|
||||||
|
export const masterModule = createApi({
|
||||||
|
reducerPath: "masterModule",
|
||||||
|
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
||||||
|
endpoints: (builder) => ({
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
getPosts: builder.query<Post[], void>({ query: () => "/posts" }),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { } = masterModule;
|
||||||
|
|
||||||
|
export type Post = {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
body: string;
|
||||||
|
};
|
||||||
@@ -1,37 +1,26 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
import { createApi } from "@reduxjs/toolkit/query";
|
||||||
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: () => "/profile-image-edit" }),
|
getPosts: builder.query<Post[], void>({ query: () => "/posts" }),
|
||||||
|
|
||||||
updateImage: builder.mutation({
|
|
||||||
query: (formData: FormData) => {
|
|
||||||
const token = localStorage.getItem("token");
|
|
||||||
|
|
||||||
return {
|
}),
|
||||||
url: "/profile-image-edit",
|
});
|
||||||
method: "POST",
|
|
||||||
body: formData,
|
export const { } = myProfile;
|
||||||
headers: {
|
|
||||||
"access-token": `${token}`,
|
export type Post = {
|
||||||
},
|
id: number;
|
||||||
};
|
title: string;
|
||||||
},
|
body: string;
|
||||||
}),
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const {
|
|
||||||
useUpdateImageMutation,
|
|
||||||
} = myProfile;
|
|
||||||
@@ -9,16 +9,8 @@ export const privacyPolicy = createApi({
|
|||||||
getPrivacyPolicy: builder.query<PrivacyPolicyResponse, void>({ // Fix types here
|
getPrivacyPolicy: builder.query<PrivacyPolicyResponse, void>({ // Fix types here
|
||||||
query: () => "/privacy-policy",
|
query: () => "/privacy-policy",
|
||||||
}),
|
}),
|
||||||
|
|
||||||
updatePrivacyPolicy: builder.mutation({
|
|
||||||
query: (updatedData) => ({
|
|
||||||
url: "/privacy-policy/update", // ✅ Updated URL
|
|
||||||
method: "POST",
|
|
||||||
body: updatedData,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Export hook
|
// Export hook
|
||||||
export const { useGetPrivacyPolicyQuery, useUpdatePrivacyPolicyMutation } = privacyPolicy;
|
export const { useGetPrivacyPolicyQuery } = privacyPolicy;
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
|
||||||
|
|
||||||
interface profileGet {
|
|
||||||
data: {
|
|
||||||
id: number,
|
|
||||||
first_name: string,
|
|
||||||
last_name: string,
|
|
||||||
phone_number: string,
|
|
||||||
profile_photo: string,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export type ProfilePass = {
|
|
||||||
password: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export const profile = createApi({
|
|
||||||
reducerPath: "profile",
|
|
||||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
|
||||||
endpoints: (builder) => ({
|
|
||||||
profilePassword: builder.mutation<ProfilePass, Partial<ProfilePass>>({
|
|
||||||
query: (data) => ({
|
|
||||||
url: "/profile-password",
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
// 🔹 GET: Fetch all posts
|
|
||||||
getProfile: builder.query<profileGet, void>({
|
|
||||||
query: () => "/profile-view",
|
|
||||||
}),
|
|
||||||
|
|
||||||
verifyOTP: builder.mutation({
|
|
||||||
query: (updatedData) => ({
|
|
||||||
url: "/profile-otp",
|
|
||||||
method: "POST",
|
|
||||||
body: updatedData,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
newPasswordSet: builder.mutation({
|
|
||||||
query: (updatedData) => ({
|
|
||||||
url: "/profile-change-password",
|
|
||||||
method: "POST",
|
|
||||||
body: updatedData,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
resendOtp: builder.mutation({
|
|
||||||
query: ({ data }) => ({
|
|
||||||
url: `/profile-resend-otp`,
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const {
|
|
||||||
useGetProfileQuery,
|
|
||||||
useProfilePasswordMutation,
|
|
||||||
useVerifyOTPMutation,
|
|
||||||
useNewPasswordSetMutation,
|
|
||||||
useResendOtpMutation
|
|
||||||
} = profile;
|
|
||||||
26
src/Redux/Service/register.user.service.ts
Normal file
26
src/Redux/Service/register.user.service.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { createApi } from "@reduxjs/toolkit/query";
|
||||||
|
import { baseQueryWithReauth } from "./apiSlice";
|
||||||
|
|
||||||
|
export const registerUser = createApi({
|
||||||
|
reducerPath: "registerUser",
|
||||||
|
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
||||||
|
endpoints: (builder) => ({
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
getPosts: builder.query<Post[], void>({ query: () => "/posts" }),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { } = registerUser;
|
||||||
|
|
||||||
|
export type Post = {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
body: string;
|
||||||
|
};
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
|
||||||
import { baseQueryWithReauth } from "./apiSlice";
|
|
||||||
|
|
||||||
interface TemplateResponse {
|
|
||||||
status: string;
|
|
||||||
status_code: number;
|
|
||||||
message: string;
|
|
||||||
data: PaginationData;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PaginationData {
|
|
||||||
current_page: number;
|
|
||||||
data: Template[];
|
|
||||||
first_page_url: string;
|
|
||||||
from: number;
|
|
||||||
last_page: number;
|
|
||||||
last_page_url: string;
|
|
||||||
links: PaginationLink[];
|
|
||||||
next_page_url: string | null;
|
|
||||||
path: string;
|
|
||||||
per_page: number;
|
|
||||||
prev_page_url: string | null;
|
|
||||||
to: number;
|
|
||||||
total: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Template {
|
|
||||||
id: number;
|
|
||||||
is_active: boolean;
|
|
||||||
principle_type_xid: number;
|
|
||||||
post_template_translate: PostTemplateTranslate[];
|
|
||||||
post_template_image: PostTemplateImage[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PostTemplateTranslate {
|
|
||||||
id: number;
|
|
||||||
title: string;
|
|
||||||
sub_title: string;
|
|
||||||
post_template_xid: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PostTemplateImage {
|
|
||||||
id: number;
|
|
||||||
post_template_xid: number;
|
|
||||||
image_name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PaginationLink {
|
|
||||||
url: string | null;
|
|
||||||
label: string;
|
|
||||||
active: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Post {
|
|
||||||
id: number,
|
|
||||||
principle_type_xid: number,
|
|
||||||
title: string,
|
|
||||||
sub_title: string,
|
|
||||||
image_name: string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export const templateMaster = createApi({
|
|
||||||
reducerPath: "templateMaster",
|
|
||||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
|
||||||
endpoints: (builder) => ({
|
|
||||||
createTemplatePost: builder.mutation<Post, FormData>({
|
|
||||||
query: (data) => ({
|
|
||||||
url: "/template-store",
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
// 🔹 GET: Fetch all posts
|
|
||||||
getTemplateMaster: builder.query<TemplateResponse, number>({
|
|
||||||
query: (page = 1) => `/template-master?page=${page}`,
|
|
||||||
}),
|
|
||||||
|
|
||||||
updateTemplateMaster: builder.mutation<Post, FormData>({
|
|
||||||
query: (updatedData) => {
|
|
||||||
const token = localStorage.getItem("token");
|
|
||||||
return {
|
|
||||||
url: "/template-update",
|
|
||||||
method: "POST",
|
|
||||||
body: updatedData,
|
|
||||||
headers: {
|
|
||||||
'access-token': `${token}`,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
templateMasterToggle: builder.mutation({
|
|
||||||
query: ({ id, is_active }) => ({
|
|
||||||
url: `/template-status`,
|
|
||||||
method: "POST",
|
|
||||||
body: { id, is_active },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const {
|
|
||||||
useGetTemplateMasterQuery,
|
|
||||||
useCreateTemplatePostMutation,
|
|
||||||
useUpdateTemplateMasterMutation,
|
|
||||||
useTemplateMasterToggleMutation,
|
|
||||||
} = templateMaster;
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user