fix: [hr] 사원 등록/수정 에러 메시지 화면 표시 개선
- API 컨트롤러 store/update/destroy에 try-catch 추가 - debug 모드에서 상세 에러 메시지 포함 응답 - create/edit 뷰에 showToast 기반 에러 표시 추가 - 422 validation 에러 필드별 메시지 표시 - 500 서버 에러 시 사용자 친화적 메시지 표시
This commit is contained in:
@@ -77,13 +77,23 @@ public function store(Request $request): JsonResponse
|
||||
'emergency_contact' => 'nullable|string|max:100',
|
||||
]);
|
||||
|
||||
$employee = $this->employeeService->createEmployee($validated);
|
||||
try {
|
||||
$employee = $this->employeeService->createEmployee($validated);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '사원이 등록되었습니다.',
|
||||
'data' => $employee,
|
||||
], 201);
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '사원이 등록되었습니다.',
|
||||
'data' => $employee,
|
||||
], 201);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => '사원 등록 중 오류가 발생했습니다.',
|
||||
'error' => config('app.debug') ? $e->getMessage() : null,
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,20 +139,30 @@ public function update(Request $request, int $id): JsonResponse
|
||||
'emergency_contact' => 'nullable|string|max:100',
|
||||
]);
|
||||
|
||||
$employee = $this->employeeService->updateEmployee($id, $validated);
|
||||
try {
|
||||
$employee = $this->employeeService->updateEmployee($id, $validated);
|
||||
|
||||
if (! $employee) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => '사원 정보를 찾을 수 없습니다.',
|
||||
], 404);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '사원 정보가 수정되었습니다.',
|
||||
'data' => $employee,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
|
||||
if (! $employee) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => '사원 정보를 찾을 수 없습니다.',
|
||||
], 404);
|
||||
'message' => '사원 수정 중 오류가 발생했습니다.',
|
||||
'error' => config('app.debug') ? $e->getMessage() : null,
|
||||
], 500);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '사원 정보가 수정되었습니다.',
|
||||
'data' => $employee,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,25 +170,42 @@ public function update(Request $request, int $id): JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $id): JsonResponse|Response
|
||||
{
|
||||
$result = $this->employeeService->deleteEmployee($id);
|
||||
try {
|
||||
$result = $this->employeeService->deleteEmployee($id);
|
||||
|
||||
if (! $result) {
|
||||
if ($request->header('HX-Request')) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => '사원 정보를 찾을 수 없습니다.',
|
||||
], 404);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => '사원 정보를 찾을 수 없습니다.',
|
||||
], 404);
|
||||
}
|
||||
|
||||
if ($request->header('HX-Request')) {
|
||||
$employees = $this->employeeService->getEmployees($request->all(), $request->integer('per_page', 20));
|
||||
|
||||
return response(view('hr.employees.partials.table', compact('employees')));
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '퇴직 처리되었습니다.',
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
|
||||
if (! $result) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => '사원 정보를 찾을 수 없습니다.',
|
||||
], 404);
|
||||
'message' => '퇴직 처리 중 오류가 발생했습니다.',
|
||||
'error' => config('app.debug') ? $e->getMessage() : null,
|
||||
], 500);
|
||||
}
|
||||
|
||||
if ($request->header('HX-Request')) {
|
||||
$employees = $this->employeeService->getEmployees($request->all(), $request->integer('per_page', 20));
|
||||
|
||||
return response(view('hr.employees.partials.table', compact('employees')));
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '퇴직 처리되었습니다.',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -192,13 +192,50 @@ class="px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-
|
||||
@push('scripts')
|
||||
<script>
|
||||
document.body.addEventListener('htmx:afterRequest', function(event) {
|
||||
if (event.detail.successful) {
|
||||
try {
|
||||
const response = JSON.parse(event.detail.xhr.responseText);
|
||||
if (response.success) {
|
||||
window.location.href = '{{ route('hr.employees.index') }}';
|
||||
if (event.detail.elt.id !== 'employeeForm') return;
|
||||
|
||||
const xhr = event.detail.xhr;
|
||||
try {
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
|
||||
if (response.success) {
|
||||
showToast(response.message || '사원이 등록되었습니다.', 'success');
|
||||
window.location.href = '{{ route('hr.employees.index') }}';
|
||||
return;
|
||||
}
|
||||
|
||||
// 서버에서 success: false 응답
|
||||
let msg = response.message || '저장에 실패했습니다.';
|
||||
if (response.error) msg += '\n' + response.error;
|
||||
showToast(msg, 'error', 5000);
|
||||
} catch (e) {
|
||||
if (!event.detail.successful) {
|
||||
showToast('서버 오류가 발생했습니다. (HTTP ' + xhr.status + ')', 'error', 5000);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Validation 에러 (422) 처리
|
||||
document.body.addEventListener('htmx:responseError', function(event) {
|
||||
if (event.detail.elt.id !== 'employeeForm') return;
|
||||
|
||||
const xhr = event.detail.xhr;
|
||||
try {
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
|
||||
if (xhr.status === 422 && response.errors) {
|
||||
const messages = [];
|
||||
for (const field in response.errors) {
|
||||
messages.push(response.errors[field].join(', '));
|
||||
}
|
||||
} catch (e) {}
|
||||
showToast(messages.join('\n'), 'error', 6000);
|
||||
} else {
|
||||
let msg = response.message || '오류가 발생했습니다.';
|
||||
if (response.error) msg += '\n' + response.error;
|
||||
showToast(msg, 'error', 5000);
|
||||
}
|
||||
} catch (e) {
|
||||
showToast('서버 오류가 발생했습니다. (HTTP ' + xhr.status + ')', 'error', 5000);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -196,13 +196,48 @@ class="px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-
|
||||
@push('scripts')
|
||||
<script>
|
||||
document.body.addEventListener('htmx:afterRequest', function(event) {
|
||||
if (event.detail.successful) {
|
||||
try {
|
||||
const response = JSON.parse(event.detail.xhr.responseText);
|
||||
if (response.success) {
|
||||
window.location.href = '{{ route('hr.employees.show', $employee->id) }}';
|
||||
if (event.detail.elt.id !== 'employeeForm') return;
|
||||
|
||||
const xhr = event.detail.xhr;
|
||||
try {
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
|
||||
if (response.success) {
|
||||
showToast(response.message || '사원 정보가 수정되었습니다.', 'success');
|
||||
window.location.href = '{{ route('hr.employees.show', $employee->id) }}';
|
||||
return;
|
||||
}
|
||||
|
||||
let msg = response.message || '저장에 실패했습니다.';
|
||||
if (response.error) msg += '\n' + response.error;
|
||||
showToast(msg, 'error', 5000);
|
||||
} catch (e) {
|
||||
if (!event.detail.successful) {
|
||||
showToast('서버 오류가 발생했습니다. (HTTP ' + xhr.status + ')', 'error', 5000);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.body.addEventListener('htmx:responseError', function(event) {
|
||||
if (event.detail.elt.id !== 'employeeForm') return;
|
||||
|
||||
const xhr = event.detail.xhr;
|
||||
try {
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
|
||||
if (xhr.status === 422 && response.errors) {
|
||||
const messages = [];
|
||||
for (const field in response.errors) {
|
||||
messages.push(response.errors[field].join(', '));
|
||||
}
|
||||
} catch (e) {}
|
||||
showToast(messages.join('\n'), 'error', 6000);
|
||||
} else {
|
||||
let msg = response.message || '오류가 발생했습니다.';
|
||||
if (response.error) msg += '\n' + response.error;
|
||||
showToast(msg, 'error', 5000);
|
||||
}
|
||||
} catch (e) {
|
||||
showToast('서버 오류가 발생했습니다. (HTTP ' + xhr.status + ')', 'error', 5000);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user