mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Fix auth page
This commit is contained in:
@@ -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,80 +50,55 @@ 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 (activeRef.current) {
|
||||||
|
const resizeObserver = new ResizeObserver((entries) => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
const height = entry.contentRect.height;
|
||||||
if (height > 0) {
|
if (height > 0) {
|
||||||
setContainerHeight(height);
|
setContainerHeight(Math.max(height, MIN_HEIGHT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [currentMode, loginFormRef, registerFormRef]);
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
if (!effectActivated) {
|
|
||||||
setEffectActivated(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
resizeObserver.observe(activeRef.current);
|
||||||
|
|
||||||
|
// Initial measurement
|
||||||
|
const initialHeight = activeRef.current.scrollHeight;
|
||||||
|
if (initialHeight > 0) {
|
||||||
|
setContainerHeight(Math.max(initialHeight, MIN_HEIGHT));
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
cancelAnimationFrame(rafId1);
|
resizeObserver.disconnect();
|
||||||
if (rafId2 !== null) {
|
|
||||||
cancelAnimationFrame(rafId2);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
}, [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>
|
||||||
@@ -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")} />
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user