Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions src/app/(refine)/refine/dashboard/_components/userTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@ export const UserTable = ({ children }: { children: React.ReactNode }) => (
<tr>
<th className="px-4 py-3 text-left text-sm font-semibold text-gray-900">UID</th>
<th className="px-4 py-3 text-left text-sm font-semibold text-gray-900">ชื่อ</th>
<th className="hidden px-4 py-3 text-left text-sm font-semibold text-gray-900 sm:table-cell">อีเมล</th>
<th className="px-4 py-3 text-left text-sm font-semibold text-gray-900">สถานะ</th>
<th className="hidden px-4 py-3 text-left text-sm font-semibold text-gray-900 sm:table-cell">คณะ</th>
<th className="px-4 py-3 text-left text-sm font-semibold text-gray-900">ขนาดเสื้อ</th>
<th className="hidden px-4 py-3 text-left text-sm font-semibold text-gray-900 sm:table-cell">เข้างานล่าสุด</th>
<th className="px-4 py-3 text-left text-sm font-semibold text-gray-900 sm:table-cell">เบอร์โทรศัพท์</th>
<th className="px-4 py-3 text-left text-sm font-semibold text-gray-900 sm:table-cell">เข้างานล่าสุด</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 bg-white">
Expand Down
37 changes: 9 additions & 28 deletions src/app/(refine)/refine/dashboard/_components/userTableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import dayjs from 'dayjs';
import { User } from '../../libs/interface';

export const UserTableRow = ({ user, onClick }: { user: User, onClick: () => void }) => {
const statusStyles = {
chula_student: 'bg-blue-600',
alumni: 'bg-pink-600',
general_student: 'bg-gray-600',
};
const style = statusStyles[user.status as keyof typeof statusStyles];
// const statusStyles = {
// chula_student: 'bg-blue-600',
// alumni: 'bg-pink-600',
// general_student: 'bg-gray-600',
// };
// const style = statusStyles[user.status as keyof typeof statusStyles];

return (
<tr className="cursor-pointer transition-colors hover:bg-gray-50" onClick={onClick}>
Expand All @@ -17,29 +17,10 @@ export const UserTableRow = ({ user, onClick }: { user: User, onClick: () => voi
<td className="whitespace-nowrap px-4 py-4 text-sm text-gray-900">
{user.name}
</td>
<td className="hidden whitespace-nowrap px-4 py-4 text-sm text-gray-500 sm:table-cell">
{user.email}
<td className="whitespace-nowrap px-4 py-4 text-sm text-gray-500 sm:table-cell">
{user.phone}
</td>
<td className="whitespace-nowrap px-4 py-4 text-sm text-gray-500">
<span
className={`text-xs inline-flex items-center rounded-full px-3 py-1 font-medium text-white ${style}`}
>
{
{
chula_student: 'นิสิตปัจจุบัน',
alumni: 'ศิษย์เก่า',
general_student: 'บุคคลทั่วไป',
}[user.status]
}
</span>
</td>
<td className="hidden whitespace-nowrap px-4 py-4 text-sm text-gray-500 sm:table-cell">
{user.faculty}
</td>
<td className="whitespace-nowrap px-4 py-4 text-sm text-gray-500">
{user.sizeJersey}
</td>
<td className="hidden whitespace-nowrap px-4 py-4 text-sm text-gray-500 sm:table-cell">
<td className="whitespace-nowrap px-4 py-4 text-sm text-gray-500 sm:table-cell">
{dayjs(user.lastEntered).isValid()
? dayjs(user.lastEntered).format('DD/MM HH:mm')
: 'ยังไม่เข้างาน'}
Expand Down
166 changes: 33 additions & 133 deletions src/app/(refine)/refine/users/[id]/_components/userDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/* eslint-disable @next/next/no-img-element */
'use client';
import { useOne } from '@refinedev/core';
import { User, FieldEntry } from '../../../libs/interface';
import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';

const formatThaiDate = (dateString: string) => {
Expand All @@ -17,40 +15,22 @@ const formatThaiDate = (dateString: string) => {

export default function UserDetails({ id }: { id: string }) {
const router = useRouter();
const [isImageOpen, setIsImageOpen] = useState(false);
const [image, setImage] = useState<string | null>(null);
const [imageError, setImageError] = useState('');
const { data, isError, isLoading } = useOne<User>({
resource: 'users',
id: id,
});

const { data: imageData, isError: isImageError } = useOne({
resource: 'users/image',
id: id,
});

const user = data?.data;

useEffect(() => {
if (isImageError) {
setImageError('คุณไม่มีสิทธิ์เข้าถึงภาพนี้');
setImage(null);
} else if (imageData?.data?.url) {
setImage(imageData.data.url);
setImageError('');
}
}, [imageData, isImageError]);

const createField = (label: string, field: keyof User): FieldEntry => ({
label,
field,
});

const renderSection = (title: string, fields: FieldEntry[]) => (
<div className="border-t border-gray-100 pt-4">
<h3 className="mb-3 text-lg font-semibold text-gray-800">{title}</h3>
<div className="space-y-3">
<div className="border-t border-dark-blue/20 pt-6">
<h3 className="mb-4 text-2xl font-semibold text-dark-blue">{title}</h3>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
{fields.map(({ label, field }) => {
const value = user?.[field];
let displayValue = value || 'N/A';
Expand All @@ -59,16 +39,16 @@ export default function UserDetails({ id }: { id: string }) {
displayValue = formatThaiDate(value as string);
} else if (field === 'graduatedYear') {
displayValue = (parseInt(value as string) + 543).toString();
} else if (field === 'status') {
displayValue = value as string;
} else if (field === 'isAcrophobic') {
displayValue = value ? 'ใช่' : 'ไม่';
}

return (
<div key={field} className="flex justify-between">
<span className="text-gray-600">{label}</span>
<span className="text-right text-gray-800">{displayValue}</span>
<div key={field} className="space-y-1">
<dt className="text-base font-medium text-dark-gray">{label}</dt>
<dd className="text-xl text-dark-blue">
{displayValue}
</dd>
</div>
);
})}
Expand All @@ -79,23 +59,23 @@ export default function UserDetails({ id }: { id: string }) {
if (isLoading) return <div className="p-4 text-center">กำลังโหลด...</div>;
if (isError)
return (
<div className="p-4 text-center text-red-500">
<div className="p-4 text-center text-error">
เกิดข้อผิดพลาดในการโหลดข้อมูลผู้ใช้
</div>
);
if (!user) return <div className="p-4 text-center">ไม่พบผู้ใช้</div>;

return (
<div className="relative mx-auto min-h-screen max-w-md bg-gray-50 p-4">
<div className="relative mx-auto min-h-screen max-w-4xl bg-gray-100 p-6">
{/* Header */}
<header className="mb-6 flex items-center justify-between">
<header className="mb-8">
<button
onClick={() => router.push('/refine/dashboard')}
className="flex items-center space-x-2 rounded-lg bg-white px-4 py-2 shadow-sm transition-all hover:shadow-md"
className="flex items-center space-x-2 text-dark-pink transition-colors hover:text-dark-blue"
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-5 w-5 text-gray-600"
className="h-6 w-6"
viewBox="0 0 20 20"
fill="currentColor"
>
Expand All @@ -105,129 +85,49 @@ export default function UserDetails({ id }: { id: string }) {
clipRule="evenodd"
/>
</svg>
<span className="text-gray-700">กลับ</span>
<span className="text-xl">กลับสู่หน้าหลัก</span>
</button>
</header>

{/* Image Preview */}
<section className="mb-6">
<div
onClick={() => setIsImageOpen(true)}
className="relative aspect-[4/3] w-full overflow-hidden rounded-2xl bg-gray-100 shadow-lg"
>
{imageError ? (
<div className="flex h-full flex-col items-center justify-center space-y-2 text-red-500">
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-8 w-8"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
/>
</svg>
<span className="text-sm">{imageError}</span>
</div>
) : (
image && (
<img
src={image}
alt="Citizen Card Preview"
className="h-full w-full object-cover"
/>
)
)}
</div>
</section>

{/* Profile Information */}
<section className="mb-6 rounded-2xl bg-white p-6 shadow-sm">
<div className="mb-4">
<h1 className="text-2xl font-bold text-gray-800">{user.name}</h1>
<div className="mt-2 flex items-center space-x-2">
<span className="rounded-full bg-blue-100 px-3 py-1 text-sm font-medium text-blue-800">
{user.role}
</span>
<span className="text-sm text-gray-500">{user.uid}</span>
<section className="rounded-xl bg-white p-8 shadow-[0_4px_20px_rgba(223,114,159,0.15)]">
<div className="mb-8 border-b border-light-pink pb-6">
<div className="flex flex-col items-start space-y-3">
<h1 className="text-3xl font-bold text-gradient-pirple">{user.name}</h1>
<div className="flex items-center space-x-4">
<span className="rounded-lg bg-dark-pink px-4 py-2 text-base font-medium text-white">
{user.role}
</span>
<span className="rounded-lg bg-dark-blue px-4 py-2 text-base font-medium text-light-pink">
{user.uid}
</span>
</div>
</div>
</div>

<div className="space-y-4">
<div className="space-y-8">
{renderSection('ข้อมูลส่วนตัว', [
createField('อีเมล', 'email'),
createField('เบอร์โทรศัพท์', 'phone'),
createField('สถานะ', 'status'),
createField('วันที่ลงทะเบียน', 'registeredAt'),
])}

{renderSection('ข้อมูลการศึกษา', [
{/* {renderSection('ข้อมูลการศึกษา', [
createField('มหาวิทยาลัย', 'university'),
createField('คณะ', 'faculty'),
createField('ระดับการศึกษา', 'education'),
createField('ปีที่จบการศึกษา', 'graduatedYear'),
])}
])} */}

{renderSection('ข้อมูลเพิ่มเติม', [
createField('ขนาดเสื้อ', 'sizeJersey'),
{renderSection('ข้อมูลสุขภาพ', [
createField('ข้อจำกัดด้านอาหาร', 'foodLimitation'),
createField('กลัวความสูงไหม', 'isAcrophobic'),
...(user.chronicDisease
? [createField('โรคประจำตัว', 'chronicDisease')]
: []),
...(user.drugAllergy
? [createField('อาการแพ้ยา', 'drugAllergy')]
: []),
createField('กลัวความสูง', 'isAcrophobic'),
createField('โรคประจำตัว', 'chronicDisease'),
createField('อาการแพ้ยา', 'drugAllergy'),
])}
</div>
</section>

{/* Image Modal */}
{isImageOpen && (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm"
onClick={() => setIsImageOpen(false)}
>
<div className="relative mx-4 w-full max-w-2xl rounded-2xl bg-white p-4">
<button
onClick={() => setIsImageOpen(false)}
className="absolute right-4 top-4 text-gray-500 hover:text-gray-700"
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-8 w-8"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
<div className="overflow-hidden rounded-xl border-2 border-gray-200">
{image ? (
<img
src={image}
alt="Citizen Card"
className="h-auto w-full object-contain"
/>
) : (
<div className="flex h-96 items-center justify-center text-red-500">
{imageError}
</div>
)}
</div>
</div>
</div>
)}
</div>
);
}
Loading