Skip to content

✨ v1.2.0 - 상세페이지 북마크 #89

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

Merged
merged 9 commits into from
Sep 11, 2024
6 changes: 3 additions & 3 deletions public/icons/bookmark_black_empty.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/apis/apis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const getPosePick = (peopleCount: number) =>
publicApi.get<PosePickResponse>(`/pose/pick/${peopleCount}`);

export const getPoseDetail = (poseId: number) =>
publicApi.get<PoseDetailResponse>(`/pose/${poseId}`);
privateApi.get<PoseDetailResponse>(`/pose/${poseId}`);

export const getPoseTalk = () => publicApi.get<PoseTalkResponse>('/pose/talk');

Expand Down
3 changes: 2 additions & 1 deletion src/apis/config/privateApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ const privateApi: CustomInstance = axios.create({
privateApi.interceptors.response.use(
(response) => response.data,
(error) => {
const status = error.response.status;
const status = error.response?.status;
console.log('🚀 ~ status:', status);
if (status === ERROR_UNAUTHORIZED || status === ERROR_UNSUPPORTED_MEDIA_TYPE) {
alert('세션이 만료되었어요. 다시 로그인이 필요해요!');
removeClientCookie(COOKIE_ACCESS_TOKEN);
Expand Down
7 changes: 5 additions & 2 deletions src/apis/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import {
FilterTagsResponse,
MyposeCountResponse,
PoseDetailResponse,
PoseFeedContents,
PoseFeedResponse,
PosePickResponse,
Expand All @@ -22,8 +23,10 @@ import {
} from '.';
import { FilterState } from '@/hooks/useFilterState';

export const usePoseDetailQuery = (poseId: number) =>
useQuery(['poseId', poseId], () => getPoseDetail(poseId));
export const usePoseDetailQuery = (
{ poseId }: { poseId: number },
options?: UseQueryOptions<PoseDetailResponse>
) => useQuery<PoseDetailResponse>(['poseId', poseId], () => getPoseDetail(poseId), { ...options });
Copy link
Collaborator

@guesung guesung Sep 10, 2024

Choose a reason for hiding this comment

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

{...options}로 넘겨준 이유가 따로 있을까요 ?

options로 넘겨줘도 괜찮을 거 같아서요 !

Copy link
Member Author

Choose a reason for hiding this comment

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

헉 이전에 다른 속성을 함께 작성했다가 지웠는데 {}를 없애는걸 까먹고 있었네요 ...! 알려주셔서 감사합니다! 반영했습니다 :)


export const usePosePickQuery = (
peopleCount: number,
Expand Down
16 changes: 3 additions & 13 deletions src/apis/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export interface PoseInfo {
tagAttributes: string;
updatedAt: string;
bookmarkCheck: boolean;
width: number;
height: number;
width?: number;
height?: number;
Comment on lines +12 to +13
Copy link
Collaborator

Choose a reason for hiding this comment

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

width와 height는 선택 조건으로 바뀐건가요 ?

Copy link
Member Author

Choose a reason for hiding this comment

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

네! 백엔드에서 같은 포즈데이터에 대해 상세페이지에서는 width와 height를 보내주지 않고, 피드에서는 보내주는 형태라서 변경했습니다 :) 현재 백엔드에 요청드린 상태인데, 추후에 상세페이지에도 사이즈 정보를 같이 보내주게 바꿔주시면 그때 다시 바꿀 에정입니답

}

// 포즈피드
Expand Down Expand Up @@ -60,17 +60,7 @@ export interface PosePickResponse {
}

export interface PoseDetailResponse {
poseInfo: {
createdAt: string;
frameCount: number;
imageKey: string;
peopleCount: number;
poseId: number;
source: string;
sourceUrl: string;
tagAttributes: string;
updatedAt: string;
};
poseInfo: PoseInfo;
}

export interface PoseTalkResponse {
Expand Down
1 change: 1 addition & 0 deletions src/app/(Main)/MainFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function MainFooter({ children, grow = true }: MainFooterI) {
{isIOS() && <AppDownloadBanner />}
</div>
<div className="h-88" />
{isIOS() && <div className="h-62" />}
Copy link
Collaborator

Choose a reason for hiding this comment

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

iOS는 높이가 62px 더 필요한가요 ?

Copy link
Member Author

Choose a reason for hiding this comment

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

네네 하단에 앱 다운로드 배너가 있어서 해당 배너만큼의 높이가 필요합니다!

</>
);
}
16 changes: 5 additions & 11 deletions src/app/(Main)/mypose/MyposeTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { useState } from 'react';

import { useMyposeCountQuery } from '@/apis';
import { COOKIE_ACCESS_TOKEN } from '@/constants';
Expand Down Expand Up @@ -37,27 +36,22 @@ export default function MyposeTab() {
const path = usePathname();
const accesstoken = getClientCookie(COOKIE_ACCESS_TOKEN);

const [countData, setCountData] = useState({ uploadCount: 0, bookmarkCount: 0 });

const query = useMyposeCountQuery({
enabled: accesstoken !== '',
onSuccess: (data) => {
setCountData(data);
},
});
const { data: countData } = useMyposeCountQuery({ enabled: accesstoken !== '' });
const uploadCount = countData === undefined ? 0 : countData.uploadCount;
const bookmarkCount = countData === undefined ? 0 : countData.bookmarkCount;

return (
<div className="h-72 px-20 py-12">
<div className="flex h-full gap-4 rounded-8 bg-divider p-4 ">
<TabItem
key="upload"
title={`${Data.upload.title} ${countData.uploadCount}`}
title={`${Data.upload.title} ${uploadCount}`}
path={Data.upload.path}
current={path === Data.upload.path}
/>
<TabItem
key="bookmark"
title={`${Data.bookmark.title} ${countData.bookmarkCount}`}
title={`${Data.bookmark.title} ${bookmarkCount}`}
path={Data.bookmark.path}
current={path === Data.bookmark.path}
/>
Expand Down
12 changes: 10 additions & 2 deletions src/app/(Sub)/detail/[id]/DetailSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import TagButton from './TagButton';
import { usePoseDetailQuery } from '@/apis';
import { MainFooter } from '@/app/(Main)/MainFooter';
import { PrimaryButton } from '@/components/Button';
import BookmarkButton from '@/components/Feed/BookmarkButton';
import Header from '@/components/Header';
import { Popup } from '@/components/Modal';
import PoseImage from '@/components/Modal/PoseImage';
import { useOverlay } from '@/components/Overlay/useOverlay';
Expand All @@ -20,15 +22,16 @@ interface DetailSectionProps {
}

export default function DetailSection({ poseId }: DetailSectionProps) {
const { data } = usePoseDetailQuery(poseId);
const { data } = usePoseDetailQuery({ poseId });
const { shareKakao } = useKakaoShare();
const { open } = useOverlay();
const pathname = usePathname();

const [isRendered, setIsRendered] = useState(false);

if (!data) return null;
const { imageKey, tagAttributes, source, sourceUrl, peopleCount, frameCount } = data.poseInfo;
const { imageKey, tagAttributes, source, sourceUrl, peopleCount, frameCount, bookmarkCheck } =
data.poseInfo;

const handleShareLink = async () => {
await copy(BASE_SITE_URL + pathname);
Expand All @@ -41,6 +44,11 @@ export default function DetailSection({ poseId }: DetailSectionProps) {

return (
<div>
<Header
close={true}
menu={true}
additional={<BookmarkButton poseId={poseId} isMarked={bookmarkCheck} style="black" />}
/>
{source && <Source source={source} url={sourceUrl} />}
<div className="block">
{isRendered || <div className="h-400 w-screen bg-sub-white" />}
Expand Down
56 changes: 20 additions & 36 deletions src/app/(Sub)/detail/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,33 @@
import { QueryAsyncBoundary } from '@suspensive/react-query';
import { Metadata } from 'next';
// import { Metadata } from 'next';

import DetailSection from './DetailSection';
import { getPoseDetail } from '@/apis';
import { RejectedFallback } from '@/components/ErrorBoundary';
import Header from '@/components/Header';
import { Loading } from '@/components/Loading';
import { PageAnimation } from '@/components/PageAnimation';
import { HydrationProvider } from '@/components/Provider';
import { OPEN_GRAPH } from '@/constants';
// import { getPoseDetail } from '@/apis';
// import { OPEN_GRAPH } from '@/constants';

export async function generateMetadata({ params }: { params: { id: string } }): Promise<Metadata> {
const id = parseInt(params.id);
const {
poseInfo: { peopleCount, frameCount, tagAttributes },
} = await getPoseDetail(id);
const description = `${tagAttributes},${frameCount}컷,${peopleCount}인 포즈추천`;
// 상세페이지 메타데이터 생성
// export async function generateMetadata({ params }: { params: { id: string } }): Promise<Metadata> {
// const id = parseInt(params.id);
// const {
// poseInfo: { peopleCount, frameCount, tagAttributes },
// } = await getPoseDetail(id);
// const description = `${tagAttributes},${frameCount}컷,${peopleCount}인 포즈추천`;
Copy link
Collaborator

Choose a reason for hiding this comment

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

머지될 PR에는 주석이 없는 게 좋을 거 같아요.

나중에 제거될 코드인가요, 혹은 수정할 코드인가요 ?

Copy link
Member Author

Choose a reason for hiding this comment

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

기존에 있던 코드인데 해당 기능이 완성되기 전까지는 작동하지 않는 부분이라 빌드할 때 경고가 떠서 주석처리하였습니다ㅠㅠ 메인에 머지할때는 지우겠습니답


return {
description,
openGraph: {
title: OPEN_GRAPH.detail.title,
description: OPEN_GRAPH.detail.description,
images: [OPEN_GRAPH.detail.image],
},
};
}
// return {
// description,
// openGraph: {
// title: OPEN_GRAPH.detail.title,
// description: OPEN_GRAPH.detail.description,
// images: [OPEN_GRAPH.detail.image],
// },
// };
// }

export default function DetailPage({ params }: { params: { id: number } }) {
const { id } = params;

return (
<div>
{/* <Header close={true} menu={true} additional={<BookmarkButton style='black'/>} /> */}
<Header close={true} menu={true} />
<QueryAsyncBoundary
rejectedFallback={RejectedFallback}
pendingFallback={<Loading className="h-[calc(100dvh-400px)]" />}
>
<PageAnimation>
<HydrationProvider queryKey={['poseId', id]} queryFn={() => getPoseDetail(id)}>
<DetailSection poseId={id} />
</HydrationProvider>
</PageAnimation>
</QueryAsyncBoundary>
<DetailSection poseId={id} />
</div>
);
}
1 change: 0 additions & 1 deletion src/components/Feed/Photo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ interface PhotoI {
export default function Photo({ data }: PhotoI) {
const { imageKey, source, bookmarkCheck, poseId, width, height } = data;
const [loaded, setLoaded] = useState(false);
console.log(width / height);

return (
<div className="relative mb-16 inline-block w-full rounded-8">
Expand Down
8 changes: 5 additions & 3 deletions src/utils/cookie.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ export const setClientCookie = (key: string, value: string, options?: { expires?
};

export const getClientCookie = (key: string) => {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${key}=`);
if (typeof window !== 'undefined') {
Copy link
Collaborator

Choose a reason for hiding this comment

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

이미 만들어둔 isServer를 활용해도 좋을 것 같아요.

if (isServer) {

Copy link
Member Author

Choose a reason for hiding this comment

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

있는지 몰랐네요..! 반영하겠습니다아!!

const value = `; ${document.cookie}`;
const parts = value.split(`; ${key}=`);

return parts.pop()?.split(';').shift();
return parts.pop()?.split(';').shift();
}
};

export const removeClientCookie = (key: string) => {
Expand Down