generated from pricelees/issue-pr-template
120 lines
4.1 KiB
TypeScript
120 lines
4.1 KiB
TypeScript
import { createTime, delTime, fetchTimes } from '@_api/time/timeAPI';
|
|
import type { TimeCreateRequest } from '@_api/time/timeTypes';
|
|
import React, { useEffect, useState } from 'react';
|
|
import { useLocation, useNavigate } from 'react-router-dom';
|
|
import { isLoginRequiredError } from '@_api/apiClient';
|
|
|
|
const AdminTimePage: React.FC = () => {
|
|
const [times, setTimes] = useState<any[]>([]);
|
|
const [isEditing, setIsEditing] = useState(false);
|
|
const [newTime, setNewTime] = useState('');
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
|
|
const handleError = (err: any) => {
|
|
if (isLoginRequiredError(err)) {
|
|
alert('로그인이 필요해요.');
|
|
navigate('/login', { state: { from: location } });
|
|
} else {
|
|
const message = err.response?.data?.message || '알 수 없는 오류가 발생했습니다.';
|
|
alert(message);
|
|
console.error(err);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
const fetchData = async () => {
|
|
await fetchTimes()
|
|
.then(response => setTimes(response.times))
|
|
.catch(handleError);
|
|
}
|
|
fetchData();
|
|
}, []);
|
|
|
|
const handleAddClick = () => {
|
|
setIsEditing(true);
|
|
};
|
|
|
|
const handleCancelClick = () => {
|
|
setIsEditing(false);
|
|
setNewTime('');
|
|
};
|
|
|
|
const handleSaveClick = async () => {
|
|
if (!newTime) {
|
|
alert('시간을 입력해주세요.');
|
|
return;
|
|
}
|
|
if (!/^\d{2}:\d{2}$/.test(newTime)) {
|
|
alert('시간 형식이 올바르지 않습니다. HH:MM 형식으로 입력해주세요.');
|
|
return;
|
|
}
|
|
const request: TimeCreateRequest = {
|
|
startAt: newTime
|
|
};
|
|
|
|
await createTime(request)
|
|
.then((response) => {
|
|
setTimes([...times, response]);
|
|
alert('시간을 추가했어요.');
|
|
handleCancelClick();
|
|
})
|
|
.catch(handleError);
|
|
};
|
|
|
|
const deleteTime = async (id: number) => {
|
|
if (!window.confirm('정말 삭제하시겠어요?')) {
|
|
return;
|
|
}
|
|
|
|
await delTime(id)
|
|
.then(() => {
|
|
setTimes(times.filter(time => time.id !== id));
|
|
alert('시간을 삭제했어요.');
|
|
})
|
|
.catch(handleError);
|
|
};
|
|
|
|
return (
|
|
<div className="content-container">
|
|
<h2 className="content-container-title">시간 관리 페이지</h2>
|
|
<div className="table-header">
|
|
<button id="add-button" className="btn btn-custom mb-2 float-end" onClick={handleAddClick}>예약시간 추가</button>
|
|
</div>
|
|
<div className="table-container" />
|
|
<table className="table">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col">순서</th>
|
|
<th scope="col">시간</th>
|
|
<th scope="col"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="table-body">
|
|
{times.map(time => (
|
|
<tr key={time.id}>
|
|
<td>{time.id}</td>
|
|
<td>{time.startAt}</td>
|
|
<td>
|
|
<button className="btn btn-danger" onClick={() => deleteTime(time.id)}>삭제</button>
|
|
</td>
|
|
</tr>
|
|
))}
|
|
{isEditing && (
|
|
<tr>
|
|
<td></td>
|
|
<td><input type="time" className="form-control" value={newTime} onChange={e => setNewTime(e.target.value)} /></td>
|
|
<td>
|
|
<button className="btn btn-custom" onClick={handleSaveClick}>확인</button>
|
|
<button className="btn btn-secondary" onClick={handleCancelClick}>취소</button>
|
|
</td>
|
|
</tr>
|
|
)}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default AdminTimePage;
|