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
4 changes: 0 additions & 4 deletions src/app/router/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@ import EditPlacePage from "@/pages/EditPlacePage";
import EntryPage from "@/pages/EntryPage";
import PrivacyPolicyPage from "@/pages/legal/PrivacyPolicyPage";
import TermsOfServicePage from "@/pages/legal/TermsOfServicePage";
import LinkPlaceSelectPage from "@/pages/LinkPlaceSelectPage";
import LoginPage from "@/pages/LoginPage";
import { mapHomeLoader } from "@/pages/map/map-home-loader";
import NicknamePage from "@/pages/onboarding/NicknamePage";
import TermsAgreementPage from "@/pages/onboarding/TermsAgreementPage";
import RoomLinkCandidatesPage from "@/pages/rooms/RoomLinkCandidatesPage";
import RoomPlaceFromLinkPage from "@/pages/rooms/RoomPlaceFromLinkPage";
import RoomPlaceSearchPage from "@/pages/rooms/RoomPlaceSearchPage";
import CoursePlannerPagePreview from "@/pages/tabs/CoursePlannerPage";

const MapHomePage = lazy(() => import("@/pages/MapHomePage"));
const RoomMainPage = lazy(() => import("@/pages/room/RoomMainPage"));
Expand All @@ -33,12 +31,10 @@ export const router = createBrowserRouter([
element: <RootLayout />,
children: [
{ index: true, element: <EntryPage /> },
{ path: "places/register/from-link", element: <LinkPlaceSelectPage /> },
{ path: "places/edit", element: <EditPlacePage /> },
{ path: "login", element: <LoginPage /> },
{ path: "privacys", element: <PrivacyPolicyPage /> },
{ path: "terms", element: <TermsOfServicePage /> },
{ path: "dev/course", element: <CoursePlannerPagePreview skipRoomGuard /> },
{
path: "auth/callback",
element: <AuthCallbackPage />,
Expand Down
5 changes: 1 addition & 4 deletions src/components/mypage/MyPlaceSummaryCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,7 @@ export function MyPlaceSummaryCard({
<MyPlaceSummarySkeletonRows />
) : hasPlaces ? (
recentPlaces.slice(0, 2).map((place) => (
<div
key={place.id}
className="flex min-w-0 items-center gap-1.5 py-2"
>
<div key={place.id} className="flex min-w-0 items-center gap-1.5 py-2">
<PlaceCategoryIconChip
place={{ category: place.category, categoryName: place.categoryName }}
className="size-4"
Expand Down
12 changes: 5 additions & 7 deletions src/components/mypage/MySavedCoursesPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AlertCircle, Check, ChevronDown, Pin, User } from "lucide-react";
import { AlertCircle, Check, ChevronDown, Pin } from "lucide-react";
import { lazy, Suspense, useCallback, useMemo, useRef, useState } from "react";

import { LIST_TOP_BAR_AFTER_TITLE_CLASS, ListTopBar } from "@/components/common/ListTopBar";
Expand All @@ -18,10 +18,11 @@ import {
savedCourseToPlannerStops,
} from "@/components/mypage/saved-course-planner-map";
import { SavedCourseCard } from "@/components/mypage/SavedCourseCard";
import { RoomAvatar } from "@/components/room/RoomAvatar";
import { useRoomsQuery } from "@/features/room";
import { usePointerDownOutside } from "@/hooks/use-pointer-down-outside";
import { cn } from "@/lib/utils";
import { MAP_INITIAL_CENTER } from "@/shared/mocks/place-mocks";
import { MAP_INITIAL_CENTER } from "@/shared/config/map";
import type { CourseSavePayload, SavedCourse } from "@/shared/types/course";
import type { SavedPlace } from "@/shared/types/my-page";
import { usePlaceDetailStore } from "@/store/place-detail-store";
Expand Down Expand Up @@ -315,11 +316,8 @@ export function MySavedCoursesPage({
className="sr-only"
aria-checked={checked}
/>
<span
className="bg-muted text-muted-foreground col-start-1 row-span-2 row-start-1 flex size-9 shrink-0 items-center justify-center self-center rounded-full"
aria-hidden
>
<User className="size-4.5" strokeWidth={2} />
<span className="col-start-1 row-span-2 row-start-1 size-9 shrink-0 self-center overflow-hidden rounded-full">
<RoomAvatar avatarSeed={room.avatarSeed} size="100%" />
</span>

<div className="text-foreground col-start-2 row-start-1 min-w-0 text-xs leading-tight font-semibold">
Expand Down
68 changes: 59 additions & 9 deletions src/components/mypage/SavedCourseCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { ChevronRight, Heart, UsersRound } from "lucide-react";
import { ChevronRight, Heart, User, UsersRound } from "lucide-react";
import { useCallback, useState } from "react";

import { RoomAvatar } from "@/components/room/RoomAvatar";
import { cn } from "@/lib/utils";
import type { SavedCourse } from "@/shared/types/course";

Expand All @@ -12,6 +14,15 @@ type SavedCourseCardProps = {
export function SavedCourseCard({ course, onSelect, className }: SavedCourseCardProps) {
const isFriendCourse = course.badgeLabel === "친구";
const Icon = isFriendCourse ? UsersRound : Heart;
const saverNickname = course.savedByNickname?.trim() ?? "";
const roomName = course.savedFromRoomName?.trim() ?? "";
const roomAvatarSeed = course.savedFromRoomAvatarSeed?.trim() ?? "";
const hasSaver = saverNickname.length > 0 || Boolean(course.savedByProfileImageUrl?.trim());
const metadata = saverNickname
? `${saverNickname}님이 저장 · ${course.executedAtLabel}`
: roomName
? `${roomName}에서 저장 · ${course.executedAtLabel}`
: course.executedAtLabel;

return (
<button
Expand All @@ -23,24 +34,63 @@ export function SavedCourseCard({ course, onSelect, className }: SavedCourseCard
className,
)}
>
<span className="bg-brand-coral-soft text-primary flex size-9 shrink-0 items-center justify-center rounded-full">
{isFriendCourse ? (
<span className="text-[0.65rem] font-semibold">친구</span>
) : (
<Icon className="size-3.5 fill-current" aria-hidden />
)}
</span>
{hasSaver ? (
<SaverAvatar imageUrl={course.savedByProfileImageUrl} />
) : roomAvatarSeed ? (
<span className="size-9 shrink-0 overflow-hidden rounded-full">
<RoomAvatar avatarSeed={roomAvatarSeed} size="100%" />
</span>
) : (
<span className="bg-brand-coral-soft text-primary flex size-9 shrink-0 items-center justify-center rounded-full">
{isFriendCourse ? (
<span className="text-[0.65rem] font-semibold">친구</span>
) : (
<Icon className="size-3.5 fill-current" aria-hidden />
)}
</span>
)}

<span className="min-w-0 flex-1">
<span className="text-foreground block truncate text-[0.8rem] font-semibold">
{course.title}
</span>
<span className="text-muted-foreground mt-0.5 block truncate text-[0.66rem] font-medium">
{course.executedAtLabel}
{metadata}
</span>
</span>

<ChevronRight className="text-muted-foreground/55 size-4 shrink-0" aria-hidden />
</button>
);
}

function SaverAvatar({ imageUrl }: { imageUrl?: string | null }) {
const url = imageUrl?.trim() ?? "";
const [failedUrl, setFailedUrl] = useState<string | null>(null);
const showImage = Boolean(url) && failedUrl !== url;

const handleImageError = useCallback(() => {
setFailedUrl(url);
}, [url]);

if (showImage) {
return (
<img
src={url}
alt=""
className="size-9 shrink-0 rounded-full object-cover"
referrerPolicy="no-referrer"
onError={handleImageError}
/>
);
}

return (
<span
className="bg-muted text-muted-foreground flex size-9 shrink-0 items-center justify-center rounded-full"
aria-hidden
>
<User className="size-4.5" strokeWidth={2} />
</span>
);
}
2 changes: 1 addition & 1 deletion src/components/mypage/map-places-from-my-saved.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MAP_INITIAL_CENTER } from "@/shared/mocks/place-mocks";
import { MAP_INITIAL_CENTER } from "@/shared/config/map";
import type { MapCoordinate, SavedPlace as MapSavedPlace } from "@/shared/types/map-home";
import type { SavedPlace as MySavedPlace } from "@/shared/types/my-page";

Expand Down
26 changes: 0 additions & 26 deletions src/components/mypage/saved-course-planner-map.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { MOCK_LEGACY_PLACE_ID_TO_ROOM_PLACE_ID } from "@/shared/mocks/course-mocks";
import { SAVED_PLACE_MOCKS } from "@/shared/mocks/place-mocks";
import type { CourseStop as PlannerCourseStop, SavedCourse } from "@/shared/types/course";
import type { SavedPlace as MapSavedPlace } from "@/shared/types/map-home";
import type { SavedPlace } from "@/shared/types/my-page";
Expand All @@ -12,11 +10,6 @@ function resolveRoomPlaceId(
return stop.roomPlaceId;
}

const mapped = MOCK_LEGACY_PLACE_ID_TO_ROOM_PLACE_ID[stop.id];
if (mapped != null) {
return mapped;
}

const fromMy = savedPlaces.find((p) => p.name === stop.name || p.address === stop.address);
if (fromMy?.roomPlaceId != null) {
return fromMy.roomPlaceId;
Expand All @@ -27,11 +20,6 @@ function resolveRoomPlaceId(
return parsedFromMy;
}

const fromMap = SAVED_PLACE_MOCKS.find((p) => p.name === stop.name || p.address === stop.address);
if (fromMap?.roomPlaceId != null) {
return fromMap.roomPlaceId;
}

const parsedStopId = Number(stop.id);
return Number.isInteger(parsedStopId) ? parsedStopId : null;
}
Expand Down Expand Up @@ -111,20 +99,6 @@ export function mapPlacesFromSavedCourses(
result.push(fromApi);
continue;
}

const mock = SAVED_PLACE_MOCKS.find(
(place) =>
place.roomPlaceId === roomPlaceId ||
MOCK_LEGACY_PLACE_ID_TO_ROOM_PLACE_ID[place.id] === roomPlaceId,
);
if (mock) {
seen.add(roomPlaceId);
result.push({
...mock,
id: String(roomPlaceId),
roomPlaceId,
});
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/place-flow/PlaceSearchMapSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import {
PROMPT_FLOW_LIST_TOP_BORDER_CLASS,
} from "@/features/place-flow/prompt-flow-layout";
import { cn } from "@/lib/utils";
import { MAP_INITIAL_CENTER } from "@/shared/config/map";
import type { LinkSourceType } from "@/shared/lib/link-source-type";
import { MAP_INITIAL_CENTER } from "@/shared/mocks/place-mocks";
import type { MapCoordinate, SavedPlace } from "@/shared/types/map-home";

const KAKAO_MAP_APP_KEY = import.meta.env.VITE_KAKAO_MAP_APP_KEY;
Expand Down
Loading
Loading