Skip to main content

Functional Specification: Voucher Tabs Data Filtering Logic

Last Updated: 16/07/2026
Type: Functional Specification Change — Voucher Filtering Logic
Screen: My Vouchers (VoucherScreen) — Tab Navigation ("Chưa sử dụng", "Quà tặng", "Đã sử dụng", "Hết hạn")

Feedback Screenshot:


1. Overview & Current Issue

The My Vouchers screen segments vouchers into 4 tabs:

  1. Chưa sử dụng (Unused)
  2. Quà tặng (Gifts)
  3. Đã sử dụng (Used)
  4. Hết hạn (Expired)

Current Bug / Misalignment:

Currently, vouchers won from the Lucky Spin (Vòng quay may mắn) are only displayed in the "Quà tặng" tab. The "Chưa sử dụng" tab remains completely empty.

This violates the natural expectations of a user, who opens "Chưa sử dụng" expecting to see all active, unredeemed vouchers they own.


2. Correct Business Filtering Logic

The data mapping and filtering logic for the 4 tabs must be refactored as follows:

┌──────────────────────────────┐
│ All Active Vouchers │
│ (API: status=active) │
└──────────────┬───────────────┘

┌───────────────────────┴───────────────────────┐
▼ ▼
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│ Tab: "Chưa sử dụng" │ │ Tab: "Quà tặng" │
├─────────────────────────────────┤ ├─────────────────────────────────┤
│ Displays ALL active, unredeemed │ │ Filters only vouchers issued as │
│ vouchers, regardless of source │ │ gifts (Lucky Spin, Marketing │
│ (Marketing, Lucky Spin, Point │ │ campaign gifts, Birthday gifts) │
│ Redemptions, etc.) │ │ │
└─────────────────────────────────┘ └─────────────────────────────────┘

Detailed Tab Specifications

Tab LabelBusiness RuleBackend Filters / Mapping criteria
Chưa sử dụng
(Unused)
"All Active Vouchers"
Must display every single voucher that is currently valid and unredeemed.
status === 'active' AND expiredAt > NOW()
Quà tặng
(Gifts)
"Gift Vouchers Only"
Displays active, unredeemed vouchers whose source/type is categorized as a gift.
status === 'active' AND expiredAt > NOW() AND sourceType IN ('lucky_spin', 'marketing_gift', 'birthday')
Đã sử dụng
(Used)
"Redeemed Vouchers"
History of used vouchers.
status === 'used'
Hết hạn
(Expired)
"Expired Vouchers"
History of expired, unused vouchers.
status === 'active' AND expiredAt <= NOW()

3. Code Implementation Spec (React Native)

Modify the selector or local state filtering rules in VoucherScreen.tsx:

// Define Voucher types
interface Voucher {
id: string;
code: string;
templateId: string;
status: 'active' | 'used';
expiredAt: string; // ISO String
sourceType: 'marketing_gift' | 'lucky_spin' | 'point_redemption' | 'purchase' | 'birthday';
}

// Data filtering logic in component:
const filterVouchersByTab = (vouchers: Voucher[]) => {
const now = new Date();

// 1. Unused Tab: ALL unredeemed and non-expired vouchers
const unusedVouchers = vouchers.filter(
(v) => v.status === 'active' && new Date(v.expiredAt) > now
);

// 2. Gifts Tab: Active unused vouchers from gift sources
const giftSources = ['lucky_spin', 'marketing_gift', 'birthday'];
const giftVouchers = vouchers.filter(
(v) => v.status === 'active' &&
new Date(v.expiredAt) > now &&
giftSources.includes(v.sourceType)
);

// 3. Used Tab
const usedVouchers = vouchers.filter((v) => v.status === 'used');

// 4. Expired Tab: Active status but past expiration timestamp
const expiredVouchers = vouchers.filter(
(v) => v.status === 'active' && new Date(v.expiredAt) <= now
);

return {
unused: unusedVouchers,
gifts: giftVouchers,
used: usedVouchers,
expired: expiredVouchers,
};
};

Technical Checklist

  • Locate the voucher list page view (VoucherScreen.tsx).
  • Inspect the state or Redux selector delivering vouchers to the tabs.
  • Refactor the "Chưa sử dụng" tab dataset to include all active vouchers (including those where sourceType === 'lucky_spin').
  • Refactor the "Quà tặng" tab dataset to display only vouchers won from campaigns, lucky spin, or birthday rewards.
  • Test case:
    • Account has 1 marketing voucher and 1 lucky spin voucher.
    • Open "Chưa sử dụng" tab → verify both vouchers are listed.
    • Open "Quà tặng" tab → verify only the lucky spin voucher is listed.
  • Verify count badges on tabs (if any) update to reflect the corrected filtering rules.