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:
parent
4686bce071
commit
86cd636b87
@ -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's approved and ready for activation.
|
||||
Your order has been created and submitted for processing. We will notify you as soon
|
||||
as it'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>
|
||||
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user