From 785f97b26d0baea2f1db6fc0aae1e0f632908372 Mon Sep 17 00:00:00 2001 From: hosseintaromi Date: Sun, 8 Feb 2026 12:55:28 +0330 Subject: [PATCH] feat(discount-reports): enhance discount usage reporting with additional filters and improved query parameters - Added new filter options for status, type, application level, and sorting in discount usage reports. - Updated API request parameters to align with new filter capabilities. - Refactored pagination logic to improve clarity and accuracy in displaying total items and pages. - Enhanced the sidebar layout for better organization and usability. These changes significantly improve the reporting functionality and user experience in the discount statistics section. --- src/components/layout/Sidebar.tsx | 90 +++++++++---------- .../discount-statistics/core/_models.ts | 33 ++++--- .../discount-statistics/core/_requests.ts | 24 +++-- .../DiscountUsageReportPage.tsx | 17 ++-- 4 files changed, 96 insertions(+), 68 deletions(-) diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index cd8b21b..d0db9a7 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -355,56 +355,56 @@ export const Sidebar = ({ isOpen, onClose }: SidebarProps) => { w-64 transform transition-transform duration-300 ease-in-out lg:translate-x-0 lg:block ${isOpen ? 'translate-x-0' : 'translate-x-full lg:translate-x-0'} - flex flex-col h-screen bg-white dark:bg-gray-800 border-l border-gray-200 dark:border-gray-700 shadow-lg lg:shadow-none + h-screen bg-white dark:bg-gray-800 border-l border-gray-200 dark:border-gray-700 shadow-lg lg:shadow-none `}> - {/* Mobile close button */} -
- - پنل مدیریت - - -
- - {/* Logo - desktop only */} -
- - پنل مدیریت - -
- - {/* Navigation - scrollable */} - - - {/* User Info - fixed at bottom */} -
-
-
- - {user?.first_name?.[0]}{user?.last_name?.[0]} - -
-
- - {user?.first_name} {user?.last_name} - - - {user?.username} - -
+
+
+ + پنل مدیریت +
+ +
+ + پنل مدیریت + +
+ +
+ +
+ +
+
+
+ + {user?.first_name?.[0]}{user?.last_name?.[0]} + +
+
+ + {user?.first_name} {user?.last_name} + + + {user?.username} + +
+ +
+
diff --git a/src/pages/reports/discount-statistics/core/_models.ts b/src/pages/reports/discount-statistics/core/_models.ts index 3fae728..aec013c 100644 --- a/src/pages/reports/discount-statistics/core/_models.ts +++ b/src/pages/reports/discount-statistics/core/_models.ts @@ -1,6 +1,6 @@ export interface DateRange { - from?: string; // ISO 8601 - to?: string; // ISO 8601 + from?: string; + to?: string; } export interface DiscountUsageFilters { @@ -8,6 +8,13 @@ export interface DiscountUsageFilters { discount_code?: string; discount_id?: number; user_id?: number; + status?: "active" | "inactive" | "expired"; + type?: "percentage" | "fixed" | "fee_percentage"; + application_level?: "invoice" | "category" | "product" | "shipping" | "product_fee"; + min_usage_count?: number; + include_unused?: boolean; + sort_by?: "usage_count" | "amount" | "date" | "code" | "created_at"; + sort_order?: "asc" | "desc"; group_by_code?: boolean; limit: number; offset: number; @@ -18,15 +25,15 @@ export interface DiscountUsage { discount_code: string; discount_name: string; usage_count: number; - total_amount: number; // ریال + total_amount: number; unique_users: number; - first_used_at: string; // ISO 8601 - last_used_at: string; // ISO 8601 + first_used_at: string; + last_used_at: string; } export interface DiscountUsageSummary { total_usages: number; - total_discount_given: number; // ریال + total_discount_given: number; unique_users: number; unique_codes: number; most_used_code: string; @@ -43,10 +50,14 @@ export interface DiscountUsageResponse { } export interface CustomerDiscountUsageFilters { - user_id: number; // Required + user_id?: number; + phone_number?: string; date_range?: DateRange; discount_code?: string; discount_id?: number; + status?: "active" | "inactive" | "expired"; + sort_by?: "date" | "amount" | "code"; + sort_order?: "asc" | "desc"; limit: number; offset: number; } @@ -60,15 +71,15 @@ export interface CustomerDiscountUsage { discount_name: string; order_id: number; order_number: string; - amount: number; // ریال - used_at: string; // ISO 8601 + amount: number; + used_at: string; } export interface CustomerDiscountUsageSummary { total_usages: number; - total_discount_amount: number; // ریال + total_discount_amount: number; unique_codes: number; - average_discount_per_order: number; // ریال + average_discount_per_order: number; } export interface CustomerDiscountUsageResponse { diff --git a/src/pages/reports/discount-statistics/core/_requests.ts b/src/pages/reports/discount-statistics/core/_requests.ts index e20270f..08573a9 100644 --- a/src/pages/reports/discount-statistics/core/_requests.ts +++ b/src/pages/reports/discount-statistics/core/_requests.ts @@ -12,17 +12,25 @@ export const getDiscountUsageReport = async ( ): Promise => { const queryParams: Record = {}; - if (filters.date_range?.from) queryParams.from = filters.date_range.from; - if (filters.date_range?.to) queryParams.to = filters.date_range.to; + queryParams.view_mode = "simple"; + if (filters.date_range?.from) queryParams.from_date = filters.date_range.from; + if (filters.date_range?.to) queryParams.to_date = filters.date_range.to; if (filters.discount_code) queryParams.discount_code = filters.discount_code; if (filters.discount_id !== undefined) queryParams.discount_id = filters.discount_id; if (filters.user_id !== undefined) queryParams.user_id = filters.user_id; if (filters.group_by_code !== undefined) queryParams.group_by_code = filters.group_by_code; + if (filters.status) queryParams.status = filters.status; + if (filters.type) queryParams.type = filters.type; + if (filters.application_level) queryParams.application_level = filters.application_level; + if (filters.min_usage_count !== undefined) queryParams.min_usage_count = filters.min_usage_count; + if (filters.include_unused !== undefined) queryParams.include_unused = filters.include_unused; + if (filters.sort_by) queryParams.sort_by = filters.sort_by; + if (filters.sort_order) queryParams.sort_order = filters.sort_order; if (filters.limit !== undefined) queryParams.limit = filters.limit; if (filters.offset !== undefined) queryParams.offset = filters.offset; const response = await httpGetRequest( - APIUrlGenerator(API_ROUTES.DISCOUNT_USAGE_REPORT, queryParams) + APIUrlGenerator(API_ROUTES.DISCOUNT_REPORTS, queryParams) ); return response.data; }; @@ -32,11 +40,15 @@ export const getCustomerDiscountUsageReport = async ( ): Promise => { const queryParams: Record = {}; - queryParams.user_id = filters.user_id; - if (filters.date_range?.from) queryParams.from = filters.date_range.from; - if (filters.date_range?.to) queryParams.to = filters.date_range.to; + if (filters.user_id !== undefined) queryParams.user_id = filters.user_id; + if (filters.phone_number) queryParams.phone_number = filters.phone_number; + if (filters.date_range?.from) queryParams.from_date = filters.date_range.from; + if (filters.date_range?.to) queryParams.to_date = filters.date_range.to; if (filters.discount_code) queryParams.discount_code = filters.discount_code; if (filters.discount_id !== undefined) queryParams.discount_id = filters.discount_id; + if (filters.status) queryParams.status = filters.status; + if (filters.sort_by) queryParams.sort_by = filters.sort_by; + if (filters.sort_order) queryParams.sort_order = filters.sort_order; if (filters.limit !== undefined) queryParams.limit = filters.limit; if (filters.offset !== undefined) queryParams.offset = filters.offset; diff --git a/src/pages/reports/discount-statistics/discount-usage-report/DiscountUsageReportPage.tsx b/src/pages/reports/discount-statistics/discount-usage-report/DiscountUsageReportPage.tsx index 09d7687..115897a 100644 --- a/src/pages/reports/discount-statistics/discount-usage-report/DiscountUsageReportPage.tsx +++ b/src/pages/reports/discount-statistics/discount-usage-report/DiscountUsageReportPage.tsx @@ -111,8 +111,13 @@ const DiscountUsageReportPage = () => { last_used_at: formatDateTime(usage.last_used_at), })); - const currentPage = Math.floor(filters.offset / filters.limit) + 1; - const totalPages = data ? Math.ceil(data.total / filters.limit) : 1; + const limit = filters.limit; + const offset = filters.offset; + const currentPage = Math.floor(offset / limit) + 1; + const totalItems = typeof data?.total === 'number' + ? data.total + : offset + (data?.usages?.length || 0) + (data?.has_more ? 1 : 0); + const totalPages = Math.max(1, Math.ceil(totalItems / limit)); return ( @@ -299,19 +304,19 @@ const DiscountUsageReportPage = () => { - {data && data.total > 0 && (data.total > filters.limit || data.has_more) && ( + {data && totalItems > limit && (
)} - {data && data.total === 0 && ( + {data && totalItems === 0 && (

داده‌ای یافت نشد