integrated collection mang. completely
This commit is contained in:
parent
95c6e71be8
commit
394d28f80d
@ -1,27 +1,53 @@
|
||||
import { useState } from 'react';
|
||||
import { useState } from "react";
|
||||
|
||||
const PreviewDocument = ({ imageUrl }) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [rotation, setRotation] = useState(0);
|
||||
|
||||
return (
|
||||
<div className="d-flex justify-content-center align-items-center" style={{ minHeight: "50vh" }}>
|
||||
<>
|
||||
<div className="d-flex justify-content-start">
|
||||
<i
|
||||
className="bx bx-rotate-right cursor-pointer"
|
||||
onClick={() => setRotation((prev) => prev + 90)}
|
||||
></i>
|
||||
</div>
|
||||
<div
|
||||
className="position-relative d-flex flex-column justify-content-center align-items-center"
|
||||
style={{ minHeight: "80vh" }}
|
||||
>
|
||||
|
||||
{loading && (
|
||||
<div className="text-secondary text-center mb-2">
|
||||
Loading...
|
||||
</div>
|
||||
<div className="text-secondary text-center mb-2">Loading...</div>
|
||||
)}
|
||||
<img
|
||||
src={imageUrl}
|
||||
alt="Full View"
|
||||
className="img-fluid"
|
||||
style={{
|
||||
maxHeight: "100vh",
|
||||
objectFit: "contain",
|
||||
display: loading ? "none" : "block",
|
||||
}}
|
||||
onLoad={() => setLoading(false)}
|
||||
/>
|
||||
|
||||
<div className="mb-3 d-flex justify-content-center align-items-center">
|
||||
<img
|
||||
src={imageUrl}
|
||||
alt="Full View"
|
||||
className="img-fluid"
|
||||
style={{
|
||||
maxHeight: "80vh",
|
||||
objectFit: "contain",
|
||||
display: loading ? "none" : "block",
|
||||
transform: `rotate(${rotation}deg)`,
|
||||
transition: "transform 0.3s ease",
|
||||
}}
|
||||
onLoad={() => setLoading(false)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="position-absolute bottom-0 start-0 justify-content-center gap-2">
|
||||
<button
|
||||
className="btn btn-outline-secondary"
|
||||
onClick={() => setRotation(0)}
|
||||
title="Reset Rotation"
|
||||
>
|
||||
<i className="bx bx-reset"></i> Reset
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
211
src/components/collections/CollectionSkeleton.jsx
Normal file
211
src/components/collections/CollectionSkeleton.jsx
Normal file
@ -0,0 +1,211 @@
|
||||
import React from "react";
|
||||
|
||||
const SkeletonLine = ({ height = 20, width = "100%", className = "" }) => (
|
||||
<div
|
||||
className={`skeleton mb-2 ${className}`}
|
||||
style={{
|
||||
height,
|
||||
width,
|
||||
}}
|
||||
></div>
|
||||
);
|
||||
|
||||
export const PaymentHistorySkeleton = ({ count = 2 }) => {
|
||||
return (
|
||||
<div className="row text-start">
|
||||
{[...Array(count)].map((_, idx) => (
|
||||
<div className="col-12 mb-2" key={idx}>
|
||||
<div className="p-2 border-start border-warning">
|
||||
{/* Top Row: Date + Amount */}
|
||||
<div className="d-flex justify-content-between align-items-center">
|
||||
<SkeletonLine width="150px" height={18} /> {/* Date */}
|
||||
<SkeletonLine width="100px" height={18} /> {/* Amount */}
|
||||
</div>
|
||||
|
||||
<div className="row mt-1">
|
||||
{/* Transaction ID */}
|
||||
<div className="col-12 col-md-6">
|
||||
<SkeletonLine width="80%" height={16} />
|
||||
</div>
|
||||
|
||||
{/* Received By (Avatar + Name) */}
|
||||
<div className="col-12 col-md-6 d-flex align-items-center gap-2">
|
||||
<SkeletonLine
|
||||
width="30px"
|
||||
height={30}
|
||||
className="rounded-circle"
|
||||
/>{" "}
|
||||
{/* Avatar */}
|
||||
<SkeletonLine width="120px" height={16} /> {/* Name */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const CollectionDetailsSkeleton = () => {
|
||||
return (
|
||||
<div className="container p-3">
|
||||
{/* Title */}
|
||||
<SkeletonLine height={24} width="200px" className="mx-auto" />
|
||||
|
||||
{/* Header Row */}
|
||||
<div className="row mb-3 px-1">
|
||||
<div className="col-10">
|
||||
<SkeletonLine height={20} />
|
||||
</div>
|
||||
<div className="col-2 d-flex justify-content-end">
|
||||
<SkeletonLine height={20} width="60px" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Project */}
|
||||
<div className="row mb-3">
|
||||
<div className="col-md-6">
|
||||
<SkeletonLine width="60%" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Invoice & E-Invoice */}
|
||||
<div className="row mb-3">
|
||||
<div className="col-md-6">
|
||||
<SkeletonLine />
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<SkeletonLine />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Invoice Date & Client Submitted */}
|
||||
<div className="row mb-3">
|
||||
<div className="col-md-6">
|
||||
<SkeletonLine />
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<SkeletonLine />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Expected Payment & Mark as Completed */}
|
||||
<div className="row mb-3">
|
||||
<div className="col-md-6">
|
||||
<SkeletonLine />
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<SkeletonLine width="40%" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Basic & Tax Amount */}
|
||||
<div className="row mb-3">
|
||||
<div className="col-md-6">
|
||||
<SkeletonLine />
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<SkeletonLine />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Balance & Created At */}
|
||||
<div className="row mb-3">
|
||||
<div className="col-md-6">
|
||||
<SkeletonLine />
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<SkeletonLine />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Created By */}
|
||||
<div className="row mb-3">
|
||||
<div className="col-md-6 d-flex align-items-center">
|
||||
<SkeletonLine
|
||||
width="40px"
|
||||
height={40}
|
||||
className="me-2 rounded-circle"
|
||||
/>
|
||||
<SkeletonLine width="100px" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<div className="row mb-3">
|
||||
<div className="col-12">
|
||||
<SkeletonLine height={50} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Attachments */}
|
||||
<div className="row mb-3">
|
||||
<div className="col-12 d-flex gap-2 flex-wrap">
|
||||
{[...Array(3)].map((_, idx) => (
|
||||
<SkeletonLine key={idx} height={60} width="80px" />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tabs */}
|
||||
<div className="row mb-2">
|
||||
<div className="col-12 d-flex gap-2">
|
||||
<SkeletonLine height={35} width="120px" />
|
||||
<SkeletonLine height={35} width="150px" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tab Content (Comments / Payments) */}
|
||||
<SkeletonLine height={200} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const CollectionTableSkeleton = () => {
|
||||
const columnCount = 8;
|
||||
|
||||
return (
|
||||
<div className="card ">
|
||||
<div
|
||||
className="card-datatable table-responsive page-min-h"
|
||||
id="horizontal-example"
|
||||
>
|
||||
<div className="dataTables_wrapper no-footer mx-5 pb-2">
|
||||
<table className="table dataTable text-nowrap">
|
||||
<thead>
|
||||
<tr >
|
||||
{[...Array(columnCount - 1)].map((_, i) => (
|
||||
<th key={i}>
|
||||
<SkeletonLine height={15} width="80px" />
|
||||
</th>
|
||||
))}
|
||||
<th className="d-flex justify-content-center">
|
||||
<SkeletonLine height={16} width="40px" />
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{[...Array(8)].map((_, rowIdx) => (
|
||||
<tr key={rowIdx}>
|
||||
{[...Array(columnCount - 1)].map((_, colIdx) => (
|
||||
<td key={colIdx}>
|
||||
<SkeletonLine height={33} />
|
||||
</td>
|
||||
))}
|
||||
<td className="d-flex justify-content-center">
|
||||
<SkeletonLine height={16} width="20px" />
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{/* Pagination Skeleton */}
|
||||
<div className="d-flex justify-content-end mt-2">
|
||||
<SkeletonLine height={30} width="200px" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -16,6 +16,7 @@ import ManageDocumentCategory from "./ManageDocumentCategory";
|
||||
import ManageDocumentType from "./ManageDocumentType";
|
||||
import ManageServices from "./Services/ManageServices";
|
||||
import ServiceGroups from "./Services/ServicesGroups";
|
||||
import ManagePaymentHead from "./paymentAdjustmentHead/ManagePaymentHead";
|
||||
|
||||
const MasterModal = ({ modaldata, closeModal }) => {
|
||||
if (!modaldata?.modalType || modaldata.modalType === "delete") {
|
||||
@ -67,6 +68,8 @@ const MasterModal = ({ modaldata, closeModal }) => {
|
||||
"Manage-Services": (
|
||||
<ServiceGroups service={item} onClose={closeModal}/>
|
||||
),
|
||||
"Payment Adjustment Head": <ManagePaymentHead onClose={closeModal} />,
|
||||
"Edit-Payment Adjustment Head": <ManagePaymentHead data={item} onClose={closeModal} />
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@ -0,0 +1,107 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import Label from "../../common/Label";
|
||||
import { useCreatePaymentAjustmentHead, useUpdatePaymentAjustmentHead } from "../../../hooks/masterHook/useMaster";
|
||||
|
||||
export const simpleFormSchema = z.object({
|
||||
name: z.string().min(1, "Name is required"),
|
||||
description: z.string().min(1, "Description is required"),
|
||||
});
|
||||
|
||||
const ManagePaymentHead = ({ data, onClose }) => {
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { errors },
|
||||
} = useForm({
|
||||
resolver: zodResolver(simpleFormSchema),
|
||||
defaultValues: {
|
||||
name: "",
|
||||
description: "",
|
||||
},
|
||||
});
|
||||
|
||||
const {mutate:CreateAjustmentHead,isPending} = useCreatePaymentAjustmentHead(()=>{
|
||||
handleClose?.()
|
||||
});
|
||||
const {mutate:UpdateAjustmentHead,isPending:isUpdating} = useUpdatePaymentAjustmentHead(()=>{
|
||||
handleClose?.()
|
||||
})
|
||||
const onSubmit = (formData) => {
|
||||
if(data){
|
||||
let id = data?.id;
|
||||
const payload = {
|
||||
...formData,
|
||||
id:id,
|
||||
}
|
||||
UpdateAjustmentHead({id:id,payload:payload})
|
||||
}else{
|
||||
let payload={
|
||||
...formData
|
||||
}
|
||||
CreateAjustmentHead(payload)
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
reset({
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
});
|
||||
}
|
||||
}, [data]);
|
||||
const handleClose = () => {
|
||||
reset();
|
||||
onClose();
|
||||
};
|
||||
return (
|
||||
<div className="row text-start">
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="p-4">
|
||||
<div className="mb-3">
|
||||
<Label htmlFor="name" required>
|
||||
Name
|
||||
</Label>
|
||||
<input
|
||||
type="text"
|
||||
{...register("name")}
|
||||
className={`form-control ${errors.name ? "is-invalid" : ""}`}
|
||||
/>
|
||||
{errors.name && (
|
||||
<div className="invalid-feedback">{errors.name.message}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<Label htmlFor="description" required>
|
||||
Description
|
||||
</Label>
|
||||
<textarea
|
||||
{...register("description")}
|
||||
className={`form-control ${errors.description ? "is-invalid" : ""}`}
|
||||
/>
|
||||
{errors.description && (
|
||||
<div className="invalid-feedback">{errors.description.message}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="d-flex flex-row justify-content-end gap-2">
|
||||
<button
|
||||
className="btn btn-sm btn-label-secondary"
|
||||
onClick={handleClose} disabled={isUpdating || isPending}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button type="submit" className="btn btn-sm btn-primary" disabled={isUpdating || isPending}>
|
||||
{isPending || isUpdating ? "Please Wait" :data ? "Update":"Submit"}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ManagePaymentHead;
|
||||
@ -10,6 +10,14 @@ import {
|
||||
} from "@tanstack/react-query";
|
||||
import showToast from "../../services/toastService";
|
||||
|
||||
export const usePaymentAjustmentHead = (isActive) => {
|
||||
return useQuery({
|
||||
queryKey: ["paymentType", isActive],
|
||||
queryFn: async () =>
|
||||
await MasterRespository.getPaymentAdjustmentHead(isActive),
|
||||
});
|
||||
};
|
||||
|
||||
export const useServices = () => {
|
||||
return useQuery({
|
||||
queryKey: ["services"],
|
||||
@ -30,7 +38,6 @@ export const useActivitiesByGroups = (groupId) => {
|
||||
queryFn: async () => await MasterRespository.getActivitesByGroup(groupId),
|
||||
|
||||
enabled: !!groupId,
|
||||
|
||||
});
|
||||
};
|
||||
export const useGlobalServices = () => {
|
||||
@ -296,6 +303,8 @@ const fetchMasterData = async (masterType) => {
|
||||
return (await MasterRespository.getDocumentTypes()).data;
|
||||
case "Document Category":
|
||||
return (await MasterRespository.getDocumentCategories()).data;
|
||||
case "Payment Adjustment Head":
|
||||
return (await MasterRespository.getPaymentAdjustmentHead(true)).data;
|
||||
case "Status":
|
||||
return [
|
||||
{
|
||||
@ -448,8 +457,6 @@ export const useUpdateApplicationRole = (onSuccessCallback) => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
//-----Create work Category-------------------------------
|
||||
export const useCreateWorkCategory = (onSuccessCallback) => {
|
||||
const queryClient = useQueryClient();
|
||||
@ -719,7 +726,12 @@ export const useCreateService = (onSuccessCallback) => {
|
||||
},
|
||||
onError: (error) => {
|
||||
debugger;
|
||||
showToast( error?.response?.data?.message || error?.message || "Something went wrong", "error");
|
||||
showToast(
|
||||
error?.response?.data?.message ||
|
||||
error?.message ||
|
||||
"Something went wrong",
|
||||
"error"
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
@ -742,7 +754,12 @@ export const useUpdateService = (onSuccessCallback) => {
|
||||
if (onSuccessCallback) onSuccessCallback(data);
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(error?.response?.data?.message || error?.message || "Something went wrong", "error");
|
||||
showToast(
|
||||
error?.response?.data?.message ||
|
||||
error?.message ||
|
||||
"Something went wrong",
|
||||
"error"
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
@ -759,16 +776,23 @@ export const useCreateActivityGroup = (onSuccessCallback) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["groups"],
|
||||
});
|
||||
debugger
|
||||
showToast( data?.message ||
|
||||
data?.response?.data?.message || "Activity Group created successfully.",
|
||||
debugger;
|
||||
showToast(
|
||||
data?.message ||
|
||||
data?.response?.data?.message ||
|
||||
"Activity Group created successfully.",
|
||||
"success"
|
||||
);
|
||||
|
||||
if (onSuccessCallback) onSuccessCallback(data);
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(error?.response?.data?.message || error?.message || "Something went wrong", "error");
|
||||
showToast(
|
||||
error?.response?.data?.message ||
|
||||
error?.message ||
|
||||
"Something went wrong",
|
||||
"error"
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
@ -776,8 +800,8 @@ export const useUpdateActivityGroup = (onSuccessCallback) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({id,payload}) => {
|
||||
const response = await MasterRespository.updateActivityGrop(id,payload);
|
||||
mutationFn: async ({ id, payload }) => {
|
||||
const response = await MasterRespository.updateActivityGrop(id, payload);
|
||||
return response;
|
||||
},
|
||||
onSuccess: (data, variables) => {
|
||||
@ -787,7 +811,8 @@ export const useUpdateActivityGroup = (onSuccessCallback) => {
|
||||
|
||||
showToast(
|
||||
data?.message ||
|
||||
data?.response?.data?.message|| "Activity Group Updated successfully.",
|
||||
data?.response?.data?.message ||
|
||||
"Activity Group Updated successfully.",
|
||||
"success"
|
||||
);
|
||||
|
||||
@ -813,7 +838,12 @@ export const useCreateActivity = (onSuccessCallback) => {
|
||||
if (onSuccessCallback) onSuccessCallback(data);
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(error?.response?.data?.message || error?.message || "Something went wrong", "error");
|
||||
showToast(
|
||||
error?.response?.data?.message ||
|
||||
error?.message ||
|
||||
"Something went wrong",
|
||||
"error"
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
@ -835,7 +865,12 @@ export const useUpdateActivity = (onSuccessCallback) => {
|
||||
if (onSuccessCallback) onSuccessCallback(data);
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(error?.response?.data?.message || error?.message || "Something went wrong", "error");
|
||||
showToast(
|
||||
error?.response?.data?.message ||
|
||||
error?.message ||
|
||||
"Something went wrong",
|
||||
"error"
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
@ -969,6 +1004,52 @@ export const useUpdateDocumentType = (onSuccessCallback) => {
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// ==============================Payment Adjustment Head =============================
|
||||
export const useCreatePaymentAjustmentHead = (onSuccessCallback) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (payload) => {
|
||||
const resp = await MasterRespository.createPaymentAjustmentHead(payload);
|
||||
return resp.data;
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["masterData", "Payment Adjustment Head"],
|
||||
});
|
||||
showToast("Payment Ajustment Head successfully", "success");
|
||||
if (onSuccessCallback) onSuccessCallback(data);
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(error.message || "Something went wrong", "error");
|
||||
},
|
||||
});
|
||||
};
|
||||
export const useUpdatePaymentAjustmentHead = (onSuccessCallback) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({ id, payload }) => {
|
||||
const resp = await MasterRespository.updatePaymentAjustmentHead(
|
||||
id,
|
||||
payload
|
||||
);
|
||||
return resp.data;
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["masterData", "Payment Adjustment Head"],
|
||||
});
|
||||
showToast("Payment Ajustment Head Updated successfully", "success");
|
||||
if (onSuccessCallback) onSuccessCallback(data);
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(error.message || "Something went wrong", "error");
|
||||
},
|
||||
});
|
||||
};
|
||||
// ====================x=x====================x=x==================================
|
||||
// -Delete Master --------
|
||||
export const useDeleteMasterItem = () => {
|
||||
const queryClient = useQueryClient();
|
||||
@ -1002,14 +1083,12 @@ export const useDeleteMasterItem = () => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
export const useDeleteServiceGroup =()=>{
|
||||
const queryClient = useQueryClient();
|
||||
export const useDeleteServiceGroup = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (id)=>await MasterRespository.deleteActivityGroup(id),
|
||||
onSuccess: ({_,variable}) => {
|
||||
|
||||
mutationFn: async (id) => await MasterRespository.deleteActivityGroup(id),
|
||||
onSuccess: ({ _, variable }) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["groups"] });
|
||||
|
||||
showToast(`Group deleted successfully.`, "success");
|
||||
@ -1023,15 +1102,13 @@ export const useDeleteServiceGroup =()=>{
|
||||
showToast(message, "error");
|
||||
},
|
||||
});
|
||||
}
|
||||
export const useDeleteActivity =()=>{
|
||||
const queryClient = useQueryClient();
|
||||
};
|
||||
export const useDeleteActivity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (id)=>await MasterRespository.deleteActivity(id),
|
||||
onSuccess: ({_,variable}) => {
|
||||
|
||||
|
||||
mutationFn: async (id) => await MasterRespository.deleteActivity(id),
|
||||
onSuccess: ({ _, variable }) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["activties"] });
|
||||
|
||||
showToast(`Acivity deleted successfully.`, "success");
|
||||
@ -1045,4 +1122,4 @@ export const useDeleteActivity =()=>{
|
||||
showToast(message, "error");
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
152
src/hooks/useCollections.jsx
Normal file
152
src/hooks/useCollections.jsx
Normal file
@ -0,0 +1,152 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { CollectionRepository } from "../repositories/ColllectionRepository";
|
||||
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 useCollection =(collectionId)=>{
|
||||
return useQuery({
|
||||
queryKey:["collection",collectionId],
|
||||
queryFn:async()=> {
|
||||
const resp = await CollectionRepository.getCollection(collectionId);
|
||||
return resp.data
|
||||
},
|
||||
enabled:!!collectionId
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// =========================Mutation======================
|
||||
|
||||
export const useCreateCollection = (onSuccessCallBack) => {
|
||||
const clinent = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async (payload) =>
|
||||
await CollectionRepository.createNewCollection(payload),
|
||||
onSuccess: (_, variables) => {
|
||||
showToast("New Collection created Successfully", "success");
|
||||
clinent.invalidateQueries({ queryKey: ["collections"] });
|
||||
if (onSuccessCallBack) onSuccessCallBack();
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(
|
||||
error.response.data.message || error.message || "Something Went wrong"
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useMarkedPaymentReceived = (onSuccessCallBack) => {
|
||||
const client = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async (payload) =>
|
||||
await CollectionRepository.markPaymentReceived(payload),
|
||||
onSuccess: async () => {
|
||||
client.invalidateQueries({ queryKey: ["collections"] });
|
||||
showToast("Payment Received marked Successfully", "success");
|
||||
if (onSuccessCallBack) onSuccessCallBack();
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(
|
||||
error.response.data.message || error.message || "Something Went wrong"
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useAddPayment = (onSuccessCallBack) => {
|
||||
const client = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (payload) => CollectionRepository.makeReceivePayment(payload),
|
||||
onSuccess: () => {
|
||||
client.invalidateQueries({ queryKey: ["collections"] });
|
||||
client.invalidateQueries({ queryKey: ["collection"] });
|
||||
showToast("Payment Received marked Successfully", "success");
|
||||
if (onSuccessCallBack) onSuccessCallBack();
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(
|
||||
error?.response?.data?.message || error.message || "Something Went wrong"
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useAddComment = (onSuccessCallBack) => {
|
||||
const client = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (payload) => CollectionRepository.addComment(payload),
|
||||
onSuccess: () => {
|
||||
client.invalidateQueries({ queryKey: ["collections"] });
|
||||
client.invalidateQueries({ queryKey: ["collection"] });
|
||||
showToast("Comment Successfully", "success");
|
||||
if (onSuccessCallBack) onSuccessCallBack();
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(
|
||||
error?.response?.data?.message || error.message || "Something Went wrong"
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateCollection =(onSuccessCallBack)=>{
|
||||
const client = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn:async({collectionId,payload})=> await CollectionRepository.updateCollection(collectionId,payload),
|
||||
onSuccess: () => {
|
||||
client.invalidateQueries({ queryKey: ["collections"] });
|
||||
client.invalidateQueries({ queryKey: ["collection"] });
|
||||
showToast("Collection Updated Successfully", "success");
|
||||
if (onSuccessCallBack) onSuccessCallBack();
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(
|
||||
error?.response?.data?.message || error.message || "Something Went wrong"
|
||||
);
|
||||
},
|
||||
})
|
||||
}
|
||||
29
src/repositories/ColllectionRepository.jsx
Normal file
29
src/repositories/ColllectionRepository.jsx
Normal file
@ -0,0 +1,29 @@
|
||||
import { api } from "../utils/axiosClient";
|
||||
import { DirectoryRepository } from "./DirectoryRepository";
|
||||
|
||||
export const CollectionRepository = {
|
||||
createNewCollection: (data) =>
|
||||
api.post(`/api/Collection/invoice/create`, data),
|
||||
updateCollection:(id,data)=>{
|
||||
api.put(`/api/Collection/invoice/edit/${id}`,data)
|
||||
},
|
||||
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}`;
|
||||
|
||||
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);
|
||||
},
|
||||
|
||||
makeReceivePayment:(data)=> api.post(`/api/Collection/invoice/payment/received`,data),
|
||||
markPaymentReceived:(invoiceId)=>api.put(`/api/Collection/invoice/marked/completed/${invoiceId}`),
|
||||
getCollection:(id)=>api.get(`/api/Collection/invoice/details/${id}`),
|
||||
addComment:(data)=>api.post(`/api/Collection/invoice/add/comment`,data)
|
||||
};
|
||||
|
||||
@ -58,6 +58,11 @@ export const MasterRespository = {
|
||||
"Document Type": (id) => api.delete(`/api/Master/document-type/delete/${id}`),
|
||||
"Document Category": (id) =>
|
||||
api.delete(`/api/Master/document-category/delete/${id}`),
|
||||
"Payment Adjustment Head": (id, isActive) =>
|
||||
api.delete(
|
||||
`/api/Master/payment-adjustment-head/delete/${id}`,
|
||||
(isActive = false)
|
||||
),
|
||||
|
||||
getWorkCategory: () => api.get(`/api/master/work-categories`),
|
||||
createWorkCategory: (data) => api.post(`/api/master/work-category`, data),
|
||||
@ -124,10 +129,16 @@ export const MasterRespository = {
|
||||
api.put(`/api/Master/activity-group/edit/${serviceId}`, data),
|
||||
getActivitesByGroup: (activityGroupId) =>
|
||||
api.get(`api/master/activities?activityGroupId=${activityGroupId}`),
|
||||
deleteActivityGroup:(id)=>api.delete(`/api/Master/activity-group/delete/${id}`),
|
||||
deleteActivityGroup: (id) =>
|
||||
api.delete(`/api/Master/activity-group/delete/${id}`),
|
||||
|
||||
|
||||
deleteActivity:(id)=>api.delete(`/api/Master/activity/delete/${id}`),
|
||||
deleteActivity: (id) => api.delete(`/api/Master/activity/delete/${id}`),
|
||||
|
||||
getOrganizationType: () => api.get("/api/Master/organization-type/list"),
|
||||
getPaymentAdjustmentHead: (isActive) =>
|
||||
api.get(`/api/Master/payment-adjustment-head/list?isActive=${isActive}`),
|
||||
createPaymentAjustmentHead: (data) =>
|
||||
api.post(`/api/Master/payment-adjustment-head`, data),
|
||||
updatePaymentAjustmentHead: (id, data) =>
|
||||
api.put(`/api/Master/payment-adjustment-head/edit/${id}`, data),
|
||||
};
|
||||
|
||||
@ -107,3 +107,31 @@ export const formatCurrency = (amount, currency = "INR", locale = "en-US") => {
|
||||
export const countDigit = (num) => {
|
||||
return Math.abs(num).toString().length;
|
||||
};
|
||||
export const formatFigure = (
|
||||
amount,
|
||||
{
|
||||
type = "number",
|
||||
currency = "INR",
|
||||
locale = "en-US",
|
||||
notation = "standard", // standard or compact
|
||||
compactDisplay = "short",
|
||||
minimumFractionDigits = 0,
|
||||
maximumFractionDigits = 2,
|
||||
} = {}
|
||||
) => {
|
||||
if (amount == null || isNaN(amount)) return "-";
|
||||
|
||||
const formatterOptions = {
|
||||
style: type === "currency" ? "currency" : type === "percent" ? "percent" : "decimal",
|
||||
notation: notation,
|
||||
compactDisplay,
|
||||
minimumFractionDigits,
|
||||
maximumFractionDigits,
|
||||
};
|
||||
|
||||
if (type === "currency") {
|
||||
formatterOptions.currency = currency;
|
||||
}
|
||||
|
||||
return new Intl.NumberFormat(locale, formatterOptions).format(amount);
|
||||
};
|
||||
@ -1,12 +1,13 @@
|
||||
export const BASE_URL = process.env.VITE_BASE_URL;
|
||||
|
||||
// export const BASE_URL = "https://api.marcoaiot.com";
|
||||
|
||||
|
||||
export const THRESH_HOLD = 48; // hours
|
||||
export const DURATION_TIME = 10; // minutes
|
||||
export const ITEMS_PER_PAGE = 20;
|
||||
export const OTP_EXPIRY_SECONDS = 300; // OTP time
|
||||
|
||||
export const BASE_URL = process.env.VITE_BASE_URL;
|
||||
|
||||
// export const BASE_URL = "https://api.marcoaiot.com";
|
||||
|
||||
export const MANAGE_MASTER = "588a8824-f924-4955-82d8-fc51956cf323";
|
||||
|
||||
export const VIEW_MASTER = "5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d";
|
||||
@ -49,7 +50,7 @@ export const DIRECTORY_ADMIN = "4286a13b-bb40-4879-8c6d-18e9e393beda";
|
||||
export const DIRECTORY_MANAGER = "62668630-13ce-4f52-a0f0-db38af2230c5";
|
||||
|
||||
export const DIRECTORY_USER = "0f919170-92d4-4337-abd3-49b66fc871bb";
|
||||
// ========================Finance=========================================================
|
||||
|
||||
// -----------------------Expense----------------------------------------
|
||||
export const VIEW_SELF_EXPENSE = "385be49f-8fde-440e-bdbc-3dffeb8dd116";
|
||||
|
||||
@ -65,6 +66,15 @@ export const PROCESS_EXPENSE = "ea5a1529-4ee8-4828-80ea-0e23c9d4dd11";
|
||||
|
||||
export const EXPENSE_MANAGE = "ea5a1529-4ee8-4828-80ea-0e23c9d4dd11";
|
||||
|
||||
export const EXPENSE_REJECTEDBY = [
|
||||
"d1ee5eec-24b6-4364-8673-a8f859c60729",
|
||||
"965eda62-7907-4963-b4a1-657fb0b2724b",
|
||||
];
|
||||
|
||||
|
||||
|
||||
export const EXPENSE_DRAFT = "297e0d8f-f668-41b5-bfea-e03b354251c8";
|
||||
|
||||
// --------------------------------Collection----------------------------
|
||||
|
||||
export const ADMIN_COLLECTION = "dbf17591-09fe-4c93-9e1a-12db8f5cc5de";
|
||||
@ -73,15 +83,6 @@ export const CREATE_COLLECTION = "b93141fd-dbd3-4051-8f57-bf25d18e3555";
|
||||
export const EDIT_COLLECTION = "455187b4-fef1-41f9-b3d0-025d0b6302c3";
|
||||
export const ADDPAYMENT_COLLECTION = "061d9ccd-85b4-4cb0-be06-2f9f32cebb72";
|
||||
|
||||
// ==========================================================================================
|
||||
|
||||
export const EXPENSE_REJECTEDBY = [
|
||||
"d1ee5eec-24b6-4364-8673-a8f859c60729",
|
||||
"965eda62-7907-4963-b4a1-657fb0b2724b",
|
||||
];
|
||||
|
||||
export const EXPENSE_DRAFT = "297e0d8f-f668-41b5-bfea-e03b354251c8";
|
||||
|
||||
// ----------------------------Tenant-------------------------
|
||||
export const SUPPER_TENANT = "d032cb1a-3f30-462c-bef0-7ace73a71c0b";
|
||||
export const MANAGE_TENANTS = "00e20637-ce8d-4417-bec4-9b31b5e65092";
|
||||
@ -154,4 +155,25 @@ export const PROJECT_STATUS = [
|
||||
label: "Completed",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
export const EXPENSE_STATUS = {
|
||||
daft:"297e0d8f-f668-41b5-bfea-e03b354251c8",
|
||||
review_pending:"6537018f-f4e9-4cb3-a210-6c3b2da999d7",
|
||||
payment_pending:"f18c5cfd-7815-4341-8da2-2c2d65778e27",
|
||||
approve_pending:"4068007f-c92f-4f37-a907-bc15fe57d4d8",
|
||||
|
||||
}
|
||||
|
||||
export const UUID_REGEX =
|
||||
/^\/employee\/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
||||
|
||||
export const ALLOW_PROJECTSTATUS_ID = [
|
||||
"603e994b-a27f-4e5d-a251-f3d69b0498ba",
|
||||
"cdad86aa-8a56-4ff4-b633-9c629057dfef",
|
||||
"b74da4c2-d07e-46f2-9919-e75e49b12731",
|
||||
];
|
||||
|
||||
export const DEFAULT_EMPTY_STATUS_ID = "00000000-0000-0000-0000-000000000000";
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user