Добавлен демо-режим: Можно открыть приложение с параметром ?demo в URL В демо-режиме эмулируется Telegram WebApp SDK Добавлена заглушка для демо-пользователя Исправлены типы и интерфейсы: Добавлен тип SafeUser для безопасной работы с mongoose документами Исправлены пропсы компонентов Обновлены типы для покупок в магазине Улучшена обработка ошибок: Добавлены информативные сообщения об ошибках Реализована корректная обработка сетевых ошибок Добавлены toast-уведомления с подробной информацией Улучшен UI: Добавлены спиннеры загрузки Улучшен внешний вид карточек товаров Добавлены информативные сообщения о состоянии
70 lines
1.9 KiB
TypeScript
70 lines
1.9 KiB
TypeScript
'use client';
|
||
|
||
import React from 'react';
|
||
import { Box, SimpleGrid, Button, Text, Image, useToast } from '@chakra-ui/react';
|
||
import { IShopItem } from '../../backend/models/ShopItem';
|
||
|
||
interface ShopProps {
|
||
items: IShopItem[];
|
||
userBalance: number;
|
||
onPurchase: (item: IShopItem) => Promise<void>;
|
||
}
|
||
|
||
export function Shop({ items, userBalance, onPurchase }: ShopProps) {
|
||
const toast = useToast();
|
||
|
||
const handlePurchase = async (item: IShopItem) => {
|
||
if (userBalance < item.price) {
|
||
toast({
|
||
title: 'Недостаточно средств',
|
||
description: `Для покупки ${item.name} нужно ${item.price} монет`,
|
||
status: 'error',
|
||
duration: 3000,
|
||
isClosable: true,
|
||
});
|
||
return;
|
||
}
|
||
|
||
await onPurchase(item);
|
||
};
|
||
|
||
return (
|
||
<Box w="100%">
|
||
<Text fontSize="2xl" mb={4}>Магазин</Text>
|
||
<Text mb={4}>Ваш баланс: {userBalance} монет</Text>
|
||
<SimpleGrid columns={[1, 2, 3]} spacing={6}>
|
||
{items.map((item) => (
|
||
<Box
|
||
key={item._id.toString()}
|
||
borderWidth="1px"
|
||
borderRadius="lg"
|
||
overflow="hidden"
|
||
p={4}
|
||
>
|
||
{item.imageUrl && (
|
||
<Image
|
||
src={item.imageUrl}
|
||
alt={item.name}
|
||
height="200px"
|
||
width="100%"
|
||
objectFit="cover"
|
||
mb={4}
|
||
/>
|
||
)}
|
||
<Text fontSize="xl" mb={2}>{item.name}</Text>
|
||
<Text mb={2}>{item.description}</Text>
|
||
<Text mb={4} color="green.500">{item.price} монет</Text>
|
||
<Button
|
||
colorScheme="blue"
|
||
onClick={() => handlePurchase(item)}
|
||
isDisabled={userBalance < item.price}
|
||
w="100%"
|
||
>
|
||
Купить
|
||
</Button>
|
||
</Box>
|
||
))}
|
||
</SimpleGrid>
|
||
</Box>
|
||
);
|
||
}
|