Добавлены новые зависимости, обновлены стили и улучшена структура проекта. Обновлен README с описанием функционала и технологий. Реализована анимация и адаптивный дизайн. Настроена авторизация с использованием Apollo Client.
This commit is contained in:
269
src/components/auth/auth-flow.tsx
Normal file
269
src/components/auth/auth-flow.tsx
Normal file
@ -0,0 +1,269 @@
|
||||
"use client"
|
||||
|
||||
import { useState, useEffect } from "react"
|
||||
import { PhoneStep } from "./phone-step"
|
||||
import { SmsStep } from "./sms-step"
|
||||
import { CabinetSelectStep } from "./cabinet-select-step"
|
||||
import { InnStep } from "./inn-step"
|
||||
import { MarketplaceApiStep } from "./marketplace-api-step"
|
||||
import { ConfirmationStep } from "./confirmation-step"
|
||||
import { CheckCircle } from "lucide-react"
|
||||
import { useAuth } from '@/hooks/useAuth'
|
||||
|
||||
type AuthStep = 'phone' | 'sms' | 'cabinet-select' | 'inn' | 'marketplace-api' | 'confirmation' | 'complete'
|
||||
type CabinetType = 'fulfillment' | 'seller' | 'logist' | 'wholesale'
|
||||
|
||||
interface OrganizationData {
|
||||
name?: string
|
||||
fullName?: string
|
||||
address?: string
|
||||
isActive?: boolean
|
||||
}
|
||||
|
||||
interface ApiKeyValidation {
|
||||
sellerId?: string
|
||||
sellerName?: string
|
||||
isValid?: boolean
|
||||
}
|
||||
|
||||
interface AuthData {
|
||||
phone: string
|
||||
smsCode: string
|
||||
cabinetType: CabinetType | null
|
||||
inn: string
|
||||
organizationData: OrganizationData | null
|
||||
wbApiKey: string
|
||||
wbApiValidation: ApiKeyValidation | null
|
||||
ozonApiKey: string
|
||||
ozonApiValidation: ApiKeyValidation | null
|
||||
isAuthenticated: boolean
|
||||
partnerCode?: string | null
|
||||
}
|
||||
|
||||
interface AuthFlowProps {
|
||||
partnerCode?: string | null
|
||||
}
|
||||
|
||||
export function AuthFlow({ partnerCode }: AuthFlowProps = {}) {
|
||||
const [step, setStep] = useState<AuthStep>('phone')
|
||||
const [authData, setAuthData] = useState<AuthData>({
|
||||
phone: '',
|
||||
smsCode: '',
|
||||
cabinetType: null,
|
||||
inn: '',
|
||||
organizationData: null,
|
||||
wbApiKey: '',
|
||||
wbApiValidation: null,
|
||||
ozonApiKey: '',
|
||||
ozonApiValidation: null,
|
||||
isAuthenticated: false,
|
||||
partnerCode: partnerCode
|
||||
})
|
||||
|
||||
const { verifySmsCode, checkAuth } = useAuth()
|
||||
|
||||
// При завершении авторизации инициируем проверку и перенаправление
|
||||
useEffect(() => {
|
||||
if (step === 'complete') {
|
||||
const timer = setTimeout(() => {
|
||||
// Принудительно перенаправляем в дашборд
|
||||
window.location.href = '/dashboard'
|
||||
}, 2000) // Задержка для показа сообщения о завершении
|
||||
|
||||
return () => clearTimeout(timer)
|
||||
}
|
||||
}, [step])
|
||||
|
||||
const handlePhoneNext = (phone: string) => {
|
||||
setAuthData(prev => ({ ...prev, phone }))
|
||||
setStep('sms')
|
||||
}
|
||||
|
||||
const handleSmsNext = async (smsCode: string) => {
|
||||
setAuthData(prev => ({ ...prev, smsCode, isAuthenticated: true }))
|
||||
|
||||
// SMS код уже проверен в SmsStep компоненте
|
||||
// Просто переходим к следующему шагу
|
||||
setStep('cabinet-select')
|
||||
}
|
||||
|
||||
const handleCabinetNext = (cabinetType: CabinetType) => {
|
||||
setAuthData(prev => ({ ...prev, cabinetType }))
|
||||
if (cabinetType === 'fulfillment' || cabinetType === 'logist' || cabinetType === 'wholesale') {
|
||||
setStep('inn')
|
||||
} else {
|
||||
setStep('marketplace-api')
|
||||
}
|
||||
}
|
||||
|
||||
const handleInnNext = (inn: string, organizationData?: OrganizationData) => {
|
||||
setAuthData(prev => ({
|
||||
...prev,
|
||||
inn,
|
||||
organizationData: organizationData || null
|
||||
}))
|
||||
setStep('confirmation')
|
||||
}
|
||||
|
||||
const handleMarketplaceApiNext = (apiData: {
|
||||
wbApiKey?: string
|
||||
wbApiValidation?: ApiKeyValidation
|
||||
ozonApiKey?: string
|
||||
ozonApiValidation?: ApiKeyValidation
|
||||
}) => {
|
||||
setAuthData(prev => ({
|
||||
...prev,
|
||||
wbApiKey: apiData.wbApiKey || '',
|
||||
wbApiValidation: apiData.wbApiValidation || null,
|
||||
ozonApiKey: apiData.ozonApiKey || '',
|
||||
ozonApiValidation: apiData.ozonApiValidation || null
|
||||
}))
|
||||
setStep('confirmation')
|
||||
}
|
||||
|
||||
const handleConfirmation = () => {
|
||||
setStep('complete')
|
||||
}
|
||||
|
||||
const handlePhoneBack = () => {
|
||||
setStep('phone')
|
||||
}
|
||||
|
||||
const handleSmsBack = () => {
|
||||
setStep('phone')
|
||||
}
|
||||
|
||||
const handleCabinetBack = () => {
|
||||
setStep('sms')
|
||||
}
|
||||
|
||||
const handleInnBack = () => {
|
||||
setStep('cabinet-select')
|
||||
}
|
||||
|
||||
const handleMarketplaceApiBack = () => {
|
||||
setStep('cabinet-select')
|
||||
}
|
||||
|
||||
const handleConfirmationBack = () => {
|
||||
if (authData.cabinetType === 'fulfillment' || authData.cabinetType === 'logist' || authData.cabinetType === 'wholesale') {
|
||||
setStep('inn')
|
||||
} else {
|
||||
setStep('marketplace-api')
|
||||
}
|
||||
}
|
||||
|
||||
if (step === 'complete') {
|
||||
return (
|
||||
<div className="min-h-screen bg-animated flex items-center justify-center p-4">
|
||||
{/* Floating Particles */}
|
||||
<div className="particles">
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
</div>
|
||||
|
||||
<div className="text-center text-white max-w-md relative z-10">
|
||||
<div className="bg-white/10 backdrop-blur rounded-2xl p-8 border border-white/20 glow-purple">
|
||||
<CheckCircle className="h-20 w-20 mx-auto mb-6 text-green-400 animate-pulse" />
|
||||
<h1 className="text-3xl font-bold text-gradient-bright mb-4">Добро пожаловать!</h1>
|
||||
<p className="text-white/80 mb-4">Регистрация успешно завершена</p>
|
||||
<div className="bg-white/5 rounded-lg p-4 mb-6">
|
||||
<p className="text-white/60 text-sm mb-2">Тип кабинета:</p>
|
||||
<p className="text-white font-medium">
|
||||
{
|
||||
authData.cabinetType === 'fulfillment' ? 'Фулфилмент' :
|
||||
authData.cabinetType === 'logist' ? 'Логистика' :
|
||||
authData.cabinetType === 'wholesale' ? 'Оптовик' :
|
||||
'Селлер'
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-2 text-white/60 text-sm">
|
||||
<div className="animate-spin h-4 w-4 border-2 border-white/20 border-t-white/60 rounded-full"></div>
|
||||
Переход в личный кабинет...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{step === 'phone' && <PhoneStep onNext={handlePhoneNext} />}
|
||||
{step === 'sms' && (
|
||||
<SmsStep
|
||||
phone={authData.phone}
|
||||
onNext={handleSmsNext}
|
||||
onBack={handleSmsBack}
|
||||
/>
|
||||
)}
|
||||
{step === 'cabinet-select' && (
|
||||
<CabinetSelectStep
|
||||
onNext={handleCabinetNext}
|
||||
onBack={handleCabinetBack}
|
||||
/>
|
||||
)}
|
||||
{step === 'inn' && (
|
||||
<InnStep
|
||||
onNext={handleInnNext}
|
||||
onBack={handleInnBack}
|
||||
/>
|
||||
)}
|
||||
{step === 'marketplace-api' && (
|
||||
<MarketplaceApiStep
|
||||
onNext={handleMarketplaceApiNext}
|
||||
onBack={handleMarketplaceApiBack}
|
||||
/>
|
||||
)}
|
||||
{step === 'confirmation' && (
|
||||
<ConfirmationStep
|
||||
data={{
|
||||
phone: authData.phone,
|
||||
cabinetType: authData.cabinetType!,
|
||||
inn: authData.inn || undefined,
|
||||
organizationData: authData.organizationData || undefined,
|
||||
wbApiKey: authData.wbApiKey || undefined,
|
||||
wbApiValidation: authData.wbApiValidation || undefined,
|
||||
ozonApiKey: authData.ozonApiKey || undefined,
|
||||
ozonApiValidation: authData.ozonApiValidation || undefined
|
||||
}}
|
||||
onConfirm={handleConfirmation}
|
||||
onBack={handleConfirmationBack}
|
||||
/>
|
||||
)}
|
||||
{step === 'complete' && (
|
||||
<div className="space-y-6 text-center">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center">
|
||||
<CheckCircle className="w-10 h-10 text-green-600" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<h2 className="text-2xl font-bold text-gray-900">
|
||||
Регистрация завершена!
|
||||
</h2>
|
||||
<p className="text-gray-600">
|
||||
Ваш {authData.cabinetType === 'fulfillment' ? 'фулфилмент кабинет' :
|
||||
authData.cabinetType === 'seller' ? 'селлер кабинет' :
|
||||
authData.cabinetType === 'logist' ? 'логистический кабинет' : 'оптовый кабинет'}
|
||||
{' '}успешно создан
|
||||
</p>
|
||||
</div>
|
||||
<div className="animate-pulse">
|
||||
<p className="text-sm text-gray-500">
|
||||
Переход в личный кабинет...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
Reference in New Issue
Block a user