# CLQMS Frontend - Code Style and Conventions ## JavaScript/TypeScript - **Language**: Plain JavaScript (no TypeScript) - **Modules**: Always use `import`/`export` (type: "module" in package.json) - **Semicolons**: Use semicolons consistently - **Quotes**: Use single quotes for strings - **Indentation**: 2 spaces - **Trailing commas**: Use in multi-line objects/arrays - **JSDoc**: Document all exported functions with JSDoc comments ## Svelte Components (Svelte 5 Runes) ### Component Structure ```svelte ``` ## Naming Conventions - **Components**: PascalCase (`LoginForm.svelte`, `DataTable.svelte`) - **Files/Routes**: lowercase with hyphens (`+page.svelte`, `user-profile/`) - **Variables**: camelCase (`isLoading`, `userName`) - **Constants**: UPPER_SNAKE_CASE (`API_URL`, `STORAGE_KEY`) - **Stores**: camelCase, descriptive (`auth`, `valuesets`) - **Event handlers**: prefix with `handle` (`handleSubmit`, `handleClick`) ## Imports Order 1. Svelte imports (`svelte`, `$app/*`) 2. $lib aliases (`$lib/stores/*`, `$lib/api/*`, `$lib/components/*`) 3. External libraries (`lucide-svelte`) 4. Relative imports (minimize these, prefer `$lib`) ## API Client Pattern ### Base Client (src/lib/api/client.js) The base client handles JWT token management and 401 redirects automatically. ### Feature-Specific API Modules ```javascript // src/lib/api/feature.js - Feature-specific endpoints import { apiClient, get, post, put, patch, del } from '$lib/api/client.js'; export async function getItem(id) { return get(`/api/items/${id}`); } export async function createItem(data) { return post('/api/items', data); } ``` ## Form Handling Pattern ```javascript let formData = { name: '', email: '' }; let errors = {}; let loading = false; async function handleSubmit() { loading = true; errors = {}; try { const result = await createItem(formData); if (result.status === 'error') { errors = result.errors || { general: result.message }; } else { // Success - redirect or show message } } catch (err) { errors = { general: err.message || 'An unexpected error occurred' }; } loading = false; } ``` ## Error Handling - API errors are thrown with message - Use try/catch blocks for async operations - Store errors in state for display - Toast notifications for user feedback ```javascript try { const result = await api.login(username, password); toast.success('Login successful'); } catch (err) { error = err.message || 'An unexpected error occurred'; console.error('Login failed:', err); toast.error('Login failed'); } ``` ## Styling with Tailwind & DaisyUI - Use Tailwind utility classes - DaisyUI components: `btn`, `card`, `alert`, `input`, `navbar`, `select` - Color scheme: `primary` (emerald), `base-100`, `base-200` - Custom colors in `app.css` with `@theme` ## Authentication Patterns - Auth state in `$lib/stores/auth.js` - Check auth in layout `onMount` or `+layout.server.js` - Redirect to `/login` if unauthenticated - API client auto-redirects on 401 ## LocalStorage - Only access in browser: check `browser` from `$app/environment` - Use descriptive keys: `auth_token` ## Reusable Components - **DataTable.svelte**: Sortable, paginated table with actions - **Modal.svelte**: Reusable modal for confirmations and forms - **SelectDropdown.svelte**: Dropdown populated from ValueSets or API data - **Sidebar.svelte**: Navigation sidebar - **ToastContainer.svelte**: Toast notifications ## SvelteKit Patterns - File-based routing with `+page.svelte`, `+layout.svelte` - Route groups with `(app)` for protected routes - Load data in `+page.js` or `+page.server.js` if needed - Use `invalidateAll()` after mutations to refresh data ## Code Quality Notes - No ESLint or Prettier configured yet - No test framework configured yet (plan: Vitest for unit tests, Playwright for E2E) - JSDoc comments are required for all exported functions - Keep components focused and reusable - Extract logic into utility functions when possible