Files
web_sport/packages/api-client/src/resources/promotions-admin.ts
T
2026-08-13 23:20:23 +07:00

71 lines
2.5 KiB
TypeScript

import type { AdminDiscount, OffsetPaginated } from '@sport/types';
import type { HttpClient } from '../http-client';
export interface DiscountListParams {
page?: number;
perPage?: number;
q?: string;
trigger?: 'AUTOMATIC' | 'CODE';
}
/**
* A discount as the admin form submits it.
*
* Deliberately not `DiscountInput` from `@sport/validation`: that is the type
* *after* parsing, with defaults already applied, so using it here would force
* every caller to supply fields the schema is perfectly happy to fill in.
*/
export interface DiscountPayload {
code?: string | null;
trigger: 'AUTOMATIC' | 'CODE';
type: 'PERCENTAGE' | 'FIXED_AMOUNT';
scope?: 'ORDER' | 'PRODUCT';
value: number;
translations: Record<string, { name: string; description?: string | null }>;
minSubtotalAmount?: number | null;
startsAt?: string | null;
endsAt?: string | null;
isActive?: boolean;
usageLimit?: number | null;
stackable?: boolean;
priority?: number;
productIds?: string[];
collectionIds?: string[];
}
/**
* Promotions and coupons, which are one resource.
*
* There is no `coupons` resource next to this one, and that is the point: a
* coupon is a promotion that needs a code typed (ADR-0020). Two client
* resources would reintroduce the split the data model exists to avoid.
*/
export interface PromotionsAdminResource {
list(params?: DiscountListParams): Promise<OffsetPaginated<AdminDiscount>>;
getById(id: string): Promise<AdminDiscount>;
create(payload: DiscountPayload): Promise<AdminDiscount>;
update(id: string, payload: DiscountPayload): Promise<AdminDiscount>;
remove(id: string): Promise<void>;
}
export function createPromotionsAdminResource(http: HttpClient): PromotionsAdminResource {
// Never cached. An operator who just switched a promotion off must see it
// off — a stale list here is a discount they believe they stopped giving.
const uncached = { cache: 'no-store' } as const;
return {
list: (params = {}) =>
http.get<OffsetPaginated<AdminDiscount>>('/admin/discounts', {
...uncached,
query: { ...params },
}),
getById: (id) =>
http.get<AdminDiscount>(`/admin/discounts/${encodeURIComponent(id)}`, uncached),
create: (payload) => http.post<AdminDiscount>('/admin/discounts', payload, uncached),
update: (id, payload) =>
http.patch<AdminDiscount>(`/admin/discounts/${encodeURIComponent(id)}`, payload, uncached),
remove: (id) => http.delete<void>(`/admin/discounts/${encodeURIComponent(id)}`, uncached),
};
}