change user_name still used as login and add display_name for dashboard view instead of username on login

This commit is contained in:
Alberto-Audrix committed 2026-09-10 10:51:51 +07:00
1 parent 7a562c18ec
commit 11b0ca26a5
33 files changed
+180 -145

No files matched your search

+1 -1
View File
@@ -28,7 +28,7 @@ const AccountAdminShell: React.FC = () => {
</nav>
<div className="border-t border-gray-200 p-4 space-y-2">
<p className="text-xs text-gray-500 truncate">
{user?.user_name} · {roleLabel}
{user?.display_name} · {roleLabel}
</p>
<button
type="button"
+3 -3
View File
@@ -181,10 +181,10 @@ const Header: React.FC<HeaderProps> = ({
className="flex items-center space-x-2 focus:outline-none"
>
<div className="w-10 h-10 rounded-full bg-red-100 text-red-700 flex items-center justify-center font-bold">
{user.user_name.slice(0, 1).toUpperCase()}
{user.display_name.slice(0, 1).toUpperCase()}
</div>
<div className="hidden lg:block text-left">
<p className="text-sm font-semibold text-gray-800">{user.user_name}</p>
<p className="text-sm font-semibold text-gray-800">{user.display_name}</p>
<p className="text-xs text-gray-500">{ROLE_LABELS[user.status]}</p>
</div>
<i className="fa-solid fa-chevron-down text-xs text-gray-500" />
@@ -192,7 +192,7 @@ const Header: React.FC<HeaderProps> = ({
{open && (
<div className="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg py-1 bg-white ring-1 ring-black ring-opacity-5 z-50">
<div className="px-4 py-3 border-b">
<p className="text-sm font-semibold text-gray-800">{user.user_name}</p>
<p className="text-sm font-semibold text-gray-800">{user.display_name}</p>
<p className="text-xs text-gray-500">{ROLE_LABELS[user.status]}</p>
</div>
<button
+3 -3
View File
@@ -134,7 +134,7 @@ const BuhViewList: React.FC = () => {
className="py-3 flex flex-wrap items-center justify-between gap-3"
>
<div>
<p className="text-sm font-semibold text-gray-800">{gm.user_name}</p>
<p className="text-sm font-semibold text-gray-800">{gm.display_name}</p>
<p className="text-xs text-gray-500">{ROLE_LABELS[gm.status] ?? gm.status}</p>
</div>
<div className="flex gap-2">
@@ -179,7 +179,7 @@ const BuhViewList: React.FC = () => {
return (
<li key={gm.id} className="border border-gray-200 rounded-lg p-4">
<div className="flex flex-wrap items-baseline justify-between gap-2 mb-2">
<p className="text-sm font-semibold text-gray-800">{gm.user_name}</p>
<p className="text-sm font-semibold text-gray-800">{gm.display_name}</p>
<p className="text-xs text-gray-500">
{ROLE_LABELS[gm.status] ?? gm.status} · {sites.length} site
</p>
@@ -361,7 +361,7 @@ const GmViewList: React.FC = () => {
<option value="">— pilih —</option>
{buhs.map((buh) => (
<option key={buh.id} value={buh.id}>
{buh.user_name}
{buh.display_name}
</option>
))}
</select>
+6 -6
View File
@@ -81,8 +81,8 @@ const UserManagementPage: React.FC = () => {
setSaving(true);
try {
await api.users.create({
user_login: userLogin.trim(),
user_name: userName.trim(),
user_name: userLogin.trim(),
display_name: userName.trim(),
status,
password,
});
@@ -115,12 +115,12 @@ const UserManagementPage: React.FC = () => {
};
const onDeactivate = (user: User) => {
if (!window.confirm(`Nonaktifkan akun "${user.user_name}"?`)) return;
if (!window.confirm(`Nonaktifkan akun "${user.display_name}"?`)) return;
void wrap(async () => {
setBusyId(user.id);
try {
await api.users.update(user.id, { status: 'inactive' });
setNotice(`Akun "${user.user_name}" dinonaktifkan.`);
setNotice(`Akun "${user.display_name}" dinonaktifkan.`);
await reload();
} finally {
setBusyId(null);
@@ -241,12 +241,12 @@ const UserManagementPage: React.FC = () => {
<tr key={user.id} className="border-b border-gray-100 align-top">
<td className="py-3 pr-4">
<div className="font-medium text-gray-900">
{user.user_name}
{user.display_name}
{isSelf ? (
<span className="ml-2 text-xs font-normal text-gray-500">(Anda)</span>
) : null}
</div>
<div className="text-xs text-gray-500">{user.user_login}</div>
<div className="text-xs text-gray-500">{user.user_name}</div>
</td>
<td className="py-3 pr-4">
{!isSelf && editId === user.id ? (
@@ -6,8 +6,8 @@ vi.mock('../../context/AuthContext.tsx', () => ({
useAuth: () => ({
user: {
id: 9,
user_login: 'account_admin',
user_name: 'account_admin',
display_name: 'account_admin',
status: 'account_admin',
is_superuser: false,
created_at: '',
+6 -6
View File
@@ -26,8 +26,8 @@ const {
authState: {
user: {
id: 5,
user_login: 'gm.user',
user_name: 'gm.user',
display_name: 'gm.user',
status: 'gm' as string,
managed_by: null as number | null,
managed_by_name: null as string | null,
@@ -85,8 +85,8 @@ describe('SettingsPage city site registry', () => {
refreshUserMock.mockReset();
authState.user = {
id: 5,
user_login: 'gm.user',
user_name: 'gm.user',
display_name: 'gm.user',
status: 'gm',
managed_by: null,
managed_by_name: null,
@@ -129,13 +129,13 @@ describe('SettingsPage city site registry', () => {
updated_at: '',
});
buhsMock.mockResolvedValue([
{ id: 2, user_login: 'buh', user_name: 'buh', status: 'buh', created_at: '', updated_at: '' },
{ id: 2, user_name: 'buh', display_name: 'buh', status: 'buh', created_at: '', updated_at: '' },
]);
usersListMock.mockResolvedValue([
{
id: 5,
user_login: 'gm',
user_name: 'gm',
display_name: 'gm',
status: 'gm',
managed_by: 2,
created_at: '',
@@ -191,8 +191,8 @@ describe('SettingsPage city site registry', () => {
it('shows pending GM confirmation for BUH', async () => {
authState.user = {
id: 2,
user_login: 'buh',
user_name: 'buh',
display_name: 'buh',
status: 'buh',
managed_by: null,
managed_by_name: null,
@@ -204,8 +204,8 @@ describe('SettingsPage city site registry', () => {
pendingMock.mockResolvedValue([
{
id: 5,
user_login: 'gm.user',
user_name: 'gm.user',
display_name: 'gm.user',
status: 'gm',
created_at: '',
updated_at: '',
@@ -10,8 +10,8 @@ const { listMock, createMock, updateMock, setPasswordMock, authState } = vi.hois
authState: {
user: {
id: 99,
user_login: 'account_admin',
user_name: 'account_admin',
display_name: 'account_admin',
status: 'account_admin' as string,
created_at: '',
updated_at: '',
@@ -45,8 +45,8 @@ describe('UserManagementPage', () => {
setPasswordMock.mockReset();
authState.user = {
id: 99,
user_login: 'account_admin',
user_name: 'account_admin',
display_name: 'account_admin',
status: 'account_admin',
created_at: '',
updated_at: '',
@@ -54,8 +54,8 @@ describe('UserManagementPage', () => {
listMock.mockResolvedValue([
{
id: 1,
user_login: 'gm1.login',
user_name: 'gm1',
user_name: 'gm1.login',
display_name: 'gm1',
status: 'gm',
managed_by_name: 'buh1',
created_at: '',
@@ -63,8 +63,8 @@ describe('UserManagementPage', () => {
},
{
id: 99,
user_login: 'account_admin',
user_name: 'account_admin',
display_name: 'account_admin',
status: 'account_admin',
managed_by_name: null,
created_at: '',
@@ -73,8 +73,8 @@ describe('UserManagementPage', () => {
]);
createMock.mockResolvedValue({
id: 2,
user_login: 'newgm',
user_name: 'newgm',
display_name: 'newgm',
status: 'gm',
created_at: '',
updated_at: '',
@@ -108,8 +108,8 @@ describe('UserManagementPage', () => {
await waitFor(() => {
expect(createMock).toHaveBeenCalledWith({
user_login: 'newgm',
user_name: 'New GM',
user_name: 'newgm',
display_name: 'New GM',
status: 'gm',
password: 'temp123',
});
+3 -3
View File
@@ -30,13 +30,13 @@ const LoginForm: React.FC = () => {
</div>
)}
<div>
<label htmlFor="user_login" className="block text-sm font-medium text-gray-700">
<label htmlFor="user_name" className="block text-sm font-medium text-gray-700">
Login
</label>
<div className="mt-1">
<input
id="user_login"
name="user_login"
id="user_name"
name="user_name"
type="text"
autoComplete="username"
required