Bug fixes and API integration sub admin

This commit is contained in:
rockyeverlast
2025-07-09 16:56:06 +05:30
parent f2d101ef16
commit f65b5f9b2d
20 changed files with 1073 additions and 528 deletions

View File

@@ -3,15 +3,14 @@ import {
HStack,
Image,
// Image,
Input,
Text,
} from "@chakra-ui/react";
import { LuSearch } from "react-icons/lu";
// import { LuSearch } from "react-icons/lu";
// import { RiDeleteBin5Line } from "react-icons/ri";
// import AlertDailog from "../../components/AlertDailog";
import DataTable from "../../components/DataTable";
import MainFrame from "../../components/MainFrame";
import { InputGroup } from "../../components/ui/input-group";
// import { InputGroup } from "../../components/ui/input-group";
import ManageJobsAdd from "./ManageJobsAdd";
import ViewManageJob from "./ViewManageJob";
import {
@@ -23,6 +22,8 @@ import { Spinner } from "../../components/Sipnner/Spinner";
import Delete from "../../components/ActionIcons/Delete";
import { 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";
@@ -40,9 +41,12 @@ const tableHeadRow = [
];
const ManageJobs = () => {
const [currentPage] = useState(1);
const [currentPage, setCurrentPage] = useState(1);
const [localData, setLocalData] = useState([]);
const { data, refetch, isLoading } = useGetManageJobsQuery(currentPage);
const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = useDebounce(searchTerm, 500);
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
const { data, refetch, isLoading, isError, isFetching } = useGetManageJobsQuery(queryArgs);
const [deleteJobsPost] = useDeleteJobsPostMutation();
const [deleteModal, setDeleteModal] = useState(false);
const [selectedJobsId, setSelectedJobsId] = useState<number | null>(null);
@@ -54,6 +58,15 @@ const ManageJobs = () => {
}, [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();
@@ -84,8 +97,8 @@ const ManageJobs = () => {
Salary: agency?.ctc_amount,
Action: (
<HStack justifyContent="center">
<ViewManageJob />
<ManageJobsAdd />
<ViewManageJob data={agency} />
<ManageJobsAdd data={agency} refetch={refetch}/>
<AlertDailog
isOpen={deleteModal}
AltertTiggerIcon={() => (
@@ -142,29 +155,10 @@ const ManageJobs = () => {
</Text>
<HStack>
<InputGroup
startElement={
<LuSearch
fontSize={"xs"}
style={{ position: "relative", left: "10px" }}
/>
}
color={"#000"}
>
<Input
p={3}
w={300}
bg={"#fff"}
colorPalette={"blue"}
_focus={{ border: "1px solid #02A0A0" }}
rounded={"md"}
size={"xs"}
fontSize={"sm"}
placeholder="Search..."
bgColor={"#EEEEEE"}
ps={8}
/>
</InputGroup>
<SearchComponent
value={searchTerm}
onChange={handleSearchChange}
/>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
</HStack>
</HStack>
@@ -172,6 +166,15 @@ const ManageJobs = () => {
sortableColumns={["Name", "Registration Date "]}
tableHeadRow={tableHeadRow}
data={managepost}
paginationData={{
current_page: data?.data.current_page || 1,
last_page: data?.data.last_page || 1,
per_page: data?.data.per_page || 10,
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
</MainFrame>

View File

@@ -1,10 +1,8 @@
import {
Field,
Input,
SelectValueText,
Span,
Stack,
createListCollection,
} from "@chakra-ui/react";
import { Button } from "../../components/ui/button";
import {
@@ -19,24 +17,151 @@ import {
} from "../../components/ui/dialog";
// import { TbEdit } from "react-icons/tb";
import {
SelectContent,
SelectItem,
SelectLabel,
SelectRoot,
SelectTrigger,
} from "../../components/ui/select";
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] = 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 (
<DialogRoot placement="center">
<DialogTrigger asChild>
@@ -73,50 +198,182 @@ function ManageJobsAdd() {
pl={1}
fontSize="12px"
height="30px"
value={state.jobTitle}
onChange={(e) =>
dispatch({
type: "SET_JOB_TITLE",
payload: e.target.value,
})
}
/>
</Field.Root>
<Field.Root>
<Field.Label color="black" pt={1} fontSize="12px">
Workspace mode
</Field.Label>
<Input
placeholder="Enter the Workspace Mode"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
/>
<select
style={{
backgroundColor: "#EEEEEE",
color: "black",
border: "none",
height: "30px",
fontSize: "12px",
padding: "4px",
borderRadius: "4px",
width: "100%",
}}
value={state.workspace_mode_xid}
onChange={(e) =>
dispatch({
type: "SET_WORKSPACE_MODE",
payload: Number(e.target.value),
})
}
>
<option value="" disabled>
Select country
</option>
{workspaceModes && workspaceModes?.data.map((mode: WorkSpace) => (
<option key={mode.id} value={mode.id}>
{getDisplayName(mode.en_name)}
</option>
))}
</select>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Category
</Field.Label>
<Input
placeholder="Enter the Category"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
/>
<select
style={{
backgroundColor: "#EEEEEE",
color: "black",
border: "none",
height: "30px",
fontSize: "12px",
padding: "4px",
borderRadius: "4px",
width: "100%",
}}
value={state.industry_xid}
onChange={(e) =>
dispatch({
type: "SET_INDUSTRY",
payload: Number(e.target.value),
})
}
>
<option value="" disabled>
Select department
</option>
{industryData && industryData?.data.map((mode: WorkSpace) => (
<option key={mode.id} value={mode.id}>
{getDisplayName(mode.en_name)}
</option>
))}
</select>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Sub-Category
</Field.Label>
<Input
placeholder="Enter the Sub-Category"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
/>
<select
style={{
backgroundColor: "#EEEEEE",
color: "black",
border: "none",
height: "30px",
fontSize: "12px",
padding: "4px",
borderRadius: "4px",
width: "100%",
}}
value={state.department_xid}
onChange={(e) =>
dispatch({
type: "SET_DEPARTMENT",
payload: Number(e.target.value),
})
}
>
<option value="" disabled>
Select department
</option>
{departmentData && departmentData?.data.map((mode: WorkSpace) => (
<option key={mode.id} value={mode.id}>
{getDisplayName(mode.en_name)}
</option>
))}
</select>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Country
</Field.Label>
<select
style={{
backgroundColor: "#EEEEEE",
color: "black",
border: "none",
height: "30px",
fontSize: "12px",
padding: "4px",
borderRadius: "4px",
width: "100%",
}}
value={state.country_xid}
onChange={(e) =>
dispatch({
type: "SET_COUNTRY",
payload: Number(e.target.value),
})
}
>
<option value="" disabled>
Select country
</option>
{countryData && countryData?.data.map((mode: WorkSpace) => (
<option key={mode.id} value={mode.id}>
{getDisplayName(mode.en_name)}
</option>
))}
</select>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Job type
</Field.Label>
<select
style={{
backgroundColor: "#EEEEEE",
color: "black",
border: "none",
height: "30px",
fontSize: "12px",
padding: "4px",
borderRadius: "4px",
width: "100%",
}}
value={state.job_type_xid}
onChange={(e) =>
dispatch({
type: "SET_JOB_TYPE",
payload: Number(e.target.value),
})
}
>
<option value="" disabled>
Select Job Type
</option>
{jobTypeData && jobTypeData?.data.data.map((mode: WorkSpace) => (
<option key={mode.id} value={mode.id}>
{getDisplayName(mode.en_name)}
</option>
))}
</select>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Salary
@@ -129,6 +386,13 @@ function ManageJobsAdd() {
pl={1}
fontSize="12px"
height="30px"
value={state.salary}
onChange={(e) =>
dispatch({
type: "SET_SALARY",
payload: e.target.value,
})
}
/>
</Field.Root>
<Field.Root>
@@ -136,13 +400,20 @@ function ManageJobsAdd() {
Experience
</Field.Label>
<Input
placeholder="Enter the Experience"
placeholder="Enter the Experience in years"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={state.experience}
onChange={(e) =>
dispatch({
type: "SET_EXPERIENCE",
payload: e.target.value,
})
}
/>
</Field.Root>
<Field.Root>
@@ -157,71 +428,34 @@ function ManageJobsAdd() {
pl={1}
fontSize="12px"
height="30px"
/>
</Field.Root>
{/* <Field.Label pt={1} color="black" fontSize="12px">Country Selection</Field.Label>
<Input placeholder="Enter the Country Selection" /> */}
<SelectRoot collection={frameworks} size="sm" w={"100%"}>
<SelectLabel pt={1} color="black" fontSize="12px">
Country Selection
</SelectLabel>
<SelectTrigger
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
borderRadius={"5px"}
>
<SelectValueText
placeholder="Enter the Country Selection"
pb={"6px"}
fontSize={"12px"}
/>
</SelectTrigger>
<SelectContent position={"relative"} zIndex={"9999"} bg={"#fff"}>
{frameworks.items.map((movie) => (
<SelectItem
item={movie}
key={movie.value}
color={"black"}
pl={2}
p={1}
_hover={{ bg: "#F0F0F0" }} // Light grey background on hover
fontSize="12px"
>
{movie.label}
</SelectItem>
))}
</SelectContent>
</SelectRoot>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Job type
</Field.Label>
<Input
placeholder="Enter the Job Type"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={state.jobLocation}
onChange={(e) =>
dispatch({
type: "SET_JOB_LOCATION",
payload: e.target.value,
})
}
/>
</Field.Root>
<Field.Root>
<Field.Label pt={1} color="black" fontSize="12px">
Skills required
Skills description
</Field.Label>
<Input
placeholder="Enter the Skills Required"
placeholder="Enter the Skills description"
bgColor="#EEEEEE"
color="black"
border="none"
pl={1}
fontSize="12px"
height="30px"
value={state.skillsDescription}
onChange={(e) =>
dispatch({
type: "SET_SKILLS_DESCRIPTION",
payload: e.target.value,
})
}
/>
</Field.Root>
<Field.Root>
@@ -236,6 +470,13 @@ function ManageJobsAdd() {
pl={1}
fontSize="12px"
height="30px"
value={state.jobDescription}
onChange={(e) =>
dispatch({
type: "SET_JOB_DESCRIPTION",
payload: e.target.value,
})
}
/>
</Field.Root>
</Stack>
@@ -247,13 +488,15 @@ function ManageJobsAdd() {
color={"#fff"}
fontSize="12px"
height="30px"
onClick={handleSubmit}
>
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
<DialogCloseTrigger color="black" ref={closeRef} />
</DialogContent>
<Toaster />
</DialogRoot>
);
}

View File

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

View File

@@ -8,6 +8,7 @@ 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";
// table data
@@ -48,10 +49,12 @@ const tableHeadRow = [
const AgencyMaster = () => {
const [currentPage, setCurrentPage] = useState(1);
const { data, refetch } = useGetAgencyMasterQuery(currentPage)
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;
@@ -77,6 +80,11 @@ const AgencyMaster = () => {
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()) ||
@@ -118,7 +126,7 @@ const AgencyMaster = () => {
),
};
});
useEffect(() => {
if (data?.data?.data) {
@@ -170,7 +178,7 @@ const AgencyMaster = () => {
</InputGroup> */}
<SearchComponent
value={searchTerm}
onChange={setSearchTerm}
onChange={handleSearchChange}
/>
{/* <ViewAgencyAddModel refetch={refetch} /> */}
</HStack>
@@ -186,8 +194,10 @@ const AgencyMaster = () => {
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
</Box>
</MainFrame>
)
}

View File

@@ -7,6 +7,7 @@ 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";
@@ -36,10 +37,13 @@ const tableHeadRow = [
const Country = () => {
const [currentPage, setCurrentPage] = useState(1);
const { data, refetch } = useGetCountryMasterQuery(currentPage)
// 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(() => {
@@ -52,6 +56,11 @@ const Country = () => {
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);
@@ -98,6 +107,7 @@ const Country = () => {
</HStack>
),
}))
return (
@@ -137,11 +147,12 @@ const Country = () => {
</InputGroup> */}
<SearchComponent
value={searchTerm}
onChange={(value) => {
setSearchTerm(value);
// setCurrentPage(1);
refetch()
}}
// onChange={(value) => {
// setSearchTerm(value);
// // setCurrentPage(1);
// refetch()
// }}
onChange={handleSearchChange}
/>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
<CountryAddModel />
@@ -158,6 +169,8 @@ const Country = () => {
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
</MainFrame>

View File

@@ -9,6 +9,7 @@ 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";
// table data
@@ -24,12 +25,14 @@ const tableHeadRow = [
const DepartmentMasterList = () => {
const [currentPage, setCurrentPage] = useState(1);
const { data, refetch } = useGetDepartmentMasterQuery(currentPage)
const [departmentToggle] = useDepartmentToggleMutation()
const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = useDebounce(searchTerm, 500);
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
const { data, refetch, isError, isFetching } = useGetDepartmentMasterQuery(queryArgs)
console.log("Department Data", data?.data.data)
console.log("Department Data", data?.data.data)
useEffect(() => {
if (data?.data?.data) {
@@ -37,6 +40,11 @@ const DepartmentMasterList = () => {
}
}, [data]);
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
@@ -112,11 +120,7 @@ const DepartmentMasterList = () => {
<HStack >
<SearchComponent
value={searchTerm}
onChange={(value) => {
setSearchTerm(value);
// setCurrentPage(1);
refetch()
}}
onChange={handleSearchChange}
/>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
{/* <ViewAgencyAddModel /> */}
@@ -134,6 +138,8 @@ const DepartmentMasterList = () => {
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
</MainFrame>

View File

@@ -9,6 +9,7 @@ import { useGetIndustryMasterQuery, useIndustryMasterToggleMutation } from "../.
import EditIndustryMaster from "./EditIndustryMaster";
import AddIndustryMaster from "./AddIndustryMaster";
import SearchComponent from "../../../components/SearchComponent";
import { useDebounce } from "../../../components/Hooks/useDebounce";
// table data
@@ -44,10 +45,12 @@ const tableHeadRow = [
const IndustryMasterList = () => {
const [currentPage, setCurrentPage] = useState(1);
const { data, refetch } = useGetIndustryMasterQuery(currentPage)
const [industryMasterToggle] = useIndustryMasterToggleMutation()
const [localData, setLocalData] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const [searchTerm, setSearchTerm] = useState("");
const debouncedSearchTerm = useDebounce(searchTerm, 500);
const queryArgs = debouncedSearchTerm ? { page: currentPage, search: debouncedSearchTerm } : { page: currentPage };
const { data, refetch, isError, isFetching } = useGetIndustryMasterQuery(queryArgs)
useEffect(() => {
if (data?.data?.data) {
@@ -55,6 +58,11 @@ const IndustryMasterList = () => {
}
}, [data]);
const handleSearchChange = (value: string) => {
setSearchTerm(value);
setCurrentPage(1);
};
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
@@ -130,11 +138,7 @@ const IndustryMasterList = () => {
<HStack >
<SearchComponent
value={searchTerm}
onChange={(value) => {
setSearchTerm(value);
// setCurrentPage(1);
refetch()
}}
onChange={handleSearchChange}
/>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
{/* <ViewAgencyAddModel /> */}
@@ -152,6 +156,8 @@ const IndustryMasterList = () => {
total: data?.data.total || 0
}}
onPageChange={handlePageChange}
isLoading={isFetching}
isError={isError}
/>
</Box>
</MainFrame>

View File

@@ -87,38 +87,44 @@ const TemplateMaster = () => {
agency.post_template_translate[0].title.toLowerCase().includes(searchTerm.toLowerCase())
);
const managepost = filteredData?.map((agency: Template, index: number) => ({
'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 key={agency.id}>
{agency.post_template_image.map((img) => (
<Image key={img.id} rounded={'lg'} w={100} h={50} src={`${APIURL}${img.image_name}`} />
))}
const activeCount = filteredData?.filter((a: any) => a.is_active === 1).length ?? 0;
{/* <Image rounded={'lg'} w={100} h={50} src={Templateimg} /> */}
</HStack>
),
const managepost = filteredData?.map((agency: Template, index: number) => {
const isOnlyActive = activeCount === 1 && Number(agency.is_active) === 1;
"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))}
/>
</Box>
</HStack>
),
}));
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 (

View File

@@ -12,11 +12,11 @@ import {
import { Field, Grid, Heading, Input, Stack, Text } from "@chakra-ui/react";
import { IoMdAdd } from "react-icons/io";
import { Checkbox } from "../../components/ui/checkbox";
import { useCreateSubAdminPostMutation } from "../../Redux/Service/manage.subadmin.service";
import { toaster } from "../../components/ui/toaster";
import { useState } from "react";
import { PermissionResponse, useCreateSubAdminPostMutation } from "../../Redux/Service/manage.subadmin.service";
import { toaster, Toaster } from "../../components/ui/toaster";
import { useEffect, useState } from "react";
function AddModel({ refetch }: { refetch: VoidFunction }) {
function AddModel({ refetch, allPermissions }: { refetch: VoidFunction, allPermissions: PermissionResponse }) {
const [createSubAdminPost] = useCreateSubAdminPostMutation();
// State fields
@@ -25,8 +25,37 @@ function AddModel({ refetch }: { refetch: VoidFunction }) {
const [userName, setUserName] = useState("");
const [dateOfBirth, setDateOfBirth] = useState("");
const [gender, setGender] = useState("");
const [email, setEmail] = useState("");
const [phonenumber, setPhonenumber] = useState("");
const [permissions, setPermission] = useState<number[]>([]);
const [isOpen, setIsOpen] = useState(false);
// const [ setIsOpen] = useState(false);
const handleOpenModal = () => {
setIsOpen(true);
};
const handleCheckboxToggle = (permissionId: number) => {
setPermission((prevData) =>
prevData.includes(permissionId)
? prevData.filter((id) => id !== permissionId)
: [...prevData, permissionId]
);
};
useEffect(() => {
if (!isOpen) {
setFirstName("");
setLastName("");
setUserName("");
setDateOfBirth("");
setGender("");
setEmail("");
setPhonenumber("");
setPermission([]);
}
}, [isOpen]);
const handleSubmit = async () => {
if (
!firstName.trim() ||
@@ -43,17 +72,35 @@ function AddModel({ refetch }: { refetch: VoidFunction }) {
return;
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
toaster.create({
title: "Invalid Email",
description: "Please enter a valid email address",
type: "error",
});
return;
}
if (phonenumber.length !== 10) {
toaster.create({
title: "Invalid Phone Number",
description: "Phone number must be exactly 10 digits",
type: "error",
});
return;
}
const payload = {
principal_type_xid: 4,
principal_source_xid: 1,
user_name: userName,
first_name: firstName,
last_name: lastName,
date_of_birth: dateOfBirth,
gender: gender,
email_address: "example@yopmail.com", // Hardcoded
phone_number: "9876543210", // Hardcoded
created_by: 1,
email_address: email,
phone_number: phonenumber,
permission: permissions.filter((id) => typeof id === "number"),
// created_by: 1,
};
try {
@@ -71,21 +118,28 @@ function AddModel({ refetch }: { refetch: VoidFunction }) {
setUserName("");
setDateOfBirth("");
setGender("");
setIsOpen(false);
}
} catch (error) {
} catch (error:any) {
console.error("Error creating sub-admin:", error);
toaster.create({
title: "Error",
description: "Failed to create sub-admin",
description: error ? error.data.message : "Failed to create sub-admin",
type: "error",
});
}
};
return (
<DialogRoot placement="center">
<DialogRoot placement="center" open={isOpen} onOpenChange={({ open }) => setIsOpen(open)}>
<DialogTrigger asChild>
<Button rounded={"md"} px={4} py={2} size={"xs"} bg={"#02A0A0"}>
<Button
rounded={"md"}
px={4} py={2}
size={"xs"}
bg={"#02A0A0"}
onClick={handleOpenModal}>
<IoMdAdd /> Add
</Button>
</DialogTrigger>
@@ -184,28 +238,56 @@ function AddModel({ refetch }: { refetch: VoidFunction }) {
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}>
{[
"Dashboard",
"Manage contact us",
"manage User",
"Manage CMS",
"Manage Post",
"Manage Reports",
"manage Sub-Admin",
"My profile",
"Manage Jobs",
"manage feedbacks",
"Manage community",
"Notification",
].map((permission) => (
<Checkbox size="sm" color="black" key={permission}>
<Text fontSize={12}>{permission}</Text>
{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>
))}
</Grid>
@@ -223,9 +305,9 @@ function AddModel({ refetch }: { refetch: VoidFunction }) {
Save
</Button>
</DialogFooter>
<DialogCloseTrigger color="black" />
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
<Toaster />
</DialogRoot>
);
}

View File

@@ -9,7 +9,7 @@ import AddModel from "./AddModel"
import EditSubAdmin from "../../components/EditSubAdmin"
import ViewSubAdmin from "./ViewSubAdmin"
import Delete from "../../components/ActionIcons/Delete"
import { useDeleteSubAdminPostMutation, useGetSubAdminQuery } from "../../Redux/Service/manage.subadmin.service"
import { PermissionResponse, useDeleteSubAdminPostMutation, useGetPermissionQuery, useGetSubAdminQuery } from "../../Redux/Service/manage.subadmin.service"
import { useEffect, useState } from "react"
import { toaster } from "../../components/ui/toaster"
@@ -56,36 +56,37 @@ const tableHeadRow = [
const SubAdmin = () => {
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()
console.log("============================",data);
useEffect(() => {
if (data?.data.data) {
setLocalData(data?.data.data);
setAllPermissions(permissions);
}
}, [data]);
}, [data, permissions]);
console.log("============================", allPermissions);
console.log('localData', localData);
const handleDeleteFaq = async (faqId: number) => {
const handleDeleteAdmin = async (faqId: number) => {
try {
const response = await deleteSubAdminPost(faqId).unwrap();
if (response.success) {
toaster.create({
title: "Success",
description: "FAQ deleted successfully",
description: "Sub Admin deleted successfully",
type: "success",
});
refetch()
console.log("FAQ deleted successfully:", response);
console.log("Sub Admin deleted successfully:", response);
}
// Optionally, refetch data or update state after deletion
} catch (error) {
console.error("Error deleting FAQ:", error);
console.error("Error deleting Sub Admin:", error);
toaster.create({
title: "Error",
description: "Something went wrong",
@@ -114,20 +115,20 @@ const SubAdmin = () => {
"Action": (
<HStack justifyContent="center">
{/* <EditDetails rowData={{ id: agency.id, question: agency.question, answer: agency.answer }} refetch={refetch} /> */}
<ViewSubAdmin id={agency.id}/>
<EditSubAdmin id={agency.id} refetch={refetch} />
<ViewSubAdmin id={agency.id} />
{allPermissions && <EditSubAdmin id={agency.id} refetch={refetch} allPermissions={allPermissions} />}
<AlertDailog
isOpen={deleteModal}
AltertTiggerIcon={() => <Delete onClick={() => setDeleteModal(prev => !prev)} />}
alertText="Delete FAQ"
alertText="Delete sub admin"
alertIcon={<Image src={"DeleteIcon"} h={"39px"} />}
alertCaption="are you sure you want to delete ?"
onClose={() => setDeleteModal(false)}
onConfirm={() => {
// console.log("User deleted:", index + 1);
setDeleteModal(false);
handleDeleteFaq(agency.id)
handleDeleteAdmin(agency.id)
}}
/>
</HStack>
@@ -171,7 +172,7 @@ const SubAdmin = () => {
/>
</InputGroup>
{/* <Button bgColor={'#EEEEEE'} pl={3} pr={3}><IoMdAdd /> <Text>Add</Text></Button> */}
<AddModel refetch={refetch}/>
{allPermissions && <AddModel refetch={refetch} allPermissions={allPermissions}/>}
</HStack>
</HStack>
<DataTable

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -40,6 +40,25 @@ interface ApiResponse {
data: PaginatedData;
}
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,
@@ -60,6 +79,10 @@ interface ResourceActionLink {
deleted_at: string | null;
created_at: string;
updated_at: string;
app_resource:{
id: number;
app_resource_title: string
}
}
interface SubAdmin {
@@ -80,8 +103,6 @@ interface SubAdminView {
}
interface CreateSubAdminPayload {
principal_type_xid: number;
principal_source_xid: number;
user_name: string;
first_name: string;
last_name: string;
@@ -89,7 +110,7 @@ interface CreateSubAdminPayload {
gender: string;
email_address: string;
phone_number: string;
created_by: number;
// created_by: number;
}
interface CreateSubAdminResponse {
@@ -117,6 +138,10 @@ export const manageSubAdmin = createApi({
query: () => `/sub-admin`,
}),
getPermission: builder.query<PermissionResponse, void>({
query: () => `/resources`,
}),
viewSubAdmin: builder.query<SubAdminView, number>({
query: (id) => `/sub-admin-view/${id}`,
}),
@@ -151,8 +176,9 @@ export const manageSubAdmin = createApi({
deleteSubAdminPost: builder.mutation<{ success: boolean }, number>({
query: (id) => ({
url: `/faq-delete/${id}`,
method: "DELETE",
url: `/sub-admin-delete`,
method: "POST",
body: { id },
}),
}),
}),
@@ -160,6 +186,7 @@ export const manageSubAdmin = createApi({
export const {
useGetSubAdminQuery,
useGetPermissionQuery,
useLazyViewSubAdminQuery,
useUpdateSubAdminMutation,
useDeleteSubAdminPostMutation,

View File

@@ -25,6 +25,8 @@ interface TableProps {
total: number;
};
onPageChange?: (page: number) => void;
isLoading?: boolean;
isError?: boolean;
}
const DataTable: React.FC<TableProps> = ({
@@ -33,6 +35,8 @@ const DataTable: React.FC<TableProps> = ({
sortableColumns = [],
paginationData,
onPageChange,
isLoading,
isError
}: TableProps) => {
const { current_page = 1, last_page = 1 } = paginationData || {};
const [sortConfig, setSortConfig] = useState<{
@@ -103,17 +107,21 @@ const DataTable: React.FC<TableProps> = ({
))}
</Table.Row>
</Table.Header>
{data?.length === 0 ? (
<Box>
<Box textAlign={"center"} py={20} position={'absolute'} w={'84%'}>
<Image src={EmptyFile} alt="No data" maxW="65px" mx="auto" />
<Text fontSize={"18px"} fontWeight={500} mt={2}>
No records found theyll appear here if available.
</Text>
</Box>
{isLoading ? (
<Box textAlign={"center"} py={20} position="absolute" w="84%">
<Text fontSize={"18px"} fontWeight={500} mt={2}>
Loading...
</Text>
</Box>
) : isError ? (
<Box textAlign={"center"} py={20} position="absolute" w="84%">
<Image src={EmptyFile} alt="No data" maxW="65px" mx="auto" />
<Text fontSize={"18px"} fontWeight={500} mt={2}>
No records found theyll appear here if available.
</Text>
</Box>
) : (
<Table.Body h={"100%"}>
<Table.Body h="100%">
{data.map((item: any, index) => (
<Table.Row
key={index}
@@ -129,8 +137,7 @@ const DataTable: React.FC<TableProps> = ({
border={"none"}
>
{(() => {
const words =
item[heading]?.toString().split(" ") || [];
const words = item[heading]?.toString().split(" ") || [];
return words.length > 5
? `${words.slice(0, 5).join(" ")}...`
: item[heading];
@@ -141,9 +148,10 @@ const DataTable: React.FC<TableProps> = ({
))}
</Table.Body>
)}
</Table.Root>
</Table.ScrollArea>
{last_page > 1 && (
{last_page > 1 && !isLoading && !isError && (
<PaginationRoot
count={paginationData?.total ?? 0}
pageSize={paginationData?.per_page ?? 0}

View File

@@ -13,9 +13,9 @@ import {
DialogTrigger,
} from "./ui/dialog";
import Edit from "./ActionIcons/Edit";
import { useLazyViewSubAdminQuery, useUpdateSubAdminMutation } from "../Redux/Service/manage.subadmin.service";
import { PermissionResponse, useLazyViewSubAdminQuery, useUpdateSubAdminMutation } from "../Redux/Service/manage.subadmin.service";
import { useEffect, useState } from "react";
import { toaster } from "./ui/toaster";
import { Toaster, toaster } from "../components/ui/toaster";
const resourceIdToLabel: { [key: number]: string } = {
1: 'Dashboard',
@@ -37,9 +37,13 @@ interface ResourceActionLink {
id: number;
app_resource_xid: number;
is_active: boolean;
app_resource: {
id: number,
app_resource_title: string
}
}
function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
function EditSubAdmin({ id, refetch, allPermissions }: { id: number, refetch: VoidFunction, allPermissions: PermissionResponse }) {
const [trigger, { data }] = useLazyViewSubAdminQuery();
const [updateSubAdmin] = useUpdateSubAdminMutation()
const [isOpen, setIsOpen] = useState(false);
@@ -62,8 +66,23 @@ function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
})
useEffect(() => {
if (data?.data && data.data.length > 0) {
const subAdmin = data.data[0]; // Extract the first item from the array
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({
@@ -73,10 +92,10 @@ function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
last_name: subAdmin.last_name,
date_of_birth: formatDateOfBirth(subAdmin.date_of_birth),
gender: subAdmin.gender,
permission: subAdmin.get_resource_action_link,
permission: mergedPermissions,
});
}
}, [data]);
}, [data, allPermissions]);
const formatDateOfBirth = (dob: string): string => {
// Convert the date to the desired format with slashes
@@ -99,7 +118,7 @@ function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
setEditData((prevData) => ({
...prevData,
permission: prevData.permission.map((permission) =>
permission.id === permissionId
permission.app_resource_xid === permissionId
? { ...permission, is_active: !permission.is_active }
: permission
),
@@ -119,6 +138,8 @@ function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
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 {
@@ -295,7 +316,7 @@ function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
size="sm"
color="black"
checked={permission.is_active}
onChange={() => handleCheckboxToggle(permission.id)}
onChange={() => handleCheckboxToggle(permission.app_resource_xid)}
cursor={'pointer'}
>
<Text fontSize={12}>{label}</Text>
@@ -312,6 +333,7 @@ function EditSubAdmin({ id, refetch }: { id: number, refetch: VoidFunction }) {
</DialogFooter>
<DialogCloseTrigger color="black" onClick={() => setIsOpen(false)} />
</DialogContent>
<Toaster/>
</DialogRoot>
);
}

View File

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