-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
32 changed files
with
697 additions
and
190 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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), | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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', | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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', | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 /> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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%', | ||
}); |
Oops, something went wrong.