From b13034a995dae823c3b454bdaf0d75bb223082d6 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Thu, 13 Nov 2025 15:14:07 +0530 Subject: [PATCH 01/10] Expense widget - Layout change --- src/components/Project/ProjectOverview.jsx | 138 ++++++++++----------- src/components/collections/AddPayment.jsx | 2 +- 2 files changed, 70 insertions(+), 70 deletions(-) diff --git a/src/components/Project/ProjectOverview.jsx b/src/components/Project/ProjectOverview.jsx index ee665144..7a8bd59e 100644 --- a/src/components/Project/ProjectOverview.jsx +++ b/src/components/Project/ProjectOverview.jsx @@ -133,10 +133,10 @@ const ProjectOverview = ({ project }) => { }, }, stroke: { - lineCap: "round", + lineCap: "round", }, - labels: ["Progress"], - series: [percentage], + labels: ["Progress"], + series: [percentage], }; }; const [radialPercentage, setRadialPercentage] = useState(75); // Initial percentage @@ -165,7 +165,7 @@ const ProjectOverview = ({ project }) => { }, [selectedProject]); return ( -
+
{" "} @@ -173,75 +173,75 @@ const ProjectOverview = ({ project }) => { Project Statistics
-
-
    -
  • -
    - {/* Centered Chart */} -
    -
    - -
    -
    - - {/* Info Section */} -
    -
    - {/* Tasks Planned */} -
    -
    - - - +
    +
      +
    • +
      + {/* Centered Chart */} +
      +
      + +
      -
      - Tasks Planned -
      - {FormattedNumber(current_project?.plannedWork)} -
      + + {/* Info Section */} +
      +
      + {/* Tasks Planned */} +
      +
      + + + +
      +
      + Tasks Planned +
      + {FormattedNumber(current_project?.plannedWork)} +
      +
      +
      + + {/* Tasks Completed */} +
      +
      + + + +
      +
      + Tasks Completed +
      + {FormattedNumber(current_project?.completedWork)} +
      +
      +
      + + {/* Team Size */} +
      +
      + + + +
      +
      + Current Team Size +
      + {FormattedNumber(current_project?.teamSize)} +
      +
      +
      +
      - - {/* Tasks Completed */} -
      -
      - - - -
      -
      - Tasks Completed -
      - {FormattedNumber(current_project?.completedWork)} -
      -
      -
      - - {/* Team Size */} -
      -
      - - - -
      -
      - Current Team Size -
      - {FormattedNumber(current_project?.teamSize)} -
      -
      -
      -
      -
    +
  • +
- - -
); diff --git a/src/components/collections/AddPayment.jsx b/src/components/collections/AddPayment.jsx index a47200ee..1ad641b8 100644 --- a/src/components/collections/AddPayment.jsx +++ b/src/components/collections/AddPayment.jsx @@ -72,7 +72,7 @@ const AddPayment = ({ onClose }) => {
- Date: Thu, 13 Nov 2025 17:22:54 +0530 Subject: [PATCH 02/10] UI implementation has been done in Expense --- src/components/Dashboard/Dashboard.jsx | 2 +- src/components/Dashboard/ExpenseAnalysis.jsx | 96 +++++++++++--------- src/components/Dashboard/ExpenseStatus.jsx | 4 +- 3 files changed, 54 insertions(+), 48 deletions(-) diff --git a/src/components/Dashboard/Dashboard.jsx b/src/components/Dashboard/Dashboard.jsx index 3d0f0a66..84e97fd6 100644 --- a/src/components/Dashboard/Dashboard.jsx +++ b/src/components/Dashboard/Dashboard.jsx @@ -57,7 +57,7 @@ const Dashboard = () => {
-
+
diff --git a/src/components/Dashboard/ExpenseAnalysis.jsx b/src/components/Dashboard/ExpenseAnalysis.jsx index 1fe27fae..6026ba20 100644 --- a/src/components/Dashboard/ExpenseAnalysis.jsx +++ b/src/components/Dashboard/ExpenseAnalysis.jsx @@ -7,11 +7,12 @@ import { FormProvider, useForm } from "react-hook-form"; import { formatCurrency, localToUtc } from "../../utils/appUtils"; import { useProjectName } from "../../hooks/useProjects"; import { SpinnerLoader } from "../common/Loader"; +import flatColors from "../Charts/flatColor"; const ExpenseAnalysis = () => { const projectId = useSelectedProject(); const [projectName, setProjectName] = useState("All Project"); - const { projectNames, loading } = useProjectName(); + const { projectNames } = useProjectName(); const methods = useForm({ defaultValues: { startDate: "", endDate: "" }, @@ -50,7 +51,7 @@ const ExpenseAnalysis = () => { labels, legend: { show: false }, dataLabels: { enabled: true, formatter: (val) => `${val.toFixed(0)}%` }, - colors: ["#7367F0", "#28C76F", "#FF9F43", "#EA5455", "#00CFE8", "#FF78B8"], + colors: flatColors, plotOptions: { pie: { donut: { @@ -79,22 +80,19 @@ const ExpenseAnalysis = () => { return ( <> -
-
+
Expense Breakdown
- {/*

Category Wise Expense Breakdown

*/}

{projectName}

-
+
- {/* Card body */}
{isLoading && (
{
)} - {!isLoading && report.length > 0 && ( <> {isFetching && ( @@ -123,50 +120,59 @@ const ExpenseAnalysis = () => {
)} -
- -
+
+ {/* Chart Column */} +
+ +
-
-
- {report.map((item, idx) => ( -
-
- - - + {/* Data/Legend Column */} +
+
+ {report.map((item, idx) => ( +
+
+ + {item.projectName} + + + {formatCurrency(item.totalApprovedAmount)} + +
-
- {item.projectName} - - {formatCurrency(item.totalApprovedAmount)} - -
-
- ))} + + ))} +
)}
- - {/* Header */} - ); }; diff --git a/src/components/Dashboard/ExpenseStatus.jsx b/src/components/Dashboard/ExpenseStatus.jsx index d6fefe7d..86a4fd8d 100644 --- a/src/components/Dashboard/ExpenseStatus.jsx +++ b/src/components/Dashboard/ExpenseStatus.jsx @@ -103,7 +103,7 @@ const ExpenseStatus = () => {
= 3 ? "text-xl" : "text-2xl" + className={`text-royalblue ${countDigit(item?.count || 0) >= 3 ? "text-xl" : "text-xl" } text-gray-500`} > {item?.count || 0} @@ -137,7 +137,7 @@ const ExpenseStatus = () => {
3 ? "text-" : "text-3xl" + className={`text-end text-royalblue ${countDigit(data?.totalAmount || 0) > 3 ? "text-xl" : "text-3xl" } text-md`} > {formatCurrency(data?.totalAmount || 0)} From 598601c515169f04d1df0559eda77c2ad3cfc145 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 14 Nov 2025 10:22:27 +0530 Subject: [PATCH 03/10] We are creating filter chips in the Payment Request filter panel. --- .../PaymentRequestFilterChips.jsx | 60 ++++++++++++++ .../PaymentRequestFilterPanel.jsx | 43 ++++++++-- .../PaymentRequest/PaymentRequestList.jsx | 38 +++------ .../PaymentRequest/PaymentRequestPage.jsx | 83 +++++++++++-------- 4 files changed, 156 insertions(+), 68 deletions(-) create mode 100644 src/components/PaymentRequest/PaymentRequestFilterChips.jsx diff --git a/src/components/PaymentRequest/PaymentRequestFilterChips.jsx b/src/components/PaymentRequest/PaymentRequestFilterChips.jsx new file mode 100644 index 00000000..201b75f9 --- /dev/null +++ b/src/components/PaymentRequest/PaymentRequestFilterChips.jsx @@ -0,0 +1,60 @@ +import React, { useMemo } from "react"; + +const PaymentRequestFilterChips = ({ filters, filterData, removeFilterChip, clearFilter }) => { + const data = filterData?.data || filterData || {}; + + const filterChips = useMemo(() => { + const chips = []; + + const addGroup = (ids, list, label, key) => { + if (!ids?.length) return; + const items = ids.map((id) => ({ + id, + name: list?.find((i) => i.id === id)?.name || id, + })); + chips.push({ key, label, items }); + }; + + addGroup(filters.createdByIds, data.createdBy, "Created By", "createdByIds"); + addGroup(filters.currencyIds, data.currency, "Currency", "currencyIds"); + addGroup(filters.expenseCategoryIds, data.expenseCategory, "Expense Category", "expenseCategoryIds"); + addGroup(filters.payees, data.payees, "Payees", "payees"); + addGroup(filters.projectIds, data.projects, "Projects", "projectIds"); + addGroup(filters.statusIds, data.status, "Status", "statusIds"); + + return chips; + }, [filters, filterData]); + + if (!filterChips.length) return null; + + return ( +
+ {filterChips.map((chipGroup) => ( +
+ {chipGroup.label}: + {chipGroup.items.map((item) => ( + + {item.name} +
+ ))} + +
+ ); +}; + +export default PaymentRequestFilterChips; diff --git a/src/components/PaymentRequest/PaymentRequestFilterPanel.jsx b/src/components/PaymentRequest/PaymentRequestFilterPanel.jsx index 65d788e9..9bbd24da 100644 --- a/src/components/PaymentRequest/PaymentRequestFilterPanel.jsx +++ b/src/components/PaymentRequest/PaymentRequestFilterPanel.jsx @@ -1,7 +1,7 @@ -import React, { useEffect, useState, useMemo } from "react"; +import React, { useEffect, useState, useMemo, forwardRef, useImperativeHandle } from "react"; import { FormProvider, useForm, Controller } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; -import { defaultPaymentRequestFilter,SearchPaymentRequestSchema } from "./PaymentRequestSchema"; +import { defaultPaymentRequestFilter, SearchPaymentRequestSchema } from "./PaymentRequestSchema"; import DateRangePicker, { DateRangePicker1 } from "../common/DateRangePicker"; import SelectMultiple from "../common/SelectMultiple"; @@ -13,7 +13,7 @@ import moment from "moment"; import { usePaymentRequestFilter } from "../../hooks/useExpense"; import { useLocation, useNavigate, useParams } from "react-router-dom"; -const PaymentRequestFilterPanel = ({ onApply, handleGroupBy }) => { +const PaymentRequestFilterPanel = forwardRef(({ onApply, handleGroupBy, setFilterdata, clearFilter }, ref) => { const { status } = useParams(); const navigate = useNavigate(); const selectedProjectId = useSelector( @@ -38,10 +38,23 @@ const PaymentRequestFilterPanel = ({ onApply, handleGroupBy }) => { const [selectedGroup, setSelectedGroup] = useState(groupByList[6]); const [resetKey, setResetKey] = useState(0); + const dynamicDefaultFilter = useMemo(() => { + return { + ...defaultPaymentRequestFilter, + projectIds: defaultPaymentRequestFilter.projectIds || [], + statusIds: status ? [status] : defaultPaymentRequestFilter.statusIds || [], + createdByIds: defaultPaymentRequestFilter.createdByIds || [], + currencyIds: defaultPaymentRequestFilter.currencyIds || [], + expenseCategoryIds: defaultPaymentRequestFilter.expenseCategoryIds || [], + payees: defaultPaymentRequestFilter.payees || [], + startDate: defaultPaymentRequestFilter.startDate, + endDate: defaultPaymentRequestFilter.endDate, + }; + }, [status, selectedProjectId]); const methods = useForm({ resolver: zodResolver(SearchPaymentRequestSchema), - defaultValues: defaultPaymentRequestFilter, + defaultValues: dynamicDefaultFilter, }); const { control, handleSubmit, reset, setValue, watch } = methods; @@ -52,12 +65,28 @@ const PaymentRequestFilterPanel = ({ onApply, handleGroupBy }) => { }; - const handleGroupChange = (e) => { const group = groupByList.find((g) => g.id === e.target.value); if (group) setSelectedGroup(group); }; + useImperativeHandle(ref, () => ({ + resetFieldValue: (name, value) => { + // Reset specific field + if (value !== undefined) { + setValue(name, value); + } else { + reset({ ...methods.getValues(), [name]: defaultFilter[name] }); + } + }, + getValues: methods.getValues, // optional, to read current filter state + })); + + useEffect(() => { + if (data && setFilterdata) { + setFilterdata(data); + } + }, [data, setFilterdata]); const onSubmit = (formData) => { onApply({ @@ -179,7 +208,7 @@ const PaymentRequestFilterPanel = ({ onApply, handleGroupBy }) => { ))}
-
+