Skip to content
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
1 change: 1 addition & 0 deletions src/app/router/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const router = createBrowserRouter([
{ path: "dev/splash", element: <SplashScreenPage /> },
{ path: "dev/click_place", element: <DevClickPlacePage /> },
{ path: "dev/SelectOption", element: <DevSelectOptionPage /> },
{ path: "dev/list", element: <PlaceListPage /> },
{ path: "dev/mypage", element: <MyPagePreview /> },
{ path: "login", element: <LoginPage /> },
{ path: "dev/course", element: <CoursePlannerPage skipRoomGuard /> },
Expand Down
2 changes: 1 addition & 1 deletion src/components/course-planner/RegionSelectionPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type RegionSelectionPanelProps = {

const cities = ["서울", "경기", "인천", "부산", "대구", "대전"];
const districtsByCity: Record<string, string[]> = {
서울: ["전체", "강남구", "강동구", "강북구", "강서구", "관악구"],
서울: ["전체", "강남구", "강동구", "강북구", "강서구", "관악구", "동대문구"],
경기: ["전체", "성남시", "수원시", "고양시", "용인시", "하남시"],
인천: ["전체", "남동구", "연수구", "부평구", "서구", "중구"],
부산: ["전체", "해운대구", "수영구", "부산진구", "동래구", "남구"],
Expand Down
97 changes: 51 additions & 46 deletions src/components/mypage/SavedPlaceItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,26 @@ import { SavedPlaceMemoEditor } from "./SavedPlaceMemoEditor";

type SavedPlaceItemProps = {
place: SavedPlace;
isMenuOpen: boolean;
isEditing: boolean;
memoDraft: string;
onToggleMenu: (id: string) => void;
onStartMemo: (place: SavedPlace) => void;
onChangeMemo: (value: string) => void;
onSaveMemo: () => void;
onClearMemo: () => void;
onDelete: (id: string) => void;
/** true면 마이페이지용 메뉴·메모 편집 없이 카드만 표시(목록 탭 등) */
readOnly?: boolean;
isMenuOpen?: boolean;
isEditing?: boolean;
memoDraft?: string;
onToggleMenu?: (id: string) => void;
onStartMemo?: (place: SavedPlace) => void;
onChangeMemo?: (value: string) => void;
onSaveMemo?: () => void;
onClearMemo?: () => void;
onDelete?: (id: string) => void;
onSelect: (place: SavedPlace) => void;
};

export function SavedPlaceItem({
place,
isMenuOpen,
isEditing,
memoDraft,
readOnly = false,
isMenuOpen = false,
isEditing = false,
memoDraft = "",
onToggleMenu,
onStartMemo,
onChangeMemo,
Expand All @@ -35,9 +38,9 @@ export function SavedPlaceItem({
}: SavedPlaceItemProps) {
const menuChromeRef = useRef<HTMLDivElement>(null);
const closeMenu = useCallback(() => {
onToggleMenu(place.id);
onToggleMenu?.(place.id);
}, [onToggleMenu, place.id]);
usePointerDownOutside(menuChromeRef, isMenuOpen, closeMenu);
usePointerDownOutside(menuChromeRef, !readOnly && isMenuOpen, closeMenu);

return (
<article className="rounded-lg border border-[#e8e8e8] bg-white px-3 py-3">
Expand All @@ -47,35 +50,37 @@ export function SavedPlaceItem({
<p className="mt-1 truncate text-[0.68rem] font-medium text-[#777777]">{place.address}</p>
</button>

<div ref={menuChromeRef} className="relative -mt-2 -mr-2 shrink-0 self-start">
<button
type="button"
onClick={() => onToggleMenu(place.id)}
className="touch-target-min flex shrink-0 items-center justify-center rounded-full text-[#222222]"
>
<MoreVertical className="size-4" aria-hidden />
<span className="sr-only">장소 메뉴 열기</span>
</button>
{!readOnly ? (
<div ref={menuChromeRef} className="relative -mt-2 -mr-2 shrink-0 self-start">
<button
type="button"
onClick={() => onToggleMenu?.(place.id)}
className="touch-target-min flex shrink-0 items-center justify-center rounded-full text-[#222222]"
>
<MoreVertical className="size-4" aria-hidden />
<span className="sr-only">장소 메뉴 열기</span>
</button>

{isMenuOpen ? (
<div className="absolute top-[calc(100%-6px)] right-2 z-10 w-24 overflow-hidden rounded-md border border-[#eaeaea] bg-white py-0.5 shadow-[0_2px_8px_rgb(0_0_0/_0.07)]">
<button
type="button"
onClick={() => onStartMemo(place)}
className="block w-full px-4 py-2.5 text-left text-xs font-medium text-[#595959] active:bg-[#f7f7f7]"
>
메모
</button>
<button
type="button"
onClick={() => onDelete(place.id)}
className="block w-full px-4 py-2.5 text-left text-xs font-medium text-[#595959] active:bg-[#f7f7f7]"
>
삭제
</button>
</div>
) : null}
</div>
{isMenuOpen ? (
<div className="absolute top-[calc(100%-6px)] right-2 z-10 w-24 overflow-hidden rounded-md border border-[#eaeaea] bg-white py-0.5 shadow-[0_2px_8px_rgb(0_0_0/_0.07)]">
<button
type="button"
onClick={() => onStartMemo?.(place)}
className="block w-full px-4 py-2.5 text-left text-xs font-medium text-[#595959] active:bg-[#f7f7f7]"
>
메모
</button>
<button
type="button"
onClick={() => onDelete?.(place.id)}
className="block w-full px-4 py-2.5 text-left text-xs font-medium text-[#595959] active:bg-[#f7f7f7]"
>
삭제
</button>
</div>
) : null}
</div>
) : null}
</div>

{place.memo && !isEditing ? (
Expand All @@ -84,12 +89,12 @@ export function SavedPlaceItem({
</p>
) : null}

{isEditing ? (
{!readOnly && isEditing ? (
<SavedPlaceMemoEditor
value={memoDraft}
onChange={onChangeMemo}
onSave={onSaveMemo}
onClear={onClearMemo}
onChange={onChangeMemo ?? (() => {})}
onSave={onSaveMemo ?? (() => {})}
onClear={onClearMemo ?? (() => {})}
/>
) : null}
</article>
Expand Down
4 changes: 4 additions & 0 deletions src/components/place-list/place-list-mock-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const PLACE_LIST_TEXT = {
emptySaved: "장소를 저장해 보세요!",
emptyFiltered: "해당하는 장소가 없습니다.",
};
Loading
Loading