Files
imphnen-frontend-service/apps/backoffice/src/app/(protected)/hackathon-users/page.tsx
T

165 lines
4.7 KiB
TypeScript
Raw Normal View History

2025-11-30 16:55:11 +07:00
import { FC, ReactElement, useState } from 'react';
import ModalUserDetail from './_components/modal-user-detail';
2025-11-30 17:22:47 +07:00
import {
BackofficeWrapper,
DataTable,
} from '@imphnen-frontend-service/ui/organisms';
2025-11-30 16:55:11 +07:00
import {
ColumnDef,
getCoreRowModel,
getPaginationRowModel,
PaginationState,
RowSelectionState,
useReactTable,
} from '@tanstack/react-table';
import { Button } from '@imphnen-frontend-service/ui/atoms';
import { cn } from '@imphnen-frontend-service/utils';
import { EditOutlined } from '@ant-design/icons';
// Removed unused SearchOutlined icon after schema revision
export const HackathonUsersPage: FC = (): ReactElement => {
2025-11-30 16:55:11 +07:00
const [showDetailModal, setShowDetailModal] = useState(false);
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
const [pagination, setPagination] = useState<PaginationState>({
pageIndex: 0,
pageSize: 9,
});
// Mock data aligned to API user schema
2025-11-30 16:55:11 +07:00
interface UserType {
id: string;
fullname: string;
2025-11-30 16:55:11 +07:00
email: string;
is_active: boolean;
location: string;
created_at: string;
updated_at: string;
avatar?: string;
phone_number?: string;
2025-11-30 16:55:11 +07:00
}
const mockData: UserType[] = Array.from({ length: 50 }, (_, i) => ({
id: `24db9e4d-ca4c-46aa-ac36-8ef04bbe015f`,
fullname: i % 3 === 0 ? 'Ahmad Wijuana' : 'Sofia Wijuana',
email: `user${i + 1}@example.com`,
is_active: i % 5 !== 0,
location: i % 2 === 0 ? 'Jakarta' : 'Bandung',
created_at: new Date(Date.now() - i * 86400000).toISOString(),
updated_at: new Date().toISOString(),
avatar: undefined,
phone_number: '+62-812-0000-000',
}));
2025-11-30 16:55:11 +07:00
const columns: ColumnDef<UserType>[] = [
{
accessorKey: 'id',
header: 'ID',
2025-11-30 16:55:11 +07:00
},
{
accessorKey: 'fullname',
header: 'Full Name',
2025-11-30 16:55:11 +07:00
},
{
accessorKey: 'email',
header: 'Email',
2025-11-30 16:55:11 +07:00
},
{
accessorKey: 'location',
header: 'Location',
2025-11-30 16:55:11 +07:00
},
{
accessorKey: 'is_active',
2025-11-30 16:55:11 +07:00
header: 'Status',
cell: ({ row }) => (
<div
className={cn(
'py-2 px-4 text-sm rounded-2xl text-center',
row.original.is_active
? 'bg-success-200 text-success-700'
: 'bg-danger-200 text-danger-700'
)}
>
{row.original.is_active ? 'Active' : 'Inactive'}
</div>
),
},
{
accessorKey: 'created_at',
header: 'Joined',
cell: ({ row }) => new Date(row.original.created_at).toLocaleDateString(),
2025-11-30 16:55:11 +07:00
},
{
header: 'Action',
meta: { cellClassName: cn('w-72') },
cell: ({ row }) => (
<Button
variant="primary"
size="sm"
className="flex items-center gap-2 w-max"
onClick={() => {
// View detail logic
}}
2025-11-30 16:55:11 +07:00
>
<EditOutlined className="text-base" /> View & Manage
2025-11-30 16:55:11 +07:00
</Button>
),
},
];
const table = useReactTable({
data: mockData,
columns,
state: {
pagination,
rowSelection,
},
enableRowSelection: true,
onRowSelectionChange: setRowSelection,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onPaginationChange: setPagination,
pageCount: Math.ceil(mockData.length / pagination.pageSize),
manualPagination: false,
});
return (
2025-11-30 17:22:47 +07:00
<BackofficeWrapper title="IMPHNEN x Kolosal.ai Hackathon 2025">
<h1 className="mb-8 text-p1 font-semibold text-neutral-700">
User Management
</h1>
2025-11-30 16:55:11 +07:00
{/* Filters and actions */}
2025-11-30 17:22:47 +07:00
<section className="bg-white rounded-md shadow p-8 flex flex-col gap-6">
2025-11-30 16:55:11 +07:00
<div className="flex flex-wrap gap-3 items-center">
<input
type="text"
className="border border-neutral-200 rounded-md px-3 py-2 text-label1 w-full sm:w-64"
placeholder="Search name or email"
/>
<select className="border border-neutral-200 rounded-md px-3 py-2 text-label1 w-full sm:w-40">
<option value="all">All Status</option>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
2025-11-30 16:55:11 +07:00
</select>
<select className="border border-neutral-200 rounded-md px-3 py-2 text-label1 w-full sm:w-40">
<option value="all">All Location</option>
2025-11-30 16:55:11 +07:00
<option value="jakarta">Jakarta</option>
<option value="bandung">Bandung</option>
</select>
</div>
{/* Table */}
<DataTable data={mockData} columns={columns} table={table} />
</section>
2025-11-30 16:55:11 +07:00
{/* Modals component */}
2025-11-30 16:55:11 +07:00
<ModalUserDetail
isOpen={showDetailModal}
onClose={() => setShowDetailModal(false)}
/>
2025-11-30 17:22:47 +07:00
</BackofficeWrapper>
);
};
export default HackathonUsersPage;