feat(WEB): 회계/HR/주문관리 모듈 개선 및 알림설정 리팩토링
- 회계: 거래처, 매입/매출, 입출금 상세 페이지 개선 - HR: 직원 관리 및 출퇴근 설정 기능 수정 - 주문관리: 상세폼 구조 분리 (cards, dialogs, hooks, tables) - 알림설정: 컴포넌트 구조 단순화 및 리팩토링 - 캘린더: 헤더 및 일정 타입 개선 - 출고관리: 액션 및 타입 정의 추가 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -125,6 +125,15 @@ function transformFrontendToApi(data: AttendanceFormData): Record<string, unknow
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 분을 휴게시간 문자열로 변환 (예: 90 -> "1:30")
|
||||
*/
|
||||
function formatMinutesToBreakTime(minutes: number): string {
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const mins = minutes % 60;
|
||||
return `${hours}:${mins.toString().padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 분을 시간 문자열로 변환 (예: 210 -> "3시간 30분")
|
||||
*/
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
EMPLOYEE_STATUS_LABELS,
|
||||
DEFAULT_FIELD_SETTINGS,
|
||||
} from './types';
|
||||
import { getPositions, getDepartments, type PositionItem, type DepartmentItem } from './actions';
|
||||
import { getPositions, getDepartments, uploadProfileImage, type PositionItem, type DepartmentItem } from './actions';
|
||||
import { getProfileImageUrl } from './utils';
|
||||
|
||||
interface EmployeeFormProps {
|
||||
@@ -464,8 +464,10 @@ export function EmployeeForm({
|
||||
if (file) {
|
||||
// 미리보기 즉시 표시
|
||||
handleChange('profileImage', URL.createObjectURL(file));
|
||||
// 서버에 업로드
|
||||
const result = await uploadProfileImage(file);
|
||||
// 서버에 업로드 (FormData로 감싸서 전송)
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
const result = await uploadProfileImage(formData);
|
||||
if (result.success && result.data?.url) {
|
||||
handleChange('profileImage', result.data.url);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
'use server';
|
||||
|
||||
import { cookies } from 'next/headers';
|
||||
import { serverFetch } from '@/lib/api/fetch-wrapper';
|
||||
import { serverFetch, getServerApiHeaders } from '@/lib/api/fetch-wrapper';
|
||||
import type { Employee, EmployeeFormData, EmployeeStats } from './types';
|
||||
import { transformApiToFrontend, transformFrontendToApi, type EmployeeApiData } from './utils';
|
||||
|
||||
@@ -365,7 +365,7 @@ export interface PositionItem {
|
||||
*/
|
||||
export async function getPositions(type?: 'rank' | 'title'): Promise<PositionItem[]> {
|
||||
try {
|
||||
const headers = await getApiHeaders();
|
||||
const headers = await getServerApiHeaders();
|
||||
const searchParams = new URLSearchParams();
|
||||
if (type) {
|
||||
searchParams.set('type', type);
|
||||
@@ -414,7 +414,7 @@ export interface DepartmentItem {
|
||||
*/
|
||||
export async function getDepartments(): Promise<DepartmentItem[]> {
|
||||
try {
|
||||
const headers = await getApiHeaders();
|
||||
const headers = await getServerApiHeaders();
|
||||
|
||||
const response = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/api/v1/departments`,
|
||||
@@ -449,7 +449,7 @@ export async function getDepartments(): Promise<DepartmentItem[]> {
|
||||
// 파일 업로드
|
||||
// ============================================
|
||||
|
||||
export async function uploadProfileImage(formData: FormData): Promise<{
|
||||
export async function uploadProfileImage(inputFormData: FormData): Promise<{
|
||||
success: boolean;
|
||||
data?: { url: string; path: string };
|
||||
error?: string;
|
||||
@@ -464,9 +464,8 @@ export async function uploadProfileImage(formData: FormData): Promise<{
|
||||
return { success: false, __authError: true };
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('directory', 'employees/profiles');
|
||||
// 디렉토리 정보 추가
|
||||
inputFormData.append('directory', 'employees/profiles');
|
||||
|
||||
const response = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/api/v1/files/upload`,
|
||||
@@ -476,7 +475,7 @@ export async function uploadProfileImage(formData: FormData): Promise<{
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'X-API-KEY': process.env.API_KEY || '',
|
||||
},
|
||||
body: formData,
|
||||
body: inputFormData,
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user