171 lines
4.8 KiB
TypeScript
171 lines
4.8 KiB
TypeScript
import { Box, Button, Typography } from '@mui/material';
|
||
import { useEffect, useState } from 'react';
|
||
import GradientTextField from '../components/GradientTextField';
|
||
import CustomNotification from '../components/Notifications/CustomNotification';
|
||
import type { NotificationPosition } from '../components/Notifications/CustomNotification';
|
||
import {
|
||
isNotificationsEnabled,
|
||
getNotifPositionFromSettings,
|
||
} from '../utils/notifications';
|
||
import { redeemPromoCode } from '../api/promocodes';
|
||
import { useNavigate } from 'react-router-dom';
|
||
|
||
export const PromoRedeem = () => {
|
||
const navigate = useNavigate();
|
||
|
||
const [username, setUsername] = useState<string>(''); // будет автозаполнение
|
||
const [code, setCode] = useState('');
|
||
|
||
const [loading, setLoading] = useState(false);
|
||
|
||
const [notifOpen, setNotifOpen] = useState(false);
|
||
const [notifMsg, setNotifMsg] = useState<React.ReactNode>('');
|
||
const [notifSeverity, setNotifSeverity] = useState<
|
||
'success' | 'info' | 'warning' | 'error'
|
||
>('info');
|
||
|
||
const [notifPos, setNotifPos] = useState<NotificationPosition>({
|
||
vertical: 'bottom',
|
||
horizontal: 'center',
|
||
});
|
||
|
||
const showNotification = (
|
||
message: React.ReactNode,
|
||
severity: 'success' | 'info' | 'warning' | 'error' = 'info',
|
||
position: NotificationPosition = getNotifPositionFromSettings(),
|
||
) => {
|
||
if (!isNotificationsEnabled()) return;
|
||
setNotifMsg(message);
|
||
setNotifSeverity(severity);
|
||
setNotifPos(position);
|
||
setNotifOpen(true);
|
||
};
|
||
|
||
// как в Profile.tsx: читаем launcher_config
|
||
useEffect(() => {
|
||
try {
|
||
const savedConfig = localStorage.getItem('launcher_config');
|
||
if (savedConfig) {
|
||
const config = JSON.parse(savedConfig);
|
||
setUsername(config.username || '');
|
||
}
|
||
} catch {
|
||
setUsername('');
|
||
}
|
||
}, []);
|
||
|
||
const handleRedeem = async () => {
|
||
if (!username) {
|
||
showNotification(
|
||
'Не удалось определить никнейм. Войдите в аккаунт заново.',
|
||
'warning',
|
||
);
|
||
// по желанию можно отправить в login/profile:
|
||
// navigate('/login', { replace: true });
|
||
return;
|
||
}
|
||
|
||
if (!code) {
|
||
showNotification('Введите промокод', 'warning');
|
||
return;
|
||
}
|
||
|
||
setLoading(true);
|
||
try {
|
||
const res = await redeemPromoCode(username, code);
|
||
|
||
showNotification(
|
||
<>
|
||
Промокод <b>{res.code}</b> успешно активирован!
|
||
</>,
|
||
'success',
|
||
);
|
||
|
||
setCode('');
|
||
} catch (e: any) {
|
||
showNotification(e?.message || 'Ошибка активации промокода', 'error');
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<>
|
||
<Box
|
||
sx={{
|
||
height: 'calc(100vh - 8vh)',
|
||
pt: '8vh',
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
px: 2,
|
||
}}
|
||
>
|
||
<Typography
|
||
variant="h4"
|
||
sx={{
|
||
textAlign: 'center',
|
||
fontFamily: 'Benzin-Bold',
|
||
backgroundImage:
|
||
'linear-gradient( 136deg, rgb(242,113,33) 0%, rgb(233,64,87) 50%, rgb(138,35,135) 100%)',
|
||
WebkitBackgroundClip: 'text',
|
||
WebkitTextFillColor: 'transparent',
|
||
mb: 2,
|
||
}}
|
||
>
|
||
Активация промокода
|
||
</Typography>
|
||
|
||
<Box
|
||
sx={{
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
alignItems: 'center',
|
||
width: '50vw',
|
||
}}
|
||
>
|
||
<GradientTextField
|
||
label=""
|
||
required
|
||
name="code"
|
||
value={code}
|
||
onChange={(e) => setCode(e.target.value.toUpperCase())}
|
||
/>
|
||
|
||
<Button
|
||
variant="contained"
|
||
color="primary"
|
||
disabled={loading}
|
||
sx={{
|
||
transition: 'transform 0.3s ease',
|
||
width: '100%',
|
||
mt: 2,
|
||
background:
|
||
'linear-gradient(71deg, #F27121 0%, #E940CD 70%, #8A2387 100%)',
|
||
fontFamily: 'Benzin-Bold',
|
||
borderRadius: '2.5vw',
|
||
fontSize: '2vw',
|
||
'&:hover': {
|
||
transform: loading ? 'none' : 'scale(1.1)',
|
||
},
|
||
}}
|
||
onClick={handleRedeem}
|
||
>
|
||
{loading ? 'Активируем...' : 'Активировать'}
|
||
</Button>
|
||
</Box>
|
||
|
||
<CustomNotification
|
||
open={notifOpen}
|
||
message={notifMsg}
|
||
severity={notifSeverity}
|
||
position={notifPos}
|
||
onClose={() => setNotifOpen(false)}
|
||
autoHideDuration={2500}
|
||
/>
|
||
</Box>
|
||
</>
|
||
);
|
||
};
|