Skip to content

Commit

Permalink
🎨 Fix conflict with develop
Browse files Browse the repository at this point in the history
  • Loading branch information
woobottle committed Feb 10, 2024
2 parents e2553a8 + aa1ce93 commit 24ca36e
Show file tree
Hide file tree
Showing 32 changed files with 697 additions and 190 deletions.
35 changes: 35 additions & 0 deletions src/apis/feed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import getQueryKey from '@/apis/getQueryKey';
import apiInstance from '@/apis/instance.api';
import { type FeedBaseType, type FeedItemType } from '@/apis/schema/feed';
import { useQuery, type UseQueryOptions } from '@tanstack/react-query';

type GetFeedMeResponse = Array<FeedItemType>;

type GetFeedByMemberIdResponse = Array<FeedBaseType>;

export const FEED_API = {
getFeedMe: async (): Promise<GetFeedMeResponse> => {
const { data } = await apiInstance.get('/feed/me');
return data;
},
getFeed: async (memberId: number): Promise<GetFeedByMemberIdResponse> => {
const { data } = await apiInstance.get(`/feed/${memberId}`);
return data;
},
};

export const useFeedMe = (options?: UseQueryOptions<GetFeedMeResponse>) => {
return useQuery<GetFeedMeResponse>({
...options,
queryKey: getQueryKey('feedMe'),
queryFn: FEED_API.getFeedMe,
});
};

export const useFeedByMemberId = (memberId: number, options?: UseQueryOptions<GetFeedByMemberIdResponse>) => {
return useQuery<GetFeedByMemberIdResponse>({
...options,
queryKey: getQueryKey('feed', { memberId }),
queryFn: () => FEED_API.getFeed(memberId),
});
};
5 changes: 4 additions & 1 deletion src/apis/getQueryKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ type QueryList = {
followList: {
targetId: number;
};

memberSocial: undefined;
searchNickname: {
nickname: string;
Expand All @@ -37,6 +36,10 @@ type QueryList = {
missionId: string;
};
finishedMissions: undefined;
feedMe: undefined;
feed: {
memberId: number;
};
};

/**
Expand Down
4 changes: 3 additions & 1 deletion src/apis/instance.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ const setInterceptors = (instance: AxiosInstance) => {
(error) => {
if (axios.isAxiosError(error)) {
if (error.response?.status === 401) {
window.location.href = ROUTER.AUTH.LOGIN;
if (typeof window !== 'undefined') {
window.location.href = ROUTER.AUTH.LOGIN;
}
}
}
return Promise.reject(error);
Expand Down
25 changes: 15 additions & 10 deletions src/apis/schema/feed.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { type MissionType } from '@/apis/schema/mission';
import { type RecordType } from '@/apis/schema/record';
export interface FeedItemType extends FeedBaseType {
remark?: string;
nickname: string;
profileImage?: string;
memberId: number;
}

/**
* @description
* @param mission - 미션
* @param records - 미션 기록
*/
export interface FeedType {
mission: MissionType;
records: RecordType[];
export interface FeedBaseType {
missionId: number;
recordId: number;
name: string;
recordImageUrl: string;
duration: number;
sinceDay: number;
startedAt: string;
finishedAt: string;
}
155 changes: 155 additions & 0 deletions src/app/feed/FeedItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
'use client';

import Link from 'next/link';
import { type FeedItemType } from '@/apis/schema/feed';
import HistoryThumbnail from '@/app/record/[id]/detail/HistoryThumbnail';
import Thumbnail from '@/components/Thumbnail/Thumbnail';
import { EVENT_LOG_CATEGORY, EVENT_LOG_NAME } from '@/constants/eventLog';
import { ROUTER } from '@/constants/router';
import { eventLogger } from '@/utils';
import { css } from '@styled-system/css';
import dayjs from 'dayjs';

function FeedItem({
sinceDay,
remark,
nickname,
memberId,
name,
profileImage,
recordImageUrl,
duration,
startedAt,
recordId,
}: FeedItemType) {
const handleClickFeedItem = () => {
eventLogger.logEvent(EVENT_LOG_CATEGORY.FEED, EVENT_LOG_NAME.FEED.CLICK_FEED);
};

const handleClickFollowProfile = () => {
eventLogger.logEvent(EVENT_LOG_CATEGORY.FEED, EVENT_LOG_NAME.FEED.CLICK_PROFILE);
};
return (
<li>
<Link href={ROUTER.PROFILE.DETAIL(memberId)} onClick={handleClickFollowProfile}>
<div className={profileWrapperCss}>
<Thumbnail size={'h24'} variant={'filled'} url={profileImage} />
<p>{nickname}</p>
</div>
</Link>
<Link href={ROUTER.RECORD.DETAIL.FOLLOW(recordId.toString())} onClick={handleClickFeedItem}>
<HistoryThumbnail imageUrl={recordImageUrl} missionDuration={duration} />
<div className={textWrapperCss}>
<p className={missionNameCss}>{name}</p>
{remark && <p className={remarkCss}>{remark}</p>}
<p className={captionCss}>
{sinceDay}일차 <div className={dotCss} /> {dayjs(startedAt).format('YYYY년 MM월 DD일')}
</p>
</div>
</Link>
</li>
);
}

export default FeedItem;

export const FeedSkeletonItem = () => {
return (
<li>
<div className={profileWrapperCss}>
<Thumbnail size={'h24'} variant={'filled'} url={null} />
<div
className={css(
{ ...skeletonTextCss },
{
width: '80px',
height: '20px',
},
)}
/>
</div>
<div className={profile} />
<div className={textWrapperCss}>
<div
className={css(
{ ...skeletonTextCss },
{
width: '80px',
height: '17px',
},
)}
/>
<div
className={css(
{ ...skeletonTextCss },
{
width: '130px',
height: '20px',
},
)}
/>
</div>
</li>
);
};

const profile = css({
animation: 'skeleton',
backgroundColor: 'bg.surface4',
width: '100%',
aspectRatio: '1 / 1',
position: 'relative',
borderRadius: '22px',
overflow: 'hidden',
maxWidth: 'calc(475px - 32px)',
maxHeight: 'calc(475px - 32px)',
});

const skeletonTextCss = {
animation: 'skeleton',
backgroundColor: 'bg.surface4',
borderRadius: '12px',
};

const textWrapperCss = css({
display: 'flex',
gap: '8px',
flexDirection: 'column',

padding: '20px 4px',
});

const missionNameCss = css({
textStyle: 'body5',
color: 'gray.gray600',
});

const remarkCss = css({
textStyle: 'body2',
color: 'text.primary',
});

const captionCss = css({
textStyle: 'body3',
color: 'text.tertiary',
display: 'flex',
gap: '5px',
alignItems: 'center',
});

const dotCss = css({
width: '2px',
height: '2px',
borderRadius: '50%',
backgroundColor: 'icon.tertiary',
});

const profileWrapperCss = css({
display: 'flex',
alignItems: 'center',
padding: '16px 12px',
textStyle: 'body3',
color: 'text.primary',
gap: '8px',
cursor: 'pointer',
});
32 changes: 32 additions & 0 deletions src/app/feed/FeedList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use client';
import { useFeedMe } from '@/apis/feed';
import FeedItem, { FeedSkeletonItem } from '@/app/feed/FeedItem';
import { css } from '@styled-system/css';

function FeedList() {
const { data } = useFeedMe();
if (!data)
return (
<ul className={feedListCss}>
<FeedSkeletonItem />
<FeedSkeletonItem />
</ul>
);

return (
<ul className={feedListCss}>
{data.map((feed) => (
<FeedItem key={feed.recordId} {...feed} />
))}
</ul>
);
}

export default FeedList;

const feedListCss = css({
padding: '0 16px 132px 16px',
display: 'flex',
flexDirection: 'column',
gap: '32px',
});
15 changes: 15 additions & 0 deletions src/app/feed/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import FeedList from '@/app/feed/FeedList';
import AppBar from '@/app/home/AppBar';
import AppBarBottom from '@/components/AppBarBottom/AppBarBottom';
import BottomDim from '@/components/BottomDim/BottomDim';

export default function FeedPage() {
return (
<>
<AppBar />
<FeedList />
<BottomDim />
<AppBarBottom />
</>
);
}
1 change: 1 addition & 0 deletions src/app/home/AppBar.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import Image from 'next/image';
import Link from 'next/link';
import Icon from '@/components/Icon';
Expand Down
6 changes: 5 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Suspense } from 'react';
import type { Metadata } from 'next';
import MonitoringInitializer from '@/components/MonitoringInitializer';
import SnackBarProvider from '@/components/SnackBar/SnackBarProvider';
Expand All @@ -11,6 +12,7 @@ import './globals.css';
export const metadata: Metadata = {
title: '10MM',
description: '10MM',
keywords: ['10mm', '10분만', '10분', '10MM', '10mm', '하루 10분', '10분 단위', '생환습관'],
openGraph: {
type: 'website',
url: 'https://www.10mm.today',
Expand Down Expand Up @@ -42,7 +44,9 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<MSWInitComponent />
<QueryProvider>
<SnackBarProvider>
<div className={css(containerCss)}>{children}</div>
<Suspense>
<div className={css(containerCss)}>{children}</div>
</Suspense>
</SnackBarProvider>
</QueryProvider>
</body>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { MISSION_CATEGORY_LABEL } from '@/constants/mission';

function MissionHistoryBannerApi({ missionId }: { missionId: string }) {
const { data } = useGetMissionDetailNoSuspense(missionId);
console.log('data: ', data);

if (!data) return <MissionHistorySkeleton />;

Expand Down
59 changes: 59 additions & 0 deletions src/app/mypage/FeedThumbnail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import Image from 'next/image';
import MissionDuration from '@/app/record/[id]/detail/MissionDuration';
import { css } from '@styled-system/css';

function FeedThumbnail({ imageUrl, missionDuration }: { imageUrl: string; missionDuration: number }) {
return (
<div className={historyThumbnailWrapperCss}>
<div className={dimmedCss} />
<Image className={imageCss} width={365} height={365} src={imageUrl} alt={'피드 이미지'} />
<div className={positionCss}>
<MissionDuration duration={missionDuration} type={'profileFeed'} />
</div>
</div>
);
}

export default FeedThumbnail;

const dimmedCss = css({
position: 'absolute',
width: '100%',
height: '60px',
background:
'linear-gradient(0deg, rgba(27, 34, 51, 0.00) 0%, rgba(27, 34, 51, 0.01) 10%, rgba(27, 34, 51, 0.03) 19.79%, rgba(27, 34, 51, 0.07) 34.79%, rgba(27, 34, 51, 0.13) 56.25%, rgba(27, 34, 51, 0.20) 77.92%, rgba(27, 34, 51, 0.30) 100%)',
top: 0,
left: 0,
right: 0,
bottom: 0,
zIndex: 1,
});

const historyThumbnailWrapperCss = css({
width: '100%',
aspectRatio: '1 / 1',
position: 'relative',
borderRadius: '16px',
overflow: 'hidden',
maxWidth: 'calc(475px - 32px)',
maxHeight: 'calc(475px - 32px)',

'@media (max-width: 475px)': {
maxWidth: 'calc(100vw - 32px)',
maxHeight: 'calc(100vw - 32px)',
},
});

const positionCss = css({
position: 'absolute',
top: '9px',
left: '8px',
zIndex: 2,
});

const imageCss = css({
width: '100%',
borderRadius: '22px',
objectFit: 'cover',
height: '100%',
});
Loading

0 comments on commit 24ca36e

Please sign in to comment.