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.
 
 
 
 
 

170 lines
6.0 KiB

import Image from "next/image";
import Link from "next/link";
import type { IconType } from "react-icons";
import {
IoCheckbox,
IoDocumentText,
IoInformation,
IoPeople,
IoPerson,
IoSchool,
} from "react-icons/io5";
import type { QuestionCardIcon, QuestionListItem } from "@/data/question-data";
import { localizePath } from "@/translations/config";
import { useI18n } from "@/translations/provider";
type QuestionCardProps = {
item: QuestionListItem;
progress?: number | null;
onInfoClick?: (item: QuestionListItem) => void;
};
const RADIUS = 8;
const CIRCUMFERENCE = 2 * Math.PI * RADIUS;
const iconAssetMap: Partial<Record<QuestionCardIcon, string>> = {
profile: "/assets/images/mingcute_user-info-fill.svg",
education: "/assets/images/boxicons_education-filled.svg",
details: "/assets/images/Grfdasfoup.svg",
checklist: "/assets/images/noun-test-4525471 1.svg",
contact: "/assets/images/solar_user-id-bold.svg",
family_marital: "/assets/images/Grfdasfoup.svg",
};
const iconMap: Record<QuestionCardIcon, IconType> = {
profile: IoPerson,
education: IoSchool,
details: IoDocumentText,
checklist: IoCheckbox,
contact: IoPeople,
family_marital: IoPeople,
};
export function QuestionCard({
item,
progress = item.progress,
onInfoClick,
}: QuestionCardProps) {
const { dictionary: t, locale } = useI18n();
const hasProgress = typeof progress === "number" && Number.isFinite(progress);
const normalizedProgress = hasProgress
? Math.max(0, Math.min(Math.round(progress), 100))
: 0;
const dashOffset = CIRCUMFERENCE - (normalizedProgress / 100) * CIRCUMFERENCE;
const CardIcon = iconMap[item.icon];
const iconAsset = iconAssetMap[item.icon];
return (
<Link
href={localizePath(`/questions-list/${item.slug}`, locale)}
aria-label={t.questions.openQuestion.replace("{title}", item.title)}
className="block rounded-[20px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-[#F26C85]"
>
<article
id={item.slug}
data-question-slug={item.slug}
className="rounded-[20px] border border-white/80 bg-white px-3 py-3 shadow-[0_12px_28px_rgba(15,23,42,0.05)] transition-transform duration-200 hover:-translate-y-0.5"
>
<div className="flex items-start gap-2.5">
<div className="rounded-[13px] bg-linear-to-br from-[#E03950]/15 to-[#E03950]/0 p-px shadow-[0_8px_18px_rgba(240,67,99,0.18)]">
<div className="relative flex h-[44px] w-[44px] shrink-0 items-center justify-center rounded-[12px] bg-linear-to-br from-[#E03950]/15 to-[#FE6F82]/15 text-white">
{iconAsset ? (
<Image
src={iconAsset}
alt=""
aria-hidden="true"
width={22}
height={22}
/>
) : (
<CardIcon aria-hidden="true" className="text-[19px]" />
)}
</div>
</div>
<div className="min-w-0 flex-1">
<h2 className="group-14 leading-tight font-bold text-[#1B1B1B] line-clamp-2">
{item.title}
</h2>
<p className="mt-1.5 group-10 leading-none font-medium text-[#7A7A7A]">
{t.common.estimateTime}: {item.estimate}
</p>
</div>
<div className="flex min-h-[44px] shrink-0 flex-col items-end justify-between self-stretch">
{item.required ? (
<span className="flex items-center justify-center rounded-full bg-[#F8D7DA] dark:bg-semantic-danger-bg px-3 py-1 text-center text-[10px] font-bold text-[#D9383A] dark:text-semantic-danger-text whitespace-nowrap">
{t.common.required}
</span>
) : item.showInfoBadge ? (
<button
type="button"
aria-label={`${item.title} details`}
onClick={(event) => {
event.preventDefault();
event.stopPropagation();
onInfoClick?.(item);
}}
className="flex h-[17px] w-[17px] cursor-pointer items-center justify-center rounded-[6px] bg-[#747474] text-white border-0 p-0 hover:bg-[#606060] transition-colors"
>
<IoInformation aria-hidden="true" className="text-[9px]" />
</button>
) : (
<span className="h-[17px] w-[17px]" aria-hidden="true" />
)}
<div className="mt-auto flex items-center gap-1">
{progress === 100 ? (
<Image
src={"/assets/images/Groupfdas 2.svg"}
width={12}
height={12}
alt="Completed"
/>
) : (
<svg
aria-hidden="true"
className="-rotate-90"
viewBox="0 0 22 22"
width="18"
height="18"
>
<circle
cx="11"
cy="11"
r={RADIUS}
fill="none"
stroke="#E9E9E9"
strokeWidth="2.25"
/>
<circle
cx="11"
cy="11"
r={RADIUS}
fill="none"
stroke="#202020"
strokeWidth="2.25"
strokeLinecap="round"
strokeDasharray={CIRCUMFERENCE}
strokeDashoffset={dashOffset}
/>
</svg>
)}
<span className="group-10 leading-none font-semibold text-[#1F1F1F]">
{hasProgress ? `${normalizedProgress}%` : "..."}
</span>
</div>
</div>
</div>
{item.note ? (
<p className="mt-2 rounded-full bg-[#FFF1F4] px-3 py-1.5 text-center group-10 leading-none font-medium text-[#F35A74]">
{item.note}
</p>
) : null}
</article>
</Link>
);
}
export default QuestionCard;