import { ActionIcon, Avatar, Badge, Box, Button, Divider, Group, Loader, Modal, Pagination, Paper, ScrollArea, Select, SimpleGrid, Stack, Switch, Table, Text, TextInput, ThemeIcon, Title, Tooltip, } from '@mantine/core' import { useDisclosure, useDebouncedValue, useMediaQuery } from '@mantine/hooks' import { notifications } from '@mantine/notifications' import { createFileRoute, useParams } from '@tanstack/react-router' import { useEffect, useState } from 'react' import { TbAlertCircle, TbArrowDown, TbArrowsSort, TbArrowUp, TbBriefcase, TbCircleCheck, TbCircleX, TbHome2, TbId, TbMail, TbPhone, TbPlus, TbSearch, TbUsers, TbX, } from 'react-icons/tb' import useSWR from 'swr' import { API_URLS } from '../config/api' export const Route = createFileRoute('/apps/$appId/users/')({ component: UsersIndexPage, }) interface APIUser { id: string name: string nik: string phone: string email: string gender: string isWithoutOTP: boolean isActive: boolean isApprover: boolean role: string village: string group: string position?: string idUserRole: string idVillage: string idGroup: string 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: '' })} /> {isLoading ? ( ) : error ? ( Failed to load users from the API. ) : users.length === 0 ? ( {searchQuery || filterStatus || filterRole || filterVillageId ? 'No users match your filters.' : 'No users found.'} ) : ( {[ { label: 'User & ID', col: 'name', width: '28%' }, { label: 'Contact', col: null, width: '25%' }, { label: 'Organization', col: null, width: '22%' }, { label: 'Role', col: 'idUserRole', width: '15%' }, { label: 'Status', col: 'isActive', width: '10%' }, ].map(({ label, col, width }) => ( handleSort(col) : undefined} > {label} {col && ( sortBy === col ? sortDir === 'asc' ? : : )} ))} {users.map((user) => ( handleEditOpen(user)} > {user.name.charAt(0)} {user.name} {user.nik} {user.email} {user.phone} {user.village} {user.group} ยท {user.position || 'Staff'} {user.role} {user.isActive ? 'ACTIVE' : 'INACTIVE'} {user.isWithoutOTP && ( NO OTP )} ))}
)} {!isLoading && !error && response?.data?.totalPage > 1 && ( )} ) }