Files
hope-events/frontend/src/components/shared/HelpGuideModal.tsx
T
joshuaandClaude Sonnet 5 51639322e2 Fix help guide popups overflowing the screen on mobile
The popup card had no overall height cap, only the tab content area
did, so the header/quick-links/footer could push the close button off
screen on short mobile viewports. The card is now capped to the
screen height with the header and footer pinned in place, and only
the tab content scrolls internally.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-07 01:14:44 +02:00

103 lines
4.7 KiB
TypeScript

"use client";
import React, { useState } from "react";
import Link from "next/link";
import { X, Mail, MessageCircleQuestion } from "lucide-react";
import type { HelpContent } from "@/content/help/types";
export default function HelpGuideModal({ content, onClose }: { content: HelpContent; onClose: () => void }) {
const [tab, setTab] = useState(content.tabs[0]?.key);
const activeTab = content.tabs.find(t => t.key === tab) || content.tabs[0];
return (
// Above the site header (Navbar is `sticky top-0 z-50`) and above any
// page-level popup (e.g. the report viewer at z-[60]), since the guide
// can be opened from the FAB while another overlay is showing.
<div className="fixed inset-0 z-[70]">
<div className="absolute inset-0 bg-black/40 animate-in fade-in duration-200" onClick={onClose} />
<div className="absolute inset-0 flex items-center justify-center p-4">
<div
className="w-full max-w-3xl max-h-full bg-white rounded-2xl shadow-2xl animate-in fade-in zoom-in-95 slide-in-from-bottom-2 duration-200 overflow-hidden flex flex-col"
onClick={e => e.stopPropagation()}
>
<div className="flex items-start justify-between px-5 py-4 border-b bg-gradient-to-r from-brand-50/60 to-white shrink-0">
<div className="flex items-start gap-3">
<div className="w-9 h-9 rounded-full bg-brand-50 flex items-center justify-center shrink-0">
<MessageCircleQuestion className="w-5 h-5 text-brand-600" />
</div>
<div>
<h2 className="text-base font-semibold text-gray-900">{content.title}</h2>
<p className="text-xs text-gray-500">{content.subtitle}</p>
</div>
</div>
<button className="p-1.5 rounded-full hover:bg-gray-100 transition-colors" onClick={onClose} aria-label="Close">
<X className="w-5 h-5" />
</button>
</div>
{content.quickLinks && content.quickLinks.length > 0 && (
<div className="flex flex-wrap gap-2 px-5 py-3 border-b bg-gray-50 shrink-0">
{content.quickLinks.map(link => (
<Link
key={link.href}
href={link.href}
onClick={onClose}
className="inline-flex items-center gap-1.5 text-xs font-medium px-3 py-1.5 rounded-full border border-brand-200 bg-white text-brand-700 hover:bg-brand-100 hover:border-brand-300 transition-colors"
>
{link.icon && <link.icon className="w-3.5 h-3.5" />}
{link.label}
</Link>
))}
</div>
)}
<div className="flex flex-col sm:flex-row flex-1 min-h-0 overflow-y-auto sm:overflow-visible">
{content.tabs.length > 1 && (
<nav className="sm:w-56 shrink-0 border-b sm:border-b-0 sm:border-r p-3 space-y-1 bg-gray-50/50 sm:overflow-y-auto">
{content.tabs.map(t => {
const Icon = t.icon;
const active = activeTab?.key === t.key;
return (
<button
key={t.key}
type="button"
onClick={() => setTab(t.key)}
className={"w-full flex items-center gap-2 text-left text-sm px-3 py-2 rounded-lg transition-colors " + (active ? "bg-brand-600 text-white font-medium shadow-sm" : "text-gray-600 hover:bg-white hover:shadow-sm")}
>
<Icon className="w-4 h-4 shrink-0" />
{t.label}
</button>
);
})}
</nav>
)}
<div className="flex-1 min-w-0 p-5 text-sm text-gray-700 sm:overflow-y-auto">
{activeTab?.content}
</div>
</div>
<div className="border-t px-5 py-3 space-y-2 bg-gray-50/50 shrink-0">
{content.supportContact && (
<div className="flex items-center gap-2 text-xs text-gray-500">
<Mail className="w-3.5 h-3.5 shrink-0" />
<span>
{content.supportContact.label}:{" "}
<a href={`mailto:${content.supportContact.email}`} className="text-brand-600 hover:underline">
{content.supportContact.email}
</a>
</span>
</div>
)}
<div className="flex items-center justify-end">
<button className="px-4 py-2 text-sm rounded-lg bg-brand-600 text-white hover:bg-brand-700 transition-colors shadow-sm" onClick={onClose}>
Got it
</button>
</div>
</div>
</div>
</div>
</div>
);
}