PTApp Component

Complete People Transport Management application with sidebar navigation and responsive design

PTApp Component

A complete People Transport Management application component with sidebar navigation, responsive design, and localization support. PTApp provides a ready-to-use shell for building transportation management applications.

Screenshots

Passengers Page

Passengers

Passenger Detail - Bookings

Passenger Bookings

Passenger Detail - Transactions

Passenger Transactions

Drivers Page

Drivers

Driver Editor

Driver Editor

Notifications Page

Notifications

Create Notification

Create Notification

Services Page

Services

Templates Page

Templates

Simulation Detail - All Routes

Map with All Routes

Simulation Detail - Single Route

Map with Single Route

Simulation Detail - Timeline

Timeline View

Features

  • Sidebar Navigation: Collapsible sidebar with passenger, driver, notification, service, and template pages
  • Responsive Design: Mobile-friendly with hamburger menu and backdrop overlay
  • Localization: Fully localized in English and Japanese
  • Theme Support: Works with light and dark themes
  • Customizable Base Path: Configure your own routing base path
  • Persistent UI State: Remembers sidebar collapsed state in localStorage
  • Active State Highlighting: Automatically highlights current page in navigation

Installation

The PTApp component is included in the sgerp-frontend-lib package:

npm install sgerp-frontend-lib

Usage

Basic Usage

import { PTApp } from '@/components/sgerp/ptapp';

export default function MyPTApp() {
  return (
    <PTApp>
      {/* Your page content goes here */}
    </PTApp>
  );
}

Custom Base Path

By default, PTApp uses /ptapp as the base path. You can customize it:

import { PTApp } from '@/components/sgerp/ptapp';

export default function MyPTApp() {
  return (
    <PTApp basePath="/transport">
      {/* Navigation will now use /transport, /transport/drivers, etc. */}
    </PTApp>
  );
}

Next.js App Router Example

This is the recommended pattern for Next.js applications:

// app/ptapp/layout.tsx
'use client'

import { PTApp } from '@/components/sgerp/ptapp';

export default function PTAppLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return <PTApp>{children}</PTApp>
}
// app/ptapp/page.tsx
'use client'

import { useSGERP } from 'sgerp-frontend-lib';
import { PassengerTable } from '@/components/sgerp/tables/passenger-table';

export default function PassengersPage() {
  const api = useSGERP();

  return (
    <div className="flex-1 flex flex-col gap-6 min-h-0">
      <div>
        <h1 className="text-3xl font-bold">Passengers</h1>
        <p className="text-muted-foreground mt-2">Manage passenger information</p>
      </div>

      <div className="flex-1 min-h-0">
        <PassengerTable
          collection={api?.collections.passenger ?? null}
          fullscreenHeight
        />
      </div>
    </div>
  );
}

Props

PropTypeDefaultRequiredDescription
childrenReact.ReactNode-YesPage content to render in the main area
basePathstring"/ptapp"NoBase path for navigation routes

The PTApp component includes navigation for these pages:

  • Passengers (/ptapp) - Passenger management and imports
  • Drivers (/ptapp/drivers) - Driver management with organization filtering
  • Notifications (/ptapp/notifications) - SMS/Push notification scheduling
  • Services (/ptapp/services) - Real operation simulations
  • Templates (/ptapp/templates) - Template simulations

You need to create these page routes in your application. See the complete example in this repository's /app/ptapp directory.

Layout Structure

The PTApp component provides a three-part layout:

1. Sidebar

  • Desktop: Collapsible sidebar (toggle button collapses to icon-only view)
  • Mobile: Full overlay with backdrop, hamburger menu to open
  • Footer: Language selector, theme toggle, and back to docs link
  • User Info: Connection information display

2. Top Bar

  • Mobile Menu: Hamburger button to open sidebar (mobile only)
  • Page Title: Displays current section title

3. Main Content Area

  • Scrollable content area with padding
  • Flexible height to fill available space
  • Renders the children prop

Features in Detail

Collapsible Sidebar

The sidebar can be collapsed on desktop to show only icons:

  • Click the chevron button to toggle
  • State persists in localStorage (ptapp-sidebar-collapsed)
  • Tooltips shown on hover when collapsed
  • Full sidebar on mobile (never collapsed)

Active State

The component automatically highlights the active navigation item based on the current pathname using Next.js usePathname() hook.

Language Selector

Built-in language selector in the sidebar footer allows users to switch between supported languages. Uses the LanguageSelector component from the library.

Theme Toggle

Built-in theme toggle (light/dark mode) in the sidebar footer using the ThemeToggle component.

User Connection Info

Shows currently connected SGERP server and user information in the sidebar footer (when not collapsed).

Complete Implementation Example

Here's how the reference implementation structures the pages:

app/ptapp/
├── layout.tsx                  # PTApp wrapper
├── page.tsx                    # Passengers (default page)
├── drivers/
│   └── page.tsx               # Drivers with DriverTable
├── notifications/
│   └── page.tsx               # Notifications with SMSScheduledTable
├── services/
│   └── page.tsx               # Services (real operations)
└── templates/
    └── page.tsx               # Templates

Example Passengers Page

'use client'

import { useSGERP } from 'sgerp-frontend-lib';
import { PassengerTable } from '@/components/sgerp/tables/passenger-table';
import { useLocalization } from 'sgerp-frontend-lib/lib/locales/useLocalization';

export default function PassengersPage() {
  const api = useSGERP();
  const { getText } = useLocalization();

  return (
    <div className="flex-1 flex flex-col gap-6 min-h-0">
      <div>
        <h1 className="text-3xl font-bold" suppressHydrationWarning>
          {getText('ptapp.passengers.title')}
        </h1>
        <p className="text-muted-foreground mt-2" suppressHydrationWarning>
          {getText('ptapp.passengers.description')}
        </p>
      </div>

      <div className="flex-1 min-h-0">
        <PassengerTable
          collection={api?.collections.passenger ?? null}
          fullscreenHeight
        />
      </div>
    </div>
  );
}

Example Drivers Page

'use client'

import { useState } from 'react';
import { useSGERP } from 'sgerp-frontend-lib';
import { DriverTable } from '@/components/sgerp/tables/driver-table';
import { DriverDrawer } from '@/components/sgerp/driver-drawer';
import { useLocalization } from 'sgerp-frontend-lib/lib/locales/useLocalization';
import { Button } from '@/components/ui/button';
import { Plus } from 'lucide-react';

export default function DriversPage() {
  const api = useSGERP();
  const { getText } = useLocalization();
  const [drawerOpen, setDrawerOpen] = useState(false);
  const [selectedDriverId, setSelectedDriverId] = useState<number | undefined>();

  const handleRowClick = (driver) => {
    setSelectedDriverId(driver.id);
    setDrawerOpen(true);
  };

  return (
    <div className="flex-1 flex flex-col gap-6 min-h-0">
      <div className="flex items-start justify-between">
        <div>
          <h1 className="text-3xl font-bold" suppressHydrationWarning>
            {getText('ptapp.drivers.title')}
          </h1>
          <p className="text-muted-foreground mt-2" suppressHydrationWarning>
            {getText('ptapp.drivers.description')}
          </p>
        </div>
        <Button onClick={() => {
          setSelectedDriverId(undefined);
          setDrawerOpen(true);
        }}>
          <Plus className="h-4 w-4 mr-2" />
          {getText('driver.create_driver')}
        </Button>
      </div>

      <div className="flex-1 min-h-0">
        <DriverTable
          collection={api?.collections.driver ?? null}
          fullscreenHeight
          onRowClick={handleRowClick}
        />
      </div>

      <DriverDrawer
        open={drawerOpen}
        onOpenChange={setDrawerOpen}
        driverId={selectedDriverId}
        api={api}
      />
    </div>
  );
}

Localization

PTApp uses localization keys from sgerplib/locales/:

  • ptapp.title - Sidebar header
  • ptapp.header - Top bar header
  • ptapp.nav.passengers - Passengers nav item
  • ptapp.nav.drivers - Drivers nav item
  • ptapp.nav.notifications - Notifications nav item
  • ptapp.nav.services - Services nav item
  • ptapp.nav.templates - Templates nav item
  • ptapp.back_to_docs - Footer link

Page Title Keys

  • ptapp.passengers.title / ptapp.passengers.description
  • ptapp.drivers.title / ptapp.drivers.description
  • ptapp.notifications.title / ptapp.notifications.description
  • ptapp.services.title / ptapp.services.description
  • ptapp.templates.title / ptapp.templates.description

Styling

The component uses:

  • Tailwind CSS for all styling
  • shadcn/ui Button component
  • Lucide React icons
  • CSS transitions for smooth sidebar animation
  • Theme-aware colors (works with light/dark themes)

Required CSS Setup

Ensure your project has:

  • Tailwind CSS configured
  • shadcn/ui components installed
  • SGERP theme variables configured

Responsive Behavior

Desktop (≥1024px)

  • Sidebar always visible
  • Collapsible to icon-only mode
  • Toggle button shows chevron icon

Mobile (<1024px)

  • Sidebar hidden by default
  • Hamburger menu button in top bar
  • Full overlay when opened
  • Backdrop click closes sidebar
  • Close X button in sidebar header

State Management

  • Stored in localStorage with key ptapp-sidebar-collapsed
  • Loaded synchronously on mount using useLayoutEffect
  • Persists across page reloads and sessions

Hydration Handling

  • Uses suppressHydrationWarning on localized elements
  • Opacity transition prevents layout shift
  • Waits for both hydration and locale loading before showing

Dependencies

Required packages:

  • next (App Router for routing)
  • react (18+)
  • lucide-react (for icons)
  • sgerp-frontend-lib (collections, hooks, components)

Components used:

  • @/components/ui/button (shadcn/ui)
  • LanguageSelector from sgerp-frontend-lib
  • ThemeToggle from your project
  • UserConnectionInfo from sgerp-frontend-lib

Full Example

For a complete working example with all pages, navigation, and data management, see the /app/ptapp directory in this repository.