164 lines
5.7 KiB
TypeScript
164 lines
5.7 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import Link from "next/link";
|
|
import { useParams } from "next/navigation";
|
|
import { PageLayout } from "@/components/templates/PageLayout";
|
|
import { SubCard } from "@/components/molecules/SubCard/SubCard";
|
|
import { simActionsService } from "@/features/subscriptions/services/sim-actions.service";
|
|
import { AlertBanner } from "@/components/molecules/AlertBanner";
|
|
import { DevicePhoneMobileIcon } from "@heroicons/react/24/outline";
|
|
|
|
export function SimTopUpContainer() {
|
|
const params = useParams();
|
|
const subscriptionId = parseInt(params.id as string);
|
|
const [gbAmount, setGbAmount] = useState<string>("1");
|
|
const [loading, setLoading] = useState(false);
|
|
const [message, setMessage] = useState<string | null>(null);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const getCurrentAmountMb = () => {
|
|
const gb = parseInt(gbAmount, 10);
|
|
return isNaN(gb) ? 0 : gb * 1000;
|
|
};
|
|
|
|
const isValidAmount = () => {
|
|
const gb = Number(gbAmount);
|
|
return Number.isInteger(gb) && gb >= 1 && gb <= 50; // Freebit API limit
|
|
};
|
|
|
|
const calculateCost = () => {
|
|
const gb = parseInt(gbAmount, 10);
|
|
return isNaN(gb) ? 0 : gb * 500; // 1GB = 500 JPY
|
|
};
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
if (!isValidAmount()) {
|
|
setError("Please enter a whole number between 1 GB and 50 GB");
|
|
return;
|
|
}
|
|
setLoading(true);
|
|
setMessage(null);
|
|
setError(null);
|
|
|
|
try {
|
|
await simActionsService.topUp(subscriptionId, { quotaMb: getCurrentAmountMb() });
|
|
setMessage(`Successfully topped up ${gbAmount} GB for ¥${calculateCost().toLocaleString()}`);
|
|
} catch (e: unknown) {
|
|
setError(e instanceof Error ? e.message : "Failed to submit top-up");
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<PageLayout
|
|
icon={<DevicePhoneMobileIcon />}
|
|
title="Top Up Data"
|
|
description="Add data to your SIM"
|
|
>
|
|
<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">
|
|
Add additional data quota to your SIM service. Enter the amount of data you want to add.
|
|
</p>
|
|
|
|
{message && (
|
|
<div className="mb-4">
|
|
<AlertBanner variant="success" title="Top-up Submitted">
|
|
{message}
|
|
</AlertBanner>
|
|
</div>
|
|
)}
|
|
{error && (
|
|
<div className="mb-4">
|
|
<AlertBanner variant="error" title="Top-up Failed">
|
|
{error}
|
|
</AlertBanner>
|
|
</div>
|
|
)}
|
|
|
|
<form onSubmit={e => void handleSubmit(e)} className="space-y-6">
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">Amount (GB)</label>
|
|
<div className="relative">
|
|
<input
|
|
type="number"
|
|
value={gbAmount}
|
|
onChange={e => setGbAmount(e.target.value)}
|
|
placeholder="Enter amount in GB"
|
|
min={1}
|
|
max={50}
|
|
step={1}
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 pr-12"
|
|
/>
|
|
<div className="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
|
|
<span className="text-gray-500 text-sm">GB</span>
|
|
</div>
|
|
</div>
|
|
<p className="text-xs text-gray-500 mt-1">
|
|
Enter the amount of data you want to add (1 - 50 GB, whole numbers)
|
|
</p>
|
|
</div>
|
|
|
|
<div className="p-4 bg-blue-50 rounded-lg border border-blue-200">
|
|
<div className="flex justify-between items-center">
|
|
<div>
|
|
<div className="text-sm font-medium text-blue-900">
|
|
{gbAmount && !isNaN(parseInt(gbAmount, 10)) ? `${gbAmount} GB` : "0 GB"}
|
|
</div>
|
|
<div className="text-xs text-blue-700">= {getCurrentAmountMb()} MB</div>
|
|
</div>
|
|
<div className="text-right">
|
|
<div className="text-lg font-bold text-blue-900">
|
|
¥{calculateCost().toLocaleString()}
|
|
</div>
|
|
<div className="text-xs text-blue-700">(1GB = ¥500)</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{!isValidAmount() && gbAmount && (
|
|
<div className="bg-red-50 border border-red-200 rounded-lg p-3">
|
|
<p className="text-sm text-red-700">
|
|
Please enter a valid whole number between 1 and 50 GB.
|
|
</p>
|
|
</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 Top Up"}
|
|
</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 SimTopUpContainer;
|
|
|
|
|