Skip to main content

Component Architecture

The application uses a well-organized component structure that separates concerns between feature components and reusable UI components. All components are built with React Server Components by default, with Client Components marked explicitly using the "use client" directive.

Component Organization

The component directory is organized into two main categories:

Feature Components

Domain-specific components that implement application features

UI Components

Reusable, generic components based on shadcn/ui and Radix UI

Feature Components

Located in src/components/, these components implement the core features of the messaging application:
  • Messages - Displays and manages message list with create/update functionality
  • People - Shows contacts list with add/edit capabilities
  • CreateMessageForm - Form for creating new scheduled messages
  • CreatePersonForm - Form for adding new contacts
  • UpdateMessageForm - Form for editing existing messages
  • UpdatePerson - Form for modifying contact information
  • Rescheduler - Component for rescheduling messages

UI Components

Located in src/components/ui/, these are shadcn/ui components built on Radix UI primitives:
  • Button - Action buttons with multiple variants
  • Card - Content containers with header, content, and footer sections
  • Dialog - Modal dialogs for forms and detailed views
  • Input - Text input fields with validation styling
  • Label - Form field labels
  • Select - Dropdown selection menus
  • Textarea - Multi-line text input areas
  • ScrollArea - Scrollable content containers
  • Alert - Notification and error messages
  • Badge - Status indicators and labels
  • Sonner - Toast notification system

Component Hierarchy

The application follows this component structure:
RootLayout (layout.tsx)
└── Page (page.tsx)
    ├── Messages
    │   ├── ScrollArea
    │   │   └── Message (Card + Dialog)
    │   │       └── MessageUpdateForm
    │   └── Dialog + CreateMessageForm
    └── People
        ├── ScrollArea
        │   └── Person (Card + Dialog)
        │       └── PersonUpdate
        └── Dialog + PersonCreate

Component Patterns

Server vs Client Components

Most components are Server Components by default, which allows them to:
  • Fetch data directly using async/await
  • Access environment variables securely
  • Reduce client-side JavaScript bundle size
src/components/Messages.tsx
export default async function Messages() {
  const data = await fetch(`${process.env.BACKEND_URL}/messages/all`, {
    headers: {
      Authorization: `Basic ${Buffer.from(
        `${process.env.USERNAME}:${process.env.PASSWORD}`
      ).toString("base64")}`,
    },
  });
  // ...
}

Composition Pattern

The application heavily uses component composition, where complex components are built from simpler ones:
<Dialog>
  <DialogTrigger asChild>
    <Card className="cursor-pointer">
      <CardHeader>{message.content.slice(0, 100)} ...</CardHeader>
      <CardContent>
        <CardDescription>Send to: {message.sendTo.name}</CardDescription>
      </CardContent>
    </Card>
  </DialogTrigger>
  <DialogContent>
    <DialogTitle>Update Message</DialogTitle>
    <MessageUpdateForm message={message} people={people} />
  </DialogContent>
</Dialog>

Data Flow

1

Fetch Data

Server Components fetch data from the Hono backend API
2

Pass Props

Data is passed down to child components via props
3

User Interaction

Client Components handle user interactions and form submissions
4

Server Actions

Form actions trigger server-side functions that update data
5

Revalidation

revalidatePath("/") refreshes the page data after mutations

TypeScript Interfaces

The application uses TypeScript interfaces to ensure type safety:
src/components/Messages.tsx
export interface Message {
  id: string;
  content: string;
  sendToPhone: string;
  sendAfter: number;
  sendTo: {
    name: string;
  };
  createdAt: Date;
}

export interface People {
  id: string;
  name: string;
  phone: string;
}
These interfaces are exported from components and reused across the application to maintain consistency.

Icon Library

The application uses lucide-react for icons:
import { MailPlus, UserPlus, Clock } from "lucide-react";

<Button>
  <MailPlus />
  <span>Add Message</span>
</Button>

Styling Approach

All components use Tailwind CSS for styling with a utility-first approach:
  • Responsive design with md: breakpoint modifiers
  • Dark mode support with dark: variants
  • Custom design system via Tailwind configuration
  • Consistent spacing and typography scales

Next Steps

UI Components

Learn about shadcn/ui components and their usage

Forms

Understand form handling with Server Actions

Layouts

Explore page layouts and responsive design

API Integration

See how components fetch data from the backend

Build docs developers (and LLMs) love