Frontend

Introduction

Introduction

Project Overview

OnMarket Landing is a comprehensive Angular-based e-commerce marketplace application. It provides a full-featured online shopping platform with product browsing, cart management, checkout, user profiles, affiliate program, and real-time chat functionality.

Key Capabilities


Technology Stack

Core Framework

UI/UX Libraries

Additional Libraries

Development Tools

Introduction

Installation and setup

Prerequisites

Before you begin, ensure you have the following installed:


Installation & Setup

1. Clone the Repository

git clone https://github.com/ondeliveroper/on-market-landing.git
cd on-market-landing

2. Install Dependencies

npm install

3. Environment Configuration

The application uses environment files located in src/environments/:

4. Start Development Server

npm start
# or for Windows
npm run startWindows

The application will be available at http://localhost:4200/

Note: The start script uses NODE_OPTIONS='--openssl-legacy-provider' due to OpenSSL compatibility with Angular 12.

Introduction

Project structure

on-market-landing/
├── e2e/                          # End-to-end tests
├── src/
│   ├── app/
│   │   ├── components/           # All UI components
│   │   │   ├── accounts/         # Login, signup, profile
│   │   │   ├── affiliate/        # Affiliate program
│   │   │   ├── all-bills/        # Bill payment features
│   │   │   ├── cart/             # Shopping cart
│   │   │   ├── checkout/         # Checkout process
│   │   │   ├── homepage/         # Home page
│   │   │   ├── personal-store/   # Store management
│   │   │   ├── product-details/  # Product detail pages
│   │   │   ├── search-result/    # Search functionality
│   │   │   └── ...               # Other components
│   │   ├── interceptors/         # HTTP interceptors
│   │   │   └── auth.interceptor.ts
│   │   ├── interfaces/           # TypeScript interfaces
│   │   │   ├── affiliate.ts
│   │   │   ├── balance.ts
│   │   │   ├── bank.ts
│   │   │   ├── products.ts
│   │   │   └── user.ts
│   │   ├── pipes/                # Custom pipes
│   │   │   ├── phone-number.pipe.ts
│   │   │   ├── short-number-pipe.pipe.ts
│   │   │   ├── time-ago.pipe.ts
│   │   │   └── transform-city.pipe.ts
│   │   ├── services/             # Business logic services
│   │   │   └── affiliate.service.ts
│   │   ├── themes/               # Multiple theme layouts
│   │   │   ├── theme-one/
│   │   │   ├── theme-two/
│   │   │   └── ...
│   │   ├── api.service.ts        # Main API service
│   │   ├── app-routing.module.ts # Route definitions
│   │   ├── app.component.ts      # Root component
│   │   ├── app.module.ts         # Main module
│   │   ├── auth.guard.ts         # Route authentication
│   │   ├── demo-material-module.ts # Material imports
│   │   ├── logger.service.ts     # Logging service
│   │   ├── sockets.service.ts    # WebSocket service
│   │   └── utility.service.ts    # Utility functions
│   ├── assets/                   # Static assets
│   │   ├── css/                  # Stylesheets
│   │   ├── images/               # Images
│   │   └── ...
│   ├── environments/             # Environment configs
│   │   ├── environment.ts
│   │   └── environment.prod.ts
│   ├── custom-theme.scss         # Material theme
│   ├── styles.scss               # Global styles
│   └── index.html                # Main HTML file
├── angular.json                  # Angular configuration
├── package.json                  # Dependencies
├── tsconfig.json                 # TypeScript configuration
├── tslint.json                   # Linting rules
└── karma.conf.js                 # Test configuration

Key Directories Explained

/src/app/components/

Contains all UI components organized by feature:

/src/app/services/

Business logic and reusable services:

/src/app/interceptors/

HTTP interceptors for:

Introduction

Core features

1. E-Commerce Functionality

2. User Management

3. Affiliate Program

4. Store Features

5. Communication

6. Additional Services

Development guidelines

Development guidelines

Architecture & Design Patterns

Component-Based Architecture

The application follows Angular's component-based architecture where each feature is encapsulated in its own component with clear responsibilities.

Modular Design

Design Patterns Used

1. Dependency Injection

Services are injected into components via Angular's DI system:

constructor(
  private apiService: ApiService,
  private router: Router
) {}

2. Observer Pattern (RxJS)

Used extensively for handling asynchronous data:

this.apiService.getProducts().subscribe(
  data => this.products = data,
  error => this.handleError(error)
);

3. Guard Pattern

Route guards protect authenticated routes:

{ path: 'cart', canActivate: [AuthGuard], component: CartComponent }

4. Interceptor Pattern

HTTP interceptors handle cross-cutting concerns:

5. Service Locator Pattern

Services are registered at the root level and accessed via DI:

@Injectable({ providedIn: 'root' })
export class ApiService { }
Development guidelines

Services & API Integration

ApiService (api.service.ts)

The main service handling all API communications.

Base URLs

// Production
BASEURL = "https://onmarket.id/";
API_USERSTATE_SERVER = "https://usapi.onindonesia.id/";
API_USERONDELIVERY_SERVER = "https://onapps-api.onindonesia.id/";
API_OSAS_SERVER = "https://api.ondelivery.id/";
API_ONMARKET_SERVER = "https://api.onmarket.id/";
API_ONBOOKING_SERVER = "https://apisat.ondelivery.id/";
API_STORAGE = "https://storage.onindonesia.id/onmarket/";

Key Methods

// User Authentication
getUser(uname: string, pwd: string): Observable<any>
verify(token: string): Observable<any>

// Products
getProductList(payload: ProductListPayload): Observable<any>
getProductDetail(id: string): Observable<any>

// Cart Management
addToCart(payload: AddCart): Observable<any>
getCart(): Observable<any>
updateCart(cartId: string, quantity: number): Observable<any>
deleteCart(cartId: string): Observable<any>

// Orders
createOrder(payload: any): Observable<any>
getOrders(): Observable<any>

SocketsService (sockets.service.ts)

Handles real-time WebSocket connections using Socket.io.

// Connect to WebSocket
connect(): void

// Disconnect
disconnect(): void

// Emit events
emitEvent(eventName: string, data?: any): void

// Listen to events
on(eventName: string): Observable<any>

AffiliateService (services/affiliate.service.ts)

Manages affiliate-specific functionality.

LoggerService (logger.service.ts)

Handles application logging with configurable log levels.

Development guidelines

Routing Structure

Main Routes

The application uses Angular Router with the following main routes:

// Home & Product Routes
{ path: "", component: HomePageComponent }
{ path: "search", component: SearchResultComponent }
{ path: "product", component: ProductDetailsComponent }
{ path: "category", component: CategoryProductComponent }

// Authentication Routes
{ path: "login", component: LoginComponent }
{ path: "signup", component: SignupComponent }
{ path: "signup/otp", component: VerifyPhoneOtpComponent }
{ path: "reset", component: ResetComponent }

// Shopping Routes (Protected)
{ path: "cart", canActivate: [AuthGuard], component: CartComponent }
{ path: "checkout", canActivate: [AuthGuard], component: CheckoutComponent }
{ path: "checkout-finish", canActivate: [AuthGuard], component: CheckoutConfirmationComponent }

// User Profile Routes (Protected)
{
  path: "user",
  canActivate: [AuthGuard],
  component: ProfileComponent,
  children: [
    { path: "profile/detail-profile", component: DetailProfileComponent },
    { path: "profile/address", component: AddressComponent },
    { path: "order", component: OrderComponent },
    { path: "change-password", component: ChangePasswordsComponent },
    { path: "chats", component: ChatComponent },
    { path: "favorite", component: FavoriteComponent },
    { path: "voucher", component: VoucherListComponent },
    { path: "voucher/history", component: VoucherHistoryComponent }
  ]
}

// Store Routes
{
  path: "store",
  component: PersonalStoreComponent,
  children: [
    { path: "store-profile", component: StoreProfileComponent },
    { path: "store-review", component: ReviewComponent },
    { path: "store-product", component: ProductComponent }
  ]
}

// Affiliate Routes (Protected)
{
  path: "affiliate",
  canActivate: [AuthGuard],
  component: AffiliateComponent,
  children: [
    { path: "register", component: RegisterComponent },
    {
      path: "",
      component: DashboardComponent,
      children: [
        { path: "dashboard", component: HomeComponent },
        { path: "commision", component: AffiliateWithdrawComponent },
        { path: "collection", component: CollectionComponent },
        { path: "payment-setting", component: PaymentSettingComponent }
      ]
    }
  ]
}

// Additional Routes
{ path: "about-us", component: AboutUsComponent }
{ path: "help", component: HelpComponent }
{ path: "faq", component: FaqTwoComponent }
{ path: "contact", component: ContactPageComponent }

// 404 Route
{ path: "**", redirectTo: "/not-found" }
{ path: "/not-found", component: PageNotFoundComponent }

Route Guards

AuthGuard (auth.guard.ts) protects routes that require authentication:

Development guidelines

State Management

BehaviorSubjects

The application uses RxJS BehaviorSubjects for state management:

ApiService State

isUpdateCart = new BehaviorSubject(true);
deletedFromCart = new BehaviorSubject(true);
login = new BehaviorSubject(true);

SocketsService State

private chatOpenSubject = new BehaviorSubject<boolean>(false);
chatOpen$ = this.chatOpenSubject.asObservable();

Local Storage

Persistent data is stored in browser localStorage:

Usage Pattern

// Subscribe to state changes
this.apiService.isUpdateCart.subscribe(
  shouldUpdate => {
    if (shouldUpdate) {
      this.loadCart();
    }
  }
);

// Update state
this.apiService.isUpdateCart.next(true);
Development guidelines

Authentication & Security

JWT Authentication

The application uses JWT (JSON Web Token) for authentication:

  1. Login Flow:

    // User logs in
    this.apiService.getUser(username, password).subscribe(
      response => {
        // Store JWT token
        localStorage.setItem('jwt', response.token);
        // Navigate to home
        this.router.navigate(['/']);
      }
    );
    
  2. Token Storage: JWT tokens are stored in localStorage with key 'jwt'

  3. Token Injection: The AuthInterceptor automatically adds the token to all requests:

    const token = localStorage.getItem("jwt") 
      ? `Bearer ${localStorage.getItem("jwt")}` 
      : "";
    
    const authReq = req.clone({
      headers: req.headers.set("authorization", token)
    });
    
  4. Token Verification: AuthGuard verifies tokens before allowing access to protected routes

HTTP Interceptor (auth.interceptor.ts)

Handles authentication and error responses:

Features:

Error Handling:

private handleAuthError(err: HttpErrorResponse): Observable<any> {
  if (err.status === 401 || err.status === 403) {
    // Show error notification
    this.Toast.fire({
      title: "Sesi berakhir, mohon login kembali",
      icon: "error"
    });
    
    // Redirect to login
    this.router.navigate(["/login"]);
    
    // Clear token
    localStorage.removeItem("jwt");
  }
  return throwError(err);
}

Security Best Practices

  1. Route Guards: Protect sensitive routes with AuthGuard
  2. Token Expiration: Tokens are verified on each protected route access
  3. Secure Communication: All API calls use HTTPS
  4. XSS Protection: Angular's built-in sanitization
  5. CSRF Protection: Handled by backend API
Development guidelines

Key Components

1. Homepage Component

Path: src/app/components/homepage/

Main landing page featuring:

2. Product Details Component

Path: src/app/components/product-details/

Displays detailed product information:

3. Cart Component

Path: src/app/components/cart/

Shopping cart management:

4. Checkout Component

Path: src/app/components/checkout/

Order completion process:

5. Profile Component

Path: src/app/components/accounts/profile/

User profile management with nested routes:

6. Affiliate Dashboard

Path: src/app/components/affiliate/dashboard/

Affiliate program features:

7. Search Result Component

Path: src/app/components/search-result/

Product search functionality:

8. Personal Store Component

Path: src/app/components/personal-store/

Store management:

Development guidelines

Custom Pipes

1. PhoneNumberPipe

File: src/app/pipes/phone-number.pipe.ts

Formats phone numbers according to Indonesian format.

Usage:

{{ phoneNumber | phoneNumber }}

2. ShortNumberPipe

File: src/app/pipes/short-number-pipe.pipe.ts

Converts large numbers to shortened format (e.g., 1000 → 1K).

Usage:

{{ largeNumber | shortNumber }}

3. TimeAgoPipe

File: src/app/pipes/time-ago.pipe.ts

Converts timestamps to relative time (e.g., "2 hours ago").

Usage:

{{ timestamp | timeAgo }}

4. TransformCityPipe

File: src/app/pipes/transform-city.pipe.ts

Formats city names according to application standards.

Usage:

{{ cityName | transformCity }}

5. SafePipe

File: src/app/safe.pipe.ts

Bypasses Angular's security for trusted content (URLs, HTML, etc.).

Usage:

<iframe [src]="url | safe:'resourceUrl'"></iframe>

6. NumberPipe

File: src/app/number.pipe.ts

Custom number formatting for Indonesian locale.

Usage:

{{ price | number }}
Development guidelines

Development Workflow

Starting Development Server

# For Unix/Linux/Mac
npm start

# For Windows
npm run startWindows

The app will automatically reload when you make changes to source files.

Code Scaffolding

Generate new components, services, etc. using Angular CLI:

# Generate a new component
ng generate component components/new-component

# Generate a new service
ng generate service services/new-service

# Generate a new module
ng generate module modules/new-module

# Generate a new pipe
ng generate pipe pipes/new-pipe

# Generate a new directive
ng generate directive directives/new-directive

Linting

Check code quality and style:

npm run lint

Building for Production

npm run build

Build artifacts will be stored in the dist/ directory.

Development guidelines

Build & Deployment

Development Build

npm run build

Production Build

ng build --configuration production

Build Configuration

Configured in angular.json:

{
  "configurations": {
    "production": {
      "fileReplacements": [{
        "replace": "src/environments/environment.ts",
        "with": "src/environments/environment.prod.ts"
      }],
      "optimization": true,
      "outputHashing": "all",
      "sourceMap": false,
      "namedChunks": false,
      "extractLicenses": true,
      "vendorChunk": false,
      "buildOptimizer": true,
      "budgets": [...]
    }
  }
}

Environment Variables

Update environment files before building:

Development (src/environments/environment.ts):

export const environment = {
  production: false,
  enableConsoleLogs: true
};

Production (src/environments/environment.prod.ts):

export const environment = {
  production: true,
  enableConsoleLogs: false
};

Deployment Options

1. Static Hosting (Recommended)

Deploy to static hosting services:

2. Web Server

Deploy to traditional web servers:

Important: Configure server to redirect all routes to index.html for Angular routing to work.

Nginx Configuration Example:

server {
  listen 80;
  server_name onmarket.id;
  root /var/www/onmarket/dist/sapp;
  index index.html;

  location / {
    try_files $uri $uri/ /index.html;
  }
}
Development guidelines

Testing

Unit Tests

Run unit tests via Karma:

npm test

Tests are written using Jasmine and located alongside components:

End-to-End Tests

Run e2e tests via Protractor:

npm run e2e

E2E tests are located in the e2e/ directory.

Test Configuration

Writing Tests

Example component test:

describe('CartComponent', () => {
  let component: CartComponent;
  let fixture: ComponentFixture<CartComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ CartComponent ]
    }).compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(CartComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should load cart items', () => {
    component.loadCart();
    expect(component.cartItems.length).toBeGreaterThan(0);
  });
});
Development guidelines

Code Style & Conventions

TypeScript Style Guide

Follow Angular's TypeScript style guide:

Component Structure

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
  // 1. Public properties
  public title: string;
  
  // 2. Private properties
  private data: any[];
  
  // 3. Constructor with DI
  constructor(
    private apiService: ApiService,
    private router: Router
  ) {}
  
  // 4. Lifecycle hooks
  ngOnInit(): void {
    this.loadData();
  }
  
  // 5. Public methods
  loadData(): void {
    // Implementation
  }
  
  // 6. Private methods
  private processData(data: any): void {
    // Implementation
  }
}

Naming Conventions

Template Guidelines

<!-- Use semantic HTML -->
<header>
  <nav>
    <!-- Navigation -->
  </nav>
</header>

<!-- Use Angular directives -->
<div *ngIf="isLoading">Loading...</div>
<ul>
  <li *ngFor="let item of items">{{ item.name }}</li>
</ul>

<!-- Use event binding -->
<button (click)="handleClick()">Click Me</button>

<!-- Use property binding -->
<img [src]="imageUrl" [alt]="imageAlt">

<!-- Use two-way binding -->
<input [(ngModel)]="searchTerm">

SCSS/CSS Guidelines

Development guidelines

Troubleshooting

Common Issues and Solutions

1. OpenSSL Error on npm start

Error: Error: error:0308010C:digital envelope routines::unsupported

Solution: The project already includes the fix in package.json:

NODE_OPTIONS='--openssl-legacy-provider' ng serve

2. Module Not Found Errors

Solution: Clear cache and reinstall:

rm -rf node_modules package-lock.json
npm cache clean --force
npm install

3. Port Already in Use

Error: Port 4200 is already in use

Solution: Kill the process or use a different port:

# Kill process on port 4200 (Unix/Mac)
lsof -ti:4200 | xargs kill -9

# Or use different port
ng serve --port 4300

4. CORS Errors

Issue: API requests blocked by CORS policy

Solution:

Create proxy.conf.json:

{
  "/api": {
    "target": "https://api.onmarket.id",
    "secure": true,
    "changeOrigin": true
  }
}

Update angular.json:

"serve": {
  "options": {
    "proxyConfig": "proxy.conf.json"
  }
}

5. JWT Token Expired

Issue: Session expired errors

Solution:

6. WebSocket Connection Issues

Issue: Socket.io connection fails

Solution:

7. Angular Material Theme Not Applied

Solution: Ensure custom-theme.scss is imported in angular.json:

"styles": [
  "src/custom-theme.scss",
  "src/styles.scss"
]

8. Build Memory Issues

Error: JavaScript heap out of memory

Solution: Increase Node.js memory limit:

export NODE_OPTIONS="--max-old-space-size=4096"
npm run build
Development guidelines

Additional resources

Official Documentation

Key Dependencies Documentation

Learning Resources

Community