# Internet & SIM Service Page Redesign - Implementation Plan > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. **Goal:** Redesign the public internet page to use a unified card with offering selector, and improve SIM page tab transitions + plan card design. **Architecture:** Two independent UI refactors. Internet page merges ConsolidatedInternetCard + AvailablePlansSection into one component with a segmented control for offering type. SIM page adds direction-aware slide transitions and richer plan cards. **Tech Stack:** React 19, Tailwind CSS, shadcn/ui, lucide-react icons --- ## Task 1: Internet - Build Unified Internet Card with Offering Selector **Files:** - Modify: `apps/portal/src/features/services/views/PublicInternetPlans.tsx` **Context:** This file currently has two separate sections: 1. `ConsolidatedInternetCard` (lines 59-209) - shows price range + 3 tier cards 2. `AvailablePlansSection` (lines 653-731) - 3 expandable offering headers that open tier details below 3. Helper components: `PlanCardHeader` (266-340), `ExpandedTierDetails` (345-465), `MobilePlanCard` (470-648) The goal is to merge these into ONE card with a segmented offering type selector. **Step 1: Replace ConsolidatedInternetCard with UnifiedInternetCard** Delete the `ConsolidatedInternetCard` component (lines 59-209) and replace with a new `UnifiedInternetCard` component that: 1. Accepts both `consolidatedPlanData` (for "All Plans" price ranges) AND `plansByOffering` (for per-offering exact prices) 2. Has internal state: `selectedOffering: "all" | "home10g" | "home1g" | "apartment"` 3. Header section: - Same Wifi icon + "NTT Fiber Internet" title - Price display that updates based on `selectedOffering`: - "all": shows full min~max range - specific offering: shows that offering's min~max (will often be exact price) 4. Segmented control below header: - Pills: "All Plans" | "Home 10G" | "Home 1G" | "Apartment" - Active pill: `bg-card text-foreground shadow-sm` - Inactive: `text-muted-foreground hover:text-foreground` - Container: `bg-muted/60 p-0.5 rounded-lg border border-border/60` (matches SIM tab style) - On mobile: horizontally scrollable with `overflow-x-auto` - Each pill shows the offering icon (Home/Building) and optional speed badge 5. Tier cards grid (same 3 columns: Silver, Gold, Platinum): - When "All Plans": show price ranges per tier (current behavior from consolidated card) - When specific offering selected: show exact prices for that offering's tiers - Wrap the grid in a container with `transition-opacity duration-200` for smooth price updates 6. Footer: same setup fee + CTA button **Step 2: Remove obsolete components** Delete from `PublicInternetPlans.tsx`: - `PlanCardHeader` component (lines 266-340) - `ExpandedTierDetails` component (lines 345-465) - `MobilePlanCard` component (lines 470-648) - `AvailablePlansSection` component (lines 653-731) **Step 3: Update PublicInternetPlansContent render** In the `PublicInternetPlansContent` component's return JSX (starts line 961): - Replace the `ConsolidatedInternetCard` usage (lines 973-987) with `UnifiedInternetCard` - Pass it both `consolidatedPlanData` and `plansByOffering` - Remove the `AvailablePlansSection` usage (lines 989-995) entirely **Step 4: Verify and commit** ```bash cd /home/barsa/projects/customer_portal/customer-portal pnpm type-check pnpm lint ``` Expected: No type errors or lint issues. ```bash git add apps/portal/src/features/services/views/PublicInternetPlans.tsx git commit -m "feat: unified internet card with offering type selector" ``` --- ## Task 2: Internet - Clean Up Unused PublicOfferingCard **Files:** - Check: `apps/portal/src/features/services/components/internet/PublicOfferingCard.tsx` **Context:** After Task 1, the `TierInfo` type is still imported from `PublicOfferingCard.tsx` in `PublicInternetPlans.tsx`. The `PublicOfferingCard` component itself is no longer used. **Step 1: Move TierInfo type inline** In `PublicInternetPlans.tsx`, the import `type { TierInfo } from "@/features/services/components/internet/PublicOfferingCard"` needs to change. Define `TierInfo` directly in `PublicInternetPlans.tsx`: ```typescript interface TierInfo { tier: "Silver" | "Gold" | "Platinum"; monthlyPrice: number; maxMonthlyPrice?: number; description: string; features: string[]; pricingNote?: string; } ``` Remove the import of `TierInfo` from `PublicOfferingCard`. **Step 2: Check if PublicOfferingCard is imported anywhere else** Search for all imports of `PublicOfferingCard` across the codebase. If no other files import it, it can be deleted. If other files import only `TierInfo`, move the type to a shared location or inline it. **Step 3: Verify and commit** ```bash pnpm type-check pnpm lint git add -A git commit -m "refactor: inline TierInfo type, remove unused PublicOfferingCard" ``` --- ## Task 3: SIM - Direction-Aware Tab Transitions **Files:** - Modify: `apps/portal/src/features/services/components/sim/SimPlansContent.tsx` **Context:** The tab switcher is at lines 348-372. The plans grid is at lines 374-410. Currently uses `animate-in fade-in duration-300` on the grid wrapper (line 377). The `SIM_TABS` array (lines 86-108) defines tab order: data-voice (0), data-only (1), voice-only (2). **Step 1: Add transition state tracking** In `SimPlansContent` component, add state to track slide direction: ```typescript import { useMemo, useRef } from "react"; // Inside SimPlansContent: const prevTabRef = useRef(activeTab); const slideDirection = useRef<"left" | "right">("left"); // Update direction when tab changes if (prevTabRef.current !== activeTab) { const tabKeys = SIM_TABS.map(t => t.key); const prevIndex = tabKeys.indexOf(prevTabRef.current); const nextIndex = tabKeys.indexOf(activeTab); slideDirection.current = nextIndex > prevIndex ? "left" : "right"; prevTabRef.current = activeTab; } ``` **Step 2: Replace the grid animation** Replace the current `animate-in fade-in duration-300` on line 377 with a keyed wrapper that triggers CSS animation: ```tsx
{plan.name}
{/* CTA - filled button */}