Frontend

Complete doc

Table of Contents

  1. Project Overview
  2. Technology Stack
  3. Getting Started
  4. Project Structure
  5. Features & Modules
  6. Authentication & Authorization
  7. API Integration
  8. Component Library
  9. State Management
  10. Routing & Navigation
  11. Development Guidelines
  12. Deployment
  13. Troubleshooting

Project Overview

OnMart POS Frontend is a modern Point of Sale (POS) system built for retail management. The application provides comprehensive functionality for managing sales, inventory, customers, and reporting across multiple outlets.

Key Features


Technology Stack

Core Framework

UI Components & Libraries

Data Fetching & State Management

Data Visualization

Additional Libraries

Development Tools


Getting Started

Prerequisites

Installation

  1. Clone the repository
git clone <repository-url>
cd onmart-pos-frontend
  1. Install dependencies
npm install
# or
yarn install
# or
pnpm install
  1. Configure environment variables

Create or update .env.local file:

NEXT_PUBLIC_API_URL=http://localhost:3000/api
ORIGIN_CORS=http://localhost:3711
  1. Run development server
npm run dev
# or
yarn dev

The application will start on http://localhost:3711

Available Scripts

# Start development server with Turbopack
npm run dev

# Build for production
npm run build

# Start production server
npm run start

# Run ESLint
npm run lint

Project Structure

onmart-pos-frontend/
├── src/
│   ├── app/                    # Next.js App Router
│   │   ├── (auth)/            # Authentication routes
│   │   │   ├── login/
│   │   │   ├── logout/
│   │   │   └── redirect/
│   │   ├── (dashboard)/       # Protected dashboard routes
│   │   │   ├── dashboard/     # Main dashboard
│   │   │   ├── products/      # Product management
│   │   │   ├── categories/    # Category management
│   │   │   ├── brands/        # Brand management
│   │   │   ├── promos/        # Promotions & discounts
│   │   │   ├── outlets/       # Outlet management
│   │   │   ├── customers/     # Customer management
│   │   │   ├── invoices/      # Invoice history
│   │   │   ├── transactions/  # Transaction reports
│   │   │   ├── posterminal/   # POS Terminal
│   │   │   ├── myshift/       # Cashier shift management
│   │   │   ├── usermanagement/# User management
│   │   │   └── accountsettings/# Account settings
│   │   ├── api/               # API routes
│   │   ├── layout.tsx         # Root layout
│   │   ├── page.tsx           # Home page
│   │   └── globals.css        # Global styles
│   ├── components/            # React components
│   │   ├── ui/               # UI primitives
│   │   ├── icons/            # Custom icons
│   │   ├── layouts/          # Layout components
│   │   └── page.tsx          # Page component
│   ├── features/             # Feature modules
│   │   ├── auth/            # Authentication
│   │   ├── products/        # Product features
│   │   ├── categories/      # Category features
│   │   ├── brands/          # Brand features
│   │   ├── promos/          # Promo features
│   │   ├── outlets/         # Outlet features
│   │   ├── customers/       # Customer features
│   │   ├── invoices/        # Invoice features
│   │   ├── transactions/    # Transaction features
│   │   ├── posTerminal/     # POS Terminal features
│   │   ├── myshift/         # Shift management
│   │   ├── userManagement/  # User management
│   │   └── accountSettings/ # Account settings
│   ├── hooks/               # Custom React hooks
│   │   └── use-mobile.ts    # Mobile detection hook
│   ├── lib/                 # Utility libraries
│   │   ├── api/            # API configuration
│   │   │   └── endpoints.ts # API endpoints
│   │   ├── fetchWithAuth.ts      # Server-side fetch
│   │   ├── fetchWithAuthClient.ts# Client-side fetch
│   │   ├── utils.ts              # Utility functions
│   │   └── alert.ts              # Alert utilities
│   ├── types/              # TypeScript types
│   │   ├── product.ts      # Product types
│   │   └── profile.ts      # Profile types
│   └── middleware.ts       # Next.js middleware
├── public/                 # Static assets
├── .env.local             # Environment variables
├── next.config.ts         # Next.js configuration
├── tailwind.config.ts     # Tailwind configuration
├── tsconfig.json          # TypeScript configuration
├── components.json        # shadcn/ui configuration
└── package.json          # Dependencies

Directory Explanation

/src/app

Contains Next.js App Router pages and layouts. Organized with route groups:

/src/components

Reusable React components:

/src/features

Feature-specific components organized by domain:

/src/lib

Utility functions and configurations:


Features & Modules

1. Dashboard

Path: /dashboard
Roles: Master Admin, Super Admin, Admin, Cashier

Features:

Components:

2. POS Terminal

Path: /posterminal
Roles: Cashier

Features:

Components:

3. Product Management

Path: /products
Roles: Master Admin, Super Admin, Admin

Features:

Components:

API Endpoints:

4. Category Management

Path: /categories
Roles: Master Admin, Super Admin, Admin

Features:

Components:

5. Brand Management

Path: /brands
Roles: Master Admin, Super Admin, Admin

Features:

Components:

6. Promotions & Discounts

Path: /promos
Roles: Master Admin, Super Admin, Admin

Features:

7. Outlet Management

Path: /outlets
Roles: Master Admin, Super Admin

Features:

8. Customer Management

Path: /customers
Roles: All roles

Features:

Components:

9. Invoice Management

Path: /invoices
Roles: All roles

Features:

Components:

10. Transaction Reports

Path: /transactions
Roles: Master Admin, Super Admin, Admin

Features:

Components:

API Endpoints:

11. My Shift

Path: /myshift
Roles: Cashier

Features:

Components:

12. User Management

Path: /usermanagement
Roles: Master Admin, Super Admin, Admin

Features:

Components:

13. Account Settings

Path: /accountsettings
Roles: All roles

Features:

Components:


Authentication & Authorization

Authentication Flow

  1. Login Process

    • User enters credentials on /login
    • loginAction validates credentials with backend
    • On success, JWT token is stored in cookies
    • User profile is stored in cookies
    • Redirect to /redirect then to appropriate dashboard
  2. Token Management

    • Access token stored in access_token cookie
    • Profile data stored in profile cookie
    • "Remember Me" extends cookie lifetime to 7 days
    • Token is automatically included in API requests
  3. Logout Process

    • /logout page calls logout API
    • Clears cookies
    • Redirects to /login

Middleware Protection

File: src/middleware.ts

// Public routes accessible without authentication
const publicRoutes = ["/login", "/auth/redirect"];

// Logic:
// - If logged in + accessing public route → redirect to /dashboard
// - If not logged in + accessing private route → redirect to /login

Protected Routes:

Role-Based Navigation

File: src/components/layouts/dashboardLayout.tsx

Navigation items are filtered based on user role:

Master Admin

Super Admin / Admin

Cashier

Authentication Helpers

Client-Side Fetch

File: src/lib/fetchWithAuthClient.ts

// Automatically adds Authorization header from localStorage
const fetchWithAuthClient = async (input, init) => {
  const token = localStorage.getItem("access_token");
  headers.set("Authorization", `Bearer ${token}`);
  return fetch(input, { ...init, headers });
};

Server-Side Fetch

File: src/lib/fetchWithAuth.ts

For server components and API routes with cookie-based authentication.


API Integration

Base URL Configuration

File: src/lib/api/endpoints.ts

// Production API
const baseUrl = "https://posapi.onemart.id/api";

// For local development, uncomment:
// const baseUrl = "http://localhost:3710/api";

API Endpoints

All endpoints are defined in src/lib/api/endpoints.ts:

Authentication

Products

Categories

Brands

Promotions

Outlets

Customers

Payment Methods

Shifts

Transactions

Dashboard

Users

Roles

Making API Calls

Using SWR (Recommended for GET requests)

import useSWR from 'swr';
import { fetchWithAuthClient } from '@/lib/fetchWithAuthClient';
import endpoints from '@/lib/api/endpoints';

const { data, error, isLoading, mutate } = useSWR(
  endpoints.product.url,
  fetchWithAuthClient
);

Using Axios

import axios from 'axios';
import endpoints from '@/lib/api/endpoints';

const response = await axios({
  url: endpoints.product.url,
  method: endpoints.product.method,
  headers: {
    Authorization: `Bearer ${token}`,
  },
  data: productData,
});

Using fetch directly

import { fetchWithAuthClient } from '@/lib/fetchWithAuthClient';
import endpoints from '@/lib/api/endpoints';

const response = await fetchWithAuthClient(
  endpoints.product.url,
  {
    method: 'POST',
    body: JSON.stringify(productData),
    headers: {
      'Content-Type': 'application/json',
    },
  }
);

Component Library

UI Components

The application uses shadcn/ui components with Radix UI primitives.

Location: src/components/ui/

Available Components

  1. Button (button.tsx)

    • Variants: default, destructive, outline, secondary, ghost, link
    • Sizes: default, sm, lg, icon
    <Button variant="default" size="default">Click me</Button>
    
  2. Input (input.tsx)

    • Standard text input
    <Input type="text" placeholder="Enter text" />
    
  3. Checkbox (checkbox.tsx)

    • Accessible checkbox component
    <Checkbox checked={checked} onCheckedChange={setChecked} />
    
  4. Select (select.tsx)

    • Dropdown select component
    <Select value={value} onValueChange={setValue}>
      <SelectOption value="option1">Option 1</SelectOption>
    </Select>
    
  5. Textarea (textarea.tsx)

    • Multi-line text input
    <Textarea placeholder="Enter description" />
    
  6. Table (table.tsx)

    • Table components (Table, TableHeader, TableBody, TableRow, TableCell)
    <Table>
      <TableHeader>
        <TableRow>
          <TableHead>Column</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        <TableRow>
          <TableCell>Data</TableCell>
        </TableRow>
      </TableBody>
    </Table>
    
  7. DataTable (dataTable.tsx)

    • Advanced table with @tanstack/react-table integration
    • Features: sorting, filtering, pagination
  8. Sheet (sheet.tsx)

    • Slide-out panel component
    <Sheet open={open} onOpenChange={setOpen}>
      <SheetContent>Content</SheetContent>
    </Sheet>
    
  9. Popover (popover.tsx)

    • Floating popover component
    <Popover>
      <PopoverTrigger>Open</PopoverTrigger>
      <PopoverContent>Content</PopoverContent>
    </Popover>
    
  10. Tooltip (tooltip.tsx)

    • Accessible tooltip component
    <Tooltip>
      <TooltipTrigger>Hover me</TooltipTrigger>
      <TooltipContent>Tooltip text</TooltipContent>
    </Tooltip>
    
  11. Separator (separator.tsx)

    • Visual divider
    <Separator orientation="horizontal" />
    
  12. Skeleton (skeleton.tsx)

    • Loading placeholder
    <Skeleton className="h-4 w-full" />
    
  13. Sidebar (sidebar.tsx)

    • Navigation sidebar component
  14. NavbarAvatar (navbarAvatar.tsx)

    • User avatar with dropdown menu

Custom Icons

Location: src/components/icons/

Custom SVG icons for navigation:

Layout Components

DashboardLayout (src/components/layouts/dashboardLayout.tsx)


State Management

Data Fetching with SWR

The application uses SWR for efficient data fetching and caching.

Benefits:

Example:

import useSWR from 'swr';
import { fetchWithAuthClient } from '@/lib/fetchWithAuthClient';

function ProductList() {
  const { data, error, isLoading, mutate } = useSWR(
    '/api/products',
    fetchWithAuthClient
  );

  // mutate() - manually revalidate
  // data - response data
  // error - error object
  // isLoading - loading state
}

Form State with React Hook Form

Forms use React Hook Form for validation and state management.

Example:

import { useForm } from 'react-hook-form';

function ProductForm() {
  const { register, handleSubmit, formState: { errors } } = useForm();

  const onSubmit = async (data) => {
    // Handle form submission
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('name', { required: true })} />
      {errors.name && <span>This field is required</span>}
    </form>
  );
}

Local State

Component-level state is managed with React hooks:


Routing & Navigation

App Router Structure

Next.js 15 uses the App Router with file-based routing.

Route Groups:

Navigation Methods

useRouter Hook

import { useRouter } from 'next/navigation';

const router = useRouter();
router.push('/dashboard');
router.back();
router.refresh();

Redirect Function

import { redirect } from 'next/navigation';

redirect('/login'); // Server-side redirect

Dynamic Routes

/transactions/[id] - Transaction detail page
/products/[id]/edit - Edit product page

Development Guidelines

Code Organization

  1. Feature-based Structure

    • Group related components in feature folders
    • Each feature has consistent file naming: listX.tsx, formX.tsx, columns.tsx, actions.tsx
  2. Component Naming

    • PascalCase for components: ProductList, CategoryForm
    • camelCase for functions and variables: fetchProducts, productData
    • kebab-case for files: product-list.tsx
  3. Type Definitions

    • Define types in src/types/
    • Use interfaces for objects with properties
    • Export types from feature modules

Styling Guidelines

  1. Tailwind CSS

    • Use Tailwind utility classes
    • Avoid inline styles
    • Use className for styling
  2. Custom Colors

    • Brand colors defined in next.config.ts:
      • brand-primary: #f45b8c
      • brand-hover: #e04a7a
      • brand-bg: #ffeef2
      • brand-bgSecondary: #fdd9e5
      • text-muted: #6b7280
  3. Responsive Design

    • Mobile-first approach
    • Use Tailwind breakpoints: sm:, md:, lg:, xl:, 2xl:

TypeScript Best Practices

  1. Type Safety

    • Always define types for props
    • Avoid any type
    • Use type inference where possible
  2. Interfaces vs Types

    • Prefer interfaces for object shapes
    • Use types for unions and intersections
  3. Path Aliases

    • Use @/ prefix for imports
    • Examples: @/components/ui/button, @/lib/utils

Error Handling

  1. API Errors

    • Handle 401 (Unauthorized) → redirect to login
    • Show user-friendly error messages
    • Use SweetAlert2 or React Hot Toast
  2. Form Validation

    • Use React Hook Form validation
    • Display inline error messages
  3. Loading States

    • Show skeletons or spinners
    • Disable buttons during submission

Performance Optimization

  1. Code Splitting

    • Use dynamic imports for large components
    • Leverage Next.js automatic code splitting
  2. Image Optimization

    • Use Next.js <Image> component
    • Optimize images before uploading
  3. Memoization

    • Use useMemo for expensive calculations
    • Use useCallback for event handlers
  4. Data Fetching

    • Use SWR for automatic caching
    • Implement pagination for large lists

Testing (Future)

While testing infrastructure is not currently set up, consider:


Deployment

Build Process

  1. Production Build
npm run build

This creates an optimized production build in .next/ directory.

  1. Start Production Server
npm run start

Runs on port 3711 by default.

Environment Variables

Production:

NEXT_PUBLIC_API_URL=https://posapi.onemart.id/api
ORIGIN_CORS=https://pos.onemart.id

Staging:

NEXT_PUBLIC_API_URL=https://staging-posapi.onemart.id/api
ORIGIN_CORS=https://staging-pos.onemart.id

Development:

NEXT_PUBLIC_API_URL=http://localhost:3710/api
ORIGIN_CORS=http://localhost:3711

Deployment Platforms

Vercel (Recommended)

  1. Connect GitHub repository
  2. Configure environment variables
  3. Deploy automatically on push

Docker

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
EXPOSE 3711
CMD ["npm", "start"]

Traditional Server

  1. Build the application
  2. Copy .next/, public/, node_modules/, package.json
  3. Run with PM2 or similar process manager
pm2 start npm --name "onmart-pos" -- start

API URL Configuration

Change API endpoint in: src/lib/api/endpoints.ts

// Production
const baseUrl = "https://posapi.onemart.id/api";

// Development
// const baseUrl = "http://localhost:3710/api";

Pre-deployment Checklist


Troubleshooting

Common Issues

1. Authentication Issues

Problem: "Sesi Anda telah habis" or automatic logout

Solutions:

Debug:

// Check token in browser console
document.cookie.split(';').find(c => c.includes('access_token'))

2. API Connection Errors

Problem: "Failed to fetch" or CORS errors

Solutions:

Debug:

// Test API directly
fetch('https://posapi.onemart.id/api/auth/me', {
  headers: { Authorization: 'Bearer YOUR_TOKEN' }
})

3. Build Errors

Problem: Build fails with TypeScript errors

Solutions:

4. Port Already in Use

Problem: Port 3711 is already in use

Solutions:

# Kill process on port 3711
lsof -ti:3711 | xargs kill -9

# Or use a different port
npm run dev -- -p 3712

5. Environment Variables Not Loading

Problem: API calls fail or incorrect URLs

Solutions:

6. Styling Issues

Problem: Tailwind classes not working

Solutions:

7. SWR Not Updating

Problem: Data not refreshing after mutation

Solutions:

// Manually revalidate
mutate('/api/products');

// Revalidate with new data
mutate('/api/products', newData, false);

// Global revalidation
import { mutate } from 'swr';
mutate(() => true); // Revalidate all

Getting Help

  1. Check Console: Open browser DevTools and check for error messages
  2. Check Network: Review API calls in Network tab
  3. Check Logs: Check terminal for server-side errors
  4. Documentation: Review this documentation
  5. Backend Team: Contact backend team for API issues

Glossary


Additional Resources

External Documentation

Internal Resources


Changelog

Version 0.1.0 (Current)


License

This project is proprietary and confidential. All rights reserved by OnMart/OnIndonesia.


Contact & Support

For questions or support:


Document Version: 1.0
Last Updated: February 2026
Maintained By: Development Team