Technology Stack
Core Technologies
| Technology | Version | Purpose |
|---|---|---|
| React | 19.2 | UI Framework |
| TypeScript | 5.8 | Type Safety |
| Vite | 6.4 | Build Tool & Dev Server |
| Tailwind CSS | 4.2 | Utility-first CSS |
| React Router | 7.6 | Client-side Routing |
UI Components
shadcn/ui
UI component library berbasis Radix UI primitives dengan styling Tailwind CSS:
// shadcn/ui setup
// Style: New York
// Base Color: Slate
// Icons: Lucide
46 Components tersedia di src/components/ui/:
Forms
- Button, Checkbox, Input, Label
- Radio Group, Select, Slider
- Switch, Textarea, Toggle, Toggle Group
Layout
- Accordion, Aspect Ratio
- Resizable Panel, Separator
- Scroll Area
Data Display
- Avatar, Badge, Card, Table
- Calendar, Day Picker
Feedback
- Alert, Alert Dialog, Dialog
- Drawer, Popover, Tooltip
- Sonner (Toast notifications)
Navigation
- Breadcrumb, Command
- Context Menu, Dropdown Menu
- Menubar, Navigation Menu
- Pagination, Tabs
Overlay
- Collapsible, Hover Card
State Management
TanStack Query (React Query)
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000, // 5 minutes
retry: 1,
},
},
});
Use cases:
- API data fetching & caching
- Background refetching
- Optimistic updates
- Infinite queries
React Context
// AppContext for global state
const Ctx = createContext<AppState | null>(null);
// Available state:
- tenantId: string
- roleId: RoleId
- isAuthed: boolean
- userName: string
- userRoles: string[]
- tenantIdClaim: string
- tenantName: string
localStorage Persistence
// State persisted to localStorage
const KEY = "tssmartlog-state-v1";
// Auto-restore on mount
// Auto-save on change
Forms & Validation
React Hook Form
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
query: z.string().min(1),
timeRange: z.enum(['1h', '24h', '7d', '30d']),
});
const form = useForm({
resolver: zodResolver(schema),
});
Charts & Visualization
Recharts
import {
LineChart, Line, BarChart, Bar,
PieChart, Pie, AreaChart, Area,
XAxis, YAxis, CartesianGrid, Tooltip, Legend
} from 'recharts';
Use cases:
- Log volume histograms
- Error rate trends
- Throughput charts
- Latency distributions
HTTP Client
Custom Fetch Wrapper
// src/api/http.ts
const BASE_URL = import.meta.env.VITE_API_BASE_URL ?? "";
export async function fetchJson<T>(input: string, init?: RequestInit): Promise<T> {
const token = getAccessToken();
const url = input.startsWith("http") ? input : `${BASE_URL}${input}`;
const response = await fetch(url, {
headers: {
"content-type": "application/json",
...(token ? { Authorization: `Bearer ${token}` } : {}),
...(init?.headers ?? {}),
},
...init,
});
if (response.status === 401) {
triggerSessionExpired();
throw new Error("Session expired");
}
return (await response.json()) as T;
}
Internationalization
i18next
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
i18n.use(initReactI18next).init({
resources: {
id: { translation: idTranslations },
en: { translation: enTranslations },
},
lng: 'id', // Default language
fallbackLng: 'id',
});
Supported languages:
id- Bahasa Indonesia (default)en- English
Development Tools
ESLint
// eslint.config.js
import js from '@eslint/js';
import globals from 'globals';
import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh';
import tseslint from 'typescript-eslint';
export default tseslint.config(
js.configs.recommended,
...tseslint.configs.recommended,
reactHooks.configs['flat/recommended'],
{
rules: {
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
},
},
);
Prettier
// .prettierrc
{
"semi": true,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"useTabs": false
}
TypeScript
// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2023", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
Vite
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tailwindcss from '@tailwindcss/vite';
import tsconfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
plugins: [react(), tailwindcss(), tsconfigPaths()],
server: {
port: 3000,
host: '0.0.0.0',
proxy: {
'/api': { target: 'http://10.8.0.48:8085/', changeOrigin: true },
'/healthz': { target: 'http://10.8.0.48:8085/', changeOrigin: true },
'/auth': { target: 'http://10.8.0.48:8085/', changeOrigin: true },
},
},
});
Build Scripts
{
"scripts": {
"dev": "vite dev",
"build": "vite build",
"build:dev": "vite build --mode development",
"preview": "vite preview",
"lint": "eslint .",
"typecheck": "tsc --noEmit",
"format": "prettier --write ."
}
}
Next Steps
- Components - Component documentation
- Routing - Route configuration
- State Management - State management