react
Technical notes on web development, DevOps, and AI integration.
53 articles
- 12:25frontend
Per-Status Counters in Admin Stats: Numbers From the Contract
Per-status snapshot counters joined AdminLayananStats additively; legacy fields kept, UI derives numbers from stats, no more meta.total tricks.
TL;DR: The dashboard showed dashes because the stats API only counted two of six statuses, leaving legacy fields at zero. The fix kept the old fields and added six current snapshot counters, with regenerated types now requiring a count for every tab and card. Counts respect user scope, and the queue badge now reads the submission counter directly with lightweight polling.
#go#api#openapi - 11:23frontend
An Honest Ticket Status Stepper: Learning from the History Array
The ticket stepper stops guessing from one status string: stage times come from the transition history, first row per status.
TL;DR: The stepper used to guess progress from one status string, now it maps real timestamps from the history array and falls back to created and updated times. Four display stages replace six cluttered steps, grouping terminal statuses while safely handling invalid dates and listing history in order. Transformations run during render, and const literal types prevent invalid pillar submissions.
#react#typescript#ux - 09:29frontend
The Tri-State Trap in React Category Pickers
A dropdown that is right for create is wrong for edit. A tri-state moduleScope makes the fetch wait for the entity to load.
TL;DR: Editing showed PARIWISATA categories instead of KEPEMUDAAN because the picker fetched before the module loaded and fell back to the default. The fix makes moduleScope tri-state and waits until it resolves before calling listAdminCategories via useEffect. The team also synced the OpenAPI spec, generated types, and frontend module list to prevent enum drift.
#react#typescript#openapi - 09:04frontend
Hiding Sidebar Links Is UX, Not Authorization
Hiding a sidebar item is a UX decision, not an authorization boundary. Layout checks go stale; the API must fail closed.
TL;DR: Hiding sidebar links isn't security since Next.js layouts don't recheck auth on navigation and typed URLs can bypass the UI. The fix belongs at the API layer, where the backend validates scopes and returns an empty list instead of a 403 to avoid leaking modules. Frontend caching keeps it efficient while tests ensure restricted URLs just show empty tables.
#nextjs#react#go - 08:16backend
The One Forgotten Line: How a DTO Mapper Crashed the Frontend
A field existed on the entity but never made it into the response mapper: the API answered with an empty string and the edit page crashed. One line plus a regression test closed it.
TL;DR: Saving announcements crashed because the backend mapper forgot to copy Status, sending an empty string that broke the frontend badge lookup. The fix added the missing field, added a regression test, and made the UI whitelist statuses to default to draft. Navigation was also switched to router push and refresh to keep toast feedback without a full reload.
#golang#react#typescript - 07:29frontend
When PARIWISATA Screams Inside a Dropdown That Should Look Tidy
Raw UPPERCASE enum values leaked into four admin render spots; one formatter became the single display door, the ?? fallback stays double-edged.
TL;DR: The database correctly stored bidang values in uppercase, but four UI spots were displaying the raw values instead of the formatted labels. An existing formatBidang helper was already available but hadn't been wired into those components. The fix routes all display through that single formatter while keeping raw values for backend validation, touching just six lines across two files.
#typescript#react - 05:37backend
COALESCE at the API Door: Keep the ALL Sentinel in the Query
A super-admin without a bidang returns NULL from the database. One COALESCE in the login query keeps the API contract total and the admin badge correct.
TL;DR: The badge broke for super-admins because their bidang is NULL and old tokens don't even have the field. Rather than patching each Go handler, the team used COALESCE(bidang, 'ALL') in SQL to guarantee a valid string everywhere. TypeScript keeps bidang optional for legacy sessions, and React only renders the badge when the value isn't ALL.
#mysql#golang#typescript - 08:16frontend
Icon Cards from a Union Type, Guarded by the Compiler
A closed icon registry plus a required union key lets the TypeScript compiler keep card icons honest.
TL;DR: Icons hardcoded in JSX drift out of sync across typed content and locale files, silently breaking the UI. Moving icon choices into content data as a closed union type, backed by a small registry, makes the compiler reject mismatches at build time. Three files changed together, zero runtime cost, no silent failures.
#typescript#react#lucide - 06:55frontend
One Card Component, Two Grids
Copying Tailwind classes from the corporate cards was not enough: the list-item identity and its keyboard handlers had to move too.
TL;DR: Copying Tailwind classes between cards failed because the divider depended on the li-in-ul structure, not styling alone. Converting the office card to a list item meant adding the button role, keyboard handlers, and proper ul wrappers. Extracting an OfficeCard component with two props made the 2+3 layout trivial, though a leftover ul rendered the list twice until deleted.
#react#tailwindcss#accessibility