PassengersPage

Passenger management page with table and CSV import functionality

PassengersPage

A complete passenger management page with table display, CSV import, and navigation to passenger details. Includes organization filtering and full list refresh logic.

Features

  • Passenger Table: Full-featured table with organization filtering
  • Import Passengers: CSV import with validation and error handling
  • Row Click Navigation: Click row to view passenger details
  • Full List Refresh: Ensures full list when landing on page
  • Localization: Fully localized in English and Japanese
  • Full Height: Table expands to fill available space

Usage

// app/passengers/page.tsx (or app/page.tsx for root)
import { PassengersPage } from '@/components/sgerp/pages/passengers-page';

export default function Page() {
  return <PassengersPage />;
}

Props

This component does not accept any props. It's a standalone page component.

Screenshot

Passengers Page

Features in Detail

Header Section

  • Title: Localized page title (ptapp.passengers.title)
  • Description: Localized description (ptapp.passengers.description)
  • Import Button: Opens CSV import dialog

Passenger Table

  • Full Table: Uses PassengerTable from predefined tables
  • Full Height: Table fills available vertical space
  • Row Click: Navigates to passenger detail page
  • Organization Filter: Filter passengers by organization
  • Active Filter: Show active/inactive passengers

Import Dialog

  • CSV Upload: Drag & drop or click to upload
  • Validation: Checks for required fields
  • Error Display: Shows validation errors
  • Success: Refreshes table after import

Full List Refresh Logic

When landing on the page, if collection has only 1 item (likely from a filter on detail page), it automatically refetches the full list:

useEffect(() => {
  const ensureFullList = async () => {
    if (!api?.collections.passenger) return;

    // If collection has only 1 item, it was likely filtered - refetch all
    if (api.collections.passenger.length <= 1) {
      await api.collections.passenger.fetch({ limit: 20 });
    }
  };

  ensureFullList();
}, [api]);

Table Columns

  • ID: Passenger ID
  • Name: Full name
  • Email: Email address (masked)
  • Phone: Phone number (masked)
  • Gender: Gender (Male/Female/Other)
  • Date of Birth: Birth date
  • Organization: Organization name
  • Active: Active status indicator

Clicking a passenger row navigates to:

/ptapp/passengers/{passengerId}

This opens the PassengerDetailPage with full booking and transaction history.

Layout Structure

<div className="flex-1 flex flex-col gap-6 min-h-0">
  {/* Header with Import Button */}
  <div className="flex-shrink-0 flex items-start justify-between">
    <div>
      <h1>{getText('ptapp.passengers.title')}</h1>
      <p>{getText('ptapp.passengers.description')}</p>
    </div>
    <Button onClick={() => setImportDialogOpen(true)}>
      <Upload /> {getText('import.passengers.button')}
    </Button>
  </div>

  {/* Table */}
  <div className="flex-1 min-h-0 flex flex-col">
    <PassengerTable
      collection={api?.collections.passenger ?? null}
      fullscreenHeight
      onRowClick={(passenger) => router.push(`/ptapp/passengers/${passenger.id}`)}
    />
  </div>

  {/* Import Dialog */}
  <ImportPassengersDialog
    open={importDialogOpen}
    onOpenChange={setImportDialogOpen}
    onSuccess={handleImportSuccess}
  />
</div>

Interaction Flow

Viewing Passenger Details

  1. Click passenger row in table
  2. Navigate to /ptapp/passengers/{id}
  3. View bookings and transactions
  4. Click back to return to list
  5. Full list is restored (not filtered)

Importing Passengers

  1. Click "Import Passengers" button
  2. Dialog opens
  3. Upload CSV file
  4. Validation runs
  5. If valid, passengers created
  6. Table refreshes with new data
  7. Dialog closes

CSV Import Format

Expected CSV columns:

  • name (required)
  • email (required)
  • phone
  • gender
  • birth_date
  • organization_id
  • is_active

Localization

Uses localization keys:

  • ptapp.passengers.title - Page title
  • ptapp.passengers.description - Page description
  • import.passengers.button - Import button text

Plus all keys from PassengerTable and ImportPassengersDialog components.

Dependencies

  • react (for useState, useEffect)
  • next (for useRouter)
  • lucide-react (for Upload icon)
  • sgerp-frontend-lib (collections, hooks, tables, dialog)
  • @/components/ui/button (shadcn/ui)

Notes

  • SGERP Context: Requires SGERPProvider wrapper
  • Collection: Uses passenger collection from SGERP client
  • Router: Uses Next.js useRouter for navigation
  • Refresh Logic: Ensures clean state when navigating from detail to list
  • Privacy: Email and phone masked by default (use detail page to unmask)