"use client"; import { useLayoutEffect, useRef, useState } from "react"; import type { QuestionField } from "@/lib/schema-adapter"; import { useI18n } from "@/translations/provider"; import { useQuestionAnswers } from "./question-answer-storage"; import QuestionTitle from "./question-title"; type QuestionSliderProps = { question: QuestionField; disabled?: boolean; }; export function QuestionSlider({ question, disabled, }: QuestionSliderProps) { const { dictionary: t } = useI18n(); const [min, max] = question.extras.range; const initialValue = Math.round((min + max) / 2); const { getAnswerValue, setAnswerValue } = useQuestionAnswers(); const storedValue = getAnswerValue(question); const isDesiredAgeRange = false; const thumbWidth = 18; const bubbleHalfWidth = 18; const steps = (() => { const range = max - min; const interval = range <= 15 ? 1 : range <= 50 ? 5 : range <= 150 ? 10 : 20; const arr: number[] = []; for (let val = min; val <= max; val += interval) { arr.push(val); } if (arr[arr.length - 1] !== max) { const lastVal = arr[arr.length - 1]; if (max - lastVal < interval * 0.5) { arr.pop(); } arr.push(max); } return arr; })(); // Multi-state logic for Age Range Slider let fromVal = 25; let toVal = 30; if (isDesiredAgeRange) { if (typeof storedValue === "string" && storedValue.includes("-")) { const parts = storedValue.split("-").map(Number); if ( parts.length === 2 && !Number.isNaN(parts[0]) && !Number.isNaN(parts[1]) ) { fromVal = parts[0]; toVal = parts[1]; } } else if (typeof storedValue === "number") { fromVal = storedValue; toVal = Math.max(storedValue, max); } fromVal = Math.max(min, Math.min(max, fromVal)); toVal = Math.max(min, Math.min(max, toVal)); if (toVal < fromVal) { toVal = fromVal; } } // Single-slider states (only used if isDesiredAgeRange is false) const value = typeof storedValue === "number" ? storedValue : initialValue; const progress = max === min ? 0 : ((value - min) / (max - min)) * 100; const sliderWrapperRef = useRef(null); const sliderRef = useRef(null); const [bubblePosition, setBubblePosition] = useState(bubbleHalfWidth); useLayoutEffect(() => { if (isDesiredAgeRange) return; const wrapper = sliderWrapperRef.current; const slider = sliderRef.current; if (!wrapper || !slider) { return; } const updateBubblePosition = () => { const wrapperRect = wrapper.getBoundingClientRect(); const sliderRect = slider.getBoundingClientRect(); const sliderLeft = sliderRect.left - wrapperRect.left; const thumbCenter = sliderLeft + thumbWidth / 2 + (progress / 100) * (sliderRect.width - thumbWidth); setBubblePosition( Math.min( Math.max(thumbCenter, bubbleHalfWidth), wrapperRect.width - bubbleHalfWidth, ), ); }; updateBubblePosition(); const resizeObserver = new ResizeObserver(updateBubblePosition); resizeObserver.observe(wrapper); resizeObserver.observe(slider); return () => resizeObserver.disconnect(); }, [progress]); if (isDesiredAgeRange) { const handleFromChange = (newFrom: number) => { const val = Math.min(newFrom, toVal); setAnswerValue(question, `${val}-${toVal}`); }; const handleToChange = (newTo: number) => { const val = Math.max(newTo, fromVal); setAnswerValue(question, `${fromVal}-${val}`); }; const progressFrom = max === min ? 0 : ((fromVal - min) / (max - min)) * 100; const progressTo = max === min ? 0 : ((toVal - min) / (max - min)) * 100; return (
{/* First Slider (From Age) */}
{t.From ?? "From"} {fromVal}
handleFromChange(Number(e.target.value))} disabled={disabled} className="question-slider-range w-full" style={{ background: `linear-gradient(to right, #F2465F 0%, #F2465F ${progressFrom}%, #FCE7EA ${progressFrom}%, #FCE7EA 100%)`, }} />
{steps.map((step) => { const leftPct = ((step - min) / (max - min)) * 100; return ( {step} ); })}
{/* Second Slider (To Age) */}
{t.To ?? "To"} {toVal}
handleToChange(Number(e.target.value))} disabled={disabled} className="question-slider-range w-full" style={{ background: `linear-gradient(to right, #F2465F 0%, #F2465F ${progressTo}%, #FCE7EA ${progressTo}%, #FCE7EA 100%)`, }} />
{steps.map((step) => { const leftPct = ((step - min) / (max - min)) * 100; return ( {step} ); })}
); } return (
{value}
setAnswerValue( question, Number(event.target.value), ) } disabled={disabled} className="question-slider-range w-full" style={{ background: `linear-gradient(to right, #F2465F 0%, #F2465F ${progress}%, #FCE7EA ${progress}%, #FCE7EA 100%)`, }} />
{steps.map((step) => { const leftPct = ((step - min) / (max - min)) * 100; return ( {step} ); })}
); } export default QuestionSlider;