107 lines
3.5 KiB
TypeScript
107 lines
3.5 KiB
TypeScript
"use client";
|
||
|
||
import { useMemo, useState } from "react";
|
||
|
||
interface Plan {
|
||
id: string;
|
||
emoji: string;
|
||
name: string;
|
||
price: string;
|
||
cover: string[];
|
||
best: string;
|
||
note: string;
|
||
}
|
||
|
||
const PLANS: Plan[] = [
|
||
{
|
||
id: "safetywing", emoji: "🛡️", name: "SafetyWing Nomad",
|
||
price: "$45–80/月", best: "多数数字游民首选",
|
||
cover: ["门诊/住院", "紧急医疗运送", "旅行延误"],
|
||
note: "覆盖全球多数国家,按月订阅灵活",
|
||
},
|
||
{
|
||
id: "worldnomads", emoji: "🌍", name: "World Nomads",
|
||
price: "按行程报价", best: "多国跳跃旅行",
|
||
cover: ["冒险运动", "行李丢失", "紧急救援"],
|
||
note: "适合含户外活动的行程,按段购买",
|
||
},
|
||
{
|
||
id: "genki", emoji: "🇯🇵", name: "Genki",
|
||
price: "€60–100/月", best: "欧洲长期旅居",
|
||
cover: ["欧盟医疗", "牙科可选", "签证材料支持"],
|
||
note: "对申根签证申请材料较友好",
|
||
},
|
||
{
|
||
id: "local", emoji: "🏥", name: "目的地本地保险",
|
||
price: "因地而异", best: "停留 6 个月+",
|
||
cover: ["本地医院", "报销便捷", "费用通常更低"],
|
||
note: "需了解当地条款与语言,适合长期定居",
|
||
},
|
||
];
|
||
|
||
const FILTERS = [
|
||
{ key: "all", label: "🌏 全部" },
|
||
{ key: "flex", label: "📅 按月灵活" },
|
||
{ key: "trip", label: "✈️ 按行程" },
|
||
{ key: "long", label: "🏠 长期" },
|
||
];
|
||
|
||
export default function InsuranceGuide() {
|
||
const [filter, setFilter] = useState("all");
|
||
const [picked, setPicked] = useState<string | null>(null);
|
||
|
||
const filtered = useMemo(() => {
|
||
if (filter === "all") return PLANS;
|
||
if (filter === "flex") return PLANS.filter((p) => p.id === "safetywing" || p.id === "genki");
|
||
if (filter === "trip") return PLANS.filter((p) => p.id === "worldnomads");
|
||
return PLANS.filter((p) => p.id === "local" || p.id === "genki");
|
||
}, [filter]);
|
||
|
||
return (
|
||
<section className="section insurance-section" id="insurance">
|
||
<div className="container">
|
||
<div className="section-header reveal">
|
||
<span className="section-tag">🏥 INSURANCE</span>
|
||
<h2>旅居保险指南</h2>
|
||
<p>远程工作不等于裸奔——选对国际医疗保险再出发</p>
|
||
</div>
|
||
|
||
<div className="events-filters reveal">
|
||
{FILTERS.map((f) => (
|
||
<button
|
||
key={f.key}
|
||
className={`filter-btn${filter === f.key ? " active" : ""}`}
|
||
onClick={() => setFilter(f.key)}
|
||
>
|
||
{f.label}
|
||
</button>
|
||
))}
|
||
</div>
|
||
|
||
<div className="insurance-grid">
|
||
{filtered.map((p, i) => (
|
||
<div
|
||
key={p.id}
|
||
className={`insurance-card reveal${picked === p.id ? " selected" : ""}`}
|
||
style={{ transitionDelay: `${i * 0.08}s` }}
|
||
onClick={() => setPicked(p.id === picked ? null : p.id)}
|
||
>
|
||
<div className="insurance-top">
|
||
<span className="insurance-emoji">{p.emoji}</span>
|
||
<span className="insurance-price">{p.price}</span>
|
||
</div>
|
||
<h3>{p.name}</h3>
|
||
<p className="insurance-best">👍 {p.best}</p>
|
||
<ul className="insurance-cover">
|
||
{p.cover.map((c) => <li key={c}>✓ {c}</li>)}
|
||
</ul>
|
||
<p className="insurance-note">{p.note}</p>
|
||
{picked === p.id && <span className="insurance-picked">✓ 已标记关注</span>}
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|