mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
UI для купонов из BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot#3042 (API: PR #3044 бота): - /admin/coupons — список партий с погашениями и offset-пагинацией; - /admin/coupons/create — мастер партии (тариф, дни, количество, учётная оптовая цена, срок), после создания — экран со ссылками (копирование всех, скачивание .txt); - /admin/coupons/:id — карточка со статистикой, экспорт актуальных ссылок, отзыв непогашенных за PermissionGate coupons:edit с подтверждением и тостом; - /coupon/:token — публичная страница купона: тариф/срок, кнопка активации в боте, для залогиненных — активация прямо в кабинете с маппингом структурированных кодов ошибок {code, message}; - пункт меню в разделе тарифов (гейт coupons:read), лениво загружаемые роуты, локали ru/en (zh/fa падают на ru-фолбэк).
113 lines
2.8 KiB
TypeScript
113 lines
2.8 KiB
TypeScript
import apiClient from './client';
|
|
|
|
// ============== Types ==============
|
|
|
|
export interface CouponBatch {
|
|
id: number;
|
|
name: string;
|
|
tariff_id: number | null;
|
|
tariff_name: string | null;
|
|
period_days: number;
|
|
coupons_total: number;
|
|
wholesale_price_kopeks: number;
|
|
valid_until: string | null;
|
|
is_revoked: boolean;
|
|
created_at: string;
|
|
active_count: number;
|
|
redeemed_count: number;
|
|
revoked_count: number;
|
|
}
|
|
|
|
export interface CouponBatchListResponse {
|
|
items: CouponBatch[];
|
|
total: number;
|
|
limit: number;
|
|
offset: number;
|
|
}
|
|
|
|
export interface CouponBatchCreateRequest {
|
|
name: string;
|
|
tariff_id: number;
|
|
period_days: number;
|
|
coupons_count: number;
|
|
wholesale_price_kopeks?: number;
|
|
valid_days?: number;
|
|
}
|
|
|
|
export interface CouponBatchCreated extends CouponBatch {
|
|
links: string[];
|
|
tokens: string[];
|
|
}
|
|
|
|
export interface CouponBatchLinks {
|
|
batch_id: number;
|
|
count: number;
|
|
links: string[];
|
|
tokens: string[];
|
|
}
|
|
|
|
export interface CouponBatchRevokeResponse {
|
|
revoked_count: number;
|
|
batch: CouponBatch;
|
|
}
|
|
|
|
export interface CouponRedeemResponse {
|
|
success: boolean;
|
|
tariff_name: string;
|
|
period_days: number;
|
|
renewed: boolean;
|
|
end_date: string | null;
|
|
}
|
|
|
|
export interface CouponStatus {
|
|
tariff_name: string;
|
|
period_days: number;
|
|
valid_until: string | null;
|
|
bot_link: string | null;
|
|
}
|
|
|
|
// ============== API ==============
|
|
|
|
export const couponsApi = {
|
|
// Admin: batches
|
|
getBatches: async (params?: {
|
|
limit?: number;
|
|
offset?: number;
|
|
}): Promise<CouponBatchListResponse> => {
|
|
const response = await apiClient.get('/cabinet/admin/coupons', { params });
|
|
return response.data;
|
|
},
|
|
|
|
getBatch: async (id: number): Promise<CouponBatch> => {
|
|
const response = await apiClient.get(`/cabinet/admin/coupons/${id}`);
|
|
return response.data;
|
|
},
|
|
|
|
createBatch: async (data: CouponBatchCreateRequest): Promise<CouponBatchCreated> => {
|
|
const response = await apiClient.post('/cabinet/admin/coupons', data);
|
|
return response.data;
|
|
},
|
|
|
|
getBatchLinks: async (id: number): Promise<CouponBatchLinks> => {
|
|
const response = await apiClient.get(`/cabinet/admin/coupons/${id}/links`);
|
|
return response.data;
|
|
},
|
|
|
|
revokeBatch: async (id: number): Promise<CouponBatchRevokeResponse> => {
|
|
const response = await apiClient.post(`/cabinet/admin/coupons/${id}/revoke`);
|
|
return response.data;
|
|
},
|
|
|
|
// User: redeem a coupon for the current cabinet user
|
|
redeemCoupon: async (token: string): Promise<CouponRedeemResponse> => {
|
|
const response = await apiClient.post('/cabinet/coupon/redeem', { token });
|
|
return response.data;
|
|
},
|
|
|
|
// Public: coupon info by token (no auth)
|
|
getCouponStatus: async (token: string): Promise<CouponStatus> => {
|
|
const response = await apiClient.get(`/cabinet/coupon/${token}/status`);
|
|
return response.data;
|
|
},
|
|
};
|