Assist_Design/docs/plans/2026-03-04-public-pages-restructuring-plan.md
barsa 5a66adb7e6 refactor: update landing page components and styles
- Removed obsolete components such as AnimatedBackground, FloatingGlassCard, TrustBadge, TrustIndicators, and ValuePropCard to streamline the landing page.
- Enhanced existing components like CTABanner and HeroSection with improved accessibility and styling.
- Updated global CSS to introduce new line-height tokens and improved typography.
- Refactored the PublicContactView to focus on a streamlined contact form and sidebar information.
- Improved the ServicesGrid component to utilize a new data structure for landing services.
- Enhanced button components with new variants for better UI consistency.
2026-03-04 13:42:03 +09:00

30 KiB

Public Pages Restructuring Implementation Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: Restructure public pages — update homepage hero, extract reusable ContactForm, clean up Contact page (form + sidebar), create Support page (knowledge base categories, remote tools, FAQ, contact form fallback).

Architecture: Extract shared ContactForm from PublicContactView into features/support/components/. Rewrite PublicContactView as focused two-column contact page. Rewrite PublicSupportView as self-service hub. Update HeroSection text. Add /support route.

Tech Stack: Next.js 15, React 19, Tailwind CSS, shadcn/ui atoms, Zod validation, lucide-react icons


Task 1: Update Homepage Hero Text

Files:

  • Modify: apps/portal/src/features/landing-page/components/HeroSection.tsx:42-49

Step 1: Update the hero heading and subtitle

Change lines 42-49 in HeroSection.tsx:

// OLD:
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-extrabold leading-tight text-foreground">
  <span className="block">English IT Support</span>
  <span className="block text-primary mt-2">for Expats in Japan</span>
</h1>
<p className="mt-6 text-base sm:text-lg text-muted-foreground leading-relaxed font-semibold max-w-2xl mx-auto">
  No Japanese required. Get reliable internet, mobile, and VPN services with full English
  support. Serving expats and international businesses for over 20 years.
</p>

// NEW:
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-extrabold leading-tight text-foreground">
  <span className="block">A One Stop Solution</span>
  <span className="block text-primary mt-2">for Your IT Needs</span>
</h1>
<p className="mt-6 text-base sm:text-lg text-muted-foreground leading-relaxed font-semibold max-w-2xl mx-auto">
  From internet and mobile to VPN and on-site tech support  we handle it all in English so you don&apos;t have to.
</p>

Step 2: Verify no lint errors

Run: pnpm lint --filter @customer-portal/portal

Step 3: Commit

feat: update homepage hero text to "A One Stop Solution for Your IT Needs"

Task 2: Extract Reusable ContactForm Component

Files:

  • Create: apps/portal/src/features/support/components/ContactForm.tsx
  • Create: apps/portal/src/features/support/components/index.ts

Step 1: Create the ContactForm component

Create apps/portal/src/features/support/components/ContactForm.tsx:

"use client";

import { useState, useCallback } from "react";
import Link from "next/link";
import { Button, Input } from "@/components/atoms";
import { FormField } from "@/components/molecules/FormField/FormField";
import { AlertBanner } from "@/components/molecules/AlertBanner/AlertBanner";
import { useZodForm } from "@/shared/hooks";
import { CheckCircle } from "lucide-react";
import {
  publicContactRequestSchema,
  type PublicContactRequest,
} from "@customer-portal/domain/support";
import { apiClient, ApiError, isApiError } from "@/core/api";
import { cn } from "@/shared/utils";

interface ContactFormProps {
  className?: string;
}

export function ContactForm({ className }: ContactFormProps) {
  const [isSubmitted, setIsSubmitted] = useState(false);
  const [submitError, setSubmitError] = useState<string | null>(null);

  const handleSubmit = useCallback(async (data: PublicContactRequest) => {
    setSubmitError(null);

    try {
      await apiClient.POST("/api/support/contact", { body: data });
      setIsSubmitted(true);
    } catch (error) {
      if (isApiError(error)) {
        setSubmitError(error.message || "Failed to send message");
        return;
      }
      if (error instanceof ApiError) {
        setSubmitError(error.message || "Failed to send message");
        return;
      }
      setSubmitError(error instanceof Error ? error.message : "Failed to send message");
    }
  }, []);

  const form = useZodForm<PublicContactRequest>({
    schema: publicContactRequestSchema,
    initialValues: {
      name: "",
      email: "",
      phone: "",
      subject: "",
      message: "",
    },
    onSubmit: handleSubmit,
  });

  if (isSubmitted) {
    return (
      <div className={cn("text-center py-12", className)}>
        <div className="w-16 h-16 bg-success/10 rounded-full flex items-center justify-center mx-auto mb-4">
          <CheckCircle className="h-8 w-8 text-success" />
        </div>
        <h3 className="text-2xl font-bold text-foreground mb-2">Message Sent!</h3>
        <p className="text-muted-foreground mb-6">
          Thank you for contacting us. We&apos;ll get back to you within 24 hours.
        </p>
        <div className="flex gap-3 justify-center">
          <Button as="a" href="/" variant="outline" size="sm">
            Back to Home
          </Button>
          <Button as="a" href="/services" size="sm">
            Browse Services
          </Button>
        </div>
      </div>
    );
  }

  return (
    <div className={cn("bg-white rounded-2xl border border-border/60 p-6", className)}>
      {submitError && (
        <AlertBanner variant="error" title="Error" className="mb-6">
          {submitError}
        </AlertBanner>
      )}

      <form onSubmit={event => void form.handleSubmit(event)} className="space-y-5">
        <div className="grid grid-cols-1 sm:grid-cols-2 gap-5">
          <FormField
            label="Name"
            error={form.touched["name"] ? form.errors["name"] : undefined}
            required
          >
            <Input
              value={form.values.name}
              onChange={e => form.setValue("name", e.target.value)}
              onBlur={() => form.setTouchedField("name")}
              placeholder="Your name"
              className="bg-muted/20"
            />
          </FormField>

          <FormField
            label="Email"
            error={form.touched["email"] ? form.errors["email"] : undefined}
            required
          >
            <Input
              type="email"
              value={form.values.email}
              onChange={e => form.setValue("email", e.target.value)}
              onBlur={() => form.setTouchedField("email")}
              placeholder="your@email.com"
              className="bg-muted/20"
            />
          </FormField>
        </div>

        <div className="grid grid-cols-1 sm:grid-cols-2 gap-5">
          <FormField label="Phone" error={form.touched["phone"] ? form.errors["phone"] : undefined}>
            <Input
              value={form.values.phone ?? ""}
              onChange={e => form.setValue("phone", e.target.value)}
              onBlur={() => form.setTouchedField("phone")}
              placeholder="+81 90-1234-5678"
              className="bg-muted/20"
            />
          </FormField>

          <FormField
            label="Subject"
            error={form.touched["subject"] ? form.errors["subject"] : undefined}
            required
          >
            <Input
              value={form.values.subject}
              onChange={e => form.setValue("subject", e.target.value)}
              onBlur={() => form.setTouchedField("subject")}
              placeholder="How can we help?"
              className="bg-muted/20"
            />
          </FormField>
        </div>

        <FormField
          label="Message"
          error={form.touched["message"] ? form.errors["message"] : undefined}
          required
        >
          <textarea
            className="flex min-h-[120px] w-full rounded-lg border border-input bg-muted/20 px-4 py-3 text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:border-transparent disabled:cursor-not-allowed disabled:opacity-50 transition-colors resize-y text-sm"
            value={form.values.message}
            onChange={e => form.setValue("message", e.target.value)}
            onBlur={() => form.setTouchedField("message")}
            placeholder="Tell us more about your inquiry..."
            rows={4}
          />
        </FormField>

        <Button
          type="submit"
          className="w-full"
          size="lg"
          disabled={form.isSubmitting}
          isLoading={form.isSubmitting}
          loadingText="Sending..."
        >
          Send Message
        </Button>
      </form>

      <p className="text-xs text-muted-foreground mt-4 pt-4 border-t border-border/60">
        By submitting, you agree to our{" "}
        <Link href="#" className="text-primary hover:underline">
          Privacy Policy
        </Link>
        . We typically respond within 24 hours.
      </p>
    </div>
  );
}

Step 2: Create barrel export

Create apps/portal/src/features/support/components/index.ts:

export { ContactForm } from "./ContactForm";

Step 3: Verify no lint errors

Run: pnpm lint --filter @customer-portal/portal

Step 4: Commit

feat: extract reusable ContactForm component from PublicContactView

Task 3: Rewrite Contact Page (Two-Column Layout)

Files:

  • Modify: apps/portal/src/features/support/views/PublicContactView.tsx (full rewrite)

Step 1: Rewrite PublicContactView

Replace the entire content of apps/portal/src/features/support/views/PublicContactView.tsx with:

"use client";

import { Mail, MapPin, Phone, MessageSquare, Clock, Send, ExternalLink } from "lucide-react";
import { ContactForm } from "@/features/support/components";

/**
 * PublicContactView - Focused contact page with form + sidebar info
 */
export function PublicContactView() {
  return (
    <div className="max-w-6xl mx-auto px-4 pb-0">
      {/* Header */}
      <div className="text-center mb-12 pt-8">
        <div className="inline-flex items-center justify-center w-16 h-16 bg-primary/10 rounded-2xl mb-4 text-primary">
          <Send className="h-8 w-8" />
        </div>
        <h1 className="text-4xl sm:text-5xl font-extrabold text-foreground mb-4 tracking-tight">
          Get in Touch
        </h1>
        <p className="text-lg text-muted-foreground max-w-2xl mx-auto leading-relaxed">
          Our English-speaking team is here to help. Fill out the form below or reach us through any
          of the channels listed.
        </p>
      </div>

      {/* Two-column layout: Form + Sidebar */}
      <div className="grid grid-cols-1 lg:grid-cols-3 gap-10 mb-16">
        {/* Contact Form - takes 2/3 width */}
        <div className="lg:col-span-2">
          <ContactForm />
        </div>

        {/* Sidebar - takes 1/3 width */}
        <div className="space-y-6">
          {/* Phone */}
          <a
            href="tel:0120-660-470"
            className="group flex items-center gap-4 bg-white rounded-2xl border border-border/60 p-5 hover:border-primary/40 hover:shadow-md transition-all duration-200"
          >
            <div className="h-11 w-11 rounded-xl bg-primary/10 flex items-center justify-center text-primary group-hover:bg-primary group-hover:text-white transition-colors shrink-0">
              <Phone className="h-5 w-5" />
            </div>
            <div>
              <h3 className="font-bold text-foreground text-sm group-hover:text-primary transition-colors">
                Call Us
              </h3>
              <p className="text-base font-bold text-primary">0120-660-470</p>
              <p className="text-xs text-muted-foreground">Toll-free in Japan</p>
            </div>
          </a>

          {/* Live Chat */}
          <button
            type="button"
            onClick={() => {
              /* Trigger chat */
            }}
            className="group flex items-center gap-4 bg-white rounded-2xl border border-border/60 p-5 hover:border-blue-500/40 hover:shadow-md transition-all duration-200 text-left w-full"
          >
            <div className="h-11 w-11 rounded-xl bg-blue-500/10 flex items-center justify-center text-blue-500 group-hover:bg-blue-500 group-hover:text-white transition-colors shrink-0">
              <MessageSquare className="h-5 w-5" />
            </div>
            <div>
              <h3 className="font-bold text-foreground text-sm group-hover:text-blue-500 transition-colors">
                Live Chat
              </h3>
              <div className="flex items-center gap-2">
                <span className="relative flex h-2 w-2">
                  <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-success opacity-75"></span>
                  <span className="relative inline-flex rounded-full h-2 w-2 bg-success"></span>
                </span>
                <span className="text-sm text-muted-foreground">Available now</span>
              </div>
            </div>
          </button>

          {/* Email */}
          <a
            href="mailto:support@assist-solutions.jp"
            className="group flex items-center gap-4 bg-white rounded-2xl border border-border/60 p-5 hover:border-emerald-500/40 hover:shadow-md transition-all duration-200"
          >
            <div className="h-11 w-11 rounded-xl bg-emerald-500/10 flex items-center justify-center text-emerald-500 group-hover:bg-emerald-500 group-hover:text-white transition-colors shrink-0">
              <Mail className="h-5 w-5" />
            </div>
            <div>
              <h3 className="font-bold text-foreground text-sm group-hover:text-emerald-500 transition-colors">
                Email Us
              </h3>
              <p className="text-sm text-muted-foreground">support@assist-solutions.jp</p>
            </div>
          </a>

          {/* Business Hours */}
          <div className="bg-muted/30 rounded-2xl p-5">
            <div className="flex items-center gap-3 mb-3">
              <Clock className="h-5 w-5 text-muted-foreground" />
              <h3 className="font-bold text-foreground text-sm">Business Hours</h3>
            </div>
            <p className="text-sm text-muted-foreground">Mon - Fri, 9:30 AM - 6:00 PM JST</p>
          </div>

          {/* Office Location */}
          <div className="bg-white rounded-2xl border border-border/60 p-5">
            <div className="flex items-center gap-3 mb-3">
              <MapPin className="h-5 w-5 text-primary" />
              <h3 className="font-bold text-foreground text-sm">Our Office</h3>
            </div>
            <address className="text-sm text-muted-foreground leading-relaxed not-italic mb-3">
              3F Azabu Maruka Bldg., 3-8-2 Higashi Azabu,
              <br />
              Minato-ku, Tokyo 106-0044
            </address>
            <p className="text-xs text-muted-foreground mb-3">
              5 min walk from Exit 6, Azabu-Juban Station
            </p>
            <a
              href="https://www.google.com/maps/dir//Assist+Solutions+Corp,+3-8-2+Higashi+Azabu,+Minato-ku,+Tokyo"
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex items-center gap-1.5 text-primary text-sm font-medium hover:underline"
            >
              Get Directions
              <ExternalLink className="h-3.5 w-3.5" />
            </a>
          </div>

          {/* Small Map */}
          <div className="rounded-2xl overflow-hidden border border-border/60 h-[200px]">
            <iframe
              title="Assist Solutions Corp Office"
              src="https://www.google.com/maps?q=Assist+Solutions+Corp,+3-8-2+Higashi+Azabu,+Minato-ku,+Tokyo&output=embed"
              className="w-full h-full"
              loading="lazy"
              allowFullScreen
              referrerPolicy="no-referrer-when-downgrade"
            />
          </div>
        </div>
      </div>
    </div>
  );
}

export default PublicContactView;

Step 2: Verify no lint errors

Run: pnpm lint --filter @customer-portal/portal

Step 3: Commit

feat: rewrite contact page with two-column layout using shared ContactForm

Task 4: Rewrite Support Page as Self-Service Hub

Files:

  • Modify: apps/portal/src/features/support/views/PublicSupportView.tsx (full rewrite)

Step 1: Rewrite PublicSupportView

Replace the entire content of apps/portal/src/features/support/views/PublicSupportView.tsx with:

"use client";

import { useState } from "react";
import Image from "next/image";
import Link from "next/link";
import {
  HelpCircle,
  Wifi,
  Smartphone,
  Lock,
  Building2,
  CreditCard,
  Wrench,
  Download,
  ChevronDown,
  Send,
} from "lucide-react";
import { ContactForm } from "@/features/support/components";
import { supportDownloads } from "@/features/landing-page/data";
import { cn } from "@/shared/utils";

// =============================================================================
// DATA
// =============================================================================

const KNOWLEDGE_BASE_CATEGORIES = [
  {
    title: "Internet & Wi-Fi",
    description: "Router setup, connection issues, speed troubleshooting",
    icon: Wifi,
    color: "text-blue-500",
    bgColor: "bg-blue-500/10",
    hoverBorder: "hover:border-blue-500/40",
  },
  {
    title: "Phone & SIM",
    description: "SIM activation, plan changes, number porting",
    icon: Smartphone,
    color: "text-green-500",
    bgColor: "bg-green-500/10",
    hoverBorder: "hover:border-green-500/40",
  },
  {
    title: "VPN & Streaming",
    description: "VPN router setup, streaming access, configuration",
    icon: Lock,
    color: "text-purple-500",
    bgColor: "bg-purple-500/10",
    hoverBorder: "hover:border-purple-500/40",
  },
  {
    title: "Business Solutions",
    description: "Office networks, dedicated lines, enterprise support",
    icon: Building2,
    color: "text-orange-500",
    bgColor: "bg-orange-500/10",
    hoverBorder: "hover:border-orange-500/40",
  },
  {
    title: "Billing & Account",
    description: "Invoices, payments, account changes, contracts",
    icon: CreditCard,
    color: "text-pink-500",
    bgColor: "bg-pink-500/10",
    hoverBorder: "hover:border-pink-500/40",
  },
  {
    title: "General Tech Support",
    description: "Device help, software issues, general troubleshooting",
    icon: Wrench,
    color: "text-amber-500",
    bgColor: "bg-amber-500/10",
    hoverBorder: "hover:border-amber-500/40",
  },
];

const FAQ_ITEMS = [
  {
    question: "How do I set up my internet router?",
    answer:
      "After your installation appointment, connect the provided router to the NTT ONU device using the included LAN cable. Power on the router and connect to the Wi-Fi network using the credentials on the router label. If you need help, contact our support team or use our remote support tools.",
  },
  {
    question: "How do I activate my SIM card?",
    answer:
      "Insert the SIM card into your unlocked phone. You should receive a confirmation email with APN settings. Go to Settings > Mobile Data > APN and enter the provided settings. Restart your phone and you should be connected within a few minutes.",
  },
  {
    question: "What payment methods do you accept?",
    answer:
      "We accept major credit cards (Visa, Mastercard, American Express), bank transfers, and convenience store payments. Foreign credit cards are accepted for all our services.",
  },
  {
    question: "How do I contact support outside business hours?",
    answer:
      "You can send us an email or submit a contact form at any time — we'll respond within 24 hours on the next business day. For urgent issues, our live chat may have extended availability.",
  },
  {
    question: "Can I change my plan after signing up?",
    answer:
      "Yes, you can change your plan at any time. Contact our support team and we'll help you switch to a plan that better fits your needs. Changes typically take effect from the next billing cycle.",
  },
];

// =============================================================================
// COMPONENT
// =============================================================================

/**
 * PublicSupportView - Self-service support hub
 */
export function PublicSupportView() {
  const [expandedFaq, setExpandedFaq] = useState<number | null>(null);

  return (
    <div className="max-w-6xl mx-auto px-4 pb-0">
      {/* Header */}
      <div className="text-center mb-12 pt-8">
        <div className="inline-flex items-center justify-center w-16 h-16 bg-primary/10 rounded-2xl mb-4 text-primary">
          <HelpCircle className="h-8 w-8" />
        </div>
        <h1 className="text-4xl sm:text-5xl font-extrabold text-foreground mb-4 tracking-tight">
          How Can We Help?
        </h1>
        <p className="text-lg text-muted-foreground max-w-2xl mx-auto leading-relaxed">
          Find answers, download remote support tools, or send us a message. Our English-speaking
          team is ready to assist.
        </p>
      </div>

      {/* Knowledge Base Categories */}
      <section className="mb-16">
        <h2 className="text-2xl font-bold text-foreground mb-6 text-center">Browse by Topic</h2>
        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
          {KNOWLEDGE_BASE_CATEGORIES.map(category => {
            const Icon = category.icon;
            return (
              <div
                key={category.title}
                className={cn(
                  "bg-white rounded-2xl border border-border/60 p-6 transition-all duration-200 hover:shadow-md",
                  category.hoverBorder
                )}
              >
                <div className="flex items-start gap-4">
                  <div
                    className={cn(
                      "h-11 w-11 rounded-xl flex items-center justify-center shrink-0",
                      category.bgColor,
                      category.color
                    )}
                  >
                    <Icon className="h-5 w-5" />
                  </div>
                  <div>
                    <h3 className="font-bold text-foreground text-sm mb-1">{category.title}</h3>
                    <p className="text-sm text-muted-foreground leading-relaxed">
                      {category.description}
                    </p>
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      </section>

      {/* Remote Support Tools */}
      <section className="mb-16">
        <h2 className="text-2xl font-bold text-foreground mb-2 text-center">
          Remote Support Tools
        </h2>
        <p className="text-muted-foreground text-center mb-6">
          Download one of these tools so our technicians can assist you remotely.
        </p>
        <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
          {supportDownloads.map(tool => (
            <a
              key={tool.title}
              href={tool.href}
              target="_blank"
              rel="noopener noreferrer"
              className="group bg-white rounded-2xl border border-border/60 p-6 hover:border-primary/40 hover:shadow-md transition-all duration-200"
            >
              <div className="flex items-start gap-5">
                <div className="w-16 h-16 rounded-xl bg-muted/30 flex items-center justify-center shrink-0 overflow-hidden">
                  <Image
                    src={tool.image}
                    alt={tool.title}
                    width={48}
                    height={48}
                    className="object-contain"
                  />
                </div>
                <div className="flex-1 min-w-0">
                  <div className="flex items-center gap-2 mb-1">
                    <h3 className="font-bold text-foreground group-hover:text-primary transition-colors">
                      {tool.title}
                    </h3>
                    <Download className="h-4 w-4 text-muted-foreground group-hover:text-primary transition-colors" />
                  </div>
                  <p className="text-sm text-muted-foreground leading-relaxed mb-2">
                    {tool.description}
                  </p>
                  <p className="text-xs font-medium text-primary">{tool.useCase}</p>
                </div>
              </div>
            </a>
          ))}
        </div>
      </section>

      {/* FAQ */}
      <section className="mb-16">
        <h2 className="text-2xl font-bold text-foreground mb-6 text-center flex items-center justify-center gap-2">
          Frequently Asked Questions
        </h2>
        <div className="max-w-3xl mx-auto space-y-3">
          {FAQ_ITEMS.map((item, index) => {
            const isExpanded = expandedFaq === index;
            return (
              <div
                key={index}
                className="bg-white rounded-xl border border-border/60 overflow-hidden"
              >
                <button
                  type="button"
                  onClick={() => setExpandedFaq(isExpanded ? null : index)}
                  className="w-full flex items-center justify-between p-4 text-left hover:bg-muted/30 transition-colors"
                >
                  <span className="font-medium text-foreground text-sm pr-4">{item.question}</span>
                  <ChevronDown
                    className={cn(
                      "h-4 w-4 text-muted-foreground flex-shrink-0 transition-transform",
                      isExpanded && "rotate-180"
                    )}
                  />
                </button>
                {isExpanded && (
                  <div className="px-4 pb-4">
                    <p className="text-sm text-muted-foreground leading-relaxed">{item.answer}</p>
                  </div>
                )}
              </div>
            );
          })}
        </div>
      </section>

      {/* Contact Form Fallback */}
      <section className="mb-12">
        <div className="text-center mb-6">
          <div className="inline-flex items-center justify-center w-12 h-12 bg-primary/10 rounded-xl mb-3 text-primary">
            <Send className="h-6 w-6" />
          </div>
          <h2 className="text-2xl font-bold text-foreground">Still Need Help?</h2>
          <p className="text-muted-foreground mt-1">
            Send us a message and we&apos;ll get back to you within 24 hours.
          </p>
        </div>
        <div className="max-w-2xl mx-auto">
          <ContactForm />
        </div>
      </section>

      {/* Existing Customer CTA */}
      <div className="text-center pt-8 border-t border-border/60">
        <p className="text-muted-foreground">
          Already have an account?{" "}
          <Link
            href="/auth/login"
            className="font-semibold text-primary hover:text-primary/80 hover:underline transition-colors"
          >
            Sign in
          </Link>{" "}
          to access your dashboard and support tickets.
        </p>
      </div>
    </div>
  );
}

export default PublicSupportView;

Step 2: Verify no lint errors

Run: pnpm lint --filter @customer-portal/portal

Step 3: Commit

feat: rewrite support page as self-service hub with knowledge base, remote tools, FAQ

Task 5: Add Support Page Route

Files:

  • Create: apps/portal/src/app/(public)/(site)/support/page.tsx

Step 1: Create the support route page

Create apps/portal/src/app/(public)/(site)/support/page.tsx:

/**
 * Public Support Page
 *
 * Self-service support hub with knowledge base categories,
 * remote support tools, FAQ, and contact form fallback.
 */

import type { Metadata } from "next";
import { PublicSupportView } from "@/features/support/views/PublicSupportView";

export const metadata: Metadata = {
  title: "Support - Self-Service Help Center | Assist Solutions",
  description:
    "Find answers to common questions, download remote support tools, or contact our English-speaking team. No Japanese required.",
  keywords: [
    "IT support Japan",
    "English tech support Tokyo",
    "remote support Japan",
    "expat tech help",
    "Assist Solutions support",
  ],
  openGraph: {
    title: "Support - Help Center | Assist Solutions",
    description:
      "Self-service support hub for expats in Japan. FAQ, remote support tools, and direct contact options.",
    type: "website",
  },
};

export default function SupportPage() {
  return <PublicSupportView />;
}

Step 2: Verify no lint errors

Run: pnpm lint --filter @customer-portal/portal

Step 3: Verify type checking passes

Run: pnpm type-check

Step 4: Commit

feat: add /support route for public support page

Task 6: Update Support Views Barrel Export

Files:

  • Modify: apps/portal/src/features/support/views/index.ts

Step 1: Add PublicSupportView and PublicContactView to the barrel export

The current views/index.ts only exports authenticated views. Add the public views:

// Current content:
export * from "./NewSupportCaseView";
export * from "./SupportCasesView";
export * from "./SupportCaseDetailView";
export * from "./SupportHomeView";

// Add these:
export * from "./PublicContactView";
export * from "./PublicSupportView";

Note: The contact page currently imports directly from the view file (@/features/support/views/PublicContactView), not from the barrel. After adding to barrel, update the contact page import in apps/portal/src/app/(public)/(site)/contact/page.tsx to use the barrel:

// OLD:
import { PublicContactView } from "@/features/support/views/PublicContactView";

// NEW:
import { PublicContactView } from "@/features/support/views";

And update the new support page import in apps/portal/src/app/(public)/(site)/support/page.tsx:

// OLD:
import { PublicSupportView } from "@/features/support/views/PublicSupportView";

// NEW:
import { PublicSupportView } from "@/features/support/views";

Step 2: Verify no lint errors

Run: pnpm lint --filter @customer-portal/portal

Step 3: Verify type checking passes

Run: pnpm type-check

Step 4: Commit

refactor: add public views to support barrel exports

Task 7: Final Verification

Step 1: Run full lint check

Run: pnpm lint

Step 2: Run type check

Run: pnpm type-check

Step 3: Verify all pages render (manual or dev server if permitted)

Check these routes work:

  • / — homepage with new hero text
  • /contact — two-column contact page
  • /support — self-service support hub
  • /help — still redirects to /contact