Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

지도 삭제/수정, 장소 삭제, 지도 상세보기 UI, 장소 상세보기 UI 구현 #140

Merged
merged 17 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="/pin.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" as="style" crossorigin
href="https://cdn.jsdelivr.net/gh/orioncactus/[email protected]/dist/web/static/pretendard.min.css" />
Expand Down
File renamed without changes
21 changes: 20 additions & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,26 @@ import MapCreateCoursePage from '@/pages/MapCreation/MapCreateCoursePage';
import PlaceCreatePage from '@/pages/PlaceCreation/PlaceCreatePage';
import LayoutCreate from '@/LayoutCreate';
import NotFound from './pages/NotFound';
import MapDetailPage from './pages/MapDetail/MapDetailPage';
import { Suspense } from 'react';
import MapEditPage from './pages/MapEditPage';

function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Homepage />} />
<Route path="/map" element={<LayoutCreate />}></Route>

<Route
path="/map"
element={
<Suspense fallback={<div>Loading...</div>}>
<LayoutCreate />
</Suspense>
}
>
<Route path=":id" element={<MapDetailPage />} />
</Route>

<Route path="/create" element={<LayoutCreate />}>
<Route index element={<MapPage />} />
Expand All @@ -21,6 +34,12 @@ function App() {
<Route path="map/:id/:placeId" element={<PlaceCreatePage />} />
<Route path="course/:id/:placeId" element={<PlaceCreatePage />} />
</Route>
<Route path="/edit" element={<LayoutCreate />}>
<Route path="map/:id" element={<MapEditPage />} />
<Route path="course/:id" element={<MapCreateCoursePage />} />
<Route path="map/:id/:placeId" element={<PlaceCreatePage />} />
<Route path="course/:id/:placeId" element={<PlaceCreatePage />} />
</Route>
<Route path="*" element={<NotFound />} />
</Routes>
</Router>
Expand Down
61 changes: 61 additions & 0 deletions frontend/src/api/map/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ import { END_POINTS } from '@/constants/api';
type MapResponse = {
id: number;
};
type EditInfoResponse = {
id: number;
title: string;
description: string;
};
type EditVisResponse = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3. public - private 변경인가요?
줄이지 않는 편이 이해하기 좋아 보여요

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 수정하겠습니다

id: number;
isPublic: boolean;
};

export const getMap = async (mapId: number) => {
const { data } = await axiosInstance.get<Map>(END_POINTS.MAP(mapId));
Expand Down Expand Up @@ -37,3 +46,55 @@ export const getCourseList = async () => {
const { data } = await axiosInstance.get<MapList>(END_POINTS.COURSES);
return data;
};

export const editMapInfo = async ({
title,
description,
mapId,
}: {
title: string;
description: string;
mapId: number;
}) => {
const { data } = await axiosInstance.patch<EditInfoResponse>(
END_POINTS.EDIT_MAP_INFO(mapId),
{
title,
description,
},
);
return data;
};

export const editMapVisibility = async ({
mapId,
isPublic,
}: {
mapId: number;
isPublic: boolean;
}) => {
const { data } = await axiosInstance.patch<EditVisResponse>(
END_POINTS.EDIT_MAP_VISIBILITY(mapId),
{
isPublic,
},
);
return data;
};

export const editMap = async (data: BaseMap & { mapId: number }) => {
const [infoResponse, visibilityResponse] = await Promise.all([
editMapInfo({
title: data.title,
description: data.description,
mapId: data.mapId,
}),
editMapVisibility({ mapId: data.mapId, isPublic: data.isPublic }),
]);
return { ...infoResponse, ...visibilityResponse };
};

export const deleteMap = async (mapId: number) => {
const { data } = await axiosInstance.delete(END_POINTS.MAP(mapId));
return data;
};
33 changes: 23 additions & 10 deletions frontend/src/api/place/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,8 @@ export const getPlace = async (queryString: string, pageParam: number) => {
page: pageParam,
},
});
const Data = data.map((place) => {
return {
...place,
location: {
lat: Number(place.location.lat),
lng: Number(place.location.lng),
},
};
});
return Data;

return data;
};

type AddPlaceParams = {
Expand All @@ -45,3 +37,24 @@ export const addPlaceToCourse = async ({
);
return { ...data, id };
};

type Response = {
code?: number;
message?: string;
};
type DeletePlaceResponse = {
deletedId: number;
} & Response;

export const deletePlaceToMap = async ({
id,
placeId,
}: {
id: number;
placeId: number;
}) => {
const { data } = await axiosInstance.delete<DeletePlaceResponse>(
END_POINTS.DELETE_PLACE_TO_MAP(id, placeId),
);
return { placeId: data.deletedId, id };
};
51 changes: 51 additions & 0 deletions frontend/src/components/Form/EditMapForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import BaseWrapper from '../common/BaseWrapper';
import FormWrapper from './FormWrapper';
import { BaseMap, Map } from '@/types';
import { useEditMapMutation } from '@/hooks/api/useEditMapMutation';
import { useMapForm } from '@/hooks/useMapForm';

import PlaceListPanel from '../Place/PlaceListPanel';
import { useNavigate } from 'react-router-dom';

type EditMapFormProps = {
mapData: Map;
};

const EditMapForm = ({ mapData }: EditMapFormProps) => {
const editMapMutation = useEditMapMutation();
const navigate = useNavigate();
const initialMapData: BaseMap = {
title: mapData.title,
description: mapData.description,
isPublic: mapData.isPublic,
thumbnailUrl: mapData.thumbnailUrl,
mode: 'MAP',
};

const { mapInfo, updateMapInfo, isMapInfoValid } = useMapForm(initialMapData);

const onSubmitHandler = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
editMapMutation.mutate({ mapId: mapData.id, ...mapInfo });
navigate(`/map/${mapData.id}`);
};
console.log(mapData);
return (
<>
<BaseWrapper position="" top="" left="" className="w-1/2">
<FormWrapper
header="지도 수정"
mapInfo={mapInfo}
updateMapInfo={updateMapInfo}
isMapInfoValid={isMapInfoValid}
onSubmitHandler={onSubmitHandler}
isEditMode={true}
/>
</BaseWrapper>
<PlaceListPanel places={mapData.places} />
</>
);
};

export default EditMapForm;
40 changes: 23 additions & 17 deletions frontend/src/components/Form/FormWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type FormWrapperProps = {
updateMapInfo: <K extends keyof BaseMap>(field: K, value: BaseMap[K]) => void;
isMapInfoValid: boolean;
onSubmitHandler: (e: React.FormEvent<HTMLFormElement>) => void;
isEditMode?: boolean;
};

const FormWrapper = ({
Expand All @@ -19,6 +20,7 @@ const FormWrapper = ({
updateMapInfo,
isMapInfoValid,
onSubmitHandler,
isEditMode = false,
}: FormWrapperProps) => {
const { title, description, isPublic, mode, thumbnailUrl } = mapInfo;

Expand All @@ -27,16 +29,18 @@ const FormWrapper = ({
<DashBoardHeader title={header} />
<div className="flex h-[200px] gap-4 p-4">
<ImageUploader />
<select
value={mode}
onChange={(e) =>
updateMapInfo('mode', e.target.value as CreateMapType)
}
className="h-[41px] w-[144px] rounded border px-3 py-2"
>
<option value="map">지도</option>
<option value="course">코스</option>
</select>
{!isEditMode && (
<select
value={mode}
onChange={(e) =>
updateMapInfo('mode', e.target.value as CreateMapType)
}
className="h-[41px] w-[144px] rounded border px-3 py-2"
>
<option value="map">지도</option>
<option value="course">코스</option>
</select>
)}
</div>

<form
Expand Down Expand Up @@ -71,13 +75,15 @@ const FormWrapper = ({
}
/>
</Box>
<button
type="submit"
className={`w-full rounded text-white ${isMapInfoValid ? 'bg-c_bg_blue' : 'bg-gray-400'}`}
disabled={!isMapInfoValid}
>
완료
</button>
<Box className="bottom-0">
<button
type="submit"
className={`h-14 w-full rounded-md ${isMapInfoValid ? 'bg-c_bg_blue' : 'bg-c_button_gray'} p-4 text-xl font-semibold text-white`}
disabled={!isMapInfoValid}
>
완료
</button>
</Box>
</form>
</div>
);
Expand Down
23 changes: 23 additions & 0 deletions frontend/src/components/Map/DeleteMapButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import useDeleteMapMutation from '@/hooks/api/useDeleteMapMutation';

/**todo : 삭제 모달 구현*/

type DeleteMapButtonProps = {
mapId: number;
text: string;
};

const DeleteMapButton = ({ mapId, text }: DeleteMapButtonProps) => {
const deleteMutation = useDeleteMapMutation();

const onClick = () => {
deleteMutation.mutate(mapId);
};
return (
<button onClick={onClick} className="text-xs text-c_placeholder_gray">
{text}
</button>
);
};

export default DeleteMapButton;
21 changes: 21 additions & 0 deletions frontend/src/components/Map/EditMapButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useNavigate } from 'react-router-dom';

type EditMapButtonProps = {
mapId: number;
text: string;
};

const EditMapButton = ({ mapId, text }: EditMapButtonProps) => {
const navigate = useNavigate();

const onClick = () => {
navigate(`/edit/map/${mapId}`);
};
return (
<button onClick={onClick} className="text-xs text-c_placeholder_gray">
{text}
</button>
);
};

export default EditMapButton;
Loading
Loading