Добавлены новые зависимости, обновлены стили и улучшена структура проекта. Обновлен README с описанием функционала и технологий. Реализована анимация и адаптивный дизайн. Настроена авторизация с использованием Apollo Client.

This commit is contained in:
Bivekich
2025-07-16 18:00:41 +03:00
parent d260749bc9
commit 823ef9a28c
69 changed files with 15539 additions and 210 deletions

View 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>
)}
</>
)
}