add bonuses in shop

This commit is contained in:
2025-12-07 20:11:41 +05:00
parent 3e03c1024d
commit 833444df2e
3 changed files with 705 additions and 15 deletions

View File

@ -207,6 +207,190 @@ export interface MeResponse {
is_admin: boolean;
}
// ===== БОНУСЫ / ПРОКАЧКА =====
export interface UserBonus {
id: string;
bonus_type_id: string;
name: string;
description: string;
effect_type: string;
effect_value: number;
level: number;
purchased_at: string;
can_upgrade: boolean;
upgrade_price: number;
is_active: boolean;
is_permanent: boolean;
expires_at?: string;
image_url?: string;
}
export type UserBonusesResponse = {
bonuses: UserBonus[];
};
export interface BonusType {
id: string;
name: string;
description: string;
effect_type: string;
base_effect_value: number;
effect_increment: number;
price: number;
upgrade_price: number;
duration: number;
max_level: number;
image_url?: string;
}
export type BonusTypesResponse = {
bonuses: BonusType[];
};
export async function fetchBonusTypes(): Promise<BonusType[]> {
const response = await fetch(`${API_BASE_URL}/api/bonuses/types`);
if (!response.ok) {
throw new Error('Не удалось получить список прокачек');
}
const data: BonusTypesResponse = await response.json();
return data.bonuses || [];
}
export async function fetchUserBonuses(username: string): Promise<UserBonus[]> {
const response = await fetch(`${API_BASE_URL}/api/bonuses/user/${username}`);
if (!response.ok) {
throw new Error('Не удалось получить бонусы игрока');
}
const data: UserBonusesResponse = await response.json();
return data.bonuses || [];
}
export async function purchaseBonus(
username: string,
bonus_type_id: string,
): Promise<{
status: string;
message: string;
remaining_coins?: number;
}> {
const response = await fetch(`${API_BASE_URL}/api/bonuses/purchase`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username,
bonus_type_id,
}),
});
if (!response.ok) {
let msg = 'Не удалось купить прокачку';
try {
const errorData = await response.json();
if (errorData.message) msg = errorData.message;
else if (Array.isArray(errorData.detail)) {
msg = errorData.detail.map((d: any) => d.msg).join(', ');
} else if (typeof errorData.detail === 'string') {
msg = errorData.detail;
}
} catch {
// оставляем дефолтное сообщение
}
throw new Error(msg);
}
return await response.json();
}
export async function upgradeBonus(
username: string,
bonus_id: string,
): Promise<{
status: string;
message: string;
bonus_id: string;
new_level?: number;
}> {
const response = await fetch(`${API_BASE_URL}/api/bonuses/upgrade`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username,
bonus_id,
}),
});
if (!response.ok) {
let msg = 'Не удалось улучшить бонус';
try {
const errorData = await response.json();
if (errorData.message) msg = errorData.message;
else if (Array.isArray(errorData.detail)) {
msg = errorData.detail.map((d: any) => d.msg).join(', ');
} else if (typeof errorData.detail === 'string') {
msg = errorData.detail;
}
} catch {
// оставляем дефолтное сообщение
}
throw new Error(msg);
}
return await response.json();
}
export async function toggleBonusActivation(
username: string,
bonus_id: string,
): Promise<{
status: string;
message: string;
bonus_id: string;
is_active: boolean;
}> {
const response = await fetch(
`${API_BASE_URL}/api/bonuses/toggle-activation`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username,
bonus_id,
}),
},
);
if (!response.ok) {
let msg = 'Не удалось переключить бонус';
try {
const errorData = await response.json();
if (errorData.message) msg = errorData.message;
else if (Array.isArray(errorData.detail)) {
msg = errorData.detail.map((d: any) => d.msg).join(', ');
} else if (typeof errorData.detail === 'string') {
msg = errorData.detail;
}
} catch {
// оставляем дефолтное сообщение
}
throw new Error(msg);
}
return await response.json();
}
// ===== КЕЙСЫ =====
export interface CaseItemMeta {