Fix auth page

This commit is contained in:
2026-01-20 16:08:50 +03:00
Unverified
parent 6b8f08885a
commit 87e6bf66f6
2 changed files with 51 additions and 74 deletions
+42 -71
View File
@@ -1,5 +1,5 @@
import { AuthContainer } from "./Auth"; import { AuthContainer } from "./Auth";
import { useState, useEffect, useRef, useLayoutEffect, useCallback, type RefObject } from "react"; import { useState, useEffect, useRef } from "react";
import { useNavigate, useSearchParams } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { motion, AnimatePresence } from "motion/react"; import { motion, AnimatePresence } from "motion/react";
import useDownloadAppScreen from "@/core/hooks/useDownloadAppScreen"; import useDownloadAppScreen from "@/core/hooks/useDownloadAppScreen";
@@ -8,18 +8,23 @@ import { RegisterForm } from "./RegisterForm";
import type { Variants, Transition } from "motion/react"; import type { Variants, Transition } from "motion/react";
import styles from "./auth.module.scss"; import styles from "./auth.module.scss";
const MIN_HEIGHT = 400;
const slideVariants: Variants = { const slideVariants: Variants = {
enter: (direction: number) => ({ enter: (direction: number) => ({
x: direction > 0 ? 300 : -300, x: direction > 0 ? 300 : -300,
opacity: 0 opacity: 0,
y: 0 // Ensure no vertical movement
}), }),
center: { center: {
x: 0, x: 0,
opacity: 1 opacity: 1,
y: 0 // Ensure no vertical movement
}, },
exit: (direction: number) => ({ exit: (direction: number) => ({
x: direction > 0 ? -300 : 300, x: direction > 0 ? -300 : 300,
opacity: 0 opacity: 0,
y: 0 // Ensure no vertical movement
}) })
}; };
@@ -45,81 +50,56 @@ export default function AuthPage() {
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const loginFormRef = useRef<HTMLDivElement>(null); const loginFormRef = useRef<HTMLDivElement>(null);
const registerFormRef = useRef<HTMLDivElement>(null); const registerFormRef = useRef<HTMLDivElement>(null);
const [containerHeight, setContainerHeight] = useState<number | "auto">("auto"); const [containerHeight, setContainerHeight] = useState<number>(400);
const [isTransitioning, setIsTransitioning] = useState(false);
const currentMode = searchParams.get("mode") || "login"; const currentMode = searchParams.get("mode") || "login";
const enteringElementRef = useRef<"login" | "register" | null>(null);
const [effectActivated, setEffectActivated] = useState(false);
useEffect(() => { useEffect(() => {
if (prevMode.current !== currentMode) { if (prevMode.current !== currentMode) {
setDirection(currentMode === "register" ? 1 : -1); setDirection(currentMode === "register" ? 1 : -1);
prevMode.current = currentMode; prevMode.current = currentMode;
enteringElementRef.current = currentMode as "login" | "register"; setIsTransitioning(true);
} }
}, [currentMode]); }, [currentMode]);
const measureActiveHeight = useCallback(() => { // Setup ResizeObserver to watch for content changes
const activeComponent = currentMode === "login" ? loginFormRef.current : registerFormRef.current; useEffect(() => {
if (activeComponent) { const activeRef = currentMode === "login" ? loginFormRef : registerFormRef;
const height = activeComponent.scrollHeight;
if (height > 0) {
setContainerHeight(height);
}
}
}, [currentMode, loginFormRef, registerFormRef]);
useLayoutEffect(() => { if (activeRef.current) {
if (!effectActivated) { const resizeObserver = new ResizeObserver((entries) => {
setEffectActivated(true); for (const entry of entries) {
return; const height = entry.contentRect.height;
} if (height > 0) {
setContainerHeight(Math.max(height, MIN_HEIGHT));
// Always measure, but prioritize the entering element during transitions }
// Use double requestAnimationFrame to ensure DOM is fully updated and layout is complete }
let rafId2: number | null = null;
const rafId1 = requestAnimationFrame(() => {
rafId2 = requestAnimationFrame(() => {
measureActiveHeight();
}); });
});
return () => { resizeObserver.observe(activeRef.current);
cancelAnimationFrame(rafId1);
if (rafId2 !== null) { // Initial measurement
cancelAnimationFrame(rafId2); const initialHeight = activeRef.current.scrollHeight;
if (initialHeight > 0) {
setContainerHeight(Math.max(initialHeight, MIN_HEIGHT));
} }
};
return () => {
resizeObserver.disconnect();
};
}
}, [currentMode]); }, [currentMode]);
function switchMode(newMode: "login" | "register") { function switchMode(newMode: "login" | "register") {
navigate(`/auth?mode=${newMode}`, { replace: true }); navigate(`/auth?mode=${newMode}`, { replace: true });
} }
function handleAnimationComplete( function handleAnimationComplete() {
currentMode: "login" | "register", setIsTransitioning(false);
mode: "login" | "register",
enteringElementRef: RefObject<"login" | "register" | null>,
formRef: React.RefObject<HTMLDivElement | null>,
setContainerHeight: (height: number) => void
) {
return () => {
if (currentMode === mode && enteringElementRef.current === mode) {
enteringElementRef.current = null;
requestAnimationFrame(() => {
requestAnimationFrame(() => {
if (formRef.current && currentMode === mode) {
const height = formRef.current.scrollHeight;
if (height > 0) {
setContainerHeight(height);
}
}
});
});
}
}
} }
return ( return (
<AuthContainer> <AuthContainer>
<div <div
@@ -127,14 +107,8 @@ export default function AuthPage() {
style={{ style={{
position: "relative", position: "relative",
width: "100%", width: "100%",
height: containerHeight === "auto" ? "auto" : `${containerHeight}px`, height: `${containerHeight}px`,
transition: "height 0.3s ease" transition: isTransitioning ? "height 0.3s ease" : "none"
}}
onAnimationStart={() => {
}}
onAnimationEnd={() => {
setContainerHeight("auto");
}} }}
> >
<AnimatePresence mode="sync" custom={direction}> <AnimatePresence mode="sync" custom={direction}>
@@ -148,11 +122,8 @@ export default function AuthPage() {
animate="center" animate="center"
exit="exit" exit="exit"
transition={slideTransition} transition={slideTransition}
onAnimationComplete={handleAnimationComplete("login", "login", enteringElementRef, loginFormRef, setContainerHeight)} onAnimationComplete={handleAnimationComplete}
className={styles.formWrapper} className={styles.formWrapper}
style={{
position: containerHeight === "auto" ? "relative" : "absolute"
}}
> >
<LoginForm onSwitchMode={() => switchMode("register")} /> <LoginForm onSwitchMode={() => switchMode("register")} />
</motion.div> </motion.div>
@@ -166,7 +137,7 @@ export default function AuthPage() {
animate="center" animate="center"
exit="exit" exit="exit"
transition={slideTransition} transition={slideTransition}
onAnimationComplete={handleAnimationComplete("register", "register", enteringElementRef, registerFormRef, setContainerHeight)} onAnimationComplete={handleAnimationComplete}
className={styles.formWrapper} className={styles.formWrapper}
> >
<RegisterForm onSwitchMode={() => switchMode("login")} /> <RegisterForm onSwitchMode={() => switchMode("login")} />
+6
View File
@@ -98,6 +98,12 @@
top: 0; top: 0;
left: 0; left: 0;
&.relative {
position: relative;
top: auto;
left: auto;
}
.authHeader { .authHeader {
margin: 0; margin: 0;
padding: 24px; padding: 24px;