Frontend
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
- Product browsing and search
- Shopping cart and checkout
- User authentication and profile management
- Affiliate marketing program
- Store management
- Real-time chat via WebSockets
- Multiple payment integrations
- Order tracking and history
- Voucher and promotion system
Technology Stack
Core Framework
- Angular: v12.2.2
- TypeScript: v4.3.5
- RxJS: v6.6.3 (Reactive Programming)
UI/UX Libraries
- Angular Material: v12.2.2 - Material Design components
- Angular Flex Layout: v12.0.0 - Responsive layout system
- Angular Animations: v12.2.2 - Animation support
- Font Awesome: v6.5.1 - Icon library
- SweetAlert2: v10.3.3 - Beautiful alerts and modals
Additional Libraries
- Socket.io Client: v4.7.5 - Real-time WebSocket communication
- Google Maps: v3.55.12 - Map integration
- ApexCharts: v3.35.0 - Interactive charts
- jwt-decode: v3.1.2 - JWT token decoding
- dayjs: v1.10.7 - Date manipulation
- ngx-translate: v13.0.0 - Internationalization (i18n)
- ngx-infinite-scroll: v10.0.1 - Infinite scrolling
- ngx-countdown: v11.0.3 - Countdown timers
- ngx-perfect-scrollbar: v10.1.1 - Custom scrollbars
Development Tools
- Angular CLI: v12.2.2
- Karma: v6.3.4 - Test runner
- Jasmine: v3.9.0 - Testing framework
- TSLint: v6.1.0 - Code linting
- Protractor: v7.0.0 - E2E testing
Installation and setup
Prerequisites
Before you begin, ensure you have the following installed:
- Node.js: v12.x or higher (recommended v14.x or v16.x)
- npm: v6.x or higher (comes with Node.js)
-
Angular CLI: v12.2.2
npm install -g @angular/cli@12.2.2
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/:
-
environment.ts- Development environment -
environment.prod.ts- Production environment
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.
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:
- accounts/ - User authentication and profile management
- affiliate/ - Affiliate marketing dashboard and features
- cart/ - Shopping cart functionality
- checkout/ - Checkout and payment process
- personal-store/ - Store owner features
- product-details/ - Product information display
- search-result/ - Search results page
/src/app/services/
Business logic and reusable services:
- API integration services
- State management services
- Utility services
/src/app/interceptors/
HTTP interceptors for:
- Adding authentication tokens
- Error handling
- Request/response transformation
Core features
1. E-Commerce Functionality
- Product catalog browsing
- Advanced search and filtering
- Product details with images and specifications
- Shopping cart management
- Checkout process with multiple payment options
- Order tracking and history
2. User Management
- User registration and login
- Phone OTP verification
- Profile management
- Address book
- Password management
- Wishlist/favorites
3. Affiliate Program
- Affiliate registration
- Dashboard with earnings analytics
- Commission withdrawal
- Collection management
- Custom affiliate links
- Payment settings
4. Store Features
- Personal store creation
- Store profile management
- Product management
- Store reviews and ratings
- Store analytics
5. Communication
- Real-time chat via WebSockets
- WhatsApp integration
- Message notifications
- Order-related messaging
6. Additional Services
- Bill payments (Pulsa, PLN, PDAM, etc.)
- Vouchers and promotions
- Flash sales
- Campaign templates
- Reviews and ratings
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
- Feature Modules: Components are organized by feature
- Shared Module: Common components, pipes, and directives
- Core Module: Singleton services and app-wide functionality
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:
- Authentication token injection
- Error handling
- Loading states
5. Service Locator Pattern
Services are registered at the root level and accessed via DI:
@Injectable({ providedIn: 'root' })
export class ApiService { }
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.
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:
- Checks for JWT token in localStorage
- Verifies token with API
- Redirects to home page if not authenticated
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:
- jwt - Authentication token
- user - User information
- cart - Shopping cart data (backup)
Usage Pattern
// Subscribe to state changes
this.apiService.isUpdateCart.subscribe(
shouldUpdate => {
if (shouldUpdate) {
this.loadCart();
}
}
);
// Update state
this.apiService.isUpdateCart.next(true);
Authentication & Security
JWT Authentication
The application uses JWT (JSON Web Token) for authentication:
-
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(['/']); } ); -
Token Storage: JWT tokens are stored in localStorage with key
'jwt' -
Token Injection: The
AuthInterceptorautomatically 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) }); -
Token Verification: AuthGuard verifies tokens before allowing access to protected routes
HTTP Interceptor (auth.interceptor.ts)
Handles authentication and error responses:
Features:
- Automatically adds JWT token to request headers
- Handles 401/403 unauthorized responses
- Redirects to login on session expiration
- Shows user-friendly error messages
- Clears localStorage on auth failure
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
- Route Guards: Protect sensitive routes with AuthGuard
- Token Expiration: Tokens are verified on each protected route access
- Secure Communication: All API calls use HTTPS
- XSS Protection: Angular's built-in sanitization
- CSRF Protection: Handled by backend API
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:
- Product images gallery
- Price and stock information
- Product description
- Seller information
- Reviews and ratings
- Add to cart functionality
3. Cart Component
Path: src/app/components/cart/
Shopping cart management:
- List of cart items
- Quantity adjustment
- Item removal
- Price calculation
- Checkout navigation
4. Checkout Component
Path: src/app/components/checkout/
Order completion process:
- Shipping address selection
- Payment method selection
- Order summary
- Order confirmation
5. Profile Component
Path: src/app/components/accounts/profile/
User profile management with nested routes:
- Personal information
- Address book
- Order history
- Password change
- Favorites/wishlist
- Vouchers
6. Affiliate Dashboard
Path: src/app/components/affiliate/dashboard/
Affiliate program features:
- Earnings dashboard with charts
- Commission history
- Withdrawal requests
- Collection management
- Affiliate links generation
- Payment settings
7. Search Result Component
Path: src/app/components/search-result/
Product search functionality:
- Search input
- Filters (category, price, rating)
- Sort options
- Infinite scroll
- Result grid/list view
8. Personal Store Component
Path: src/app/components/personal-store/
Store management:
- Store profile
- Product listing
- Store reviews
- Store statistics
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 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.
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:
- Firebase Hosting
- Netlify
- Vercel
- AWS S3 + CloudFront
- GitHub Pages
2. Web Server
Deploy to traditional web servers:
- Apache
- Nginx
- IIS
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;
}
}
Testing
Unit Tests
Run unit tests via Karma:
npm test
Tests are written using Jasmine and located alongside components:
-
*.spec.tsfiles
End-to-End Tests
Run e2e tests via Protractor:
npm run e2e
E2E tests are located in the e2e/ directory.
Test Configuration
-
Karma:
karma.conf.js -
Protractor:
e2e/protractor.conf.js -
TypeScript:
tsconfig.spec.json
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);
});
});
Code Style & Conventions
TypeScript Style Guide
Follow Angular's TypeScript style guide:
- Use 2 spaces for indentation
- Use single quotes for strings
- Use camelCase for variables and functions
- Use PascalCase for classes and interfaces
- Use UPPER_CASE for constants
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
-
Components:
feature-name.component.ts -
Services:
feature-name.service.ts -
Pipes:
pipe-name.pipe.ts -
Guards:
guard-name.guard.ts -
Interfaces:
interface-name.ts -
Modules:
module-name.module.ts
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
- Use component-scoped styles
- Follow BEM naming convention for complex components
- Use Angular Material theming
- Avoid
!importantunless absolutely necessary
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:
- Configure backend to allow frontend origin
- Use proxy configuration during development:
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:
- Token verification happens on each protected route
- User is automatically redirected to login
- No manual intervention needed
6. WebSocket Connection Issues
Issue: Socket.io connection fails
Solution:
- Check if WebSocket server is running
- Verify JWT token is valid
- Check network connectivity
- Verify API_ONMARKET_SERVER URL
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