- Revised metadata titles and descriptions across various service pages to better reflect offerings and improve SEO. - Updated content in the About Us, Contact, and Support pages to emphasize English support and services for expats in Japan. - Removed TV Services references from the portal, streamlining service offerings and focusing on core services. - Enhanced service descriptions to clarify benefits and features, ensuring users understand the value of each service.
266 lines
8.8 KiB
TypeScript
266 lines
8.8 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
ShieldCheck,
|
|
Router,
|
|
Globe,
|
|
Tv,
|
|
Wifi,
|
|
Package,
|
|
Headphones,
|
|
CreditCard,
|
|
Play,
|
|
} from "lucide-react";
|
|
import { usePublicVpnCatalog } from "@/features/services/hooks";
|
|
import { LoadingCard } from "@/components/atoms";
|
|
import { AsyncBlock } from "@/components/molecules/AsyncBlock/AsyncBlock";
|
|
import { AlertBanner } from "@/components/molecules/AlertBanner/AlertBanner";
|
|
import { VpnPlanCard } from "@/features/services/components/vpn/VpnPlanCard";
|
|
import { ServicesBackLink } from "@/features/services/components/base/ServicesBackLink";
|
|
import { ServicesHero } from "@/features/services/components/base/ServicesHero";
|
|
import { useServicesBasePath } from "@/features/services/hooks/useServicesBasePath";
|
|
import {
|
|
ServiceHighlights,
|
|
type HighlightFeature,
|
|
} from "@/features/services/components/base/ServiceHighlights";
|
|
|
|
/**
|
|
* Public VPN Plans View
|
|
*
|
|
* Displays VPN plans for unauthenticated users.
|
|
*/
|
|
export function PublicVpnPlansView() {
|
|
const servicesBasePath = useServicesBasePath();
|
|
const { data, error } = usePublicVpnCatalog();
|
|
const vpnPlans = data?.plans || [];
|
|
const activationFees = data?.activationFees || [];
|
|
// Simple loading check: show skeleton until we have data or an error
|
|
const isLoading = !data && !error;
|
|
|
|
if (isLoading || error) {
|
|
return (
|
|
<div className="max-w-6xl mx-auto px-4">
|
|
<ServicesBackLink href={servicesBasePath} label="Back to Services" />
|
|
|
|
<AsyncBlock
|
|
isLoading={isLoading}
|
|
error={error}
|
|
loadingText="Loading VPN plans..."
|
|
variant="page"
|
|
>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 max-w-4xl mx-auto">
|
|
{Array.from({ length: 4 }).map((_, index) => (
|
|
<LoadingCard key={index} className="h-64" />
|
|
))}
|
|
</div>
|
|
</AsyncBlock>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const vpnFeatures: HighlightFeature[] = [
|
|
{
|
|
icon: <Router className="h-6 w-6" />,
|
|
title: "Zero Setup Required",
|
|
description: "Router arrives pre-configured. Just plug in and you're connected",
|
|
highlight: "Plug & play",
|
|
},
|
|
{
|
|
icon: <Tv className="h-6 w-6" />,
|
|
title: "Stream from Home",
|
|
description: "Watch Netflix, Hulu, BBC iPlayer and more from the US or UK",
|
|
highlight: "Your content",
|
|
},
|
|
{
|
|
icon: <Globe className="h-6 w-6" />,
|
|
title: "US & UK Servers",
|
|
description: "Choose San Francisco for US content or London for UK content",
|
|
highlight: "2 regions",
|
|
},
|
|
{
|
|
icon: <Wifi className="h-6 w-6" />,
|
|
title: "Dedicated VPN WiFi",
|
|
description: "Separate network for VPN. Your regular internet stays fast",
|
|
highlight: "No slowdown",
|
|
},
|
|
{
|
|
icon: <Package className="h-6 w-6" />,
|
|
title: "All-Inclusive Rental",
|
|
description: "Router rental included in your monthly fee. Nothing extra to buy",
|
|
highlight: "Simple pricing",
|
|
},
|
|
{
|
|
icon: <Headphones className="h-6 w-6" />,
|
|
title: "English Support",
|
|
description: "Questions? Our English-speaking team is here to help",
|
|
highlight: "We speak your language",
|
|
},
|
|
];
|
|
|
|
return (
|
|
<div className="max-w-6xl mx-auto px-4 pb-16">
|
|
<ServicesBackLink href={servicesBasePath} label="Back to Services" />
|
|
|
|
<ServicesHero
|
|
title="Stream Your Favorites from Home"
|
|
description="Missing shows from back home? Our VPN lets you watch US and UK content in Japan. Pre-configured router, just plug in and stream."
|
|
/>
|
|
|
|
{/* Service Highlights */}
|
|
<ServiceHighlights features={vpnFeatures} className="mb-12" />
|
|
|
|
{vpnPlans.length > 0 ? (
|
|
<div className="mb-8">
|
|
<div className="text-center mb-8">
|
|
<span className="text-sm font-semibold text-primary uppercase tracking-wider">
|
|
Choose Your Region
|
|
</span>
|
|
<h2 className="text-2xl font-bold text-foreground mt-1">Available Plans</h2>
|
|
<p className="text-sm text-muted-foreground mt-2">
|
|
Select one region per router rental
|
|
</p>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 max-w-4xl mx-auto">
|
|
{vpnPlans.map(plan => (
|
|
<VpnPlanCard key={plan.id} plan={plan} />
|
|
))}
|
|
</div>
|
|
|
|
{activationFees.length > 0 && (
|
|
<AlertBanner variant="info" className="mt-6 max-w-4xl mx-auto" title="Activation Fee">
|
|
A one-time activation fee of ¥3,000 applies per router rental. Tax (10%) not included.
|
|
</AlertBanner>
|
|
)}
|
|
</div>
|
|
) : (
|
|
<div className="text-center py-12">
|
|
<ShieldCheck className="h-12 w-12 text-muted-foreground mx-auto mb-4" />
|
|
<h3 className="text-lg font-medium text-foreground mb-2">No VPN Plans Available</h3>
|
|
<p className="text-muted-foreground mb-6">
|
|
We couldn't find any VPN plans available at this time.
|
|
</p>
|
|
<ServicesBackLink
|
|
href={servicesBasePath}
|
|
label="Back to Services"
|
|
align="center"
|
|
className="mt-4 mb-0"
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
{/* How It Works Section */}
|
|
<VpnHowItWorksSection />
|
|
|
|
<AlertBanner variant="warning" title="Important Disclaimer" className="mb-8">
|
|
<p className="text-sm">
|
|
Content subscriptions are NOT included in the VPN package. Our VPN service establishes a
|
|
network connection that virtually locates you in the designated server location. Not all
|
|
services can be unblocked. We do not guarantee access to any specific website or streaming
|
|
service quality.
|
|
</p>
|
|
</AlertBanner>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
interface HowItWorksStepProps {
|
|
number: number;
|
|
icon: React.ReactNode;
|
|
title: string;
|
|
description: string;
|
|
}
|
|
|
|
function HowItWorksStep({ number, icon, title, description }: HowItWorksStepProps) {
|
|
return (
|
|
<div className="flex flex-col items-center text-center flex-1 min-w-0">
|
|
{/* Icon with number badge */}
|
|
<div className="relative mb-4">
|
|
<div className="flex h-16 w-16 items-center justify-center rounded-xl bg-gray-50 border border-gray-200 text-primary shadow-sm">
|
|
{icon}
|
|
</div>
|
|
{/* Number badge */}
|
|
<div className="absolute -top-1 -right-1 flex h-6 w-6 items-center justify-center rounded-full bg-primary text-white text-xs font-bold shadow-sm">
|
|
{number}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Content */}
|
|
<h4 className="font-semibold text-foreground mb-2">{title}</h4>
|
|
<p className="text-sm text-muted-foreground leading-relaxed max-w-[180px]">{description}</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function VpnHowItWorksSection() {
|
|
const steps = [
|
|
{
|
|
icon: <CreditCard className="h-6 w-6" />,
|
|
title: "Sign Up",
|
|
description: "Create your account to get started",
|
|
},
|
|
{
|
|
icon: <Globe className="h-6 w-6" />,
|
|
title: "Choose Region",
|
|
description: "Select US (San Francisco) or UK (London)",
|
|
},
|
|
{
|
|
icon: <Package className="h-6 w-6" />,
|
|
title: "Place Order",
|
|
description: "Complete checkout and receive router",
|
|
},
|
|
{
|
|
icon: <Play className="h-6 w-6" />,
|
|
title: "Connect & Stream",
|
|
description: "Plug in, connect devices, enjoy",
|
|
},
|
|
];
|
|
|
|
return (
|
|
<section className="bg-card rounded-xl border border-border shadow-[var(--cp-shadow-1)] p-8 mb-8">
|
|
{/* Header */}
|
|
<div className="text-center mb-8">
|
|
<span className="text-sm font-semibold text-primary uppercase tracking-wider">
|
|
Simple Setup
|
|
</span>
|
|
<h3 className="text-2xl font-bold text-foreground mt-1">How It Works</h3>
|
|
</div>
|
|
|
|
{/* Steps with connecting line */}
|
|
<div className="relative">
|
|
{/* Connecting line - hidden on mobile */}
|
|
<div className="hidden md:block absolute top-8 left-[12%] right-[12%] h-0.5 bg-gray-200" />
|
|
|
|
{/* Curved path SVG for visual connection - hidden on mobile */}
|
|
<svg
|
|
className="hidden md:block absolute top-[30px] left-0 right-0 w-full h-4 pointer-events-none"
|
|
preserveAspectRatio="none"
|
|
>
|
|
<path
|
|
d="M 12% 8 Q 30% 8, 37.5% 8 Q 45% 8, 50% 8 Q 55% 8, 62.5% 8 Q 70% 8, 88% 8"
|
|
fill="none"
|
|
stroke="#e5e7eb"
|
|
strokeWidth="2"
|
|
strokeDasharray="6 4"
|
|
/>
|
|
</svg>
|
|
|
|
{/* Steps grid */}
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-8 relative z-10">
|
|
{steps.map((step, index) => (
|
|
<HowItWorksStep
|
|
key={index}
|
|
number={index + 1}
|
|
icon={step.icon}
|
|
title={step.title}
|
|
description={step.description}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|
|
|
|
export default PublicVpnPlansView;
|