From 31bd4ba8c6dcf8c7a57c4fec394314cffdb9d11e Mon Sep 17 00:00:00 2001 From: barsa Date: Wed, 22 Oct 2025 18:00:54 +0900 Subject: [PATCH] Refactor InternetPlanCard and InternetConfigureContainer for improved UI and feature display - Enhanced InternetPlanCard to better format plan names and display features dynamically. - Updated InternetConfigureContainer to include a back button and improved plan header presentation. - Refactored ServiceConfigurationStep to enhance the display of important information for Platinum subscribers and improve access mode selection. - Streamlined styling and layout across components for better visual consistency and user experience. --- .../components/internet/InternetPlanCard.tsx | 100 +++++++++++----- .../configure/InternetConfigureContainer.tsx | 63 +++++++--- .../steps/ServiceConfigurationStep.tsx | 110 +++++++++++------- 3 files changed, 186 insertions(+), 87 deletions(-) diff --git a/apps/portal/src/features/catalog/components/internet/InternetPlanCard.tsx b/apps/portal/src/features/catalog/components/internet/InternetPlanCard.tsx index f47cce69..8bdc0b84 100644 --- a/apps/portal/src/features/catalog/components/internet/InternetPlanCard.tsx +++ b/apps/portal/src/features/catalog/components/internet/InternetPlanCard.tsx @@ -53,7 +53,8 @@ export function InternetPlanCard({ return "border border-yellow-200 bg-white shadow-lg hover:shadow-xl ring-1 ring-yellow-100"; if (isPlatinum) return "border border-indigo-200 bg-white shadow-lg hover:shadow-xl ring-1 ring-indigo-100"; - if (isSilver) return "border border-gray-200 bg-white shadow-lg hover:shadow-xl ring-1 ring-gray-100"; + if (isSilver) + return "border border-gray-200 bg-white shadow-lg hover:shadow-xl ring-1 ring-gray-100"; return "border border-gray-200 bg-white shadow hover:shadow-lg"; }; @@ -64,25 +65,60 @@ export function InternetPlanCard({ return "default"; }; - // Format plan name display to show just the plan tier prominently - const formatPlanName = () => { - if (plan.name) { - // Extract tier and offering type from name like "Internet Gold Plan (Home 1G)" - const match = plan.name.match(/(\w+)\s+Plan\s+\((.*?)\)/); - if (match) { - return ( -
- {match[1]} Plan ({match[2]}) -
- ); - } + const renderFeature = (feature: string, index: number) => { + const [label, detail] = feature.split(":"); + + if (detail) { return ( -
- {plan.name} -
+
  • + + + {label.trim()}:{" "} + {detail.trim()} + +
  • ); } - return

    {plan.name}

    ; + + return ( +
  • + + {feature} +
  • + ); + }; + + const renderPlanFeatures = () => { + if (plan.catalogMetadata?.features && plan.catalogMetadata.features.length > 0) { + return plan.catalogMetadata.features.map(renderFeature); + } + + const priceSummaryParts = [ + typeof plan.monthlyPrice === "number" && plan.monthlyPrice > 0 + ? `Monthly: ¥${plan.monthlyPrice.toLocaleString()}` + : null, + typeof plan.oneTimePrice === "number" && plan.oneTimePrice > 0 + ? `One-time: ¥${plan.oneTimePrice.toLocaleString()}` + : null, + ].filter(Boolean) as string[]; + + const fallbackFeatures = [ + "NTT Optical Fiber (Flet's Hikari Next)", + `${plan.internetOfferingType?.includes("Apartment") ? "Mansion" : "Home"} ${ + plan.internetOfferingType?.includes("10G") + ? "10Gbps" + : plan.internetOfferingType?.includes("100M") + ? "100Mbps" + : "1Gbps" + } connection`, + "ISP connection protocols: IPoE and PPPoE", + ...(priceSummaryParts.length > 0 ? [priceSummaryParts.join(" | ")] : []), + installations.length > 0 && minInstallationPrice > 0 + ? `Installation from ¥${minInstallationPrice.toLocaleString()}` + : null, + ].filter((Boolean)) as string[]; + + return fallbackFeatures.map(renderFeature); }; return ( @@ -90,15 +126,24 @@ export function InternetPlanCard({ variant="static" className={`overflow-hidden flex flex-col h-full transition-all duration-300 ease-out hover:-translate-y-1 ${getBorderClass()}`} > -
    +
    {/* Header with badges and pricing */}
    -
    -
    - {formatPlanName()} - {isGold && ( - - )} +
    +
    + + {isGold && } +
    + +
    +

    + {plan.name} +

    + {plan.catalogMetadata?.tierDescription || plan.description ? ( +

    + {plan.catalogMetadata?.tierDescription || plan.description} +

    + ) : null}
    @@ -112,14 +157,9 @@ export function InternetPlanCard({
    - {/* Description */} -

    - {plan.catalogMetadata?.tierDescription || plan.description} -

    - {/* Features */}
    -

    Plan Includes:

    +

    Your Plan Includes:

      {plan.catalogMetadata?.features && plan.catalogMetadata.features.length > 0 ? ( plan.catalogMetadata.features.map((feature, index) => ( diff --git a/apps/portal/src/features/catalog/components/internet/configure/InternetConfigureContainer.tsx b/apps/portal/src/features/catalog/components/internet/configure/InternetConfigureContainer.tsx index 2221a49f..02824ff6 100644 --- a/apps/portal/src/features/catalog/components/internet/configure/InternetConfigureContainer.tsx +++ b/apps/portal/src/features/catalog/components/internet/configure/InternetConfigureContainer.tsx @@ -2,8 +2,10 @@ import { PageLayout } from "@/components/templates/PageLayout"; import { ProgressSteps } from "@/components/molecules"; -import { ServerIcon } from "@heroicons/react/24/outline"; -import { CatalogBackLink } from "@/features/catalog/components/base/CatalogBackLink"; +import { Button } from "@/components/atoms/button"; +import { CardBadge } from "@/features/catalog/components/base/CardBadge"; +import type { BadgeVariant } from "@/features/catalog/components/base/CardBadge"; +import { ServerIcon, ArrowLeftIcon } from "@heroicons/react/24/outline"; import type { InternetPlanCatalogItem, InternetInstallationCatalogItem, @@ -93,8 +95,6 @@ export function InternetConfigureContainer({ description="Set up your internet service options" >
      - - {/* Plan Header */} @@ -162,18 +162,36 @@ function PlanHeader({ }) { return (
      -

      {plan.name}

      -
      - - ¥{(plan.monthlyPrice ?? 0).toLocaleString()} - - - per month - {plan.oneTimePrice && plan.oneTimePrice > 0 && ( + + +

      Configure {plan.name}

      + +
      + {plan.internetPlanTier && ( <> - - - ¥{plan.oneTimePrice.toLocaleString()} setup + + + + )} + {plan.name} + {plan.monthlyPrice && plan.monthlyPrice > 0 && ( + <> + + + ¥{plan.monthlyPrice.toLocaleString()}/month )} @@ -181,3 +199,18 @@ function PlanHeader({
      ); } + +function getTierBadgeVariant(tier?: string | null): BadgeVariant { + switch (tier) { + case "Gold": + return "gold"; + case "Platinum": + return "platinum"; + case "Silver": + return "silver"; + case "Recommended": + return "recommended"; + default: + return "default"; + } +} diff --git a/apps/portal/src/features/catalog/components/internet/configure/steps/ServiceConfigurationStep.tsx b/apps/portal/src/features/catalog/components/internet/configure/steps/ServiceConfigurationStep.tsx index 915093ef..3af49c69 100644 --- a/apps/portal/src/features/catalog/components/internet/configure/steps/ServiceConfigurationStep.tsx +++ b/apps/portal/src/features/catalog/components/internet/configure/steps/ServiceConfigurationStep.tsx @@ -2,8 +2,8 @@ import { AnimatedCard } from "@/components/molecules"; import { Button } from "@/components/atoms/button"; -import { AlertBanner } from "@/components/molecules/AlertBanner/AlertBanner"; import { ArrowRightIcon } from "@heroicons/react/24/outline"; +import type { ReactNode } from "react"; import type { InternetPlanCatalogItem } from "@customer-portal/domain/catalog"; import type { AccessMode } from "../../../../hooks/useConfigureParams"; @@ -34,21 +34,27 @@ export function ServiceConfigurationStep({ plan, mode, setMode, isTransitioning,
      {plan?.internetPlanTier === "Platinum" && ( - -

      - Additional fees are incurred for the PLATINUM service. Please refer to the information - from our tech team for details. -

      -

      - * Will appear on the invoice as "Platinum Base Plan". Device subscriptions - will be added later. -

      -
      +
      +
      + + + +
      +

      IMPORTANT - For PLATINUM subscribers

      +

      + Additional fees are incurred for the PLATINUM service. Please refer to the information + from our tech team for details. +

      +

      + * Will appear on the invoice as "Platinum Base Plan". Device subscriptions will be added later. +

      +
      +
      +
      )} {plan?.internetPlanTier === "Silver" ? ( @@ -85,17 +91,31 @@ function SilverPlanConfiguration({ mode="PPPoE" selectedMode={mode} onSelect={setMode} - title="PPPoE" - description="Point-to-Point Protocol over Ethernet" - details="Traditional connection method with username/password authentication. Compatible with most routers and ISPs." + title="Any Router + PPPoE" + description="Works with most routers you already own or can purchase anywhere." + note="PPPoE may experience network congestion during peak hours, potentially resulting in slower speeds." + tone="warning" /> + Recommended: Faster speeds with less congestion.{" "} + + Check compatibility → + + + } + tone="success" />
      @@ -108,24 +128,31 @@ function ModeSelectionCard({ onSelect, title, description, - details, + note, + tone, }: { mode: AccessMode; selectedMode: AccessMode | null; onSelect: (mode: AccessMode) => void; title: string; description: string; - details: string; + note: ReactNode; + tone: "warning" | "success"; }) { const isSelected = selectedMode === mode; + const toneClasses = + tone === "warning" + ? "bg-orange-100 text-orange-800 border-orange-200" + : "bg-green-100 text-green-800 border-green-200"; + return (

    {description}

    -

    {details}

    +
    {note}
    ); } function StandardPlanConfiguration({ plan }: { plan: InternetPlanCatalogItem }) { return ( -
    -

    Plan Details

    -
    -
    - Plan Name: - {plan.name} +
    +
    + + + +
    +

    Access Mode Pre-configured

    +

    + Access Mode: IPoE-HGW (Pre-configured for {plan.internetPlanTier} plan) +

    -
    - Tier: - {plan.internetPlanTier} -
    - {plan.description && ( -
    -

    {plan.description}

    -
    - )}
    );