Files
2026-06-06 04:29:46 -05:00

181 lines
6.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useEffect, useState } from "react";
import { useTranslation, Link } from "@/i18n/navigation";
import Footer from "@/app/components/Footer";
import { apiFetch } from "@/app/lib/api-client";
interface Service {
id: string;
slug: string;
icon: string;
title: string;
titleEn?: string;
description: string;
descriptionEn?: string;
features: string[];
price: number;
priceLabel: string;
category: string;
gradientFrom: string;
gradientTo: string;
}
const FALLBACK_SERVICES: Service[] = [
{
id: "remote-health-insurance",
slug: "remote-health-insurance",
icon: "🛡️",
title: "远程工作者医疗与旅行保障",
titleEn: "Remote Health & Travel Coverage",
description: "覆盖国内旅居、短期出境、设备丢失和紧急医疗咨询。",
features: ["国内外医疗协助", "设备丢失补偿", "7x24 中文支持", "城市风险提醒"],
price: 15,
priceLabel: "¥15/天起",
category: "保障",
gradientFrom: "#10b981",
gradientTo: "#0f766e",
},
];
export default function ServicesPage() {
const { t } = useTranslation("services");
const [services, setServices] = useState<Service[]>(FALLBACK_SERVICES);
const [activeSlug, setActiveSlug] = useState<string | null>(null);
const [message, setMessage] = useState("");
useEffect(() => {
apiFetch<{ items: Service[] }>("/api/services")
.then((data) => {
if (data.items?.length) {
setServices(data.items);
}
})
.catch(() => setServices(FALLBACK_SERVICES));
}, []);
const submitLead = async (service: Service) => {
setActiveSlug(service.slug);
setMessage("");
try {
await apiFetch("/api/services/leads", {
method: "POST",
body: JSON.stringify({
serviceSlug: service.slug,
note: `用户从服务页咨询:${service.title}`,
}),
});
setMessage(`${service.title} 已记录咨询线索,可在 PocketBase 查看。`);
} catch (error) {
setMessage(error instanceof Error ? error.message : "提交失败");
} finally {
setActiveSlug(null);
}
};
return (
<div className="min-h-screen bg-[#fafafa] dark:bg-gray-950">
<main className="max-w-[1200px] mx-auto px-4 sm:px-6 py-6 sm:py-8">
<div className="text-center mb-10 sm:mb-12">
<h1 className="text-2xl sm:text-3xl md:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-3">
{t("title")}
</h1>
<p className="text-gray-500 dark:text-gray-400 text-sm sm:text-base">
{t("subtitle")}
</p>
</div>
{message && (
<div className="mb-6 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-800 dark:border-emerald-800/60 dark:bg-emerald-950/30 dark:text-emerald-200">
{message}
</div>
)}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5 sm:gap-6">
{services.map((service) => (
<article
key={service.slug}
className="bg-white dark:bg-gray-900 rounded-2xl overflow-hidden shadow-sm border border-gray-100 dark:border-gray-800 hover:shadow-lg transition-shadow"
>
<div
className="h-2"
style={{ background: `linear-gradient(90deg, ${service.gradientFrom}, ${service.gradientTo})` }}
/>
<div className="p-5 sm:p-6">
<div className="flex items-start justify-between mb-4">
<div className="flex items-center gap-3">
<span className="text-3xl">{service.icon}</span>
<div>
<h3 className="font-bold text-gray-900 dark:text-gray-100 text-lg">
{service.title}
</h3>
<p className="text-xs text-gray-500 dark:text-gray-400">
{service.titleEn || service.category}
</p>
</div>
</div>
</div>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-4 line-clamp-3">
{service.description}
</p>
<ul className="space-y-2 mb-5">
{(service.features || []).slice(0, 5).map((feature) => (
<li
key={feature}
className="flex items-center gap-2 text-xs sm:text-sm text-gray-500 dark:text-gray-400"
>
<span className="text-[#ff4d4f]"></span>
{feature}
</li>
))}
</ul>
<div className="flex items-center justify-between gap-3 pt-4 border-t border-gray-100 dark:border-gray-800">
<span className="font-bold text-gray-900 dark:text-gray-100">
{service.priceLabel || `¥${service.price}`}
</span>
<div className="flex items-center gap-2">
<button
type="button"
onClick={() => submitLead(service)}
disabled={activeSlug === service.slug}
className="rounded-lg bg-[#ff4d4f] px-3 py-2 text-xs font-medium text-white hover:bg-[#ff3333] disabled:cursor-not-allowed disabled:bg-gray-300"
>
{activeSlug === service.slug ? "提交中" : "咨询"}
</button>
<Link
href="/join"
className="text-sm font-medium text-[#ff4d4f] hover:text-[#ff7a45] transition-colors"
>
{t("learnMore")}
</Link>
</div>
</div>
</div>
</article>
))}
</div>
<div className="mt-12 sm:mt-16 bg-gradient-to-r from-[#ff4d4f] to-[#ff7a45] rounded-2xl p-6 sm:p-10 text-center">
<h2 className="text-xl sm:text-2xl font-bold text-white mb-3">
</h2>
<p className="text-white/80 mb-5 text-sm sm:text-base">
线
</p>
<Link
href="/contact"
className="inline-block bg-white text-[#ff4d4f] px-6 py-2.5 rounded-full font-medium hover:bg-gray-100 transition-colors"
>
{t("contactSupport")}
</Link>
</div>
</main>
<Footer />
</div>
);
}