refactor: 로딩 스피너 표준화 및 프로젝트 헬스 개선
- LoadingSpinner 컴포넌트 5가지 변형 구현 - LoadingSpinner (인라인/버튼용) - ContentLoadingSpinner (상세/수정 페이지) - PageLoadingSpinner (페이지 전환) - TableLoadingSpinner (테이블/리스트) - ButtonSpinner (버튼 내부) - 18개+ 페이지 로딩 UI 표준화 - HR 페이지 (사원, 휴가, 부서, 급여, 근태) - 영업 페이지 (견적, 거래처) - 게시판, 팝업관리, 품목기준정보 - API 키 보안 개선 (NEXT_PUBLIC_API_KEY → API_KEY) - Textarea 다크모드 스타일 개선 - DropdownField Radix UI Select 버그 수정 (key prop) - 프로젝트 헬스 개선 계획서 문서화 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -57,6 +57,10 @@ const initialFormData: EmployeeFormData = {
|
||||
confirmPassword: '',
|
||||
role: 'user',
|
||||
accountStatus: 'active',
|
||||
clockInLocation: '',
|
||||
clockOutLocation: '',
|
||||
resignationDate: '',
|
||||
resignationReason: '',
|
||||
};
|
||||
|
||||
export function EmployeeDialog({
|
||||
@@ -103,6 +107,10 @@ export function EmployeeDialog({
|
||||
confirmPassword: '',
|
||||
role: employee.userInfo?.role || 'user',
|
||||
accountStatus: employee.userInfo?.accountStatus || 'active',
|
||||
clockInLocation: employee.clockInLocation || '',
|
||||
clockOutLocation: employee.clockOutLocation || '',
|
||||
resignationDate: employee.resignationDate || '',
|
||||
resignationReason: employee.resignationReason || '',
|
||||
});
|
||||
} else if (open && mode === 'create') {
|
||||
setFormData(initialFormData);
|
||||
|
||||
@@ -125,6 +125,8 @@ export interface Employee {
|
||||
clockOutLocation?: string; // 퇴근 위치
|
||||
resignationDate?: string; // 퇴사일
|
||||
resignationReason?: string; // 퇴직사유
|
||||
concurrentPosition?: string; // 겸직 직위
|
||||
concurrentReason?: string; // 겸직 사유
|
||||
|
||||
// 사용자 정보 (시스템 계정)
|
||||
userInfo?: UserInfo;
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import type { VacationUsageRecord, VacationAdjustment, VacationType } from './types';
|
||||
import type { VacationUsageRecord, VacationAdjustment, AdjustableVacationType } from './types';
|
||||
import { VACATION_TYPE_LABELS } from './types';
|
||||
|
||||
interface VacationAdjustDialogProps {
|
||||
@@ -62,7 +62,7 @@ export function VacationAdjustDialog({
|
||||
}, [open]);
|
||||
|
||||
// 조정값 증가
|
||||
const handleIncrease = (type: VacationType) => {
|
||||
const handleIncrease = (type: AdjustableVacationType) => {
|
||||
setAdjustments(prev => ({
|
||||
...prev,
|
||||
[type]: prev[type] + 1,
|
||||
@@ -70,7 +70,7 @@ export function VacationAdjustDialog({
|
||||
};
|
||||
|
||||
// 조정값 감소
|
||||
const handleDecrease = (type: VacationType) => {
|
||||
const handleDecrease = (type: AdjustableVacationType) => {
|
||||
setAdjustments(prev => ({
|
||||
...prev,
|
||||
[type]: prev[type] - 1,
|
||||
@@ -78,7 +78,7 @@ export function VacationAdjustDialog({
|
||||
};
|
||||
|
||||
// 조정값 직접 입력
|
||||
const handleInputChange = (type: VacationType, value: string) => {
|
||||
const handleInputChange = (type: AdjustableVacationType, value: string) => {
|
||||
const numValue = parseInt(value, 10);
|
||||
if (!isNaN(numValue)) {
|
||||
setAdjustments(prev => ({
|
||||
@@ -97,7 +97,7 @@ export function VacationAdjustDialog({
|
||||
const handleSave = () => {
|
||||
const adjustmentList: VacationAdjustment[] = [];
|
||||
|
||||
(Object.keys(adjustments) as VacationType[]).forEach((type) => {
|
||||
(Object.keys(adjustments) as AdjustableVacationType[]).forEach((type) => {
|
||||
if (adjustments[type] !== 0) {
|
||||
adjustmentList.push({
|
||||
vacationType: type,
|
||||
@@ -116,7 +116,7 @@ export function VacationAdjustDialog({
|
||||
|
||||
if (!record) return null;
|
||||
|
||||
const vacationTypes: VacationType[] = ['annual', 'monthly', 'reward', 'other'];
|
||||
const vacationTypes: AdjustableVacationType[] = ['annual', 'monthly', 'reward', 'other'];
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
|
||||
@@ -9,6 +9,9 @@ export type MainTabType = 'usage' | 'grant' | 'request';
|
||||
// 휴가 유형
|
||||
export type VacationType = 'annual' | 'monthly' | 'reward' | 'condolence' | 'other';
|
||||
|
||||
// 조정 가능한 휴가 유형 (VacationAdjustDialog에서 사용)
|
||||
export type AdjustableVacationType = 'annual' | 'monthly' | 'reward' | 'other';
|
||||
|
||||
// 필터 옵션
|
||||
export type FilterOption = 'all' | 'hasVacation' | 'noVacation';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user