diff --git a/src/app/intro/intro-client.test.tsx b/src/app/intro/intro-client.test.tsx
new file mode 100644
index 0000000..ab1a1d3
--- /dev/null
+++ b/src/app/intro/intro-client.test.tsx
@@ -0,0 +1,76 @@
+import { render, screen, cleanup } from "@testing-library/react";
+import { describe, it, expect, vi, afterEach } from "vitest";
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+import IntroClient from "./intro-client";
+
+vi.mock("next/navigation", () => ({
+ useRouter: () => ({
+ push: vi.fn(),
+ replace: vi.fn(),
+ back: vi.fn(),
+ }),
+}));
+
+vi.mock("@/translations/provider", () => ({
+ useI18n: () => ({
+ locale: "en",
+ dictionary: {
+ "heavenly marriage": "heavenly marriage",
+ "A Path to Heavenly Marriage": "A Path to Heavenly Marriage",
+ 'We have come together with the goal of creating a secure and confidential path for "permanent marriage" among Muslims':
+ 'We have come together with the goal of creating a secure and confidential path for "permanent marriage" among Muslims',
+ "user profiles": "user profiles",
+ matches: "matches",
+ marriages: "marriages",
+ Submit: "Submit",
+ video: "video",
+ },
+ }),
+}));
+
+vi.mock("@/hooks/marriage/use-profile-main", () => ({
+ useMarriageProfileQuery: () => ({
+ data: undefined,
+ refetch: vi.fn(),
+ }),
+}));
+
+vi.mock("@/hooks/marriage/use-marriage-config", () => ({
+ useMarriageConfigQuery: () => ({
+ data: {
+ intro_video_url: "https://example.com/intro.mp4",
+ intro_video_thumbnail_url: "/assets/images/Frame 2095586523.png",
+ },
+ }),
+}));
+
+vi.mock("@/hooks/use-habib-web-ready", () => ({
+ useHabibWebReady: vi.fn(),
+}));
+
+vi.mock("@/hooks/use-hardware-back-handler", () => ({
+ useHardwareBackHandler: vi.fn(),
+}));
+
+describe("IntroClient", () => {
+ afterEach(() => {
+ cleanup();
+ });
+
+ it("renders intro page without video card when SHOW_INTRO_VIDEOS is false", () => {
+ const queryClient = new QueryClient();
+ render(
+
+
+ ,
+ );
+
+ expect(screen.getByText("A Path to Heavenly Marriage")).toBeInTheDocument();
+ expect(screen.getByText("120")).toBeInTheDocument();
+ expect(screen.getByText("user profiles")).toBeInTheDocument();
+ expect(screen.getByText("Submit")).toBeInTheDocument();
+
+ // Video thumbnail image should NOT be rendered
+ expect(screen.queryByAltText("video")).not.toBeInTheDocument();
+ });
+});
diff --git a/src/app/intro/intro-client.tsx b/src/app/intro/intro-client.tsx
index a2dc838..f1d794e 100644
--- a/src/app/intro/intro-client.tsx
+++ b/src/app/intro/intro-client.tsx
@@ -20,6 +20,7 @@ import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main";
import { useHabibWebReady } from "@/hooks/use-habib-web-ready";
import { useHardwareBackHandler } from "@/hooks/use-hardware-back-handler";
import { authBridge } from "@/lib/auth-bridge";
+import { SHOW_INTRO_VIDEOS } from "@/config/features";
import { getSubmitPath } from "@/lib/get-submit-path";
import { localizePath } from "@/translations/config";
import { useI18n } from "@/translations/provider";
@@ -125,10 +126,27 @@ export default function IntroClient() {
return (
<>
-
+
-
-
+
+
-
+
@@ -177,27 +200,31 @@ export default function IntroClient() {
-
setIsPlayerOpen(true)}
- >
-
-
-
-
+ {SHOW_INTRO_VIDEOS && (
+ <>
+
setIsPlayerOpen(true)}
+ >
+
+
+
+
-
setIsPlayerOpen(false)}
- videoUrl={config?.intro_video_url}
- />
+ setIsPlayerOpen(false)}
+ videoUrl={config?.intro_video_url}
+ />
+ >
+ )}
{
void handleSecondaryAction();
}}
- disabled={paymentMutation.isPending}
+ disabled={
+ paymentMutation.isPending ||
+ isFetchingContact ||
+ (isMalePaymentDone &&
+ contactInfoQuery.isFetching &&
+ !contactInfoQuery.data)
+ }
className={
isFemaleProfile
- ? "flex-1 min-h-[48px] px-3.5 py-2.5 rounded-[14px] bg-gradient-to-r from-[#FF6687] to-[#FF456C] text-white font-bold text-[13.5px] leading-tight flex items-center justify-center text-center whitespace-nowrap shadow-sm transition-all cursor-pointer hover:opacity-95 active:scale-[0.98] disabled:opacity-50 disabled:cursor-not-allowed"
- : "flex-1 max-w-[170px] min-h-[48px] appearance-none border-0 bg-transparent p-0 text-center cursor-pointer transition-transform active:scale-[0.98] disabled:opacity-50 disabled:cursor-not-allowed"
+ ? "flex-1 min-h-[48px] px-3.5 py-2.5 rounded-[14px] bg-gradient-to-r from-[#FF6687] to-[#FF456C] text-white font-bold text-[13.5px] leading-tight flex items-center justify-center text-center whitespace-nowrap shadow-sm transition-all duration-150 cursor-pointer hover:opacity-95 active:scale-[0.96] disabled:opacity-50 disabled:cursor-not-allowed"
+ : "flex-1 max-w-[170px] min-h-[48px] appearance-none border-0 bg-transparent p-0 text-center cursor-pointer transition-transform duration-150 active:scale-[0.96] disabled:opacity-50 disabled:cursor-not-allowed"
}
>
{isFemaleProfile ? (
@@ -707,8 +723,12 @@ export default function RequestAcceptedClient() {
secondaryActionText
)
) : (
-
- {paymentMutation.isPending ? (
+
+ {paymentMutation.isPending ||
+ isFetchingContact ||
+ (isMalePaymentDone &&
+ contactInfoQuery.isFetching &&
+ !contactInfoQuery.data) ? (
) : (
secondaryActionText
diff --git a/src/components/Componentes/slider-header.tsx b/src/components/Componentes/slider-header.tsx
index 90a49c6..0a03618 100644
--- a/src/components/Componentes/slider-header.tsx
+++ b/src/components/Componentes/slider-header.tsx
@@ -1,4 +1,5 @@
import type { ReactNode } from "react";
+import { SHOW_INTRO_VIDEOS } from "@/config/features";
type SliderHeaderProps = {
index: number;
@@ -10,7 +11,7 @@ type SliderHeaderProps = {
export function SliderHeader({
index,
title,
- totalSteps = 5,
+ totalSteps = SHOW_INTRO_VIDEOS ? 5 : 4,
stepLabel,
}: SliderHeaderProps) {
return (
diff --git a/src/components/Componentes/slider-page.test.tsx b/src/components/Componentes/slider-page.test.tsx
index adceb6d..4a6fc5f 100644
--- a/src/components/Componentes/slider-page.test.tsx
+++ b/src/components/Componentes/slider-page.test.tsx
@@ -76,10 +76,22 @@ describe('SliderPage', () => {
fireEvent.click(acceptBtn);
}
const dots = screen.getAllByRole('button', { name: /go to slide/i });
- fireEvent.click(dots[4]); // Go directly to slide 5
+ fireEvent.click(dots[dots.length - 1]); // Go directly to final slide
return await screen.findByText('Finish');
};
+ it('renders 4 dots and skips video slide when SHOW_INTRO_VIDEOS is false', () => {
+ render(
+
+
+
+ );
+
+ const dots = screen.getAllByRole('button', { name: /go to slide/i });
+ expect(dots).toHaveLength(4);
+ expect(screen.queryByText('Watch Video')).not.toBeInTheDocument();
+ });
+
it('a. Success: PATCH ok, GET ok -> replace', async () => {
const finishBtn = await navigateToFinalSlide();
const initialRemoveCount = mockRemoveItem.mock.calls.filter(call => call[0] === 'marriage-slider-answers').length;
diff --git a/src/components/Componentes/slider-page.tsx b/src/components/Componentes/slider-page.tsx
index 8965023..c3ac3b8 100644
--- a/src/components/Componentes/slider-page.tsx
+++ b/src/components/Componentes/slider-page.tsx
@@ -14,13 +14,14 @@ import Button from "./button";
import ErrorToast from "./error-toast";
import NavigationButton from "./navigation-button";
import type { GenderAnswer, RegistrationAnswer } from "./slider-slide";
+import { SHOW_INTRO_VIDEOS } from "@/config/features";
import { SliderSlideFive } from "./slider-slide-five";
import { SliderSlideFour } from "./slider-slide-four";
import { SliderSlideOne, SliderSlideOneActions } from "./slider-slide-one";
import { SliderSlideThree } from "./slider-slide-three";
import { SliderSlideTwo } from "./slider-slide-two";
-const FINAL_SLIDE_COUNT = 5;
+const FINAL_SLIDE_COUNT = SHOW_INTRO_VIDEOS ? 5 : 4;
const SLIDER_ANSWERS_STORAGE_KEY = "marriage-slider-answers";
export type SliderPageProps = {
@@ -192,20 +193,30 @@ export default function SliderPage({ onClose }: SliderPageProps = {}) {
>
setHasReadRules(true)}
/>
-
+ {SHOW_INTRO_VIDEOS && (
+
+ )}
- {hasFinalNotice ? : null}
+ {hasFinalNotice ? (
+
+ ) : null}
diff --git a/src/components/Componentes/slider-slide-five.tsx b/src/components/Componentes/slider-slide-five.tsx
index e2685a3..9051abc 100644
--- a/src/components/Componentes/slider-slide-five.tsx
+++ b/src/components/Componentes/slider-slide-five.tsx
@@ -10,14 +10,14 @@ const NOTICE_ITEMS = [
"We provide a safe and respectful environment at every step.",
];
-export function SliderSlideFive({ index }: SliderSlideProps) {
+export function SliderSlideFive({ index, totalSteps }: SliderSlideProps) {
return (
-
+
diff --git a/src/components/Componentes/slider-slide-four.tsx b/src/components/Componentes/slider-slide-four.tsx
index e4c8d62..9824720 100644
--- a/src/components/Componentes/slider-slide-four.tsx
+++ b/src/components/Componentes/slider-slide-four.tsx
@@ -11,6 +11,7 @@ type SliderSlideFourProps = SliderSlideProps & {
export function SliderSlideFour({
index,
+ totalSteps,
selectedRegistration,
onRegistrationChange,
}: SliderSlideFourProps) {
@@ -25,7 +26,7 @@ export function SliderSlideFour({
className="flex h-full min-h-0 w-full shrink-0 flex-col"
>
-
+
You can register both for yourself and for your loved ones, but
obtaining the explicit consent and permission of the person you are
diff --git a/src/components/Componentes/slider-slide-one.tsx b/src/components/Componentes/slider-slide-one.tsx
index 83a7ed6..f57e498 100644
--- a/src/components/Componentes/slider-slide-one.tsx
+++ b/src/components/Componentes/slider-slide-one.tsx
@@ -12,7 +12,7 @@ type SliderSlideOneProps = SliderSlideProps & {
onScrollToEnd?: () => void;
};
-export function SliderSlideOne({ index, onScrollToEnd }: SliderSlideOneProps) {
+export function SliderSlideOne({ index, totalSteps, onScrollToEnd }: SliderSlideOneProps) {
const containerRef = useRef(null);
useEffect(() => {
@@ -59,7 +59,7 @@ export function SliderSlideOne({ index, onScrollToEnd }: SliderSlideOneProps) {
maskImage: CONTENT_MASK,
}}
>
-
+
Welcome to Habib Marriage. Please review our terms of service before
diff --git a/src/components/Componentes/slider-slide-three.tsx b/src/components/Componentes/slider-slide-three.tsx
index cfee8d4..4014ba9 100644
--- a/src/components/Componentes/slider-slide-three.tsx
+++ b/src/components/Componentes/slider-slide-three.tsx
@@ -36,6 +36,7 @@ type SliderSlideThreeProps = SliderSlideProps & {
export function SliderSlideThree({
index,
+ totalSteps,
selectedGender,
onGenderChange,
}: SliderSlideThreeProps) {
@@ -44,7 +45,7 @@ export function SliderSlideThree({
aria-label={`Slide ${index + 1}`}
className="flex h-full min-h-0 w-full shrink-0 flex-col justify-between"
>
-
+
{GENDER_OPTIONS.map((option) => {
diff --git a/src/components/Componentes/slider-slide-two.tsx b/src/components/Componentes/slider-slide-two.tsx
index 9d08344..3c2ead9 100644
--- a/src/components/Componentes/slider-slide-two.tsx
+++ b/src/components/Componentes/slider-slide-two.tsx
@@ -9,7 +9,7 @@ import type { SliderSlideProps } from "./slider-slide";
import VideoPlayer from "./video-player";
import NetworkImage from "./network-image";
-export function SliderSlideTwo({ index }: SliderSlideProps) {
+export function SliderSlideTwo({ index, totalSteps }: SliderSlideProps) {
const [isPlayerOpen, setIsPlayerOpen] = useState(false);
const { data: config } = useMarriageConfigQuery();
const { dictionary: t } = useI18n();
@@ -28,7 +28,7 @@ export function SliderSlideTwo({ index }: SliderSlideProps) {
>