Files
sfera/src/components/auth/phone-step.tsx

140 lines
4.5 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 { useState } from "react"
import { Button } from "@/components/ui/button"
import { GlassInput } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { AuthLayout } from "./auth-layout"
import { Phone, ArrowRight } from "lucide-react"
import { useMutation } from '@apollo/client'
import { SEND_SMS_CODE } from '@/graphql/mutations'
interface PhoneStepProps {
onNext: (phone: string) => void
}
export function PhoneStep({ onNext }: PhoneStepProps) {
const [phone, setPhone] = useState("")
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const [sendSmsCode] = useMutation(SEND_SMS_CODE)
const formatPhoneNumber = (value: string) => {
const numbers = value.replace(/\D/g, '')
if (numbers.length === 0) return ''
if (numbers[0] === '8') {
const withoutFirst = numbers.slice(1)
return formatRussianNumber('7' + withoutFirst)
}
if (numbers[0] === '7') {
return formatRussianNumber(numbers)
}
return formatRussianNumber('7' + numbers)
}
const formatRussianNumber = (numbers: string) => {
if (numbers.length <= 1) return '+7'
if (numbers.length <= 4) return `+7 (${numbers.slice(1)}`
if (numbers.length <= 7) return `+7 (${numbers.slice(1, 4)}) ${numbers.slice(4)}`
if (numbers.length <= 9) return `+7 (${numbers.slice(1, 4)}) ${numbers.slice(4, 7)}-${numbers.slice(7)}`
return `+7 (${numbers.slice(1, 4)}) ${numbers.slice(4, 7)}-${numbers.slice(7, 9)}-${numbers.slice(9, 11)}`
}
const handlePhoneChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const formatted = formatPhoneNumber(e.target.value)
setPhone(formatted)
setError(null)
}
const isValidPhone = (phone: string) => {
const numbers = phone.replace(/\D/g, '')
return numbers.length === 11 && (numbers.startsWith('7') || numbers.startsWith('8'))
}
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
if (!isValidPhone(phone)) {
setError('Введите корректный номер телефона')
return
}
setIsLoading(true)
setError(null)
try {
const cleanPhone = phone.replace(/\D/g, '')
const formattedPhone = cleanPhone.startsWith('8')
? '7' + cleanPhone.slice(1)
: cleanPhone
const { data } = await sendSmsCode({
variables: { phone: formattedPhone }
})
if (data.sendSmsCode.success) {
onNext(phone)
} else {
setError('Ошибка отправки SMS. Попробуйте позже.')
}
} catch (error: unknown) {
console.error('SMS sending error:', error)
setError(error instanceof Error ? error.message : 'Ошибка отправки SMS. Попробуйте позже.')
} finally {
setIsLoading(false)
}
}
return (
<AuthLayout
title="Добро пожаловать!"
description="Введите номер телефона для входа в систему"
currentStep={1}
totalSteps={5}
stepName="Авторизация"
>
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="phone" className="text-white text-sm font-medium flex items-center gap-2">
<Phone className="h-4 w-4" />
Номер телефона
</Label>
<GlassInput
id="phone"
type="tel"
placeholder="+7 (___) ___-__-__"
value={phone}
onChange={handlePhoneChange}
className={`h-12 text-lg ${error ? 'border-red-400/50' : ''}`}
style={{ caretColor: 'white' }}
onFocus={(e) => {
// Устанавливаем курсор в начало если поле пустое или содержит только +7
if (phone === '' || phone === '+7') {
setTimeout(() => {
e.target.setSelectionRange(0, 0);
}, 0);
}
}}
/>
{error && (
<p className="text-red-400 text-xs">{error}</p>
)}
</div>
<Button
type="submit"
variant="glass"
size="lg"
className="w-full h-12 flex items-center gap-2"
disabled={!isValidPhone(phone) || isLoading}
>
{isLoading ? "Отправка..." : "Получить SMS код"}
<ArrowRight className="h-4 w-4" />
</Button>
</form>
</AuthLayout>
)
}