Files
plagiat/src/features/auth/login/ui/form.tsx

166 lines
6.2 KiB
TypeScript

'use client';
import { useCallback, useState } from 'react';
import { X } from 'lucide-react';
import {
formatPhone,
normalizeDigits,
} from '../../../../shared/lib/formatPhone';
import PhonePrefix from '../../../../shared/ui/phonePrefix';
import { MotionWrapper } from '../../../../shared/ui/motion';
import { useLoginForm } from '../lib/useLoginForm';
import { useLoginModal } from '@/shared/zustand/auth';
import Link from 'next/link';
export function LoginForm() {
const [isFocused, setIsFocused] = useState(false);
const { phone, setPhone, submit, error, loading } = useLoginForm();
const toggleLoginModal = useLoginModal((state) => state.toggleLoginModal);
const handlePhoneChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
setPhone(normalizeDigits(e.target.value));
},
[setPhone],
);
return (
<>
{/* Backdrop */}
<div
className="fixed inset-0 z-10 bg-black/40 backdrop-blur-sm"
onClick={toggleLoginModal}
/>
{/* Modal */}
<div className="fixed inset-0 z-20 flex items-center justify-center pointer-events-none px-6">
<MotionWrapper>
<div className="pointer-events-auto w-full max-w-sm rounded border border-stone-200 bg-white px-8 pb-8 pt-10 shadow-sm">
{/* Close */}
<div className="flex justify-end -mt-2 mb-4">
<button
onClick={toggleLoginModal}
className="flex h-7 w-7 items-center justify-center rounded-sm text-stone-400 transition-colors hover:bg-stone-100 hover:text-stone-700"
>
<X className="h-4 w-4" />
</button>
</div>
{/* Header */}
<p className="mb-1 text-[0.65rem] font-semibold uppercase tracking-[0.16em] text-stone-400">
Xush kelibsiz
</p>
<h1 className="mb-1 font-serif text-3xl leading-tight text-stone-900">
Kirish
</h1>
<p className="mb-8 text-sm text-stone-400">
Telefon raqamingizni kiriting.
</p>
<form onSubmit={submit} noValidate className="flex flex-col gap-5">
{/* Phone field */}
<div className="flex flex-col gap-1.5">
<label
htmlFor="phone"
className="text-[0.7rem] font-medium tracking-widest uppercase text-stone-500"
>
Telefon raqam
</label>
<div
className={`relative transition-transform duration-200 ${isFocused ? 'scale-[1.01]' : ''}`}
>
<PhonePrefix isFocused={isFocused} />
<input
id="phone"
type="tel"
placeholder="90 123 45 67"
value={formatPhone(phone)}
onChange={handlePhoneChange}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
className={`
w-full rounded-sm border bg-stone-50 py-2.5 pl-30 pr-3.5
text-[0.95rem] font-medium text-stone-900 outline-none
placeholder:text-stone-300 transition-all duration-150
${
error
? 'border-red-400 ring-2 ring-red-200/40'
: isFocused
? 'border-stone-400 ring-2 ring-stone-300/30'
: 'border-stone-200 hover:border-stone-300'
}
`}
/>
</div>
{/* Digit counter / complete hint */}
<div className="flex items-center justify-between px-0.5">
<span className="text-[0.7rem] text-stone-400">
{phone.length > 0 && `${phone.length} ta raqam kiritildi`}
</span>
{phone.length === 9 && (
<span className="text-[0.7rem] font-medium text-emerald-600">
To&lsquo;liq
</span>
)}
</div>
</div>
{/* Error */}
{error && (
<div className="rounded-sm border border-red-200 bg-red-50 px-3.5 py-2.5 text-[0.8rem] text-red-500">
{error}
</div>
)}
{/* Submit */}
<button
type="submit"
disabled={loading || phone.length !== 9}
className="
mt-1 w-full rounded-sm bg-stone-900 py-3
text-[0.82rem] font-semibold uppercase tracking-widest text-stone-100
transition-all duration-150
hover:bg-stone-800 active:scale-[0.99]
disabled:cursor-not-allowed disabled:opacity-40
"
>
{loading ? (
<span className="flex items-center justify-center gap-2">
<span className="h-3.5 w-3.5 rounded-full border-2 border-stone-500 border-t-stone-100 animate-spin" />
Yuborilmoqda
</span>
) : (
'Kodni yuborish'
)}
</button>
{/* Divider */}
<div className="relative flex items-center gap-3 py-1">
<span className="h-px flex-1 bg-stone-200" />
<span className="text-[0.65rem] font-medium uppercase tracking-widest text-stone-400">
yoki
</span>
<span className="h-px flex-1 bg-stone-200" />
</div>
{/* Register hint */}
<p className="text-center text-[0.78rem] text-stone-400">
Hisobingiz yo&lsquo;qmi?
<Link
href="/register"
className="text-stone-800 underline underline-offset-2 hover:text-stone-600 transition-colors"
>
Ro&lsquo;yxatdan o&lsquo;tish
</Link>
</p>
</form>
</div>
</MotionWrapper>
</div>
</>
);
}