generated from pricelees/issue-pr-template
refactor: 일정 관련 프론트엔드 페이지 및 기능 구현
This commit is contained in:
parent
cdf7a98867
commit
163b7991d3
@ -28,7 +28,7 @@ export interface UserLoginSuccessResponse extends LoginSuccessResponse {
|
|||||||
|
|
||||||
export interface AdminLoginSuccessResponse extends LoginSuccessResponse {
|
export interface AdminLoginSuccessResponse extends LoginSuccessResponse {
|
||||||
type: AdminType;
|
type: AdminType;
|
||||||
storeId: number | null;
|
storeId: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CurrentUserContext {
|
export interface CurrentUserContext {
|
||||||
|
|||||||
@ -8,28 +8,28 @@ import type {
|
|||||||
ScheduleUpdateRequest
|
ScheduleUpdateRequest
|
||||||
} from './scheduleTypes';
|
} from './scheduleTypes';
|
||||||
|
|
||||||
export const fetchAvailableThemesByDate = async (date: string): Promise<AvailableThemeIdListResponse> => {
|
export const fetchStoreAvailableThemesByDate = async (storeId: string, date: string): Promise<AvailableThemeIdListResponse> => {
|
||||||
return await apiClient.get<AvailableThemeIdListResponse>(`/schedules/themes?date=${date}`);
|
return await apiClient.get<AvailableThemeIdListResponse>(`/stores/${storeId}/themes?date=${date}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchSchedulesByDateAndTheme = async (storeId: number, date: string, themeId: string): Promise<ScheduleRetrieveListResponse> => {
|
export const fetchStoreSchedulesByDateAndTheme = async (storeId: string, date: string, themeId: string): Promise<ScheduleRetrieveListResponse> => {
|
||||||
return await apiClient.get<ScheduleRetrieveListResponse>(`/schedules?storeId=${storeId}&date=${date}&themeId=${themeId}`);
|
return await apiClient.get<ScheduleRetrieveListResponse>(`/stores/${storeId}/schedules?date=${date}&themeId=${themeId}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchScheduleById = async (id: string): Promise<ScheduleDetailRetrieveResponse> => {
|
export const fetchScheduleDetailById = async (id: string): Promise<ScheduleDetailRetrieveResponse> => {
|
||||||
return await apiClient.get<ScheduleDetailRetrieveResponse>(`/schedules/${id}`);
|
return await apiClient.get<ScheduleDetailRetrieveResponse>(`/admin/schedules/${id}`);
|
||||||
}
|
};
|
||||||
|
|
||||||
export const createSchedule = async (request: ScheduleCreateRequest): Promise<ScheduleCreateResponse> => {
|
export const createSchedule = async (storeId: string, request: ScheduleCreateRequest): Promise<ScheduleCreateResponse> => {
|
||||||
return await apiClient.post<ScheduleCreateResponse>('/schedules', request);
|
return await apiClient.post<ScheduleCreateResponse>(`/admin/stores/${storeId}/schedules`, request);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateSchedule = async (id: string, request: ScheduleUpdateRequest): Promise<void> => {
|
export const updateSchedule = async (id: string, request: ScheduleUpdateRequest): Promise<void> => {
|
||||||
await apiClient.patch(`/schedules/${id}`, request);
|
await apiClient.patch(`/admin/schedules/${id}`, request);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteSchedule = async (id: string): Promise<void> => {
|
export const deleteSchedule = async (id: string): Promise<void> => {
|
||||||
await apiClient.del(`/schedules/${id}`);
|
await apiClient.del(`/admin/schedules/${id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const holdSchedule = async (id: string): Promise<void> => {
|
export const holdSchedule = async (id: string): Promise<void> => {
|
||||||
|
|||||||
@ -2,12 +2,12 @@ import { type AuditInfo } from '@_api/common/commonTypes';
|
|||||||
import type { RegionInfoResponse } from '@_api/region/regionTypes';
|
import type { RegionInfoResponse } from '@_api/region/regionTypes';
|
||||||
|
|
||||||
export interface SimpleStoreResponse {
|
export interface SimpleStoreResponse {
|
||||||
id: number;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StoreDetailResponse {
|
export interface StoreDetailResponse {
|
||||||
id: number;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
address: string;
|
address: string;
|
||||||
contact: string;
|
contact: string;
|
||||||
|
|||||||
@ -10,7 +10,7 @@ interface AdminAuthContextType {
|
|||||||
isAdmin: boolean;
|
isAdmin: boolean;
|
||||||
name: string | null;
|
name: string | null;
|
||||||
type: AdminType | null;
|
type: AdminType | null;
|
||||||
storeId: number | null;
|
storeId: string | null;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
login: (data: Omit<LoginRequest, 'principalType'>) => Promise<AdminLoginSuccessResponse>;
|
login: (data: Omit<LoginRequest, 'principalType'>) => Promise<AdminLoginSuccessResponse>;
|
||||||
logout: () => Promise<void>;
|
logout: () => Promise<void>;
|
||||||
@ -22,7 +22,7 @@ export const AdminAuthProvider: React.FC<{ children: ReactNode }> = ({ children
|
|||||||
const [isAdmin, setIsAdmin] = useState(false);
|
const [isAdmin, setIsAdmin] = useState(false);
|
||||||
const [name, setName] = useState<string | null>(null);
|
const [name, setName] = useState<string | null>(null);
|
||||||
const [type, setType] = useState<AdminType | null>(null);
|
const [type, setType] = useState<AdminType | null>(null);
|
||||||
const [storeId, setStoreId] = useState<number | null>(null);
|
const [storeId, setStoreId] = useState<string | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -36,7 +36,7 @@ export const AdminAuthProvider: React.FC<{ children: ReactNode }> = ({ children
|
|||||||
setIsAdmin(true);
|
setIsAdmin(true);
|
||||||
setName(storedName);
|
setName(storedName);
|
||||||
setType(storedType);
|
setType(storedType);
|
||||||
setStoreId(storedStoreId ? parseInt(storedStoreId, 10) : null);
|
setStoreId(storedStoreId ? storedStoreId : null);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to load admin auth state from storage", error);
|
console.error("Failed to load admin auth state from storage", error);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import {isLoginRequiredError} from '@_api/apiClient';
|
import {isLoginRequiredError} from '@_api/apiClient';
|
||||||
import {fetchAvailableThemesByDate, fetchSchedulesByDateAndTheme, holdSchedule} from '@_api/schedule/scheduleAPI';
|
import {fetchStoreAvailableThemesByDate, fetchStoreSchedulesByDateAndTheme, holdSchedule} from '@_api/schedule/scheduleAPI';
|
||||||
import {type ScheduleRetrieveResponse, ScheduleStatus} from '@_api/schedule/scheduleTypes';
|
import {type ScheduleRetrieveResponse, ScheduleStatus} from '@_api/schedule/scheduleTypes';
|
||||||
import {fetchThemesByIds} from '@_api/theme/themeAPI';
|
import {fetchThemesByIds} from '@_api/theme/themeAPI';
|
||||||
import {mapThemeResponse, type ThemeInfoResponse} from '@_api/theme/themeTypes';
|
import {mapThemeResponse, type ThemeInfoResponse} from '@_api/theme/themeTypes';
|
||||||
@ -35,7 +35,7 @@ const ReservationStep1Page: React.FC = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedDate) {
|
if (selectedDate) {
|
||||||
const dateStr = selectedDate.toLocaleDateString('en-CA'); // yyyy-mm-dd
|
const dateStr = selectedDate.toLocaleDateString('en-CA'); // yyyy-mm-dd
|
||||||
fetchAvailableThemesByDate(dateStr)
|
fetchStoreAvailableThemesByDate(dateStr)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
console.log('Available themes response:', res);
|
console.log('Available themes response:', res);
|
||||||
const themeIds: string[] = res.themeIds;
|
const themeIds: string[] = res.themeIds;
|
||||||
@ -69,7 +69,7 @@ const ReservationStep1Page: React.FC = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedDate && selectedTheme) {
|
if (selectedDate && selectedTheme) {
|
||||||
const dateStr = selectedDate.toLocaleDateString('en-CA');
|
const dateStr = selectedDate.toLocaleDateString('en-CA');
|
||||||
fetchSchedulesByDateAndTheme(dateStr, selectedTheme.id)
|
fetchStoreSchedulesByDateAndTheme(dateStr, selectedTheme.id)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
setSchedules(res.schedules);
|
setSchedules(res.schedules);
|
||||||
setSelectedSchedule(null);
|
setSelectedSchedule(null);
|
||||||
|
|||||||
@ -2,8 +2,8 @@ import { isLoginRequiredError } from '@_api/apiClient';
|
|||||||
import {
|
import {
|
||||||
createSchedule,
|
createSchedule,
|
||||||
deleteSchedule,
|
deleteSchedule,
|
||||||
fetchScheduleById,
|
fetchScheduleDetailById,
|
||||||
fetchSchedulesByDateAndTheme,
|
fetchStoreSchedulesByDateAndTheme,
|
||||||
updateSchedule
|
updateSchedule
|
||||||
} from '@_api/schedule/scheduleAPI';
|
} from '@_api/schedule/scheduleAPI';
|
||||||
import {
|
import {
|
||||||
@ -108,7 +108,7 @@ const AdminSchedulePage: React.FC = () => {
|
|||||||
const fetchSchedules = () => {
|
const fetchSchedules = () => {
|
||||||
const storeId = adminType === 'HQ' ? selectedStoreId : adminStoreId;
|
const storeId = adminType === 'HQ' ? selectedStoreId : adminStoreId;
|
||||||
if (storeId && selectedDate && selectedThemeId) {
|
if (storeId && selectedDate && selectedThemeId) {
|
||||||
fetchSchedulesByDateAndTheme(Number(storeId), selectedDate, selectedThemeId)
|
fetchStoreSchedulesByDateAndTheme(storeId, selectedDate, selectedThemeId)
|
||||||
.then(res => setSchedules(res.schedules))
|
.then(res => setSchedules(res.schedules))
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
setSchedules([]);
|
setSchedules([]);
|
||||||
@ -147,8 +147,16 @@ const AdminSchedulePage: React.FC = () => {
|
|||||||
alert('시간 형식이 올바르지 않습니다. HH:MM 형식으로 입력해주세요.');
|
alert('시간 형식이 올바르지 않습니다. HH:MM 형식으로 입력해주세요.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (adminType !== 'STORE' || !adminStoreId) {
|
||||||
|
alert('매장 관리자만 일정을 추가할 수 있습니다.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!selectedDate || !selectedThemeId) {
|
||||||
|
alert('날짜와 테마를 선택해주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
await createSchedule({
|
await createSchedule(adminStoreId, {
|
||||||
date: selectedDate,
|
date: selectedDate,
|
||||||
themeId: selectedThemeId,
|
themeId: selectedThemeId,
|
||||||
time: newScheduleTime,
|
time: newScheduleTime,
|
||||||
@ -183,7 +191,7 @@ const AdminSchedulePage: React.FC = () => {
|
|||||||
if (!detailedSchedules[scheduleId]) {
|
if (!detailedSchedules[scheduleId]) {
|
||||||
setIsLoadingDetails(true);
|
setIsLoadingDetails(true);
|
||||||
try {
|
try {
|
||||||
const details = await fetchScheduleById(scheduleId);
|
const details = await fetchScheduleDetailById(scheduleId);
|
||||||
setDetailedSchedules(prev => ({ ...prev, [scheduleId]: details }));
|
setDetailedSchedules(prev => ({ ...prev, [scheduleId]: details }));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error);
|
handleError(error);
|
||||||
@ -222,7 +230,7 @@ const AdminSchedulePage: React.FC = () => {
|
|||||||
status: editingSchedule.status,
|
status: editingSchedule.status,
|
||||||
});
|
});
|
||||||
// Refresh data
|
// Refresh data
|
||||||
const details = await fetchScheduleById(editingSchedule.id);
|
const details = await fetchScheduleDetailById(editingSchedule.id);
|
||||||
setDetailedSchedules(prev => ({ ...prev, [editingSchedule.id]: details }));
|
setDetailedSchedules(prev => ({ ...prev, [editingSchedule.id]: details }));
|
||||||
setSchedules(schedules.map(s => s.id === editingSchedule.id ? { ...s, time: details.time, status: details.status } : s));
|
setSchedules(schedules.map(s => s.id === editingSchedule.id ? { ...s, time: details.time, status: details.status } : s));
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user