The GSM frontend is divided into self-contained feature modules underDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/ti-infinite/GSMApplication/llms.txt
Use this file to discover all available pages before exploring further.
src/features/. Each module owns its pages, sub-components, hooks, and types. This page documents every major feature area with the real API contracts and component logic sourced directly from the codebase.
Login & Tenant Resolution
The login page is a two-panel layout: a form on the left and a branded hero on the right. Before credentials are accepted, the application resolves the tenant to fetch its theme and branding.Tenant resolution
The login form pre-populates a Company ID from the A successful response contains a
VITE_TENANT_DEFAULT build variable. When the ID changes (either via the tenant switcher buttons or a manual edit), resolveCompany() fires a POST request:jsonStyles field — a serialised TenantTheme object with meta (name, initials, logo, tagline, defaultLocale) and light / dark CSS custom property maps. The app parses this and injects the properties onto document.documentElement so Tailwind’s CSS variables pick them up instantly.CSS variable application
applyThemeVarsFromCache() in src/shared/lib/theme.ts replays the last known tenant’s CSS variables from localStorage on every hard reload, preventing a flash of unstyled content before the resolve request completes.Credential submission
After the company name and logo appear, the user enters their username and password. Submitting the form calls On success the backend sets the HttpOnly
login() in src/shared/lib/auth.ts:gsm_token cookie. The frontend simultaneously writes three non-HttpOnly cookies for client-side use:| Cookie | Value |
|---|---|
gsm_exp | JWT expiry as Unix timestamp |
gsm_user_name | Authenticated user’s display name |
gsm_company | The resolved Company ID |
Both
Unauthorized and NotFound error types from the login endpoint are mapped to the generic errors.unauthorized translation key to prevent user enumeration.Dashboard
DashboardPage is the landing screen shown at /:locale/dashboard. It is composed of two sections rendered in sequence.
QuickCards
Shortcut items from the menu API (IsShortcut: true) are rendered as clickable cards that navigate directly to their respective module routes. If exactly one shortcut exists and the user has just logged in (detected via location.state?.fromLogin), the app auto-redirects to that module instead of showing the dashboard.
DashboardActivity
DashboardActivity fetches two lists from the operations API and renders them as clickable item lists inside a two-column grid:
- Release Activity (
activitysection) — common operational tasks, shown with a primary-coloured dot indicator - Company News (
newssection) — latest updates, shown with a secondary-coloured dot indicator
Dialog that renders the item’s content. The content type determines the viewer:
type: 'url'→ an external link button- Any other type → a responsive iframe via
ResponsiveIframe
Productivity Module
ProductivityPage (src/features/productivity/) is the most complex module in the application. It records herb harvest labor assignments and tracks their real-time progress. The page toggles between two views via a tab bar.
Assignment View (Wizard)
AssignmentWizard is a three-step wizard:
Step 1 — Product / Variety / SKU
The user selects a product category, subcategory, and parameters to build a SKU string. Available varieties for the generated SKU are fetched from the products API. An initial quantity field completes the product selection.
Step 2 — Employees
Employees are loaded from the operations API and displayed grouped by role. The user can assign them in Groups mode (automatic grouping with configurable min/max per group) or Individual mode (manual per-person selection). A search field filters the list in real time.
handleComplete() calls createTransaction() for every assignment unit in parallel:
PRDLBR prefix and is created with INPROGRESS status.
Checkout View
The Checkout view shows cards for every activeINPROGRESS transaction. It uses a stale-while-revalidate pattern: the app immediately renders existing card state while loadActiveCheckout() refreshes from the backend in the background.
| Action | API call | Optimistic update |
|---|---|---|
| Lap (record partial quantity + waste) | PATCH /api/operations/v1/operations/:id with lap detail | Yes — reverted on error |
| Complete (close the transaction) | PATCH with complete payload + optional final lap | Yes — reverted on error |
| Cancel (void the transaction) | PATCH with cancel payload | Yes — card restored on error |
Products Module
ProductsPage (src/features/products/) renders a ProductWizard that lets users browse and select herb products by navigating category → subcategory → parameters → SKU. The selected product and initial quantity are surfaced for use in downstream operations such as the Productivity wizard. The page layout mirrors the Productivity step 1 but operates as a standalone module accessible from the sidebar.
Module Renderers
When a menu item has anExternalRoute value, ModulePage hands control to ExternalPage, which selects a renderer based on the item’s ActiveType field.
- IframeRenderer
- NhBiRenderer
- NewTabRenderer
- Built-in Modules
Embeds the external URL in a full-height
<iframe> inside a card shell. A header bar shows the module title and an “open in new tab” button. The sandbox attribute permits scripts, same-origin requests, forms, and pop-ups.Session Management
Session state is stored across two mechanisms: an HttpOnly cookie for the JWT itself, and several readable cookies plussessionStorage for client-accessible metadata.
Cookie reference
Cookie reference
sessionStorage key
sessionStorage key
| Key | Contents |
|---|---|
gsm_user | Serialised AuthenticatedUserDto (full name, username, email, location, department, profile ID) |
Password Change
If the backend setspasswordChangeRequired: true in the login response, the frontend sets gsm_pwd_change=1. AuthGuard detects this flag and redirects to the forced password-change form before any protected route is accessible. The change is submitted to:
gsm_pwd_change is removed and the user proceeds normally.
Logout
logout() in src/shared/lib/auth.ts removes all client-side cookies and clears sessionStorage, then fires a fire-and-forget POST /api/security/v1/Auth/logout to instruct the server to clear the HttpOnly gsm_token cookie.
/:locale/login.