feat: profile image upload in accounts page

This commit is contained in:
pray4skylark
2026-06-02 20:12:08 +09:00
parent b471598d6c
commit face097785
+45 -1
View File
@@ -1,7 +1,7 @@
'use client';
import React, { useState, useEffect } from 'react';
import { Users, Plus, Pencil, Trash2, X, Search, AlertTriangle } from 'lucide-react';
import { Users, Plus, Pencil, Trash2, X, Search, AlertTriangle, Camera, Loader2 } from 'lucide-react';
import { useAuthStore } from '@/stores';
import employeeService from '@/services/employeeService';
import type { Employee, RoleCode, EmpStatus } from '@/types';
@@ -273,9 +273,13 @@ export default function AccountsPage() {
<tr key={emp.empId} className="hover:bg-gray-50/30 transition-colors">
<td className="px-4 sm:px-6 py-3">
<div className="flex items-center gap-3">
{emp.profileImage ? (
<img src={emp.profileImage} alt={emp.name} className="w-8 h-8 rounded-full object-cover border border-border flex-shrink-0" />
) : (
<div className={`w-8 h-8 rounded-full ${getInitialColor(emp.name, idx)} flex items-center justify-center text-xs font-medium text-white flex-shrink-0`}>
{emp.name[0]}
</div>
)}
<span className="font-medium text-text-main">{emp.name}</span>
</div>
</td>
@@ -495,6 +499,46 @@ export default function AccountsPage() {
<p className="text-xs font-semibold text-text-muted uppercase tracking-wider mb-3">추가 정보</p>
</div>
{/* Profile Image */}
<div>
<label className={labelClass}>프로필 사진</label>
<div className="flex items-center gap-3 mt-1">
<div className="w-14 h-14 rounded-full bg-surface-container flex items-center justify-center overflow-hidden border border-border flex-shrink-0">
{targetEmployee.profileImage ? (
<img src={targetEmployee.profileImage} alt="" className="w-full h-full object-cover" />
) : (
<span className="text-lg font-bold text-text-muted">{targetEmployee.name[0]}</span>
)}
</div>
<label className="flex items-center gap-1.5 px-3 py-2 rounded-xl border border-border text-xs font-medium text-text-muted hover:bg-gray-50 cursor-pointer transition-colors">
<Camera className="w-3.5 h-3.5" /> 업로드
<input type="file" accept="image/*" className="hidden" onChange={async (e) => {
const file = e.target.files?.[0];
if (!file) return;
const form = new FormData();
form.append('file', file);
try {
const uploadRes = await fetch('/api/v1/files/upload', { method: 'POST', body: form });
const uploadData = await uploadRes.json();
if (uploadData.success) {
await employeeService.updateProfileImage(targetEmployee.empId, uploadData.data);
await fetchEmployees();
const emp = (await employeeService.getOne(targetEmployee.empId)).data;
setTargetEmployee(emp);
}
} catch { alert('업로드 실패'); }
}} />
</label>
{targetEmployee.profileImage && (
<button type="button" onClick={async () => {
await employeeService.updateProfileImage(targetEmployee.empId, '');
setTargetEmployee({ ...targetEmployee, profileImage: '' });
await fetchEmployees();
}} className="text-xs text-status-critical-text hover:underline">삭제</button>
)}
</div>
</div>
<div className="grid grid-cols-2 gap-3">
<div>
<label className={labelClass}>생년월일</label>