Files
neomovies/src/app/verify/VerificationClient.tsx
Foxix ebf23e4246 Update 103 files
- /public/file.svg
- /public/globe.svg
- /public/next.svg
- /public/vercel.svg
- /public/window.svg
- /public/google.svg
- /public/logo.png
- /src/eslint.config.mjs
- /src/api.ts
- /src/middleware.ts
- /src/app/favicon.ico
- /src/app/globals.css
- /src/app/layout.tsx
- /src/app/page.tsx
- /src/app/providers.tsx
- /src/app/not-found.tsx
- /src/app/error.tsx
- /src/app/metadata.ts
- /src/app/styles.tsx
- /src/app/api/auth/[...nextauth]/route.ts
- /src/app/api/auth/register/route.ts
- /src/app/api/auth/verify/route.ts
- /src/app/api/auth/check-verification/route.ts
- /src/app/api/auth/resend-code/route.ts
- /src/app/api/movies/search/route.ts
- /src/app/api/movies/sync/route.ts
- /src/app/api/admin/send-verification/route.ts
- /src/app/api/admin/verify-code/route.ts
- /src/app/api/admin/movies/route.ts
- /src/app/api/admin/movies/toggle-visibility/route.ts
- /src/app/api/admin/create/route.ts
- /src/app/api/admin/users/toggle-admin/route.ts
- /src/app/api/admin/toggle-admin/route.ts
- /src/app/login/page.tsx
- /src/app/login/LoginClient.tsx
- /src/app/verify/page.tsx
- /src/app/verify/VerificationClient.tsx
- /src/app/profile/page.tsx
- /src/app/movie/[id]/page.tsx
- /src/app/movie/[id]/MoviePage.tsx
- /src/app/movie/[id]/MovieContent.tsx
- /src/app/settings/page.tsx
- /src/app/tv/[id]/page.tsx
- /src/app/tv/[id]/TVShowPage.tsx
- /src/app/tv/[id]/TVShowContent.tsx
- /src/app/admin/login/page.tsx
- /src/app/admin/login/AdminLoginClient.tsx
- /src/lib/db.ts
- /src/lib/jwt.ts
- /src/lib/registry.tsx
- /src/lib/api.ts
- /src/lib/mongodb.ts
- /src/lib/mailer.ts
- /src/lib/auth.ts
- /src/lib/utils.ts
- /src/lib/email.ts
- /src/lib/movieSync.ts
- /src/models/User.ts
- /src/models/index.ts
- /src/models/Movie.ts
- /src/types/auth.ts
- /src/types/movie.ts
- /src/components/MovieCard.tsx
- /src/components/Notification.tsx
- /src/components/Pagination.tsx
- /src/components/GoogleIcon.tsx
- /src/components/StyleProvider.tsx
- /src/components/Providers.tsx
- /src/components/VerificationCodeInput.tsx
- /src/components/GlassCard.tsx
- /src/components/AppLayout.tsx
- /src/components/SearchModal.tsx
- /src/components/DarkReaderFix.tsx
- /src/components/ClientLayout.tsx
- /src/components/MenuItem.tsx
- /src/components/MoviePlayer.tsx
- /src/components/PageLayout.tsx
- /src/components/SettingsContent.tsx
- /src/components/Navbar.tsx
- /src/components/LayoutContent.tsx
- /src/components/SearchResults.tsx
- /src/components/Icons/Icons.tsx
- /src/components/Icons/HeartIcon.tsx
- /src/components/Icons/PlayIcon.tsx
- /src/components/admin/MovieSearch.tsx
- /src/hooks/useUser.ts
- /src/hooks/useMovies.ts
- /src/hooks/useSettings.ts
- /src/hooks/useSearch.ts
- /src/styles/GlobalStyles.ts
- /src/styles/GlobalStyles.tsx
- /src/providers/AuthProvider.tsx
- /src/data/movies.ts
- /types/next-auth.d.ts
- /middleware.ts
- /next.config.js
- /next-env.d.ts
- /package.json
- /postcss.config.mjs
- /README.md
- /tailwind.config.ts
- /tsconfig.json
- /package-lock.json
2024-12-23 18:42:18 +00:00

232 lines
5.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import React, { useState, useEffect } from 'react';
import styled from 'styled-components';
import { useRouter, useSearchParams } from 'next/navigation';
import { signIn } from 'next-auth/react';
const Container = styled.div`
width: 100%;
display: flex;
flex-direction: column;
gap: 2rem;
text-align: center;
`;
const Title = styled.h2`
font-size: 1.5rem;
font-weight: 600;
color: #fff;
margin-bottom: 0.5rem;
`;
const Subtitle = styled.p`
color: rgba(255, 255, 255, 0.7);
font-size: 0.875rem;
margin-bottom: 2rem;
`;
const CodeInput = styled.input`
width: 100%;
padding: 1rem;
font-size: 2rem;
letter-spacing: 0.5rem;
text-align: center;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
color: #fff;
transition: all 0.2s;
&:focus {
outline: none;
border-color: ${({ theme }) => theme.colors.primary};
box-shadow: 0 0 0 4px rgba(33, 150, 243, 0.1);
}
&::placeholder {
letter-spacing: normal;
color: rgba(255, 255, 255, 0.3);
}
`;
const VerifyButton = styled.button`
width: 100%;
background: linear-gradient(to right, #2196f3, #1e88e5);
color: white;
padding: 1rem;
border-radius: 12px;
border: none;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
&:hover {
background: linear-gradient(to right, #1e88e5, #1976d2);
transform: translateY(-1px);
box-shadow: 0 4px 15px rgba(33, 150, 243, 0.3);
}
&:active {
transform: translateY(0);
}
&:disabled {
opacity: 0.7;
cursor: not-allowed;
transform: none;
}
`;
const ResendButton = styled.button`
background: none;
border: none;
color: ${({ theme }) => theme.colors.primary};
font-size: 0.875rem;
cursor: pointer;
padding: 0.5rem;
transition: opacity 0.2s;
&:hover {
opacity: 0.8;
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
`;
const ErrorMessage = styled.div`
color: #f44336;
font-size: 0.875rem;
margin-top: 0.5rem;
`;
export function VerificationClient({ email }: { email: string }) {
const [code, setCode] = useState('');
const [error, setError] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [countdown, setCountdown] = useState(0);
const router = useRouter();
const searchParams = useSearchParams();
useEffect(() => {
let timer: NodeJS.Timeout;
if (countdown > 0) {
timer = setInterval(() => {
setCountdown((prev) => prev - 1);
}, 1000);
}
return () => {
if (timer) clearInterval(timer);
};
}, [countdown]);
const handleVerify = async () => {
if (code.length !== 6) {
setError('Код должен состоять из 6 цифр');
return;
}
setIsLoading(true);
setError('');
try {
const response = await fetch('/api/auth/verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, code }),
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Ошибка верификации');
}
// Выполняем вход после успешной верификации
const result = await signIn('credentials', {
redirect: false,
email,
password: localStorage.getItem('password'),
});
if (result?.error) {
throw new Error(result.error);
}
router.push('/');
} catch (err) {
setError(err instanceof Error ? err.message : 'Произошла ошибка');
} finally {
setIsLoading(false);
}
};
const handleResend = async () => {
try {
const response = await fetch('/api/auth/resend-code', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email }),
});
if (!response.ok) {
throw new Error('Не удалось отправить код');
}
setCountdown(60);
} catch (err) {
setError('Не удалось отправить код');
}
};
return (
<Container>
<div>
<Title>Подтвердите ваш email</Title>
<Subtitle>Мы отправили код подтверждения на {email}</Subtitle>
</div>
<div>
<CodeInput
type="text"
maxLength={6}
value={code}
onChange={(e) => {
const value = e.target.value.replace(/\D/g, '');
setCode(value);
setError('');
}}
placeholder="Введите код"
/>
{error && <ErrorMessage>{error}</ErrorMessage>}
</div>
<div>
<VerifyButton
onClick={handleVerify}
disabled={isLoading || code.length !== 6}
>
{isLoading ? 'Проверка...' : 'Подтвердить'}
</VerifyButton>
<ResendButton
onClick={handleResend}
disabled={countdown > 0 || isLoading}
>
{countdown > 0
? `Отправить код повторно (${countdown}с)`
: 'Отправить код повторно'}
</ResendButton>
</div>
</Container>
);
}