Login: 6-digit OTP + desktop layout
- OTP input now 6 digits (matches backend 6-digit codes): maxLength 6, six slots with responsive widths, verify enabled at length === 6 - login page: centered desktop card on a neutral canvas with brand mark - MyLayout: auth pages (/login, /logout) get full-width desktop canvas and no mobile bottom nav at lg (no shopping header/footer) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
232f7d1b3c
commit
d0571f8253
@ -36,6 +36,10 @@ const MyLayout = React.memo(({ children }: { children: React.ReactNode }) => {
|
||||
p.startsWith("/search/") ||
|
||||
p.startsWith("/seller/") ||
|
||||
p === "/cart";
|
||||
// Auth pages get a full-width desktop canvas (so they can center their own
|
||||
// card) but no shopping header/footer.
|
||||
const isAuth = p === "/login" || p === "/logout";
|
||||
const expandOnDesktop = isDesktopReady || isAuth;
|
||||
const isThread = !!location.pathname.split("threads")[1];
|
||||
|
||||
return (
|
||||
@ -43,18 +47,22 @@ const MyLayout = React.memo(({ children }: { children: React.ReactNode }) => {
|
||||
{isDesktopReady && <DesktopHeader />}
|
||||
<div
|
||||
className={`max-w-md mx-auto bg-WHITE min-h-screen shadow-lg lg:shadow-xl ${
|
||||
isDesktopReady
|
||||
expandOnDesktop
|
||||
? "lg:max-w-none lg:mx-0 lg:min-h-0 lg:shadow-none"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`pb-[calc(50px+env(safe-area-inset-bottom))] ${
|
||||
isDesktopReady ? "lg:pb-0" : ""
|
||||
expandOnDesktop ? "lg:pb-0" : ""
|
||||
}`}
|
||||
>
|
||||
{children}
|
||||
{isThread ? <></> : <MobileBottomNavigation hideOnDesktop={isDesktopReady} />}
|
||||
{isThread ? (
|
||||
<></>
|
||||
) : (
|
||||
<MobileBottomNavigation hideOnDesktop={expandOnDesktop} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{isDesktopReady && <DesktopFooter />}
|
||||
|
||||
@ -21,6 +21,7 @@ import AppInput from "~/components/AppInput";
|
||||
import { useToast } from "~/hooks/use-toast";
|
||||
import { useSubmit, useLoaderData } from "@remix-run/react";
|
||||
import { User } from "~/utils/token-manager.server";
|
||||
import logo from "~/assets/logo/SVG-07.svg";
|
||||
|
||||
// Only allow same-site, path-relative redirects. Rejects absolute URLs
|
||||
// (https://evil.com) and protocol-relative URLs (//evil.com) to prevent
|
||||
@ -106,8 +107,14 @@ export default function LoginPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 px-[20px] py-12 items-center w-full">
|
||||
{enableVerifySection ? (
|
||||
<div className="lg:min-h-screen lg:flex lg:items-center lg:justify-center lg:bg-WHITE2 lg:py-12">
|
||||
<div className="flex flex-col gap-6 px-[20px] py-12 items-center w-full lg:max-w-[460px] lg:bg-WHITE lg:rounded-2xl lg:border lg:border-WHITE3 lg:shadow-lg lg:px-8 lg:py-10 lg:my-12">
|
||||
{/* Brand (desktop) */}
|
||||
<div className="hidden lg:flex items-center gap-2.5 mb-1">
|
||||
<img src={logo} alt="ویترون" className="w-7 h-9 object-contain" />
|
||||
<b className="text-[22px] font-extrabold text-VITROWN_BLUE">ویترون</b>
|
||||
</div>
|
||||
{enableVerifySection ? (
|
||||
<>
|
||||
<div className="flex flex-col gap-4 w-full items-center">
|
||||
<img alt="" src={verifyBanner} className="w-[85px] h-[70px]" />
|
||||
@ -127,7 +134,7 @@ export default function LoginPage() {
|
||||
</div>
|
||||
<div className="w-full mt-2 flex justify-center">
|
||||
<InputOTP
|
||||
maxLength={4}
|
||||
maxLength={6}
|
||||
onComplete={(finalValue) => {
|
||||
const convertedValue = convertPersianToEnglish(finalValue);
|
||||
setOtpValue(convertedValue);
|
||||
@ -138,17 +145,19 @@ export default function LoginPage() {
|
||||
setOtpValue(convertedValue);
|
||||
}}
|
||||
>
|
||||
<InputOTPGroup dir="ltr" className="gap-4">
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPGroup dir="ltr" className="gap-1.5 sm:gap-3">
|
||||
<InputOTPSlot index={0} className="!w-9 sm:!w-12" />
|
||||
<InputOTPSlot index={1} className="!w-9 sm:!w-12" />
|
||||
<InputOTPSlot index={2} className="!w-9 sm:!w-12" />
|
||||
<InputOTPSlot index={3} className="!w-9 sm:!w-12" />
|
||||
<InputOTPSlot index={4} className="!w-9 sm:!w-12" />
|
||||
<InputOTPSlot index={5} className="!w-9 sm:!w-12" />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</div>
|
||||
<div className="gap-4 w-full flex flex-col items-center">
|
||||
<Button
|
||||
disabled={verifyOtpMutation.isPending || !(otpValue.length === 4)}
|
||||
disabled={verifyOtpMutation.isPending || !(otpValue.length === 6)}
|
||||
className="w-[90%]"
|
||||
size={"xl"}
|
||||
variant="dark"
|
||||
@ -235,6 +244,7 @@ export default function LoginPage() {
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user