165 lines
5.4 KiB
TypeScript
Raw Normal View History

"use client";
import { useMemo, useState } from "react";
import Link from "next/link";
import { useParams } from "next/navigation";
import { PageLayout } from "@/components/layout/PageLayout";
import { SubCard } from "@/components/ui/sub-card";
import { DevicePhoneMobileIcon } from "@heroicons/react/24/outline";
import { simActionsService } from "@/features/subscriptions/services/sim-actions.service";
import { AlertBanner } from "@/components/common/AlertBanner";
const PLAN_CODES = ["PASI_5G", "PASI_10G", "PASI_25G", "PASI_50G"] as const;
type PlanCode = (typeof PLAN_CODES)[number];
const PLAN_LABELS: Record<PlanCode, string> = {
PASI_5G: "5GB",
PASI_10G: "10GB",
PASI_25G: "25GB",
PASI_50G: "50GB",
};
export function SimChangePlanContainer() {
const params = useParams();
const subscriptionId = parseInt(params.id as string);
const [currentPlanCode] = useState<string>("");
const [newPlanCode, setNewPlanCode] = useState<"" | PlanCode>("");
const [assignGlobalIp, setAssignGlobalIp] = useState(false);
const [scheduledAt, setScheduledAt] = useState("");
const [message, setMessage] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const options = useMemo(
() => (PLAN_CODES as readonly PlanCode[]).filter(c => c !== (currentPlanCode as PlanCode)),
[currentPlanCode]
);
const submit = async (e: React.FormEvent) => {
e.preventDefault();
if (!newPlanCode) {
setError("Please select a new plan");
return;
}
setLoading(true);
setMessage(null);
setError(null);
try {
await simActionsService.changePlan(subscriptionId, {
newPlanCode,
assignGlobalIp,
scheduledAt: scheduledAt ? scheduledAt.replace(/-/g, "") : undefined,
});
setMessage("Plan change submitted successfully");
} catch (e: unknown) {
setError(e instanceof Error ? e.message : "Failed to change plan");
} finally {
setLoading(false);
}
};
return (
<PageLayout
icon={<DevicePhoneMobileIcon />}
title="Change Plan"
description="Switch to a different data plan"
>
<div className="max-w-3xl mx-auto">
<div className="mb-4">
<Link
href={`/subscriptions/${subscriptionId}#sim-management`}
className="text-blue-600 hover:text-blue-700"
>
Back to SIM Management
</Link>
</div>
<SubCard>
<p className="text-sm text-gray-600 mb-6">
Change Plan: Switch to a different data plan. Important: Plan changes must be requested
before the 25th of the month. Changes will take effect on the 1st of the following
month.
</p>
{message && (
<div className="mb-4">
<AlertBanner variant="success" title="Plan Change Submitted">
{message}
</AlertBanner>
</div>
)}
{error && (
<div className="mb-4">
<AlertBanner variant="error" title="Plan Change Failed">
{error}
</AlertBanner>
</div>
)}
<form onSubmit={e => void submit(e)} className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">New Plan</label>
<select
value={newPlanCode}
onChange={e => setNewPlanCode(e.target.value as PlanCode)}
className="w-full px-3 py-2 border border-gray-300 rounded-md"
>
<option value="">Choose a plan</option>
{options.map(code => (
<option key={code} value={code}>
{PLAN_LABELS[code]}
</option>
))}
</select>
</div>
<div className="flex items-center">
<input
id="globalip"
type="checkbox"
checked={assignGlobalIp}
onChange={e => setAssignGlobalIp(e.target.checked)}
className="h-4 w-4 text-blue-600 border-gray-300 rounded"
/>
<label htmlFor="globalip" className="ml-2 text-sm text-gray-700">
Assign global IP
</label>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Schedule (optional)
</label>
<input
type="date"
value={scheduledAt}
onChange={e => setScheduledAt(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-md"
/>
</div>
<div className="flex gap-3">
<button
type="submit"
disabled={loading}
className="px-4 py-2 rounded-md bg-blue-600 text-white text-sm disabled:opacity-50"
>
{loading ? "Processing…" : "Submit Plan Change"}
</button>
<Link
href={`/subscriptions/${subscriptionId}#sim-management`}
className="px-4 py-2 rounded-md border border-gray-300 text-sm text-gray-700 bg-white hover:bg-gray-50"
>
Back
</Link>
</div>
</form>
</SubCard>
</div>
</PageLayout>
);
}
export default SimChangePlanContainer;