Implemented complete Coupons list page following PROJECT_SOP.md Created: CouponsApi helper (lib/api/coupons.ts) - TypeScript interfaces for Coupon and CouponFormData - Full CRUD methods: list, get, create, update, delete - Pagination and filtering support Updated: Coupons/index.tsx (Complete rewrite) - Full CRUD list page with SOP-compliant UI - Toolbar with bulk actions and filters - Desktop table + Mobile cards (responsive) - Pagination support - Search and filter by discount type Following PROJECT_SOP.md Standards: ✅ Toolbar pattern: Bulk delete, Refresh (REQUIRED), Filters ✅ Table UI: p-3 padding, hover:bg-muted/30, bg-muted/50 header ✅ Button styling: bg-red-600 for delete, inline-flex gap-2 ✅ Reset filters: Text link style (NOT button) ✅ Empty state: Icon + message + helper text ✅ Mobile responsive: Cards with md:hidden ✅ Error handling: ErrorCard for page loads ✅ Loading state: LoadingState component ✅ FAB configuration: Navigate to /coupons/new Features: - Bulk selection with checkbox - Bulk delete with confirmation - Search by coupon code - Filter by discount type - Pagination (prev/next) - Formatted discount amounts - Usage tracking display - Expiry date display - Edit navigation UI Components Used: - Card, Input, Select, Checkbox, Badge - Lucide icons: Trash2, RefreshCw, Edit, Tag - Consistent spacing and typography Next Steps: - Create New.tsx (create coupon form) - Create Edit.tsx (edit coupon form) - Update NavigationRegistry.php - Update API_ROUTES.md
96 lines
2.3 KiB
TypeScript
96 lines
2.3 KiB
TypeScript
import { api } from '../api';
|
|
|
|
export interface Coupon {
|
|
id: number;
|
|
code: string;
|
|
amount: number;
|
|
discount_type: 'percent' | 'fixed_cart' | 'fixed_product';
|
|
description: string;
|
|
usage_count: number;
|
|
usage_limit: number | null;
|
|
date_expires: string | null;
|
|
individual_use?: boolean;
|
|
product_ids?: number[];
|
|
excluded_product_ids?: number[];
|
|
usage_limit_per_user?: number | null;
|
|
limit_usage_to_x_items?: number | null;
|
|
free_shipping?: boolean;
|
|
product_categories?: number[];
|
|
excluded_product_categories?: number[];
|
|
exclude_sale_items?: boolean;
|
|
minimum_amount?: number | null;
|
|
maximum_amount?: number | null;
|
|
email_restrictions?: string[];
|
|
}
|
|
|
|
export interface CouponListResponse {
|
|
coupons: Coupon[];
|
|
total: number;
|
|
page: number;
|
|
per_page: number;
|
|
total_pages: number;
|
|
}
|
|
|
|
export interface CouponFormData {
|
|
code: string;
|
|
amount: number;
|
|
discount_type: 'percent' | 'fixed_cart' | 'fixed_product';
|
|
description?: string;
|
|
date_expires?: string | null;
|
|
individual_use?: boolean;
|
|
product_ids?: number[];
|
|
excluded_product_ids?: number[];
|
|
usage_limit?: number | null;
|
|
usage_limit_per_user?: number | null;
|
|
limit_usage_to_x_items?: number | null;
|
|
free_shipping?: boolean;
|
|
product_categories?: number[];
|
|
excluded_product_categories?: number[];
|
|
exclude_sale_items?: boolean;
|
|
minimum_amount?: number | null;
|
|
maximum_amount?: number | null;
|
|
email_restrictions?: string[];
|
|
}
|
|
|
|
export const CouponsApi = {
|
|
/**
|
|
* List coupons with pagination and filtering
|
|
*/
|
|
list: async (params?: {
|
|
page?: number;
|
|
per_page?: number;
|
|
search?: string;
|
|
discount_type?: string;
|
|
}): Promise<CouponListResponse> => {
|
|
return api.get('/coupons', { params });
|
|
},
|
|
|
|
/**
|
|
* Get single coupon
|
|
*/
|
|
get: async (id: number): Promise<Coupon> => {
|
|
return api.get(`/coupons/${id}`);
|
|
},
|
|
|
|
/**
|
|
* Create new coupon
|
|
*/
|
|
create: async (data: CouponFormData): Promise<Coupon> => {
|
|
return api.post('/coupons', data);
|
|
},
|
|
|
|
/**
|
|
* Update coupon
|
|
*/
|
|
update: async (id: number, data: Partial<CouponFormData>): Promise<Coupon> => {
|
|
return api.put(`/coupons/${id}`, data);
|
|
},
|
|
|
|
/**
|
|
* Delete coupon
|
|
*/
|
|
delete: async (id: number, force: boolean = false): Promise<{ success: boolean; id: number }> => {
|
|
return api.del(`/coupons/${id}?force=${force ? 'true' : 'false'}`);
|
|
},
|
|
};
|