From 4bd7b93b4aeda743e1786844fae368a79c8985f7 Mon Sep 17 00:00:00 2001 From: mobiniqow Date: Sat, 19 Sep 2026 22:17:29 +0330 Subject: [PATCH] Fix onboarding bottom button not staying pinned, and swipe card crash - OnboardingScreen used min-h-dvh instead of h-dvh, so the scrollable content area never actually clipped/scrolled internally; the page just grew and the primary CTA button scrolled away with it instead of staying visible. Switch to h-dvh and give each step's button a sticky footer (StepFooterButton). - SwipeCard crashed with "Cannot read properties of null" when a candidate had no photos, because the backend could return null instead of an empty array; guard with optional chaining. --- src/components/discover/SwipeCard.tsx | 2 +- .../onboarding/OnboardingScreen.tsx | 6 ++--- .../onboarding/StepFooterButton.tsx | 25 +++++++++++++++++++ .../onboarding/steps/BasicInfoStep.tsx | 6 ++--- .../onboarding/steps/BodyInfoStep.tsx | 6 ++--- .../onboarding/steps/EducationStep.tsx | 6 ++--- .../onboarding/steps/GenericOptionStep.tsx | 6 ++--- .../onboarding/steps/PhotosStep.tsx | 6 ++--- .../onboarding/steps/ProfileQuestionsStep.tsx | 6 ++--- 9 files changed, 47 insertions(+), 22 deletions(-) create mode 100644 src/components/onboarding/StepFooterButton.tsx diff --git a/src/components/discover/SwipeCard.tsx b/src/components/discover/SwipeCard.tsx index b9dc57d..002d7aa 100644 --- a/src/components/discover/SwipeCard.tsx +++ b/src/components/discover/SwipeCard.tsx @@ -33,7 +33,7 @@ export function SwipeCard({ } } - const photo = profile.photos[0]; + const photo = profile.photos?.[0]; return ( -
+
+
-
+

{title} {emoji}

diff --git a/src/components/onboarding/StepFooterButton.tsx b/src/components/onboarding/StepFooterButton.tsx new file mode 100644 index 0000000..e95b5b4 --- /dev/null +++ b/src/components/onboarding/StepFooterButton.tsx @@ -0,0 +1,25 @@ +"use client"; + +import { ButtonHTMLAttributes } from "react"; +import { Button } from "@/components/ui/Button"; + +interface StepFooterButtonProps extends ButtonHTMLAttributes { + isLoading?: boolean; +} + +// دکمه‌ی اصلی هر مرحله‌ی onboarding؛ چون داخل ناحیه‌ی overflow-y-auto صفحه است، +// sticky bottom-0 نسبت به همون ناحیه چسبیده می‌مونه، نه اینکه ته لیست اسکرول بشه. +export function StepFooterButton({ + children, + isLoading, + disabled, + ...props +}: StepFooterButtonProps) { + return ( +
+ +
+ ); +} diff --git a/src/components/onboarding/steps/BasicInfoStep.tsx b/src/components/onboarding/steps/BasicInfoStep.tsx index d3ba156..30973ed 100644 --- a/src/components/onboarding/steps/BasicInfoStep.tsx +++ b/src/components/onboarding/steps/BasicInfoStep.tsx @@ -1,7 +1,7 @@ "use client"; import { useState } from "react"; -import { Button } from "@/components/ui/Button"; +import { StepFooterButton } from "@/components/onboarding/StepFooterButton"; import { TextField } from "@/components/ui/TextField"; import { ErrorBanner } from "@/components/ui/ErrorBanner"; import { cn } from "@/lib/utils"; @@ -79,9 +79,9 @@ export function BasicInfoStep({ - +
); } diff --git a/src/components/onboarding/steps/BodyInfoStep.tsx b/src/components/onboarding/steps/BodyInfoStep.tsx index 4b0a63d..defef84 100644 --- a/src/components/onboarding/steps/BodyInfoStep.tsx +++ b/src/components/onboarding/steps/BodyInfoStep.tsx @@ -1,7 +1,7 @@ "use client"; import { useState } from "react"; -import { Button } from "@/components/ui/Button"; +import { StepFooterButton } from "@/components/onboarding/StepFooterButton"; import { TextField } from "@/components/ui/TextField"; import { ErrorBanner } from "@/components/ui/ErrorBanner"; import { submitBodyInfo, FullProfile } from "@/lib/api"; @@ -58,9 +58,9 @@ export function BodyInfoStep({ onChange={(e) => setWeight(e.target.value)} /> - +
); } diff --git a/src/components/onboarding/steps/EducationStep.tsx b/src/components/onboarding/steps/EducationStep.tsx index 375d613..f33ca14 100644 --- a/src/components/onboarding/steps/EducationStep.tsx +++ b/src/components/onboarding/steps/EducationStep.tsx @@ -1,7 +1,7 @@ "use client"; import { useEffect, useState } from "react"; -import { Button } from "@/components/ui/Button"; +import { StepFooterButton } from "@/components/onboarding/StepFooterButton"; import { ErrorBanner } from "@/components/ui/ErrorBanner"; import { FullScreenLoader } from "@/components/ui/FullScreenLoader"; import { OptionPicker } from "@/components/ui/OptionPicker"; @@ -84,9 +84,9 @@ export function EducationStep({ - +
); } diff --git a/src/components/onboarding/steps/GenericOptionStep.tsx b/src/components/onboarding/steps/GenericOptionStep.tsx index 1104fa1..8b1453a 100644 --- a/src/components/onboarding/steps/GenericOptionStep.tsx +++ b/src/components/onboarding/steps/GenericOptionStep.tsx @@ -1,7 +1,7 @@ "use client"; import { useEffect, useState } from "react"; -import { Button } from "@/components/ui/Button"; +import { StepFooterButton } from "@/components/onboarding/StepFooterButton"; import { ErrorBanner } from "@/components/ui/ErrorBanner"; import { FullScreenLoader } from "@/components/ui/FullScreenLoader"; import { OptionPicker } from "@/components/ui/OptionPicker"; @@ -83,9 +83,9 @@ export function GenericOptionStep({ max={max} /> - +
); } diff --git a/src/components/onboarding/steps/PhotosStep.tsx b/src/components/onboarding/steps/PhotosStep.tsx index 79a80fb..f920502 100644 --- a/src/components/onboarding/steps/PhotosStep.tsx +++ b/src/components/onboarding/steps/PhotosStep.tsx @@ -2,7 +2,7 @@ import { useRef, useState } from "react"; import { Plus, X } from "lucide-react"; -import { Button } from "@/components/ui/Button"; +import { StepFooterButton } from "@/components/onboarding/StepFooterButton"; import { ErrorBanner } from "@/components/ui/ErrorBanner"; import { confirmPhotosStep, uploadPhoto, deletePhoto, photoUrl, FullProfile, Photo } from "@/lib/api"; import { formatApiError } from "@/lib/hooks"; @@ -102,9 +102,9 @@ export function PhotosStep({ - + ); } diff --git a/src/components/onboarding/steps/ProfileQuestionsStep.tsx b/src/components/onboarding/steps/ProfileQuestionsStep.tsx index 4cf13d7..67d84fe 100644 --- a/src/components/onboarding/steps/ProfileQuestionsStep.tsx +++ b/src/components/onboarding/steps/ProfileQuestionsStep.tsx @@ -1,7 +1,7 @@ "use client"; import { useEffect, useState } from "react"; -import { Button } from "@/components/ui/Button"; +import { StepFooterButton } from "@/components/onboarding/StepFooterButton"; import { ErrorBanner } from "@/components/ui/ErrorBanner"; import { FullScreenLoader } from "@/components/ui/FullScreenLoader"; import { cn } from "@/lib/utils"; @@ -139,9 +139,9 @@ export function ProfileQuestionsStep({ - + ); }