Update field mapping for billing address and enhance order page components

- Updated default field mappings for billing address in SalesforceFieldMap to maintain backward compatibility.
- Added new icons for service types in OrdersPage and OrderStatusPage for improved visual representation.
- Revised next action and timeline messages for clarity and consistency across order status components.
- Enhanced layout and styling for better user experience in order details and service overview sections.
This commit is contained in:
tema 2025-09-02 18:55:17 +09:00
parent 22baa0af06
commit 75e205b1e3
3 changed files with 268 additions and 266 deletions

View File

@ -176,11 +176,13 @@ export function getSalesforceFieldMap(): SalesforceFieldMap {
// Billing address snapshot fields // Billing address snapshot fields
billing: { billing: {
street: process.env.ORDER_BILL_TO_STREET_FIELD || "BillToStreet", // Default to standard Order BillingAddress components
city: process.env.ORDER_BILL_TO_CITY_FIELD || "BillToCity", // Env overrides maintain backward compatibility if orgs used custom fields
state: process.env.ORDER_BILL_TO_STATE_FIELD || "BillToState", street: process.env.ORDER_BILL_TO_STREET_FIELD || "BillingStreet",
postalCode: process.env.ORDER_BILL_TO_POSTAL_CODE_FIELD || "BillToPostalCode", city: process.env.ORDER_BILL_TO_CITY_FIELD || "BillingCity",
country: process.env.ORDER_BILL_TO_COUNTRY_FIELD || "BillToCountry", state: process.env.ORDER_BILL_TO_STATE_FIELD || "BillingState",
postalCode: process.env.ORDER_BILL_TO_POSTAL_CODE_FIELD || "BillingPostalCode",
country: process.env.ORDER_BILL_TO_COUNTRY_FIELD || "BillingCountry",
}, },
}, },
orderItem: { orderItem: {

View File

@ -3,7 +3,7 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useParams, useSearchParams } from "next/navigation"; import { useParams, useSearchParams } from "next/navigation";
import { PageLayout } from "@/components/layout/page-layout"; import { PageLayout } from "@/components/layout/page-layout";
import { ClipboardDocumentCheckIcon, CheckCircleIcon } from "@heroicons/react/24/outline"; import { ClipboardDocumentCheckIcon, CheckCircleIcon, WifiIcon, DevicePhoneMobileIcon, LockClosedIcon, CubeIcon, StarIcon, WrenchScrewdriverIcon, PlusIcon, BoltIcon, ExclamationTriangleIcon, EnvelopeIcon, PhoneIcon } from "@heroicons/react/24/outline";
import { SubCard } from "@/components/ui/sub-card"; import { SubCard } from "@/components/ui/sub-card";
import { StatusPill } from "@/components/ui/status-pill"; import { StatusPill } from "@/components/ui/status-pill";
import { authenticatedApi } from "@/lib/api"; import { authenticatedApi } from "@/lib/api";
@ -71,8 +71,8 @@ const getDetailedStatusInfo = (
color: "text-blue-800", color: "text-blue-800",
bgColor: "bg-blue-50 border-blue-200", bgColor: "bg-blue-50 border-blue-200",
description: "Our team is reviewing your order details", description: "Our team is reviewing your order details",
nextAction: "We'll contact you within 1-2 business days with next steps", nextAction: "We will contact you within 1 business day with next steps",
timeline: "Review typically takes 1-2 business days", timeline: "Review typically takes 1 business day",
}; };
} }
@ -111,20 +111,20 @@ const getDetailedStatusInfo = (
color: "text-gray-800", color: "text-gray-800",
bgColor: "bg-gray-50 border-gray-200", bgColor: "bg-gray-50 border-gray-200",
description: "Your order is being processed", description: "Your order is being processed",
timeline: "We'll update you as progress is made", timeline: "We will update you as progress is made",
}; };
}; };
const getServiceTypeIcon = (orderType?: string) => { const getServiceTypeIcon = (orderType?: string) => {
switch (orderType) { switch (orderType) {
case "Internet": case "Internet":
return "🌐"; return <WifiIcon className="h-6 w-6" />;
case "SIM": case "SIM":
return "📱"; return <DevicePhoneMobileIcon className="h-6 w-6" />;
case "VPN": case "VPN":
return "🔒"; return <LockClosedIcon className="h-6 w-6" />;
default: default:
return "📦"; return <CubeIcon className="h-6 w-6" />;
} }
}; };
@ -182,7 +182,7 @@ export default function OrderStatusPage() {
{/* Success Banner for New Orders */} {/* Success Banner for New Orders */}
{isNewOrder && ( {isNewOrder && (
<div className="bg-green-50 border border-green-200 rounded-xl p-6 mb-6"> <div className="bg-green-50 border border-green-200 rounded-xl p-4 sm:p-6 mb-6">
<div className="flex items-start"> <div className="flex items-start">
<CheckCircleIcon className="h-6 w-6 text-green-600 mt-0.5 mr-3 flex-shrink-0" /> <CheckCircleIcon className="h-6 w-6 text-green-600 mt-0.5 mr-3 flex-shrink-0" />
<div> <div>
@ -190,7 +190,7 @@ export default function OrderStatusPage() {
Order Submitted Successfully! Order Submitted Successfully!
</h3> </h3>
<p className="text-green-800 mb-3"> <p className="text-green-800 mb-3">
Your order has been created and submitted for processing. We&apos;ll notify you as Your order has been created and submitted for processing. We will notify you as
soon as it&apos;s approved and ready for activation. soon as it&apos;s approved and ready for activation.
</p> </p>
<div className="text-sm text-green-700"> <div className="text-sm text-green-700">
@ -198,9 +198,9 @@ export default function OrderStatusPage() {
<strong>What happens next:</strong> <strong>What happens next:</strong>
</p> </p>
<ul className="list-disc list-inside space-y-1 ml-4"> <ul className="list-disc list-inside space-y-1 ml-4">
<li>Our team will review your order (usually within 1-2 business days)</li> <li>Our team will review your order (within 1 business day)</li>
<li>You&apos;ll receive an email confirmation once approved</li> <li>You&apos;ll receive an email confirmation once approved</li>
<li>We&apos;ll schedule activation based on your preferences</li> <li>We will schedule activation based on your preferences</li>
<li>This page will update automatically as your order progresses</li> <li>This page will update automatically as your order progresses</li>
</ul> </ul>
</div> </div>
@ -209,8 +209,8 @@ export default function OrderStatusPage() {
</div> </div>
)} )}
{/* Service Overview */} {/* Status Section - Moved to top */}
{data && {data && (
(() => { (() => {
const statusInfo = getDetailedStatusInfo( const statusInfo = getDetailedStatusInfo(
data.status, data.status,
@ -218,7 +218,6 @@ export default function OrderStatusPage() {
data.activationType, data.activationType,
data.scheduledAt data.scheduledAt
); );
const serviceIcon = getServiceTypeIcon(data.orderType);
const statusVariant = statusInfo.label.includes("Active") const statusVariant = statusInfo.label.includes("Active")
? "success" ? "success"
@ -229,268 +228,269 @@ export default function OrderStatusPage() {
: "neutral"; : "neutral";
return ( return (
<div className="bg-white border rounded-2xl p-8 mb-8"> <SubCard
{/* Service Header */} className="mb-9"
<div className="flex items-start gap-6 mb-6"> header={
<div className="text-4xl">{serviceIcon}</div> <h3 className="text-xl font-bold text-gray-900">Status</h3>
<div className="flex-1"> }
<h2 className="text-2xl font-bold text-gray-900 mb-2"> >
{data.orderType} Service <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 mb-6">
</h2> <div className="text-gray-700 text-lg sm:text-xl">{statusInfo.description}</div>
<p className="text-gray-600 mb-4"> <StatusPill
Order #{data.orderNumber || data.id.slice(-8)} Placed{" "} label={statusInfo.label}
{new Date(data.createdDate).toLocaleDateString("en-US", { variant={statusVariant as "info" | "success" | "warning" | "error"}
weekday: "long", />
month: "long",
day: "numeric",
year: "numeric",
})}
</p>
</div>
{data.items &&
data.items.length > 0 &&
(() => {
const totals = calculateDetailedTotals(data.items);
return (
<div className="text-right">
<div className="space-y-2">
{totals.monthlyTotal > 0 && (
<div>
<p className="text-3xl font-bold text-gray-900">
¥{totals.monthlyTotal.toLocaleString()}
</p>
<p className="text-gray-500">per month</p>
</div>
)}
{totals.oneTimeTotal > 0 && (
<div className="mt-2">
<p className="text-2xl font-bold text-orange-600">
¥{totals.oneTimeTotal.toLocaleString()}
</p>
<p className="text-gray-500">one-time</p>
</div>
)}
{/* Fallback to TotalAmount if no items or calculation fails */}
{totals.monthlyTotal === 0 &&
totals.oneTimeTotal === 0 &&
data.totalAmount && (
<div>
<p className="text-3xl font-bold text-gray-900">
¥{data.totalAmount.toLocaleString()}
</p>
<p className="text-gray-500">total amount</p>
</div>
)}
</div>
</div>
);
})()}
</div> </div>
{/* Status Card (standardized) */} {/* Highlighted Next Steps Section */}
<SubCard {statusInfo.nextAction && (
title="Status" <div className="bg-blue-50 border-2 border-blue-200 rounded-xl p-4 mb-4 shadow-sm">
right={ <div className="flex items-center gap-2 mb-2">
<StatusPill <div className="w-2 h-2 bg-blue-500 rounded-full animate-pulse"></div>
label={statusInfo.label} <p className="font-bold text-blue-900 text-base">Next Steps</p>
variant={statusVariant as "info" | "success" | "warning" | "error"}
/>
}
>
<div className="text-gray-700 mb-2">{statusInfo.description}</div>
{statusInfo.nextAction && (
<div className="bg-gray-50 rounded-lg p-3 mb-3 border border-gray-200">
<p className="font-medium text-gray-900 text-sm">Next Steps</p>
<p className="text-gray-700 text-sm">{statusInfo.nextAction}</p>
</div> </div>
)} <p className="text-blue-800 text-base leading-relaxed">{statusInfo.nextAction}</p>
{statusInfo.timeline && ( </div>
)}
{statusInfo.timeline && (
<div className="bg-gray-50 rounded-lg p-3 border border-gray-200">
<p className="text-sm text-gray-600"> <p className="text-sm text-gray-600">
<span className="font-medium">Timeline:</span> {statusInfo.timeline} <span className="font-medium">Timeline:</span> {statusInfo.timeline}
</p> </p>
)}
</SubCard>
</div>
);
})()}
{/* Service Details */}
{data?.items && data.items.length > 0 && (
<SubCard title="Your Services & Products">
<div className="space-y-3">
{data.items.map(item => {
// Use the actual Item_Class__c values from Salesforce documentation
const itemClass = item.product.itemClass;
// Get appropriate icon and color based on actual item class
const getItemTypeInfo = () => {
switch (itemClass) {
case "Service":
return {
icon: "⭐",
bg: "bg-blue-50 border-blue-200",
iconBg: "bg-blue-100 text-blue-600",
label: "Service",
labelColor: "text-blue-600",
};
case "Installation":
return {
icon: "🔧",
bg: "bg-orange-50 border-orange-200",
iconBg: "bg-orange-100 text-orange-600",
label: "Installation",
labelColor: "text-orange-600",
};
case "Add-on":
return {
icon: "+",
bg: "bg-green-50 border-green-200",
iconBg: "bg-green-100 text-green-600",
label: "Add-on",
labelColor: "text-green-600",
};
case "Activation":
return {
icon: "⚡",
bg: "bg-purple-50 border-purple-200",
iconBg: "bg-purple-100 text-purple-600",
label: "Activation",
labelColor: "text-purple-600",
};
default:
return {
icon: "📦",
bg: "bg-gray-50 border-gray-200",
iconBg: "bg-gray-100 text-gray-600",
label: itemClass || "Other",
labelColor: "text-gray-600",
};
}
};
const typeInfo = getItemTypeInfo();
return (
<div key={item.id} className={`rounded-lg p-4 border ${typeInfo.bg}`}>
<div className="flex justify-between items-start">
<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>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1">
<h3 className="font-semibold text-gray-900 truncate">
{item.product.name}
</h3>
<span
className={`text-xs px-2 py-1 rounded-full font-medium ${typeInfo.bg} ${typeInfo.labelColor} flex-shrink-0`}
>
{typeInfo.label}
</span>
</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-right ml-3 flex-shrink-0">
{item.totalPrice && (
<div className="font-semibold text-gray-900">
¥{item.totalPrice.toLocaleString()}
</div>
)}
<div className="text-xs text-gray-500">
{item.product.billingCycle === "Monthly" ? "/month" : "one-time"}
</div>
</div>
</div>
</div> </div>
); )}
})}
</div>
</SubCard>
)}
{/* Pricing Summary */}
{data?.items &&
data.items.length > 0 &&
(() => {
const totals = calculateDetailedTotals(data.items);
return (
<SubCard title="Pricing Summary">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
{totals.monthlyTotal > 0 && (
<div className="bg-blue-50 rounded-lg p-4 text-center">
<p className="text-2xl font-bold text-blue-600">
¥{totals.monthlyTotal.toLocaleString()}
</p>
<p className="text-sm text-gray-600">Monthly Charges</p>
</div>
)}
{totals.oneTimeTotal > 0 && (
<div className="bg-orange-50 rounded-lg p-4 text-center">
<p className="text-2xl font-bold text-orange-600">
¥{totals.oneTimeTotal.toLocaleString()}
</p>
<p className="text-sm text-gray-600">One-time Charges</p>
</div>
)}
</div>
{/* Compact Fee Disclaimer */}
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-3">
<div className="flex items-start gap-2">
<span className="text-yellow-600 text-sm"></span>
<div>
<p className="text-sm font-medium text-yellow-900">Additional fees may apply</p>
<p className="text-xs text-yellow-800 mt-1">
Weekend installation (+¥3,000), express setup, or special configuration
charges may be added. We&apos;ll contact you before applying any additional
fees.
</p>
</div>
</div>
</div>
</SubCard> </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-1">
<h2 className="text-2xl font-bold text-gray-900 mb-2 flex items-center">
{data.orderType} Service
</h2>
<p className="text-gray-600 mb-4 text-sm sm:text-base">
Order #{data.orderNumber || data.id.slice(-8)} Placed{" "}
{new Date(data.createdDate).toLocaleDateString("en-US", {
weekday: "long",
month: "long",
day: "numeric",
year: "numeric",
})}
</p>
</div>
{data.items &&
data.items.length > 0 &&
(() => {
const totals = calculateDetailedTotals(data.items);
return (
<div className="text-left sm:text-right w-full sm:w-auto mt-2 sm:mt-0">
<div className="space-y-2 sm:space-y-2">
{totals.monthlyTotal > 0 && (
<div>
<p className="text-2xl sm:text-3xl font-bold text-gray-900 tabular-nums">
¥{totals.monthlyTotal.toLocaleString()}
</p>
<p className="text-sm text-gray-500">per month</p>
</div>
)}
{totals.oneTimeTotal > 0 && (
<div className="mt-2">
<p className="text-2xl sm:text-3xl font-bold text-orange-600 tabular-nums">
¥{totals.oneTimeTotal.toLocaleString()}
</p>
<p className="text-sm text-gray-500">one-time</p>
</div>
)}
{/* Fallback to TotalAmount if no items or calculation fails */}
{totals.monthlyTotal === 0 &&
totals.oneTimeTotal === 0 &&
data.totalAmount && (
<div>
<p className="text-2xl sm:text-3xl font-bold text-gray-900 tabular-nums">
¥{data.totalAmount.toLocaleString()}
</p>
<p className="text-sm text-gray-500">total amount</p>
</div>
)}
</div>
</div>
);
})()}
</div>
{/* Services & Products Section */}
{data?.items && data.items.length > 0 && (
<div className="border-t pt-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4">Your Services & Products</h3>
<div className="space-y-3">
{data.items
.sort((a, b) => {
// Sort: Services first, then Installations, then others
const aIsService = a.product.itemClass === "Service";
const bIsService = b.product.itemClass === "Service";
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;
if (!aIsInstallation && bIsInstallation) return 1;
return 0;
})
.map(item => {
// 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",
};
}
};
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>
<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 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>
);
})}
{/* Additional fees warning */}
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-3 mt-4">
<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-xs text-yellow-800 mt-1">
Weekend installation (+¥3,000), express setup, or special configuration
charges may be added. We will contact you before applying any additional
fees.
</p>
</div>
</div>
</div>
</div>
</div>
)}
</div>
)}
{/* Support Contact */} {/* Support Contact */}
<SubCard title="Need Help?"> <SubCard title="Need Help?">
<div className="flex items-center justify-between"> <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3">
<div> <div>
<p className="text-gray-700 text-sm"> <p className="text-gray-700 text-sm">
Questions about your order? Contact our support team. Questions about your order? Contact our support team.
</p> </p>
</div> </div>
<div className="flex gap-2"> <div className="flex gap-2 w-full sm:w-auto sm:justify-end">
<a <a
href="mailto:support@example.com" href="mailto:support@example.com"
className="bg-blue-600 text-white px-3 py-2 rounded-lg text-sm font-medium hover:bg-blue-700 transition-colors" className="bg-blue-600 text-white px-3 py-2 rounded-lg text-sm font-medium hover:bg-blue-700 transition-colors flex items-center gap-2 justify-center w-full sm:w-auto"
> >
📧 Email <EnvelopeIcon className="h-4 w-4" />
Email
</a> </a>
<a <a
href="tel:+1234567890" href="tel:+1234567890"
className="bg-white text-blue-600 border border-blue-600 px-3 py-2 rounded-lg text-sm font-medium hover:bg-blue-50 transition-colors" className="bg-white text-blue-600 border border-blue-600 px-3 py-2 rounded-lg text-sm font-medium hover:bg-blue-50 transition-colors flex items-center gap-2 justify-center w-full sm:w-auto"
> >
📞 Call <PhoneIcon className="h-4 w-4" />
Call
</a> </a>
</div> </div>
</div> </div>

View File

@ -3,7 +3,7 @@
import { useEffect, useState, Suspense } from "react"; import { useEffect, useState, Suspense } from "react";
import { useRouter, useSearchParams } from "next/navigation"; import { useRouter, useSearchParams } from "next/navigation";
import { PageLayout } from "@/components/layout/page-layout"; import { PageLayout } from "@/components/layout/page-layout";
import { ClipboardDocumentListIcon, CheckCircleIcon } from "@heroicons/react/24/outline"; import { ClipboardDocumentListIcon, CheckCircleIcon, WifiIcon, DevicePhoneMobileIcon, LockClosedIcon, CubeIcon } from "@heroicons/react/24/outline";
import { StatusPill } from "@/components/ui/status-pill"; import { StatusPill } from "@/components/ui/status-pill";
import { authenticatedApi } from "@/lib/api"; import { authenticatedApi } from "@/lib/api";
@ -92,7 +92,7 @@ export default function OrdersPage() {
color: "text-blue-800", color: "text-blue-800",
bgColor: "bg-blue-100", bgColor: "bg-blue-100",
description: "We're reviewing your order", description: "We're reviewing your order",
nextAction: "We'll contact you within 1-2 business days", nextAction: "We'll contact you within 1 business day",
}; };
} }
@ -117,13 +117,13 @@ export default function OrdersPage() {
const getServiceTypeDisplay = (orderType?: string) => { const getServiceTypeDisplay = (orderType?: string) => {
switch (orderType) { switch (orderType) {
case "Internet": case "Internet":
return { icon: "🌐", label: "Internet Service" }; return { icon: <WifiIcon className="h-6 w-6" />, label: "Internet Service" };
case "SIM": case "SIM":
return { icon: "📱", label: "Mobile Service" }; return { icon: <DevicePhoneMobileIcon className="h-6 w-6" />, label: "Mobile Service" };
case "VPN": case "VPN":
return { icon: "🔒", label: "VPN Service" }; return { icon: <LockClosedIcon className="h-6 w-6" />, label: "VPN Service" };
default: default:
return { icon: "📦", label: "Service" }; return { icon: <CubeIcon className="h-6 w-6" />, label: "Service" };
} }
}; };