mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
fix: mobile/responsive issues in FAQ and info pages
- FAQ builder: touch targets 36px → 44px (move up/down/delete buttons) - Filter tabs: add flex-wrap to prevent overflow on narrow screens - Accordion: add ResizeObserver for dynamic content height (images loading, viewport rotation won't clip content anymore) - Accordion: use stable key (index+question) instead of filtered array index — search+toggle no longer opens wrong item
This commit is contained in:
@@ -325,7 +325,7 @@ function FaqBuilder({ items, onChange, locale, localeLabel }: FaqBuilderProps) {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleMoveUp(index)}
|
onClick={() => handleMoveUp(index)}
|
||||||
disabled={index === 0}
|
disabled={index === 0}
|
||||||
className="min-h-[36px] min-w-[36px] rounded-lg p-2 text-dark-400 transition-colors hover:bg-dark-700 hover:text-dark-200 disabled:cursor-not-allowed disabled:opacity-30"
|
className="min-h-[44px] min-w-[44px] rounded-lg p-2 text-dark-400 transition-colors hover:bg-dark-700 hover:text-dark-200 disabled:cursor-not-allowed disabled:opacity-30"
|
||||||
title={t('admin.infoPages.faq.moveUp')}
|
title={t('admin.infoPages.faq.moveUp')}
|
||||||
>
|
>
|
||||||
<ChevronUpIcon />
|
<ChevronUpIcon />
|
||||||
@@ -334,7 +334,7 @@ function FaqBuilder({ items, onChange, locale, localeLabel }: FaqBuilderProps) {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleMoveDown(index)}
|
onClick={() => handleMoveDown(index)}
|
||||||
disabled={index >= items.length - 1}
|
disabled={index >= items.length - 1}
|
||||||
className="min-h-[36px] min-w-[36px] rounded-lg p-2 text-dark-400 transition-colors hover:bg-dark-700 hover:text-dark-200 disabled:cursor-not-allowed disabled:opacity-30"
|
className="min-h-[44px] min-w-[44px] rounded-lg p-2 text-dark-400 transition-colors hover:bg-dark-700 hover:text-dark-200 disabled:cursor-not-allowed disabled:opacity-30"
|
||||||
title={t('admin.infoPages.faq.moveDown')}
|
title={t('admin.infoPages.faq.moveDown')}
|
||||||
>
|
>
|
||||||
<ChevronDownIcon />
|
<ChevronDownIcon />
|
||||||
@@ -342,7 +342,7 @@ function FaqBuilder({ items, onChange, locale, localeLabel }: FaqBuilderProps) {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleRemove(index)}
|
onClick={() => handleRemove(index)}
|
||||||
className="min-h-[36px] min-w-[36px] rounded-lg p-2 text-dark-400 transition-colors hover:bg-error-500/10 hover:text-error-400"
|
className="min-h-[44px] min-w-[44px] rounded-lg p-2 text-dark-400 transition-colors hover:bg-error-500/10 hover:text-error-400"
|
||||||
title={t('admin.infoPages.faq.removeQuestion')}
|
title={t('admin.infoPages.faq.removeQuestion')}
|
||||||
>
|
>
|
||||||
<TrashSmallIcon />
|
<TrashSmallIcon />
|
||||||
|
|||||||
@@ -324,7 +324,7 @@ export default function AdminInfoPages() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Filter tabs */}
|
{/* Filter tabs */}
|
||||||
<div className="flex gap-1">
|
<div className="flex flex-wrap gap-1">
|
||||||
{(['all', 'page', 'faq'] as const).map((tab) => (
|
{(['all', 'page', 'faq'] as const).map((tab) => (
|
||||||
<button
|
<button
|
||||||
key={tab}
|
key={tab}
|
||||||
|
|||||||
@@ -216,6 +216,16 @@ function FaqAccordionItem({
|
|||||||
}
|
}
|
||||||
}, [isOpen]);
|
}, [isOpen]);
|
||||||
|
|
||||||
|
// Update height when content resizes (images loading, viewport rotation)
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isOpen || !contentRef.current) return;
|
||||||
|
const observer = new ResizeObserver(() => {
|
||||||
|
if (contentRef.current) setHeight(contentRef.current.scrollHeight);
|
||||||
|
});
|
||||||
|
observer.observe(contentRef.current);
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
const sanitizedAnswer = useMemo(() => sanitizeHtml(item.a), [item.a]);
|
const sanitizedAnswer = useMemo(() => sanitizeHtml(item.a), [item.a]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -246,15 +256,12 @@ function FaqAccordionItem({
|
|||||||
|
|
||||||
function FaqView({ items }: { items: FaqItem[] }) {
|
function FaqView({ items }: { items: FaqItem[] }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [openIndex, setOpenIndex] = useState<number | null>(null);
|
const [openKey, setOpenKey] = useState<string | null>(null);
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
|
|
||||||
const handleToggle = useCallback(
|
const handleToggle = useCallback((key: string) => {
|
||||||
(index: number) => {
|
setOpenKey((prev) => (prev === key ? null : key));
|
||||||
setOpenIndex(openIndex === index ? null : index);
|
}, []);
|
||||||
},
|
|
||||||
[openIndex],
|
|
||||||
);
|
|
||||||
|
|
||||||
const filteredItems = useMemo(() => {
|
const filteredItems = useMemo(() => {
|
||||||
if (!search.trim()) return items;
|
if (!search.trim()) return items;
|
||||||
@@ -275,7 +282,7 @@ function FaqView({ items }: { items: FaqItem[] }) {
|
|||||||
value={search}
|
value={search}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setSearch(e.target.value);
|
setSearch(e.target.value);
|
||||||
setOpenIndex(null);
|
setOpenKey(null);
|
||||||
}}
|
}}
|
||||||
placeholder={t('admin.infoPages.faq.searchPlaceholder')}
|
placeholder={t('admin.infoPages.faq.searchPlaceholder')}
|
||||||
className="input pl-9 text-sm"
|
className="input pl-9 text-sm"
|
||||||
@@ -290,14 +297,17 @@ function FaqView({ items }: { items: FaqItem[] }) {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{filteredItems.map((item, index) => (
|
{filteredItems.map((item, index) => {
|
||||||
|
const key = `${index}-${item.q.slice(0, 50)}`;
|
||||||
|
return (
|
||||||
<FaqAccordionItem
|
<FaqAccordionItem
|
||||||
key={index}
|
key={key}
|
||||||
item={item}
|
item={item}
|
||||||
isOpen={openIndex === index}
|
isOpen={openKey === key}
|
||||||
onToggle={() => handleToggle(index)}
|
onToggle={() => handleToggle(key)}
|
||||||
/>
|
/>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user