From b79c63a5e83687fc3bfc271dd860b083763e1f96 Mon Sep 17 00:00:00 2001 From: amaliadwiy Date: Fri, 22 May 2026 11:04:56 +0800 Subject: [PATCH] refactor: improve users page code quality - extract shared UserFormFields component to eliminate form duplication between Add and Edit modals - debounce search input (400ms) to prevent excessive API calls - fix validation messages to show human-readable labels instead of internal field names - fix pagination visibility condition (totalPage > 1) - remove unused TbEdit import --- .../routes/apps.$appId.users.index.tsx | 436 ++++++++---------- 1 file changed, 204 insertions(+), 232 deletions(-) diff --git a/src/frontend/routes/apps.$appId.users.index.tsx b/src/frontend/routes/apps.$appId.users.index.tsx index 1b2015d..23d5a05 100644 --- a/src/frontend/routes/apps.$appId.users.index.tsx +++ b/src/frontend/routes/apps.$appId.users.index.tsx @@ -22,16 +22,15 @@ import { Title, Tooltip, } from '@mantine/core' -import { useDisclosure, useMediaQuery } from '@mantine/hooks' +import { useDisclosure, useDebouncedValue, useMediaQuery } from '@mantine/hooks' import { notifications } from '@mantine/notifications' import { createFileRoute, useParams } from '@tanstack/react-router' -import { useState } from 'react' +import { useEffect, useState } from 'react' import { TbAlertCircle, TbBriefcase, TbCircleCheck, TbCircleX, - TbEdit, TbHome2, TbId, TbMail, @@ -68,13 +67,161 @@ interface APIUser { idPosition: string } +interface BaseUserForm { + name: string + nik: string + phone: string + email: string + gender: string + idUserRole: string + idVillage: string + idGroup: string + idPosition: string +} + +const FIELD_LABELS: Record = { + name: 'Full Name', + nik: 'NIK', + phone: 'Phone Number', + email: 'Email Address', + gender: 'Gender', + idUserRole: 'User Role', + idVillage: 'Village', + idGroup: 'Group', +} + +const REQUIRED_FIELDS = ['name', 'nik', 'phone', 'email', 'gender', 'idUserRole', 'idVillage', 'idGroup'] + const fetcher = (url: string) => fetch(url).then((res) => res.json()) +interface UserFormFieldsProps { + values: BaseUserForm + onChange: (updates: Partial) => void + villageSearch: string + onVillageSearchChange: (v: string) => void + rolesOptions: { value: string; label: string }[] + villagesOptions: { value: string; label: string }[] + groupsOptions: { value: string; label: string }[] + positionsOptions: { value: string; label: string }[] +} + +function UserFormFields({ + values, + onChange, + onVillageSearchChange, + rolesOptions, + villagesOptions, + groupsOptions, + positionsOptions, +}: UserFormFieldsProps) { + return ( + <> + + + Personal Information + + + onChange({ name: e.target.value })} + /> + onChange({ nik: e.target.value })} + /> + + + + onChange({ email: e.target.value })} + /> + onChange({ phone: e.target.value })} + /> + + + onChange({ idUserRole: v || '' })} + /> + + onChange({ idGroup: v || '', idPosition: '' })} + /> + setForm(f => ({ ...f, gender: v || '' }))} - /> - - - - - - setForm(f => ({ ...f, idVillage: v || '', idGroup: '', idPosition: '' }))} - /> - - - setForm(f => ({ ...f, idPosition: v || '' }))} - /> - - + setForm((f) => ({ ...f, ...updates }))} + {...sharedFormProps} + />