From 75e205b1e33841f01bb664e67b0c8629fe923522 Mon Sep 17 00:00:00 2001 From: tema Date: Tue, 2 Sep 2025 18:55:17 +0900 Subject: [PATCH] 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. --- apps/bff/src/common/config/field-map.ts | 12 +- apps/portal/src/app/orders/[id]/page.tsx | 510 +++++++++++------------ apps/portal/src/app/orders/page.tsx | 12 +- 3 files changed, 268 insertions(+), 266 deletions(-) diff --git a/apps/bff/src/common/config/field-map.ts b/apps/bff/src/common/config/field-map.ts index ecc2344f..b62cde0a 100644 --- a/apps/bff/src/common/config/field-map.ts +++ b/apps/bff/src/common/config/field-map.ts @@ -176,11 +176,13 @@ export function getSalesforceFieldMap(): SalesforceFieldMap { // Billing address snapshot fields billing: { - street: process.env.ORDER_BILL_TO_STREET_FIELD || "BillToStreet", - city: process.env.ORDER_BILL_TO_CITY_FIELD || "BillToCity", - state: process.env.ORDER_BILL_TO_STATE_FIELD || "BillToState", - postalCode: process.env.ORDER_BILL_TO_POSTAL_CODE_FIELD || "BillToPostalCode", - country: process.env.ORDER_BILL_TO_COUNTRY_FIELD || "BillToCountry", + // Default to standard Order BillingAddress components + // Env overrides maintain backward compatibility if orgs used custom fields + street: process.env.ORDER_BILL_TO_STREET_FIELD || "BillingStreet", + city: process.env.ORDER_BILL_TO_CITY_FIELD || "BillingCity", + 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: { diff --git a/apps/portal/src/app/orders/[id]/page.tsx b/apps/portal/src/app/orders/[id]/page.tsx index 41ffb570..50d49348 100644 --- a/apps/portal/src/app/orders/[id]/page.tsx +++ b/apps/portal/src/app/orders/[id]/page.tsx @@ -3,7 +3,7 @@ import { useEffect, useState } from "react"; import { useParams, useSearchParams } from "next/navigation"; 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 { StatusPill } from "@/components/ui/status-pill"; import { authenticatedApi } from "@/lib/api"; @@ -71,8 +71,8 @@ const getDetailedStatusInfo = ( color: "text-blue-800", bgColor: "bg-blue-50 border-blue-200", description: "Our team is reviewing your order details", - nextAction: "We'll contact you within 1-2 business days with next steps", - timeline: "Review typically takes 1-2 business days", + nextAction: "We will contact you within 1 business day with next steps", + timeline: "Review typically takes 1 business day", }; } @@ -111,20 +111,20 @@ const getDetailedStatusInfo = ( color: "text-gray-800", bgColor: "bg-gray-50 border-gray-200", 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) => { switch (orderType) { case "Internet": - return "🌐"; + return ; case "SIM": - return "📱"; + return ; case "VPN": - return "🔒"; + return ; default: - return "📦"; + return ; } }; @@ -182,7 +182,7 @@ export default function OrderStatusPage() { {/* Success Banner for New Orders */} {isNewOrder && ( -
+
@@ -190,7 +190,7 @@ export default function OrderStatusPage() { Order Submitted Successfully!

- Your order has been created and submitted for processing. We'll notify you as + Your order has been created and submitted for processing. We will notify you as soon as it's approved and ready for activation.

@@ -198,9 +198,9 @@ export default function OrderStatusPage() { What happens next:

    -
  • Our team will review your order (usually within 1-2 business days)
  • +
  • Our team will review your order (within 1 business day)
  • You'll receive an email confirmation once approved
  • -
  • We'll schedule activation based on your preferences
  • +
  • We will schedule activation based on your preferences
  • This page will update automatically as your order progresses
@@ -209,8 +209,8 @@ export default function OrderStatusPage() {
)} - {/* Service Overview */} - {data && + {/* Status Section - Moved to top */} + {data && ( (() => { const statusInfo = getDetailedStatusInfo( data.status, @@ -218,7 +218,6 @@ export default function OrderStatusPage() { data.activationType, data.scheduledAt ); - const serviceIcon = getServiceTypeIcon(data.orderType); const statusVariant = statusInfo.label.includes("Active") ? "success" @@ -229,268 +228,269 @@ export default function OrderStatusPage() { : "neutral"; return ( -
- {/* Service Header */} -
-
{serviceIcon}
-
-

- {data.orderType} Service -

-

- Order #{data.orderNumber || data.id.slice(-8)} • Placed{" "} - {new Date(data.createdDate).toLocaleDateString("en-US", { - weekday: "long", - month: "long", - day: "numeric", - year: "numeric", - })} -

-
- - {data.items && - data.items.length > 0 && - (() => { - const totals = calculateDetailedTotals(data.items); - - return ( -
-
- {totals.monthlyTotal > 0 && ( -
-

- ¥{totals.monthlyTotal.toLocaleString()} -

-

per month

-
- )} - - {totals.oneTimeTotal > 0 && ( -
-

- ¥{totals.oneTimeTotal.toLocaleString()} -

-

one-time

-
- )} - - {/* Fallback to TotalAmount if no items or calculation fails */} - {totals.monthlyTotal === 0 && - totals.oneTimeTotal === 0 && - data.totalAmount && ( -
-

- ¥{data.totalAmount.toLocaleString()} -

-

total amount

-
- )} -
-
- ); - })()} + Status + } + > +
+
{statusInfo.description}
+
- - {/* Status Card (standardized) */} - - } - > -
{statusInfo.description}
- {statusInfo.nextAction && ( -
-

Next Steps

-

{statusInfo.nextAction}

+ + {/* Highlighted Next Steps Section */} + {statusInfo.nextAction && ( +
+
+
+

Next Steps

- )} - {statusInfo.timeline && ( +

{statusInfo.nextAction}

+
+ )} + + {statusInfo.timeline && ( +

Timeline: {statusInfo.timeline}

- )} - -
- ); - })()} - - {/* Service Details */} - {data?.items && data.items.length > 0 && ( - -
- {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 ( -
-
-
-
- {typeInfo.icon} -
- -
-
-

- {item.product.name} -

- - {typeInfo.label} - -
- -
- {item.product.billingCycle} - {item.quantity > 1 && Qty: {item.quantity}} - {item.product.itemClass && ( - - {item.product.itemClass} - - )} -
-
-
- -
- {item.totalPrice && ( -
- ¥{item.totalPrice.toLocaleString()} -
- )} -
- {item.product.billingCycle === "Monthly" ? "/month" : "one-time"} -
-
-
- ); - })} -
-
- )} - - {/* Pricing Summary */} - {data?.items && - data.items.length > 0 && - (() => { - const totals = calculateDetailedTotals(data.items); - - return ( - -
- {totals.monthlyTotal > 0 && ( -
-

- ¥{totals.monthlyTotal.toLocaleString()} -

-

Monthly Charges

-
- )} - - {totals.oneTimeTotal > 0 && ( -
-

- ¥{totals.oneTimeTotal.toLocaleString()} -

-

One-time Charges

-
- )} -
- - {/* Compact Fee Disclaimer */} -
-
- ⚠️ -
-

Additional fees may apply

-

- Weekend installation (+¥3,000), express setup, or special configuration - charges may be added. We'll contact you before applying any additional - fees. -

-
-
-
+ )}
); - })()} + })() + )} + + {/* Combined Service Overview and Products */} + {data && ( +
+ {/* Service Header */} +
+
{getServiceTypeIcon(data.orderType)}
+
+

+ {data.orderType} Service +

+

+ Order #{data.orderNumber || data.id.slice(-8)} • Placed{" "} + {new Date(data.createdDate).toLocaleDateString("en-US", { + weekday: "long", + month: "long", + day: "numeric", + year: "numeric", + })} +

+
+ + {data.items && + data.items.length > 0 && + (() => { + const totals = calculateDetailedTotals(data.items); + + return ( +
+
+ {totals.monthlyTotal > 0 && ( +
+

+ ¥{totals.monthlyTotal.toLocaleString()} +

+

per month

+
+ )} + + {totals.oneTimeTotal > 0 && ( +
+

+ ¥{totals.oneTimeTotal.toLocaleString()} +

+

one-time

+
+ )} + + {/* Fallback to TotalAmount if no items or calculation fails */} + {totals.monthlyTotal === 0 && + totals.oneTimeTotal === 0 && + data.totalAmount && ( +
+

+ ¥{data.totalAmount.toLocaleString()} +

+

total amount

+
+ )} +
+
+ ); + })()} +
+ + {/* Services & Products Section */} + {data?.items && data.items.length > 0 && ( +
+

Your Services & Products

+
+ {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: , + 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: , + 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: , + 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: , + 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 ( +
+
+
+
+ {typeInfo.icon} +
+ +
+
+

+ {item.product.name} +

+ + {typeInfo.label} + +
+ +
+ {item.product.billingCycle} + {item.quantity > 1 && Qty: {item.quantity}} + {item.product.itemClass && ( + + {item.product.itemClass} + + )} +
+
+
+ +
+ {item.totalPrice && ( +
+ ¥{item.totalPrice.toLocaleString()} +
+ )} +
+ {item.product.billingCycle === "Monthly" ? "/month" : "one-time"} +
+
+
+
+ ); + })} + + {/* Additional fees warning */} +
+
+ +
+

Additional fees may apply

+

+ Weekend installation (+¥3,000), express setup, or special configuration + charges may be added. We will contact you before applying any additional + fees. +

+
+
+
+
+
+ )} +
+ )} + + {/* Support Contact */} -
+

Questions about your order? Contact our support team.

- diff --git a/apps/portal/src/app/orders/page.tsx b/apps/portal/src/app/orders/page.tsx index 1aab3e63..4f456973 100644 --- a/apps/portal/src/app/orders/page.tsx +++ b/apps/portal/src/app/orders/page.tsx @@ -3,7 +3,7 @@ import { useEffect, useState, Suspense } from "react"; import { useRouter, useSearchParams } from "next/navigation"; 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 { authenticatedApi } from "@/lib/api"; @@ -92,7 +92,7 @@ export default function OrdersPage() { color: "text-blue-800", bgColor: "bg-blue-100", 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) => { switch (orderType) { case "Internet": - return { icon: "🌐", label: "Internet Service" }; + return { icon: , label: "Internet Service" }; case "SIM": - return { icon: "📱", label: "Mobile Service" }; + return { icon: , label: "Mobile Service" }; case "VPN": - return { icon: "🔒", label: "VPN Service" }; + return { icon: , label: "VPN Service" }; default: - return { icon: "📦", label: "Service" }; + return { icon: , label: "Service" }; } };