Merge branch 'Service_Project_Managment' of https://git.marcoaiot.com/admin/marco.pms.web into Service_Project_Managment

This commit is contained in:
Kartik Sharma 2025-11-17 18:35:49 +05:30
commit d6b2ed9f84
21 changed files with 435 additions and 341 deletions

View File

@ -100,9 +100,9 @@ const AttendanceOverview = () => {
}; };
return ( return (
<div className="bg-white p-4 rounded shadow d-flex flex-column h-100"> <div className="bg-white px-4 rounded shadow d-flex flex-column h-100">
{/* Header */} {/* Header */}
<div className="d-flex justify-content-between align-items-center mb-3"> <div className="d-flex mt-2 justify-content-between align-items-center mb-3">
<div className="card-title mb-0 text-start"> <div className="card-title mb-0 text-start">
<h5 className="mb-1 fw-bold">Attendance Overview</h5> <h5 className="mb-1 fw-bold">Attendance Overview</h5>
<p className="card-subtitle">Role-wise present count</p> <p className="card-subtitle">Role-wise present count</p>

View File

@ -12,11 +12,11 @@ import Teams from "./Teams";
import TasksCard from "./Tasks"; import TasksCard from "./Tasks";
import ProjectCompletionChart from "./ProjectCompletionChart"; import ProjectCompletionChart from "./ProjectCompletionChart";
import ProjectProgressChart from "./ProjectProgressChart"; import ProjectProgressChart from "./ProjectProgressChart";
import ProjectOverview from "../Project/ProjectOverview"; import AttendanceOverview from "./AttendanceOverview";
import AttendanceOverview from "./AttendanceChart";
import ExpenseAnalysis from "./ExpenseAnalysis"; import ExpenseAnalysis from "./ExpenseAnalysis";
import ExpenseStatus from "./ExpenseStatus"; import ExpenseStatus from "./ExpenseStatus";
import ExpenseByProject from "./ExpenseByProject"; import ExpenseByProject from "./ExpenseByProject";
import ProjectStatistics from "../Project/ProjectStatistics";
const Dashboard = () => { const Dashboard = () => {
@ -46,32 +46,31 @@ const Dashboard = () => {
<ProjectCompletionChart /> <ProjectCompletionChart />
</div> </div>
)} )}
{!isAllProjectsSelected && (
<div className="col-xxl-6 col-lg-6">
<ProjectOverview />
</div>
)}
<div className="col-xxl-6 col-lg-6"> <div className="col-xxl-6 col-lg-6">
<ProjectProgressChart /> <ProjectProgressChart />
</div> </div>
<div className="col-12 col-xl-8">
<div className="card h-100">
<ExpenseAnalysis />
</div>
</div>
<div className="col-12 col-xl-4 col-md-6">
<div className="card h-100">
<ExpenseStatus />
</div>
</div>
{!isAllProjectsSelected && ( {!isAllProjectsSelected && (
<div className="col-12 col-md-6 mb-sm-0 mb-4"> <div className="col-12 col-md-6 mb-sm-0 mb-4">
<AttendanceOverview /> <AttendanceOverview />
</div> </div>
)} )}
{!isAllProjectsSelected && (
<div className="col-xxl-4 col-lg-4">
<ProjectStatistics />
</div>
)}
<div className="col-12 col-xl-4 col-md-6">
<div className="card ">
<ExpenseStatus />
</div>
</div>
<div className="col-12 col-xl-8">
<div className="card h-100">
<ExpenseAnalysis />
</div>
</div>
<div className="col-12 col-md-6"> <div className="col-12 col-md-6">
<ExpenseByProject /> <ExpenseByProject />
</div> </div>

View File

@ -7,11 +7,12 @@ import { FormProvider, useForm } from "react-hook-form";
import { formatCurrency, localToUtc } from "../../utils/appUtils"; import { formatCurrency, localToUtc } from "../../utils/appUtils";
import { useProjectName } from "../../hooks/useProjects"; import { useProjectName } from "../../hooks/useProjects";
import { SpinnerLoader } from "../common/Loader"; import { SpinnerLoader } from "../common/Loader";
import flatColors from "../Charts/flatColor";
const ExpenseAnalysis = () => { const ExpenseAnalysis = () => {
const projectId = useSelectedProject(); const projectId = useSelectedProject();
const [projectName, setProjectName] = useState("All Project"); const [projectName, setProjectName] = useState("All Project");
const { projectNames, loading } = useProjectName(); const { projectNames } = useProjectName();
const methods = useForm({ const methods = useForm({
defaultValues: { startDate: "", endDate: "" }, defaultValues: { startDate: "", endDate: "" },
@ -50,7 +51,7 @@ const ExpenseAnalysis = () => {
labels, labels,
legend: { show: false }, legend: { show: false },
dataLabels: { enabled: true, formatter: (val) => `${val.toFixed(0)}%` }, dataLabels: { enabled: true, formatter: (val) => `${val.toFixed(0)}%` },
colors: ["#7367F0", "#28C76F", "#FF9F43", "#EA5455", "#00CFE8", "#FF78B8"], colors: flatColors,
plotOptions: { plotOptions: {
pie: { pie: {
donut: { donut: {
@ -79,11 +80,9 @@ const ExpenseAnalysis = () => {
return ( return (
<> <>
<div className="card-header d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center gap-2"> <div className="card-header d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center gap-2">
<div className="text-start"> <div className="text-start">
<h5 className="mb-1 card-title">Expense Breakdown</h5> <h5 className="mb-1 card-title">Expense Breakdown</h5>
{/* <p className="card-subtitle mb-0">Category Wise Expense Breakdown</p> */}
<p className="card-subtitle m-0">{projectName}</p> <p className="card-subtitle m-0">{projectName}</p>
</div> </div>
@ -94,7 +93,6 @@ const ExpenseAnalysis = () => {
</div> </div>
</div> </div>
{/* Card body */}
<div className="card-body position-relative"> <div className="card-body position-relative">
{isLoading && ( {isLoading && (
<div <div
@ -114,7 +112,6 @@ const ExpenseAnalysis = () => {
</div> </div>
)} )}
{!isLoading && report.length > 0 && ( {!isLoading && report.length > 0 && (
<> <>
{isFetching && ( {isFetching && (
@ -123,50 +120,59 @@ const ExpenseAnalysis = () => {
</div> </div>
)} )}
<div className="d-flex justify-content-center mb-3"> <div className="row">
{/* Chart Column */}
<div className="col-12 col-lg-6 d-flex justify-content-center mt-5 mb-3 mb-lg-0">
<Chart <Chart
options={donutOptions} options={donutOptions}
series={series} series={series}
type="donut" type="donut"
width="100%" width="70%"
height={320} height={320}
/> />
</div> </div>
<div className="mb-2 w-100"> {/* Data/Legend Column */}
<div className="row g-2"> <div className="col-12 mt-6 col-lg-6">
<div className="row g-4">
{report.map((item, idx) => ( {report.map((item, idx) => (
<div <div
className="col-12 col-sm-6 d-flex align-items-start" className="col-6"
key={idx} key={idx}
>
<div className="avatar me-2">
<span
className="avatar-initial rounded-2"
style={{ style={{
backgroundColor: borderLeft: `3px solid ${flatColors[idx % flatColors.length]}`,
donutOptions.colors[idx % donutOptions.colors.length], }}
>
<div className="d-flex flex-column text-start">
<small
className="fw-semibold text-wrap text-dark"
style={{
fontSize: "0.8rem",
whiteSpace: "normal",
wordBreak: "break-word",
lineHeight: "1.2",
}}
>
{item.projectName}
</small>
<span
className="fw-semibold text-muted"
style={{
fontSize: "0.75rem",
}} }}
> >
<i className="bx bx-receipt fs-4"></i>
</span>
</div>
<div className="d-flex flex-column gap-1 text-start">
<small className="fw-semibold">{item.projectName}</small>
<span className="fw-semibold text-muted ms-1">
{formatCurrency(item.totalApprovedAmount)} {formatCurrency(item.totalApprovedAmount)}
</span> </span>
</div> </div>
</div> </div>
))} ))}
</div> </div>
</div> </div>
</div>
</> </>
)} )}
</div> </div>
{/* Header */}
</> </>
); );
}; };

View File

@ -92,7 +92,7 @@ const ExpenseByProject = () => {
<div className="card shadow-sm h-100 rounded "> <div className="card shadow-sm h-100 rounded ">
{/* Header */} {/* Header */}
<div className="card-header"> <div className="card-header">
<div className="d-flex justify-content-start align-items-center mb-1 mt-1"> <div className="d-flex justify-content-between align-items-center mb-1 mt-1">
<div className="text-start"> <div className="text-start">
<h5 className="mb-1 me-6 card-title">Monthly Expense -</h5> <h5 className="mb-1 me-6 card-title">Monthly Expense -</h5>
<p className="card-subtitle m-0">{projectName}</p> <p className="card-subtitle m-0">{projectName}</p>

View File

@ -103,7 +103,7 @@ const ExpenseStatus = () => {
</div> </div>
<div> <div>
<small <small
className={`text-royalblue ${countDigit(item?.count || 0) >= 3 ? "text-xl" : "text-2xl" className={`text-royalblue ${countDigit(item?.count || 0) >= 3 ? "text-xl" : "text-xl"
} text-gray-500`} } text-gray-500`}
> >
{item?.count || 0} {item?.count || 0}
@ -137,7 +137,7 @@ const ExpenseStatus = () => {
</div> </div>
<div className="d-flex align-items-center gap-2"> <div className="d-flex align-items-center gap-2">
<span <span
className={`text-end text-royalblue ${countDigit(data?.totalAmount || 0) > 3 ? "text-" : "text-3xl" className={`text-end text-royalblue ${countDigit(data?.totalAmount || 0) > 3 ? "text-xl" : "text-3xl"
} text-md`} } text-md`}
> >
{formatCurrency(data?.totalAmount || 0)} {formatCurrency(data?.totalAmount || 0)}

View File

@ -1,11 +1,14 @@
import React from "react"; import React, { useState } from "react";
import HorizontalBarChart from "../Charts/HorizontalBarChart"; import HorizontalBarChart from "../Charts/HorizontalBarChart";
import { useProjects } from "../../hooks/useProjects"; import { useProjects } from "../../hooks/useProjects";
import { ITEMS_PER_PAGE } from "../../utils/constants";
const ProjectCompletionChart = () => { const ProjectCompletionChart = () => {
const { data: projects = [], isLoading: loading, isError, error } = useProjects();
const [currentPage, setCurrentPage] = useState(1);
const { data: projects, isLoading: loading, isError, error } = useProjects(currentPage, ITEMS_PER_PAGE);
console.log("Kartik", projects)
// Bar chart logic // Bar chart logic
const projectNames = projects?.map((p) => p.name) || []; const projectNames = projects?.map((p) => p.name) || [];
const projectProgress = const projectProgress =

View File

@ -99,7 +99,7 @@ const MenuItem = (item) => {
className={`menu-link ${hasSubmenu ? "menu-toggle" : ""}`} className={`menu-link ${hasSubmenu ? "menu-toggle" : ""}`}
target={item.link?.includes("http") ? "_blank" : undefined} target={item.link?.includes("http") ? "_blank" : undefined}
> >
<i className={`menu-icon tf-icons ${item.icon}`}></i> {item.icon && <i className={`menu-icon tf-icons ${item.icon}`}></i>}
<div>{item.name}</div> <div>{item.name}</div>
{item.available === false && ( {item.available === false && (
<div className="badge bg-label-primary fs-tiny rounded-pill ms-auto"> <div className="badge bg-label-primary fs-tiny rounded-pill ms-auto">

View File

@ -9,7 +9,7 @@ import {
import ReactApexChart from "react-apexcharts"; import ReactApexChart from "react-apexcharts";
import Chart from "react-apexcharts"; import Chart from "react-apexcharts";
const ProjectOverview = ({ project }) => { const ProjectStatistics = ({ project }) => {
const { data } = useProjects(); const { data } = useProjects();
const [current_project, setCurrentProject] = useState( const [current_project, setCurrentProject] = useState(
data?.find((pro) => pro.id == project) data?.find((pro) => pro.id == project)
@ -165,7 +165,7 @@ const ProjectOverview = ({ project }) => {
}, [selectedProject]); }, [selectedProject]);
return ( return (
<div className="card" style={{ minHeight: "490px" }}> <div className="card h-100">
<div className="card-header text-start"> <div className="card-header text-start">
<h5 className="card-action-title mb-0"> <h5 className="card-action-title mb-0">
{" "} {" "}
@ -247,4 +247,4 @@ const ProjectOverview = ({ project }) => {
); );
}; };
export default ProjectOverview; export default ProjectStatistics;

View File

@ -72,7 +72,7 @@ const AddPayment = ({ onClose }) => {
<div className="col-12 col-md-6 mb-2"> <div className="col-12 col-md-6 mb-2">
<Label required>Transaction Date </Label> <Label required>Transaction Date </Label>
<DatePicker <DatePicker className="w-100"
name="paymentReceivedDate" name="paymentReceivedDate"
control={control} control={control}
minDate={ minDate={

View File

@ -29,14 +29,14 @@ const CollectionList = ({ fromDate, toDate, isPending, searchString }) => {
const searchDebounce = useDebounce(searchString, 500); const searchDebounce = useDebounce(searchString, 500);
const { data, isLoading, isError, error } = useCollections( const { data, isLoading, isError, error } = useCollections(
ITEMS_PER_PAGE, selectedProject,
currentPage, searchDebounce,
localToUtc(fromDate), localToUtc(fromDate),
localToUtc(toDate), localToUtc(toDate),
isPending, ITEMS_PER_PAGE,
currentPage,
true, true,
selectedProject, isPending
searchDebounce
); );
const { setProcessedPayment, setAddPayment, setViewCollection } = const { setProcessedPayment, setAddPayment, setViewCollection } =
useCollectionContext(); useCollectionContext();

View File

@ -2,39 +2,80 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { CollectionRepository } from "../repositories/ColllectionRepository"; import { CollectionRepository } from "../repositories/ColllectionRepository";
import showToast from "../services/toastService"; import showToast from "../services/toastService";
// export const useCollections = (
// pageSize,
// pageNumber,
// fromDate,
// toDate,
// isPending,
// isActive,
// projectId,
// searchString
// ) => {
// return useQuery({
// queryKey: [
// "collections",
// pageSize,
// pageNumber,
// fromDate,
// toDate,
// isPending,
// isActive,
// projectId,
// searchString,
// ],
// queryFn: async () => {
// const response = await CollectionRepository.getCollections(
// pageSize,
// pageNumber,
// fromDate,
// toDate,
// isPending,
// isActive,
// projectId,
// searchString
// );
// return response.data;
// },
// keepPreviousData: true,
// staleTime: 1000 * 60 * 1,
// });
// };
export const useCollections = ( export const useCollections = (
pageSize, projectId,
pageNumber, searchString,
fromDate, fromDate,
toDate, toDate,
isPending, pageSize,
pageNumber,
isActive, isActive,
projectId, isPending
searchString
) => { ) => {
return useQuery({ return useQuery({
queryKey: [ queryKey: [
"collections", "collections",
pageSize,
pageNumber,
fromDate,
toDate,
isPending,
isActive,
projectId, projectId,
searchString, searchString,
fromDate,
toDate,
pageSize,
pageNumber,
isActive,
isPending,
], ],
queryFn: async () => { queryFn: async () => {
const response = await CollectionRepository.getCollections( const response = await CollectionRepository.getCollections(
pageSize, projectId,
pageNumber, searchString,
fromDate, fromDate,
toDate, toDate,
isPending, pageSize,
pageNumber,
isActive, isActive,
projectId, isPending
searchString
); );
return response.data; return response.data;
}, },
@ -44,7 +85,6 @@ export const useCollections = (
}); });
}; };
export const useCollection = (collectionId) => { export const useCollection = (collectionId) => {
return useQuery({ return useQuery({
queryKey: ["collection", collectionId], queryKey: ["collection", collectionId],

View File

@ -20,13 +20,13 @@ export const useCurrentService = () => {
// ------------------------------Query------------------- // ------------------------------Query-------------------
export const useProjects = (pageSize,pageNumber) => { export const useProjects = (pageNumber,pageSize) => {
const loggedUser = useSelector((store) => store.globalVariables.loginUser); const loggedUser = useSelector((store) => store.globalVariables.loginUser);
return useQuery({ return useQuery({
queryKey: ["ProjectsList",pageSize,pageNumber], queryKey: ["ProjectsList",pageNumber,pageSize],
queryFn: async () => { queryFn: async () => {
const response = await ProjectRepository.getProjectList(pageSize,pageNumber); const response = await ProjectRepository.getProjectList(pageNumber,pageSize);
return response.data; return response?.data?.data;
}, },
enabled: !!loggedUser, enabled: !!loggedUser,
}); });

View File

@ -40,13 +40,12 @@ const AdvancePaymentPage = () => {
}); });
}, [reset]); }, [reset]);
return ( return (
<AdvancePaymentContext.Provider value={{ setBalance }}> <AdvancePaymentContext.Provider value={{ setBalance }}>
<div className="container-fluid"> <div className="container-fluid">
<Breadcrumb <Breadcrumb
data={[ data={[
{ label: "Home", link: "/" }, { label: "Home", link: "/dashboard" },
{ label: "Finance", link: "/advance-payment" }, { label: "Finance", link: "/advance-payment" },
{ label: "Advance Payment" }, { label: "Advance Payment" },
]} ]}
@ -73,7 +72,12 @@ const AdvancePaymentPage = () => {
balance > 0 ? "text-success" : "text-danger" balance > 0 ? "text-success" : "text-danger"
} fs-5 fw-bold ms-1`} } fs-5 fw-bold ms-1`}
> >
{ balance > 0 ? <i className="bx bx-plus b-sm"></i> : <i className="bx bx-minus b-sm"></i>} {formatFigure(balance, { {balance > 0 ? (
<i className="bx bx-plus b-sm"></i>
) : (
<i className="bx bx-minus b-sm"></i>
)}{" "}
{formatFigure(balance, {
type: "currency", type: "currency",
currency: "INR", currency: "INR",
})} })}
@ -85,8 +89,6 @@ const AdvancePaymentPage = () => {
</div> </div>
</div> </div>
<AdvancePaymentList employeeId={selectedEmployeeId} /> <AdvancePaymentList employeeId={selectedEmployeeId} />
</div> </div>
</div> </div>
</AdvancePaymentContext.Provider> </AdvancePaymentContext.Provider>

View File

@ -1,4 +1,10 @@
import React, { createContext, useContext, useState, useEffect, useRef } from "react"; import React, {
createContext,
useContext,
useState,
useEffect,
useRef,
} from "react";
import { useForm, useFormContext } from "react-hook-form"; import { useForm, useFormContext } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
@ -19,7 +25,10 @@ import {
VIEW_SELF_EXPENSE, VIEW_SELF_EXPENSE,
} from "../../utils/constants"; } from "../../utils/constants";
import { defaultFilter, SearchSchema } from "../../components/Expenses/ExpenseSchema"; import {
defaultFilter,
SearchSchema,
} from "../../components/Expenses/ExpenseSchema";
import PreviewDocument from "../../components/Expenses/PreviewDocument"; import PreviewDocument from "../../components/Expenses/PreviewDocument";
// Context // Context
@ -102,14 +111,14 @@ const ExpensePage = () => {
setManageExpenseModal, setManageExpenseModal,
setDocumentView, setDocumentView,
filterData, filterData,
removeFilterChip removeFilterChip,
}; };
return ( return (
<ExpenseContext.Provider value={contextValue}> <ExpenseContext.Provider value={contextValue}>
<div className="container-fluid"> <div className="container-fluid">
<Breadcrumb <Breadcrumb
data={[{ label: "Home", link: "/" }, { label: "Expense" }]} data={[{ label: "Home", link: "/dashboard" }, { label: "Expense" }]}
/> />
{IsViewAll || IsViewSelf || IsCreatedAble ? ( {IsViewAll || IsViewSelf || IsCreatedAble ? (
@ -128,7 +137,6 @@ const ExpensePage = () => {
</div> </div>
<div className="col-6 text-end mt-2 mt-sm-0"> <div className="col-6 text-end mt-2 mt-sm-0">
{IsCreatedAble && ( {IsCreatedAble && (
<button <button
className="btn btn-sm btn-primary" className="btn btn-sm btn-primary"
@ -151,8 +159,6 @@ const ExpensePage = () => {
</div> </div>
</div> </div>
<ExpenseList <ExpenseList
filters={filters} filters={filters}
groupBy={groupBy} groupBy={groupBy}

View File

@ -36,11 +36,10 @@ export const useGalleryContext = () => {
}; };
const ImageGalleryPage = () => { const ImageGalleryPage = () => {
const [filter,setFilter] = useState() const [filter, setFilter] = useState();
const selectedProjectId = useSelectedProject(); const selectedProjectId = useSelectedProject();
const { projectNames } = useProjectName(); const { projectNames } = useProjectName();
const [openGallery, setOpenGallery] = useState({ isOpen: false, data: null }); const [openGallery, setOpenGallery] = useState({ isOpen: false, data: null });
const { data: assignedServices = [], isLoading } = const { data: assignedServices = [], isLoading } =
@ -60,20 +59,22 @@ const ImageGalleryPage = () => {
useEffect(() => { useEffect(() => {
setShowTrigger(true); setShowTrigger(true);
setOffcanvasContent("Gallery Filter",<GalleryFilterPanel onApply={setFilter}/>); setOffcanvasContent(
"Gallery Filter",
<GalleryFilterPanel onApply={setFilter} />
);
return () => { return () => {
setOffcanvasContent("",null) setOffcanvasContent("", null);
setShowTrigger(false); setShowTrigger(false);
} };
},[]) }, []);
return ( return (
<GalleryContext.Provider value={contextMessager}> <GalleryContext.Provider value={contextMessager}>
<div className="container-fluid"> <div className="container-fluid">
<Breadcrumb <Breadcrumb
data={[{ label: "Home", link: "/" }, { label: "Gallery" }]} data={[{ label: "Home", link: "/dashboard" }, { label: "Gallery" }]}
/> />
<div className="card page-min-h p-2"> <div className="card page-min-h p-2">

View File

@ -6,12 +6,15 @@ import OrganizationsList from "../../components/Organization/OrganizationsList";
const OrganizationPage = () => { const OrganizationPage = () => {
const { isOpen, orgData, startStep, onOpen, flowType } = const { isOpen, orgData, startStep, onOpen, flowType } =
useOrganizationModal(); useOrganizationModal();
const [searchText, setSearchText] = useState("") const [searchText, setSearchText] = useState("");
return ( return (
<div className="container-fluid"> <div className="container-fluid">
<Breadcrumb <Breadcrumb
data={[{ label: "Home", link: "/" }, { label: "Organizations" }]} data={[
{ label: "Home", link: "/dashboard" },
{ label: "Organizations" },
]}
/> />
<div className="card my-3 px-sm-4 px-0"> <div className="card my-3 px-sm-4 px-0">
<div className="card-body py-2 px-3"> <div className="card-body py-2 px-3">
@ -42,14 +45,11 @@ const OrganizationPage = () => {
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div className="card page-min-h px-sm-4"> <div className="card page-min-h px-sm-4">
<OrganizationsList searchText={searchText} /> <OrganizationsList searchText={searchText} />
</div> </div>
</div> </div>
); );
}; };

View File

@ -6,7 +6,10 @@ import ExpenseFilterPanel from "../../components/Expenses/ExpenseFilterPanel";
import { useFab } from "../../Context/FabContext"; import { useFab } from "../../Context/FabContext";
import PaymentRequestList from "../../components/PaymentRequest/PaymentRequestList"; import PaymentRequestList from "../../components/PaymentRequest/PaymentRequestList";
import PaymentRequestFilterPanel from "../../components/PaymentRequest/PaymentRequestFilterPanel"; import PaymentRequestFilterPanel from "../../components/PaymentRequest/PaymentRequestFilterPanel";
import { defaultPaymentRequestFilter,SearchPaymentRequestSchema } from "../../components/PaymentRequest/PaymentRequestSchema"; import {
defaultPaymentRequestFilter,
SearchPaymentRequestSchema,
} from "../../components/PaymentRequest/PaymentRequestSchema";
import ViewPaymentRequest from "../../components/PaymentRequest/ViewPaymentRequest"; import ViewPaymentRequest from "../../components/PaymentRequest/ViewPaymentRequest";
import PreviewDocument from "../../components/Expenses/PreviewDocument"; import PreviewDocument from "../../components/Expenses/PreviewDocument";
import MakeExpense from "../../components/PaymentRequest/MakeExpense"; import MakeExpense from "../../components/PaymentRequest/MakeExpense";
@ -15,7 +18,9 @@ export const PaymentRequestContext = createContext();
export const usePaymentRequestContext = () => { export const usePaymentRequestContext = () => {
const context = useContext(PaymentRequestContext); const context = useContext(PaymentRequestContext);
if (!context) { if (!context) {
throw new Error("usePaymentRequestContext must be used within an ExpenseProvider"); throw new Error(
"usePaymentRequestContext must be used within an ExpenseProvider"
);
} }
return context; return context;
}; };
@ -24,16 +29,21 @@ const PaymentRequestPage = () => {
IsOpen: null, IsOpen: null,
RequestId: null, RequestId: null,
}); });
const [ViewRequest,setVieRequest] = useState({view:false,requestId:null}) const [ViewRequest, setVieRequest] = useState({
view: false,
requestId: null,
});
const { setOffcanvasContent, setShowTrigger } = useFab(); const { setOffcanvasContent, setShowTrigger } = useFab();
const [filters, setFilters] = useState(defaultPaymentRequestFilter); const [filters, setFilters] = useState(defaultPaymentRequestFilter);
const [ViewDocument, setDocumentView] = useState({ const [ViewDocument, setDocumentView] = useState({
IsOpen: false, IsOpen: false,
Image: null, Image: null,
}); });
const [isExpenseGenerate,setIsExpenseGenerate] = useState({IsOpen: null, const [isExpenseGenerate, setIsExpenseGenerate] = useState({
RequestId: null,}) IsOpen: null,
const [modalSize,setModalSize] = useState("md") RequestId: null,
});
const [modalSize, setModalSize] = useState("md");
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const contextValue = { const contextValue = {
@ -42,11 +52,10 @@ const PaymentRequestPage = () => {
setDocumentView, setDocumentView,
setModalSize, setModalSize,
setIsExpenseGenerate, setIsExpenseGenerate,
isExpenseGenerate isExpenseGenerate,
}; };
useEffect(() => { useEffect(() => {
setShowTrigger(true); setShowTrigger(true);
setOffcanvasContent( setOffcanvasContent(
"Payment Request Filters", "Payment Request Filters",
@ -65,7 +74,7 @@ const PaymentRequestPage = () => {
{/* Breadcrumb */} {/* Breadcrumb */}
<Breadcrumb <Breadcrumb
data={[ data={[
{ label: "Home", link: "/" }, { label: "Home", link: "/dashboard" },
{ label: "Finance", link: "/Payment Request" }, { label: "Finance", link: "/Payment Request" },
{ label: "Payment Request" }, { label: "Payment Request" },
]} ]}
@ -106,10 +115,7 @@ const PaymentRequestPage = () => {
</div> </div>
</div> </div>
</div> </div>
<PaymentRequestList <PaymentRequestList search={search} filters={filters} />
search={search}
filters={filters}
/>
{/* Add/Edit Modal */} {/* Add/Edit Modal */}
{ManageRequest.IsOpen && ( {ManageRequest.IsOpen && (
@ -144,10 +150,16 @@ const PaymentRequestPage = () => {
<GlobalModel <GlobalModel
isOpen isOpen
size="md" size="md"
closeModal={() => setIsExpenseGenerate({IsOpen:false, requestId: null})} closeModal={() =>
setIsExpenseGenerate({ IsOpen: false, requestId: null })
}
> >
<MakeExpe <MakeExpe
nse onClose={() => setIsExpenseGenerate({IsOpen:false, requestId: null})} /> nse
onClose={() =>
setIsExpenseGenerate({ IsOpen: false, requestId: null })
}
/>
</GlobalModel> </GlobalModel>
)} )}
@ -161,7 +173,6 @@ const PaymentRequestPage = () => {
<PreviewDocument imageUrl={ViewDocument.Image} /> <PreviewDocument imageUrl={ViewDocument.Image} />
</GlobalModel> </GlobalModel>
)} )}
</div> </div>
</PaymentRequestContext.Provider> </PaymentRequestContext.Provider>
); );

View File

@ -101,7 +101,7 @@ const CollectionPage = () => {
) { ) {
return ( return (
<AccessDenied <AccessDenied
data={[{ label: "Home", link: "/" }, { label: "Collection" }]} data={[{ label: "Home", link: "/dashboard" }, { label: "Collection" }]}
/> />
); );
} }
@ -109,7 +109,10 @@ const CollectionPage = () => {
<CollectionContext.Provider value={contextMassager}> <CollectionContext.Provider value={contextMassager}>
<div className="container-fluid"> <div className="container-fluid">
<Breadcrumb <Breadcrumb
data={[{ label: "Home", link: "/" }, { label: "Collection" }]} data={[
{ label: "Home", link: "/dashboard" },
{ label: "Collection" },
]}
/> />
<div className="card my-3 py-2 px-sm-4 px-2"> <div className="card my-3 py-2 px-sm-4 px-2">
@ -117,7 +120,8 @@ const CollectionPage = () => {
{/* Left side: Date Picker + Show Pending (stacked on mobile) */} {/* Left side: Date Picker + Show Pending (stacked on mobile) */}
<div className="col-12 col-md-6 d-flex flex-column flex-md-row flex-wrap align-items-start align-md-items-center gap-2 gap-md-3 mb-3 mb-md-0"> <div className="col-12 col-md-6 d-flex flex-column flex-md-row flex-wrap align-items-start align-md-items-center gap-2 gap-md-3 mb-3 mb-md-0">
<FormProvider {...methods}> <FormProvider {...methods}>
<DateRangePicker1 howManyDay={180} /> <DateRangePicker1 howManyDay={180} startField="fromDate"
endField="toDate" />
</FormProvider> </FormProvider>
<div className="form-check form-switch d-flex align-items-center mt-1"> <div className="form-check form-switch d-flex align-items-center mt-1">
@ -152,16 +156,18 @@ const CollectionPage = () => {
<button <button
className="btn btn-sm btn-primary" className="btn btn-sm btn-primary"
type="button" type="button"
onClick={() => setCollection({ isOpen: true, invoiceId: null })} onClick={() =>
setCollection({ isOpen: true, invoiceId: null })
}
> >
<i className="bx bx-plus-circle me-2"></i> <i className="bx bx-plus-circle me-2"></i>
<span className="d-none d-md-inline-block">Add New Collection</span> <span className="d-none d-md-inline-block">
Add New Collection
</span>
</button> </button>
)} )}
</div> </div>
</div> </div>
</div> </div>
<CollectionList <CollectionList

View File

@ -2,7 +2,7 @@ import React, { useState, useEffect, useCallback } from "react";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import ProjectOverview from "../../components/Project/ProjectOverview"; import ProjectOverview from "../../components/Project/ProjectStatistics";
import AboutProject from "../../components/Project/AboutProject"; import AboutProject from "../../components/Project/AboutProject";
import ProjectNav from "../../components/Project/ProjectNav"; import ProjectNav from "../../components/Project/ProjectNav";
import Teams from "../../components/Project/Team/Teams"; import Teams from "../../components/Project/Team/Teams";
@ -15,7 +15,7 @@ import { useProjectDetails, useProjectName } from "../../hooks/useProjects";
import { ComingSoonPage } from "../Misc/ComingSoonPage"; import { ComingSoonPage } from "../Misc/ComingSoonPage";
import eventBus from "../../services/eventBus"; import eventBus from "../../services/eventBus";
import ProjectProgressChart from "../../components/Dashboard/ProjectProgressChart"; import ProjectProgressChart from "../../components/Dashboard/ProjectProgressChart";
import AttendanceOverview from "../../components/Dashboard/AttendanceChart"; import AttendanceOverview from "../../components/Dashboard/AttendanceOverview";
import { setProjectId } from "../../slices/localVariablesSlice"; import { setProjectId } from "../../slices/localVariablesSlice";
import ProjectDocuments from "../../components/Project/ProjectDocuments"; import ProjectDocuments from "../../components/Project/ProjectDocuments";
import ProjectSetting from "../../components/Project/ProjectSetting"; import ProjectSetting from "../../components/Project/ProjectSetting";

View File

@ -7,17 +7,37 @@ export const CollectionRepository = {
updateCollection: (id, data) => { updateCollection: (id, data) => {
api.put(`/api/Collection/invoice/edit/${id}`, data) api.put(`/api/Collection/invoice/edit/${id}`, data)
}, },
getCollections: (pageSize, pageNumber,fromDate,toDate, isPending,isActive,projectId, searchString) => { // getCollections: (pageSize, pageNumber,fromDate,toDate, isPending,isActive,projectId, searchString) => {
let url = `/api/Collection/invoice/list?pageSize=${pageSize}&pageNumber=${pageNumber}&isPending=${isPending}&isActive=${isActive}&searchString=${searchString}`; // let url = `/api/Collection/invoice/list?pageSize=${pageSize}&pageNumber=${pageNumber}&isPending=${isPending}&isActive=${isActive}&searchString=${searchString}`;
// const params = [];
// if (fromDate) params.push(`fromDate=${fromDate}`);
// if (toDate) params.push(`toDate=${toDate}`);
// if(projectId) params.push(`projectId=${projectId}`)
// if (params.length > 0) {
// url += `&${params.join("&")}`;
// }
// return api.get(url);
// },
getCollections: (projectId, searchString, fromDate, toDate, pageSize, pageNumber, isActive, isPending) => {
let url = `/api/Collection/invoice/list`;
const params = []; const params = [];
if (fromDate) params.push(`fromDate=${fromDate}`);
if (toDate) params.push(`toDate=${toDate}`); if (projectId) params.push(`projectId=${projectId}`);
if(projectId) params.push(`projectId=${projectId}`) if (searchString) params.push(`search=${searchString}`);
if (fromDate) params.push(`dateFrom=${fromDate}`);
if (toDate) params.push(`dateTo=${toDate}`);
if (pageSize) params.push(`pageSize=${pageSize}`);
if (pageNumber) params.push(`pageNumber=${pageNumber}`);
if (isActive) params.push(`isActive=${isActive}`);
if (isPending) params.push(`isPending=${isPending}`);
if (params.length > 0) { if (params.length > 0) {
url += `&${params.join("&")}`; url += "?" + params.join("&");
} }
return api.get(url); return api.get(url);
}, },

View File

@ -1,7 +1,7 @@
import { api } from "../utils/axiosClient"; import { api } from "../utils/axiosClient";
const ProjectRepository = { const ProjectRepository = {
getProjectList: (pageSize,pageNumber) => api.get(`/api/project/list?pageSize=${pageSize}&pageNumber=${pageNumber}`), getProjectList: (pageNumber,pageSize) => api.get(`/api/project/list?&pageNumber=${pageNumber}&pageSize=${pageSize}`),
getProjectByprojectId: (projetid) => getProjectByprojectId: (projetid) =>
api.get(`/api/project/details/${projetid}`), api.get(`/api/project/details/${projetid}`),