You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
4.0 KiB
150 lines
4.0 KiB
"use client";
|
|
|
|
import Image from "next/image";
|
|
import type { HTMLAttributes, ReactNode } from "react";
|
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
import { useHardwareBackHandler } from "@/hooks/use-hardware-back-handler";
|
|
import { useI18n } from "@/translations/provider";
|
|
|
|
const EXIT_ANIMATION_MS = 200;
|
|
|
|
export type FemaleConsentSheetProps = Omit<
|
|
HTMLAttributes<HTMLDivElement>,
|
|
"children" | "title"
|
|
> & {
|
|
title: ReactNode;
|
|
description?: ReactNode;
|
|
buttons?: ReactNode | ((controls: { close: () => void }) => ReactNode);
|
|
closeOnOutside?: boolean;
|
|
onClose?: () => void;
|
|
};
|
|
|
|
export function FemaleConsentSheet({
|
|
title,
|
|
description,
|
|
buttons,
|
|
closeOnOutside = true,
|
|
onClose,
|
|
className,
|
|
...props
|
|
}: FemaleConsentSheetProps) {
|
|
const { dictionary: t } = useI18n();
|
|
const [isVisible, setIsVisible] = useState(true);
|
|
const [isClosing, setIsClosing] = useState(false);
|
|
const isMountedRef = useRef(true);
|
|
|
|
useEffect(() => {
|
|
isMountedRef.current = true;
|
|
return () => {
|
|
isMountedRef.current = false;
|
|
};
|
|
}, []);
|
|
|
|
const closeSheet = useCallback(() => {
|
|
if (isClosing) return;
|
|
setIsClosing(true);
|
|
window.setTimeout(() => {
|
|
if (isMountedRef.current) {
|
|
setIsVisible(false);
|
|
}
|
|
onClose?.();
|
|
}, EXIT_ANIMATION_MS);
|
|
}, [isClosing, onClose]);
|
|
|
|
useHardwareBackHandler(closeSheet, isVisible && !isClosing);
|
|
|
|
const controls = { close: closeSheet };
|
|
const resolvedButtons =
|
|
typeof buttons === "function" ? buttons(controls) : buttons;
|
|
|
|
useEffect(() => {
|
|
if (!isVisible) {
|
|
return;
|
|
}
|
|
|
|
const previousBodyOverflow = document.body.style.overflow;
|
|
const previousHtmlOverflow = document.documentElement.style.overflow;
|
|
|
|
document.body.style.overflow = "hidden";
|
|
document.documentElement.style.overflow = "hidden";
|
|
|
|
return () => {
|
|
document.body.style.overflow = previousBodyOverflow;
|
|
document.documentElement.style.overflow = previousHtmlOverflow;
|
|
};
|
|
}, [isVisible]);
|
|
|
|
if (!isVisible) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className={[
|
|
"fixed inset-0 z-50 flex items-end justify-center",
|
|
isClosing ? "flutter-scrim-exit" : "flutter-scrim",
|
|
]
|
|
.filter(Boolean)
|
|
.join(" ")}
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-label={t["Information sheet"]}
|
|
tabIndex={-1}
|
|
onClick={(event) => {
|
|
if (closeOnOutside && event.target === event.currentTarget) {
|
|
closeSheet();
|
|
}
|
|
}}
|
|
onKeyDown={(event) => {
|
|
if (
|
|
closeOnOutside &&
|
|
event.target === event.currentTarget &&
|
|
(event.key === "Escape" || event.key === "Enter" || event.key === " ")
|
|
) {
|
|
event.preventDefault();
|
|
closeSheet();
|
|
}
|
|
}}
|
|
>
|
|
<section
|
|
{...props}
|
|
className={[
|
|
"w-full sm:max-w-[375px] rounded-t-[22px] bg-white py-5 px-4 text-left shadow-[0_20px_60px_rgba(15,23,42,0.08)]",
|
|
isClosing ? "flutter-sheet-surface-exit" : "flutter-sheet-surface",
|
|
className,
|
|
]
|
|
.filter(Boolean)
|
|
.join(" ")}
|
|
>
|
|
<div className="flex items-center justify-between gap-4">
|
|
<h2 className="text-sm font-bold leading-[1.2] tracking-[-0.03em] text-[#8B8B8B]">
|
|
{title}
|
|
</h2>
|
|
<button
|
|
type="button"
|
|
onClick={closeSheet}
|
|
aria-label="Close"
|
|
className="items-center justify-center rounded-full text-[#A0A0A0]"
|
|
>
|
|
<Image
|
|
src={"/assets/images/Vecfadsftor.svg"}
|
|
alt="close"
|
|
width={18}
|
|
height={18}
|
|
/>
|
|
</button>
|
|
</div>
|
|
|
|
{description ? (
|
|
<div className="mt-5 text-sm leading-[1.45] text-[#2B2B2B]">
|
|
{description}
|
|
</div>
|
|
) : null}
|
|
|
|
{resolvedButtons ? <div className="mt-5">{resolvedButtons}</div> : null}
|
|
</section>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default FemaleConsentSheet;
|