Skip to content

Commit

Permalink
feat(bottle): sent bottles page
Browse files Browse the repository at this point in the history
  • Loading branch information
stakbucks committed Oct 3, 2024
1 parent 4ef3bde commit c962224
Show file tree
Hide file tree
Showing 13 changed files with 157 additions and 45 deletions.
13 changes: 5 additions & 8 deletions apps/bottle/src/app/bottles/recommendations/Recommendations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,16 @@ export function Recommendations() {
return (
<>
<ProfileLayout.Title>{`${currentUser.name}님에게\n추천하는 분들이에요!`}</ProfileLayout.Title>
<ProfileLayout.Subtitle>시간이 지나면 새로운 분들을 추천해 드려요</ProfileLayout.Subtitle>
<ProfileLayout.Subtitle style={{ marginTop: spacings.sm }}>
시간이 지나면 새로운 분들을 추천해 드려요
</ProfileLayout.Subtitle>
<section style={{ marginTop: spacings.xxl, display: 'flex', flexDirection: 'column', gap: spacings.md }}>
{recommendationBottles.randomBottles.map(bottle => (
<BottleCard key={bottle.id}>
<BottleCard.TimeTag>{bottle.expiredAt}</BottleCard.TimeTag>
<BottleCard.Introduction>
{
// FIXME
'어떤 날은 아침에 눈이 번쩍 떠지는 게 힘이 펄펄 나는 것 같은가 하면 또 어떤 날은 몸이 진흙으로 만들어진 것 같은 때가 있습니다...'
}
</BottleCard.Introduction>
<BottleCard.Introduction>{bottle.introduction[0]?.answer}</BottleCard.Introduction>
<BottleCard.UserInformation
{...pick(bottle, ['userName', 'age', 'mbti', 'userImageUrl', 'likeEmoji', 'lastActivatedAt'])}
{...pick(bottle, ['userName', 'age', 'mbti', 'userImageUrl', 'lastActivatedAt'])}
/>
</BottleCard>
))}
Expand Down
15 changes: 9 additions & 6 deletions apps/bottle/src/app/bottles/recommendations/page.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { ProfileLayout } from '@/components/profile/layout';
import { getServerSideTokens } from '@/features/server/serverSideTokens';
import { ServerFetchBoundary } from '@/store/query/ServerFetchBoundary';
import { bottlesQueryOptions } from '@/store/query/useBottlesQuery';
import { recommendationBottlesQueryOptions } from '@/store/query/useRecommendationBottlesQuery';
import { userInfoQueryOptions } from '@/store/query/useUserInfoQuery';
import { Suspense } from 'react';
import { HeaderArea } from './HeaderArea';
import { Recommendations } from './Recommendations';

export default function RecommendationsPage() {
const tokens = getServerSideTokens();
const serverFetchOptions = [userInfoQueryOptions(tokens), bottlesQueryOptions(tokens)];
const serverFetchOptions = [userInfoQueryOptions(tokens), recommendationBottlesQueryOptions(tokens)];

return (
<ProfileLayout>
<ProfileLayout hasCTAButton={false}>
<HeaderArea />
<ServerFetchBoundary fetchOptions={serverFetchOptions}>
<Recommendations />
</ServerFetchBoundary>
<Suspense>
<ServerFetchBoundary fetchOptions={serverFetchOptions}>
<Recommendations />
</ServerFetchBoundary>
</Suspense>
</ProfileLayout>
);
}
16 changes: 16 additions & 0 deletions apps/bottle/src/app/bottles/sents/HeaderArea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use client';

import { Header } from '@/components/common/header';
import { AppBridgeMessageType, useAppBridge } from '@/features/app-bridge';

export function HeaderArea() {
const { send } = useAppBridge();

return (
<Header
onGoBack={() => {
send({ type: AppBridgeMessageType.WEB_VIEW_CLOSE });
}}
/>
);
}
35 changes: 35 additions & 0 deletions apps/bottle/src/app/bottles/sents/Sents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use client';

import { BottleCard } from '@/components/common/bottle-card';
import { ProfileLayout } from '@/components/profile/layout';
import { useSentBottlesQuery } from '@/store/query/useSentBottlesQuery';
import { useUserInfoQuery } from '@/store/query/useUserInfoQuery';
import { spacings } from '@bottlesteam/ui';
import { pick } from 'es-toolkit';

export function Sents() {
const { data: currentUser } = useUserInfoQuery();
const { data: sentBottlesData } = useSentBottlesQuery();

console.log('DATA', sentBottlesData.sentBottles);

return (
<>
<ProfileLayout.Title>{`${currentUser.name}님을 마음에\n들어한 분들이에요`}</ProfileLayout.Title>
<ProfileLayout.Subtitle style={{ marginTop: spacings.sm }}>
시간 내에 보틀을 열지 않으면 사라져요
</ProfileLayout.Subtitle>
<section style={{ marginTop: spacings.xxl, display: 'flex', flexDirection: 'column', gap: spacings.md }}>
{sentBottlesData.sentBottles.map(bottle => (
<BottleCard key={bottle.id}>
<BottleCard.TimeTag>{bottle.expiredAt}</BottleCard.TimeTag>
<BottleCard.Introduction>{bottle.introduction[0]?.answer}</BottleCard.Introduction>
<BottleCard.UserInformation
{...pick(bottle, ['userName', 'age', 'mbti', 'userImageUrl', 'likeEmoji', 'lastActivatedAt'])}
/>
</BottleCard>
))}
</section>
</>
);
}
24 changes: 24 additions & 0 deletions apps/bottle/src/app/bottles/sents/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ProfileLayout } from '@/components/profile/layout';
import { getServerSideTokens } from '@/features/server/serverSideTokens';
import { ServerFetchBoundary } from '@/store/query/ServerFetchBoundary';
import { sentBottlesQueryOptions } from '@/store/query/useSentBottlesQuery';
import { userInfoQueryOptions } from '@/store/query/useUserInfoQuery';
import { Suspense } from 'react';
import { HeaderArea } from './HeaderArea';
import { Sents } from './Sents';

export default function SentBottlesPage() {
const tokens = getServerSideTokens();
const serverFetchOptions = [userInfoQueryOptions(tokens), sentBottlesQueryOptions(tokens)];

return (
<ProfileLayout hasCTAButton={false}>
<HeaderArea />
<Suspense>
<ServerFetchBoundary fetchOptions={serverFetchOptions}>
<Sents />
</ServerFetchBoundary>
</Suspense>
</ProfileLayout>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@ import { introductionBoxStyle } from './bottleCardstyle.css';
export function IntroductionBox({ children }: { children: ReactNode }) {
return (
<div className={introductionBoxStyle}>
<Paragraph color="neutral900" typography="bo">
<Paragraph
color="neutral900"
typography="bo"
style={{
width: '264px',
overflow: 'hidden',
WebkitLineClamp: 3,
textOverflow: 'ellipsis',
}}
>
{children}
</Paragraph>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import {
} from './bottleCardstyle.css';

type Props =
| Pick<RecommendationBottlePreview, 'userName' | 'age' | 'mbti' | 'userImageUrl' | 'likeEmoji' | 'lastActivatedAt'>
| Pick<SentBottlePreview, 'userName' | 'age' | 'mbti' | 'userImageUrl' | 'lastActivatedAt'>;
| Pick<RecommendationBottlePreview, 'userName' | 'age' | 'mbti' | 'userImageUrl' | 'lastActivatedAt'>
| Pick<SentBottlePreview, 'userName' | 'age' | 'mbti' | 'userImageUrl' | 'lastActivatedAt' | 'likeEmoji'>;

export function UserInformationArea({ userName, userImageUrl, age, mbti, lastActivatedAt, ...rest }: Props) {
console.log('????', rest.likeEmoji, rest);
return (
<div className={userInformationAreaStyle}>
<div className={userPreviewStyle}>
Expand Down Expand Up @@ -42,8 +43,11 @@ export function UserInformationArea({ userName, userImageUrl, age, mbti, lastAct
</div>
<div className={avatarAreaStyle}>
<Avatar size="sm" src={userImageUrl} />
{'likeEmjoi' in rest && (
<Paragraph style={{ position: 'absolute', bottom: -2, left: -8 }}>{rest.likeEmjoi as string}</Paragraph>
{Object.hasOwn(rest, 'likeEmoji') && (
<Paragraph typography="t2" style={{ position: 'absolute', bottom: -2, left: -8 }}>
{(rest as any).likeEmoji as string}
{/* {'😘'} */}
</Paragraph>
)}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@ export const timeTagStyle = style({

export const introductionBoxStyle = style({
width: '100%',
height: 'auto',
height: '95px',
backgroundColor: colors.neutral100,
padding: spacings.md,
borderRadius: radius.md,
maxLines: 3,
});

export const userInformationAreaStyle = style({
Expand Down
5 changes: 3 additions & 2 deletions apps/bottle/src/components/profile/layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { containerStyle } from './profileLayoutStyle.css';

interface Props {
children: ReactNode;
hasCTAButton?: boolean;
}

function ProfileContainer({ children }: Props) {
return <div className={containerStyle}>{children}</div>;
function ProfileContainer({ children, hasCTAButton = true }: Props) {
return <div className={containerStyle({ hasCTAButton })}>{children}</div>;
}

function Title({ children, ...rest }: Omit<ParagraphProps, 'typography' | 'color'>) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CTA_HEIGHT, spacings } from '@bottlesteam/ui';
import { style } from '@vanilla-extract/css';
import { recipe } from '@vanilla-extract/recipes';

/**
* NOTE: This is a trick to make sure that
Expand All @@ -20,13 +21,25 @@ export const buttonContainer = style({
background: 'linear-gradient(180deg, rgba(251, 251, 251, 0) 0%, #FBFBFB 25%)',
});

export const containerStyle = style({
height: `calc(100vh - ${CONTAINER_OFFSET_HEIGHT - OVERLAP_HEIGHT}px - env(safe-area-inset-top))`,
overflow: 'scroll',
msOverflowStyle: 'none',
scrollbarWidth: 'none',
'::-webkit-scrollbar': {
display: 'none',
export const containerStyle = recipe({
base: {
overflow: 'scroll',
msOverflowStyle: 'none',
scrollbarWidth: 'none',
'::-webkit-scrollbar': {
display: 'none',
},
},
variants: {
hasCTAButton: {
true: {
height: `calc(100vh - ${CONTAINER_OFFSET_HEIGHT - OVERLAP_HEIGHT}px - env(safe-area-inset-top))`,
},
false: {
height: `calc(100vh - env(safe-area-inset-top))`,
paddingBottom: spacings.xl,
},
},
},
});

Expand Down
6 changes: 3 additions & 3 deletions apps/bottle/src/models/bottle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export interface BaseBottlePreview
lastActivatedAt: string;
}

export interface RecommendationBottlePreview extends BaseBottlePreview {
export interface RecommendationBottlePreview extends BaseBottlePreview {}

export interface SentBottlePreview extends BaseBottlePreview {
likeEmoji: string;
}

export interface SentBottlePreview extends BaseBottlePreview {}
15 changes: 3 additions & 12 deletions apps/bottle/src/store/query/useRecommendationBottlesQuery.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,17 @@
import { createInit, GET } from '@/features/server';
import { Tokens } from '@/features/server/auth';
import { getClientSideTokens } from '@/features/server/clientSideTokens';
import { OtherUser } from '@/models/user';
import { RecommendationBottlePreview } from '@/models/bottle';
import { useSuspenseQuery, UseSuspenseQueryOptions } from '@tanstack/react-query';

export interface RecommendationBottlePreview
extends Pick<OtherUser, 'age' | 'userImageUrl' | 'userName'>,
Pick<OtherUser['profileSelect'], 'keyword' | 'mbti'> {
userId: number;
expiredAt: string; // Date
id: number;
lastActivatedAt: string;
likeEmoji: string;
}

interface RandomBottlesQuery {
nextBottleLeftHours: number;
randomBottles: RecommendationBottlePreview[];
}

export const recommendationBottlesQueryOptions = (tokens: Tokens): UseSuspenseQueryOptions<RandomBottlesQuery> => ({
queryKey: ['bottles', 'random'],
queryKey: ['bottles', 'recommendation'],
// NOTE: should ALWAYS be stale
queryFn: () => GET<RandomBottlesQuery>(`/api/v2/bottles/random`, tokens, createInit(tokens.accessToken)),
});

Expand Down
20 changes: 20 additions & 0 deletions apps/bottle/src/store/query/useSentBottlesQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createInit, GET } from '@/features/server';
import { Tokens } from '@/features/server/auth';
import { getClientSideTokens } from '@/features/server/clientSideTokens';
import { SentBottlePreview } from '@/models/bottle';
import { useSuspenseQuery, UseSuspenseQueryOptions } from '@tanstack/react-query';

interface SentBottlesQuery {
sentBottles: SentBottlePreview[];
}

export const sentBottlesQueryOptions = (tokens: Tokens): UseSuspenseQueryOptions<SentBottlesQuery> => ({
queryKey: ['bottles', 'sent'],
queryFn: () => GET<SentBottlesQuery>(`/api/v2/bottles/sent`, tokens, createInit(tokens.accessToken)),
// NOTE: should ALWAYS be stale
staleTime: 0,
});

export function useSentBottlesQuery() {
return useSuspenseQuery(sentBottlesQueryOptions(getClientSideTokens()));
}

0 comments on commit c962224

Please sign in to comment.