Refactor OrderStatusPage and SimChangePlanPage for improved readability and functionality

- Removed duplicate text and unnecessary comments in OrderStatusPage for cleaner code.
- Moved the status section to the top for better user experience.
- Simplified the handling of item types in SimChangePlanPage and added new state variables for global IP assignment and scheduling.
- Streamlined form submission and error handling in SimChangePlanPage, enhancing user feedback.
This commit is contained in:
T. Narantuya 2025-09-11 16:21:47 +09:00
parent 4686bce071
commit 86cd636b87
2 changed files with 10 additions and 157 deletions

View File

@ -206,8 +206,6 @@ export default function OrderStatusPage() {
<p className="text-green-800 mb-3">
Your order has been created and submitted for processing. We will notify you as soon
as it&apos;s approved and ready for activation.
Your order has been created and submitted for processing. We will notify you as soon
as it&apos;s approved and ready for activation.
</p>
<div className="text-sm text-green-700">
<p className="mb-1">
@ -226,7 +224,6 @@ export default function OrderStatusPage() {
)}
{/* Status Section - Moved to top */}
{data &&
{data &&
(() => {
const statusInfo = getDetailedStatusInfo(
@ -245,11 +242,9 @@ export default function OrderStatusPage() {
: "neutral";
return (
<SubCard
<SubCard
className="mb-9"
header={<h3 className="text-xl font-bold text-gray-900">Status</h3>}
header={<h3 className="text-xl font-bold text-gray-900">Status</h3>}
>
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 mb-6">
<div className="text-gray-700 text-lg sm:text-xl">{statusInfo.description}</div>
@ -259,7 +254,6 @@ export default function OrderStatusPage() {
/>
</div>
{/* Highlighted Next Steps Section */}
{statusInfo.nextAction && (
<div className="bg-blue-50 border-2 border-blue-200 rounded-xl p-4 mb-4 shadow-sm">
@ -271,7 +265,6 @@ export default function OrderStatusPage() {
</div>
)}
{statusInfo.timeline && (
<div className="bg-gray-50 rounded-lg p-3 border border-gray-200">
<p className="text-sm text-gray-600">
@ -282,16 +275,12 @@ export default function OrderStatusPage() {
</SubCard>
);
})()}
})()}
{/* Combined Service Overview and Products */}
{data && (
<div className="bg-white border rounded-2xl p-4 sm:p-8 mb-8">
{/* Service Header */}
<div className="flex flex-col sm:flex-row items-start gap-4 sm:gap-6 mb-6">
<div className="flex items-center text-3xl sm:text-4xl">
{getServiceTypeIcon(data.orderType)}
</div>
<div className="flex items-center text-3xl sm:text-4xl">
{getServiceTypeIcon(data.orderType)}
</div>
@ -366,7 +355,6 @@ export default function OrderStatusPage() {
const aIsInstallation = a.product.itemClass === "Installation";
const bIsInstallation = b.product.itemClass === "Installation";
if (aIsService && !bIsService) return -1;
if (!aIsService && bIsService) return 1;
if (aIsInstallation && !bIsInstallation) return -1;
@ -376,53 +364,7 @@ export default function OrderStatusPage() {
.map(item => {
// Use the actual Item_Class__c values from Salesforce documentation
const itemClass = item.product.itemClass;
// Use the actual Item_Class__c values from Salesforce documentation
const itemClass = item.product.itemClass;
// Get appropriate icon and color based on item type and billing cycle
const getItemTypeInfo = () => {
const isMonthly = item.product.billingCycle === "Monthly";
const isService = itemClass === "Service";
const isInstallation = itemClass === "Installation";
if (isService && isMonthly) {
// Main service products - Blue theme
return {
icon: <StarIcon className="h-4 w-4" />,
bg: "bg-blue-50 border-blue-200",
iconBg: "bg-blue-100 text-blue-600",
label: itemClass || "Service",
labelColor: "text-blue-600",
};
} else if (isInstallation) {
// Installation items - Green theme
return {
icon: <WrenchScrewdriverIcon className="h-4 w-4" />,
bg: "bg-green-50 border-green-200",
iconBg: "bg-green-100 text-green-600",
label: itemClass || "Installation",
labelColor: "text-green-600",
};
} else if (isMonthly) {
// Other monthly products - Blue theme
return {
icon: <StarIcon className="h-4 w-4" />,
bg: "bg-blue-50 border-blue-200",
iconBg: "bg-blue-100 text-blue-600",
label: itemClass || "Service",
labelColor: "text-blue-600",
};
} else {
// One-time products - Orange theme
return {
icon: <CubeIcon className="h-4 w-4" />,
bg: "bg-orange-50 border-orange-200",
iconBg: "bg-orange-100 text-orange-600",
label: itemClass || "Add-on",
labelColor: "text-orange-600",
};
}
};
// Get appropriate icon and color based on item type and billing cycle
const getItemTypeInfo = () => {
const isMonthly = item.product.billingCycle === "Monthly";
@ -468,21 +410,8 @@ export default function OrderStatusPage() {
}
};
const typeInfo = getItemTypeInfo();
const typeInfo = getItemTypeInfo();
return (
<div
key={item.id}
className={`rounded-lg p-4 border ${typeInfo.bg} transition-shadow hover:shadow-sm`}
>
<div className="flex flex-col sm:flex-row justify-between items-start gap-3">
<div className="flex items-start gap-3 flex-1">
<div
className={`w-8 h-8 rounded-full flex items-center justify-center text-sm ${typeInfo.iconBg} flex-shrink-0`}
>
{typeInfo.icon}
</div>
return (
<div
key={item.id}
@ -496,17 +425,6 @@ export default function OrderStatusPage() {
{typeInfo.icon}
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1 flex-wrap">
<h3 className="font-semibold text-gray-900 truncate flex-1 min-w-0">
{item.product.name}
</h3>
<span
className={`text-xs px-2 py-1 rounded-full font-medium ${typeInfo.bg} ${typeInfo.labelColor}`}
>
{typeInfo.label}
</span>
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1 flex-wrap">
<h3 className="font-semibold text-gray-900 truncate flex-1 min-w-0">
@ -530,32 +448,6 @@ export default function OrderStatusPage() {
</div>
</div>
</div>
<div className="flex flex-wrap items-center gap-3 text-sm text-gray-600">
<span className="font-medium">{item.product.billingCycle}</span>
{item.quantity > 1 && <span>Qty: {item.quantity}</span>}
{item.product.itemClass && (
<span className="text-xs bg-gray-100 px-2 py-1 rounded">
{item.product.itemClass}
</span>
)}
</div>
</div>
</div>
<div className="text-left sm:text-right ml-0 sm:ml-3 mt-2 sm:mt-0 flex-shrink-0 sm:w-32">
{item.totalPrice && (
<div className="font-semibold text-gray-900 tabular-nums">
¥{item.totalPrice.toLocaleString()}
</div>
)}
<div className="text-xs text-gray-500">
{item.product.billingCycle === "Monthly" ? "/month" : "one-time"}
</div>
</div>
</div>
</div>
);
})}
<div className="text-left sm:text-right ml-0 sm:ml-3 mt-2 sm:mt-0 flex-shrink-0 sm:w-32">
{item.totalPrice && (
@ -577,9 +469,6 @@ export default function OrderStatusPage() {
<div className="flex items-start gap-2">
<ExclamationTriangleIcon className="h-4 w-4 text-yellow-600 flex-shrink-0" />
<div>
<p className="text-sm font-medium text-yellow-900">
Additional fees may apply
</p>
<p className="text-sm font-medium text-yellow-900">
Additional fees may apply
</p>

View File

@ -2,12 +2,12 @@
import { useState, useMemo } from "react";
import Link from "next/link";
import { DashboardLayout } from "@/components/layout/dashboard-layout";
import { useParams } from "next/navigation";
import { authenticatedApi } from "@/lib/api";
const PLAN_CODES = ["PASI_5G", "PASI_10G", "PASI_25G", "PASI_50G"] as const;
type PlanCode = (typeof PLAN_CODES)[number];
type PlanCode = (typeof PLAN_CODES)[number];
const PLAN_LABELS: Record<PlanCode, string> = {
PASI_5G: "5GB",
PASI_10G: "10GB",
@ -20,14 +20,12 @@ export default function SimChangePlanPage() {
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 options = useMemo(
() => (PLAN_CODES as readonly PlanCode[]).filter(c => c !== (currentPlanCode as PlanCode)),
[currentPlanCode]
@ -45,9 +43,11 @@ export default function SimChangePlanPage() {
try {
await authenticatedApi.post(`/subscriptions/${subscriptionId}/sim/change-plan`, {
newPlanCode,
assignGlobalIp,
scheduledAt: scheduledAt ? scheduledAt.replace(/-/g, "") : undefined,
});
setMessage("Plan change submitted successfully");
} catch (e: unknown) {
} catch (e: any) {
setError(e instanceof Error ? e.message : "Failed to change plan");
} finally {
setLoading(false);
@ -55,7 +55,8 @@ export default function SimChangePlanPage() {
};
return (
<div className="max-w-3xl mx-auto p-6">
<DashboardLayout>
<div className="max-w-3xl mx-auto p-6">
<div className="mb-4">
<Link
href={`/subscriptions/${subscriptionId}#sim-management`}
@ -63,12 +64,6 @@ export default function SimChangePlanPage() {
>
Back to SIM Management
</Link>
<Link
href={`/subscriptions/${subscriptionId}#sim-management`}
className="text-blue-600 hover:text-blue-700"
>
Back to SIM Management
</Link>
</div>
<div className="bg-white rounded-xl border border-gray-200 p-6">
<h1 className="text-xl font-semibold text-gray-900 mb-1">Change Plan</h1>
@ -87,29 +82,13 @@ export default function SimChangePlanPage() {
{error}
</div>
)}
<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 text-green-700 bg-green-50 border border-green-200 rounded p-3">
{message}
</div>
)}
{error && (
<div className="mb-4 text-red-700 bg-red-50 border border-red-200 rounded p-3">
{error}
</div>
)}
<form onSubmit={e => void submit(e)} className="space-y-6">
<form onSubmit={submit} 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)}
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>
@ -117,9 +96,6 @@ export default function SimChangePlanPage() {
<option key={code} value={code}>
{PLAN_LABELS[code]}
</option>
<option key={code} value={code}>
{PLAN_LABELS[code]}
</option>
))}
</select>
</div>
@ -163,22 +139,10 @@ export default function SimChangePlanPage() {
>
Back
</Link>
<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>
</div>
</div>
</DashboardLayout>
);
}