From e0e5577ea8e642abc678ce96bd5ebb3567f540ac Mon Sep 17 00:00:00 2001 From: Yared Yemane Date: Tue, 9 Jun 2026 05:12:52 -0700 Subject: [PATCH] feat(admin): expand payments list filters to match admin API Add currency and reference query params plus full status chips on the payments page so filtering aligns with GET /admin/payments. Co-authored-by: Cursor --- src/api/payments.api.ts | 8 +- src/pages/payments/PaymentsPage.tsx | 135 ++++++++++++++++++++++++++-- src/types/payment.types.ts | 5 ++ 3 files changed, 139 insertions(+), 9 deletions(-) diff --git a/src/api/payments.api.ts b/src/api/payments.api.ts index 860e0bd..2a956a0 100644 --- a/src/api/payments.api.ts +++ b/src/api/payments.api.ts @@ -82,8 +82,14 @@ function buildQueryParams(params: GetPaymentsParams): Record("") const [providerFilter, setProviderFilter] = useState("") const [planCategoryFilter, setPlanCategoryFilter] = useState("") + const [currencyInput, setCurrencyInput] = useState("") + const [referenceInput, setReferenceInput] = useState("") + const [currencyFilter, setCurrencyFilter] = useState("") + const [referenceFilter, setReferenceFilter] = useState("") const [selected, setSelected] = useState(null) + useEffect(() => { + const timer = window.setTimeout(() => { + setCurrencyFilter(currencyInput.trim().toUpperCase()) + }, TEXT_FILTER_DEBOUNCE_MS) + return () => window.clearTimeout(timer) + }, [currencyInput]) + + useEffect(() => { + const timer = window.setTimeout(() => { + setReferenceFilter(referenceInput.trim()) + }, TEXT_FILTER_DEBOUNCE_MS) + return () => window.clearTimeout(timer) + }, [referenceInput]) + + useEffect(() => { + setOffset(0) + }, [currencyFilter, referenceFilter]) + const listFilters: PaymentListFilters = { status: statusFilter, provider: providerFilter, planCategory: planCategoryFilter, + currency: currencyFilter, + reference: referenceFilter, } const hasActiveFilters = Boolean( - listFilters.status || listFilters.provider || listFilters.planCategory, + listFilters.status || + listFilters.provider || + listFilters.planCategory || + listFilters.currency || + listFilters.reference, ) const fetchPayments = useCallback( @@ -105,6 +143,8 @@ export function PaymentsPage() { ...(filters.status ? { status: filters.status } : {}), ...(filters.provider ? { provider: filters.provider } : {}), ...(filters.planCategory ? { plan_category: filters.planCategory } : {}), + ...(filters.currency ? { currency: filters.currency } : {}), + ...(filters.reference ? { reference: filters.reference } : {}), }) setPayments(res.data.payments) setTotalCount(res.data.total_count) @@ -123,7 +163,16 @@ export function PaymentsPage() { useEffect(() => { void fetchPayments(offset, pageSize, listFilters) - }, [offset, pageSize, statusFilter, providerFilter, planCategoryFilter, fetchPayments]) + }, [ + offset, + pageSize, + statusFilter, + providerFilter, + planCategoryFilter, + currencyFilter, + referenceFilter, + fetchPayments, + ]) const toggleStatus = (value: PaymentStatus) => { setStatusFilter((current) => (current === value ? "" : value)) @@ -144,6 +193,10 @@ export function PaymentsPage() { setStatusFilter("") setProviderFilter("") setPlanCategoryFilter("") + setCurrencyInput("") + setReferenceInput("") + setCurrencyFilter("") + setReferenceFilter("") setOffset(0) } @@ -271,19 +324,85 @@ export function PaymentsPage() { onClick={() => togglePlanCategory(value)} /> ))} - {hasActiveFilters ? ( + +
+
+ +
+ setCurrencyInput(e.target.value)} + placeholder="e.g. ETB" + disabled={loading} + className="h-9 rounded-[6px] border-grayScale-200 pr-8 text-sm uppercase" + /> + {currencyInput ? ( + + ) : null} +
+
+
+ +
+ + setReferenceInput(e.target.value)} + placeholder="Session, nonce, or transaction ID" + disabled={loading} + className="h-9 rounded-[6px] border-grayScale-200 pl-8 pr-8 text-sm" + /> + {referenceInput ? ( + + ) : null} +
+

+ Partial match on session ID, nonce, or transaction ID +

+
+
+ {hasActiveFilters ? ( +
- ) : null} -
+ + ) : null} {loading ? ( diff --git a/src/types/payment.types.ts b/src/types/payment.types.ts index 751a0e5..ea5aa32 100644 --- a/src/types/payment.types.ts +++ b/src/types/payment.types.ts @@ -54,8 +54,13 @@ export interface PaymentsListResponse { export interface GetPaymentsParams { status?: PaymentStatus + /** Takes precedence over `payment_method` when both are sent. */ provider?: PaymentProvider + payment_method?: PaymentMethod plan_category?: PaymentPlanCategory + currency?: string + /** Partial match on session_id, nonce, or transaction_id. */ + reference?: string limit?: number offset?: number }