modal location updated
This commit is contained in:
@@ -9,8 +9,7 @@ import {
|
|||||||
import PhonePrefix from '../../../../shared/ui/phonePrefix';
|
import PhonePrefix from '../../../../shared/ui/phonePrefix';
|
||||||
import { MotionWrapper } from '../../../../shared/ui/motion';
|
import { MotionWrapper } from '../../../../shared/ui/motion';
|
||||||
import { useLoginForm } from '../lib/useLoginForm';
|
import { useLoginForm } from '../lib/useLoginForm';
|
||||||
import { useLoginModal } from '@/shared/zustand/auth';
|
import { useLoginModal, useRegisterModal } from '@/shared/zustand/auth';
|
||||||
import Link from 'next/link';
|
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
|
|
||||||
export function LoginForm() {
|
export function LoginForm() {
|
||||||
@@ -20,6 +19,9 @@ export function LoginForm() {
|
|||||||
|
|
||||||
const { phone, setPhone, submit, error, loading } = useLoginForm();
|
const { phone, setPhone, submit, error, loading } = useLoginForm();
|
||||||
const toggleLoginModal = useLoginModal((state) => state.toggleLoginModal);
|
const toggleLoginModal = useLoginModal((state) => state.toggleLoginModal);
|
||||||
|
const toggleRegisterModal = useRegisterModal(
|
||||||
|
(state) => state.toggleRegisterModal,
|
||||||
|
);
|
||||||
|
|
||||||
const handlePhoneChange = useCallback(
|
const handlePhoneChange = useCallback(
|
||||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
@@ -149,14 +151,17 @@ export function LoginForm() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Register hint */}
|
{/* Register hint */}
|
||||||
<p className="text-center text-[0.78rem] text-stone-400">
|
<p className="text-center text-[0.78rem] text-stone-400 flex items-center justify-center gap-2">
|
||||||
{t('registerPrompt')}
|
{t('registerPrompt')}
|
||||||
<Link
|
<p
|
||||||
href="/register"
|
onClick={() => {
|
||||||
className="text-stone-800 underline underline-offset-2 hover:text-stone-600 transition-colors"
|
toggleLoginModal();
|
||||||
|
toggleRegisterModal();
|
||||||
|
}}
|
||||||
|
className="text-stone-800 hover:cursor-pointer underline underline-offset-2 hover:text-stone-600 transition-colors"
|
||||||
>
|
>
|
||||||
{t('registerLink')}
|
{t('registerLink')}
|
||||||
</Link>
|
</p>
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useRegisterForm } from '../lib/useRegisterForm';
|
|||||||
import { formatPhone, normalizeDigits } from '@/shared/lib/formatPhone';
|
import { formatPhone, normalizeDigits } from '@/shared/lib/formatPhone';
|
||||||
import PhonePrefix from '@/shared/ui/phonePrefix';
|
import PhonePrefix from '@/shared/ui/phonePrefix';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
|
import { useLoginModal, useRegisterModal } from '@/shared/zustand/auth';
|
||||||
|
|
||||||
function Field({
|
function Field({
|
||||||
id,
|
id,
|
||||||
@@ -66,6 +67,7 @@ function Field({
|
|||||||
export function RegisterFormUI() {
|
export function RegisterFormUI() {
|
||||||
const [phone, setPhone] = React.useState('');
|
const [phone, setPhone] = React.useState('');
|
||||||
const t = useTranslations('Auth.Register');
|
const t = useTranslations('Auth.Register');
|
||||||
|
const t_login = useTranslations('Auth.Login');
|
||||||
const tCommon = useTranslations('Common');
|
const tCommon = useTranslations('Common');
|
||||||
const {
|
const {
|
||||||
registerData,
|
registerData,
|
||||||
@@ -77,6 +79,10 @@ export function RegisterFormUI() {
|
|||||||
handleSubmit,
|
handleSubmit,
|
||||||
setItem,
|
setItem,
|
||||||
} = useRegisterForm();
|
} = useRegisterForm();
|
||||||
|
const toggleLoginModal = useLoginModal((state) => state.toggleLoginModal);
|
||||||
|
const toggleRegisterModal = useRegisterModal(
|
||||||
|
(state) => state.toggleRegisterModal,
|
||||||
|
);
|
||||||
const [isFocused, setIsFocused] = React.useState(false);
|
const [isFocused, setIsFocused] = React.useState(false);
|
||||||
const handlePhoneChange = useCallback(
|
const handlePhoneChange = useCallback(
|
||||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
@@ -233,6 +239,29 @@ export function RegisterFormUI() {
|
|||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
{/* 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">
|
||||||
|
{tCommon('or')}
|
||||||
|
</span>
|
||||||
|
<span className="h-px flex-1 bg-stone-200" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Register hint */}
|
||||||
|
<p className="text-center text-[0.78rem] text-stone-400 flex items-center justify-center gap-2">
|
||||||
|
{t('loginPrompt')}
|
||||||
|
<p
|
||||||
|
onClick={() => {
|
||||||
|
toggleLoginModal();
|
||||||
|
toggleRegisterModal();
|
||||||
|
}}
|
||||||
|
className="text-stone-800 hover:cursor-pointer underline underline-offset-2 hover:text-stone-600 transition-colors"
|
||||||
|
>
|
||||||
|
{t_login('title')}
|
||||||
|
</p>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,7 +188,8 @@
|
|||||||
"namePlaceholder": "Ali",
|
"namePlaceholder": "Ali",
|
||||||
"surnamePlaceholder": "Karimov",
|
"surnamePlaceholder": "Karimov",
|
||||||
"terms": "I agree to the Terms of Service and Privacy Policy",
|
"terms": "I agree to the Terms of Service and Privacy Policy",
|
||||||
"submitButton": "Create account"
|
"submitButton": "Create account",
|
||||||
|
"loginPrompt": "Already have an account?"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Payment": {
|
"Payment": {
|
||||||
|
|||||||
@@ -188,7 +188,8 @@
|
|||||||
"namePlaceholder": "Али",
|
"namePlaceholder": "Али",
|
||||||
"surnamePlaceholder": "Каримов",
|
"surnamePlaceholder": "Каримов",
|
||||||
"terms": "Я согласен с Условиями обслуживания и Политикой конфиденциальности",
|
"terms": "Я согласен с Условиями обслуживания и Политикой конфиденциальности",
|
||||||
"submitButton": "Создать аккаунт"
|
"submitButton": "Создать аккаунт",
|
||||||
|
"loginPrompt": "Уже есть аккаунт?"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Payment": {
|
"Payment": {
|
||||||
|
|||||||
@@ -192,6 +192,7 @@ declare const messages: {
|
|||||||
surnamePlaceholder: 'Karimov';
|
surnamePlaceholder: 'Karimov';
|
||||||
terms: "Men Xizmat ko'rsatish shartlari va Maxfiylik siyosatiga roziman";
|
terms: "Men Xizmat ko'rsatish shartlari va Maxfiylik siyosatiga roziman";
|
||||||
submitButton: 'Hisob yaratish';
|
submitButton: 'Hisob yaratish';
|
||||||
|
loginPrompt: 'Hisobingiz bormi?';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
Payment: {
|
Payment: {
|
||||||
|
|||||||
@@ -188,7 +188,8 @@
|
|||||||
"namePlaceholder": "Ali",
|
"namePlaceholder": "Ali",
|
||||||
"surnamePlaceholder": "Karimov",
|
"surnamePlaceholder": "Karimov",
|
||||||
"terms": "Men Xizmat ko'rsatish shartlari va Maxfiylik siyosatiga roziman",
|
"terms": "Men Xizmat ko'rsatish shartlari va Maxfiylik siyosatiga roziman",
|
||||||
"submitButton": "Hisob yaratish"
|
"submitButton": "Hisob yaratish",
|
||||||
|
"loginPrompt": "Hisobingiz bormi?"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Payment": {
|
"Payment": {
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import type { FC } from 'react';
|
'use client';
|
||||||
import { motion, type MotionStyle, type MotionValue } from 'framer-motion';
|
import {
|
||||||
|
motion,
|
||||||
|
useScroll,
|
||||||
|
useTransform,
|
||||||
|
type MotionStyle,
|
||||||
|
} from 'framer-motion';
|
||||||
import { fadeUp, stagger } from '../animations';
|
import { fadeUp, stagger } from '../animations';
|
||||||
import { C } from '../tokens';
|
import { C } from '../tokens';
|
||||||
import { STATS } from '../constants';
|
import { STATS } from '../constants';
|
||||||
@@ -10,16 +15,15 @@ import Section from './Section';
|
|||||||
import Stat from './Stat';
|
import Stat from './Stat';
|
||||||
import StartButton from './StartButton';
|
import StartButton from './StartButton';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
|
import { useLoginModal } from '@/shared/zustand/auth';
|
||||||
|
|
||||||
interface HeroProps {
|
const Hero = () => {
|
||||||
onStart: () => void;
|
|
||||||
blobY: MotionValue<number>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Hero: FC<HeroProps> = ({ onStart, blobY }) => {
|
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
const t = useTranslations('Hero');
|
const t = useTranslations('Hero');
|
||||||
const tStats = useTranslations('Stats');
|
const tStats = useTranslations('Stats');
|
||||||
|
const { scrollY } = useScroll();
|
||||||
|
const blobY = useTransform(scrollY, [0, 600], [0, 80]);
|
||||||
|
const toggleLoginModal = useLoginModal((state) => state.toggleLoginModal);
|
||||||
|
|
||||||
const getTranslatedLabel = (label: string) => {
|
const getTranslatedLabel = (label: string) => {
|
||||||
switch (label) {
|
switch (label) {
|
||||||
@@ -149,7 +153,7 @@ const Hero: FC<HeroProps> = ({ onStart, blobY }) => {
|
|||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StartButton onClick={onStart} />
|
<StartButton onClick={() => toggleLoginModal()} />
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
color: C.textMuted,
|
color: C.textMuted,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { FC } from 'react';
|
'use client';
|
||||||
|
import { useRef } from 'react';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { fadeUp } from '../animations';
|
import { fadeUp } from '../animations';
|
||||||
import { C } from '../tokens';
|
import { C } from '../tokens';
|
||||||
@@ -8,15 +9,13 @@ import Section from './Section';
|
|||||||
import StartButton from './StartButton';
|
import StartButton from './StartButton';
|
||||||
import StepCard from './StepCard';
|
import StepCard from './StepCard';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
|
import { useLoginModal } from '@/shared/zustand/auth';
|
||||||
|
|
||||||
interface StepsSectionProps {
|
const StepsSection = () => {
|
||||||
stepsRef: React.RefObject<HTMLDivElement | null>;
|
|
||||||
onScrollTop: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const StepsSection: FC<StepsSectionProps> = ({ stepsRef, onScrollTop }) => {
|
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
const t = useTranslations('StepsSection');
|
const t = useTranslations('StepsSection');
|
||||||
|
const stepsRef = useRef<HTMLDivElement>(null);
|
||||||
|
const toggleLoginModal = useLoginModal((state) => state.toggleLoginModal);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -120,7 +119,7 @@ const StepsSection: FC<StepsSectionProps> = ({ stepsRef, onScrollTop }) => {
|
|||||||
{t('ctaDescription')}
|
{t('ctaDescription')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<StartButton onClick={onScrollTop} />
|
<StartButton onClick={() => toggleLoginModal()} />
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
|
|||||||
@@ -1,27 +1,16 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { useRef, type FC } from 'react';
|
|
||||||
import { useScroll, useTransform } from 'framer-motion';
|
|
||||||
import Hero from './components/Hero';
|
import Hero from './components/Hero';
|
||||||
import InfoSection from './components/InfoSection';
|
import InfoSection from './components/InfoSection';
|
||||||
import StepsSection from './components/StepsSection';
|
import StepsSection from './components/StepsSection';
|
||||||
import Ticker from './components/Ticker';
|
import Ticker from './components/Ticker';
|
||||||
|
|
||||||
const PlagiarismLanding: FC = () => {
|
const PlagiarismLanding = () => {
|
||||||
const stepsRef = useRef<HTMLDivElement>(null);
|
|
||||||
const { scrollY } = useScroll();
|
|
||||||
const blobY = useTransform(scrollY, [0, 600], [0, 80]);
|
|
||||||
|
|
||||||
const scrollToSteps = () =>
|
|
||||||
stepsRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
||||||
|
|
||||||
const scrollToTop = () => window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Hero onStart={scrollToSteps} blobY={blobY} />
|
<Hero />
|
||||||
<Ticker />
|
<Ticker />
|
||||||
<InfoSection />
|
<InfoSection />
|
||||||
<StepsSection stepsRef={stepsRef} onScrollTop={scrollToTop} />
|
<StepsSection />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user