Skip to content

Commit 65954f9

Browse files
committed
Merge branch 'main' of https://github.com/Nexters/DDD-web into feat/#15
2 parents b8b49a1 + 7a0069a commit 65954f9

File tree

14 files changed

+265
-51
lines changed

14 files changed

+265
-51
lines changed

src/app/api/v1/chat/room/route.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ import { NextResponse } from "next/server";
44
export async function POST() {
55
const mockData: CreateChatRoomResponse = {
66
roomId: 1,
7-
message: {
8-
messageId: 1,
9-
type: "SYSTEM_NORMAL",
10-
sender: "SYSTEM",
11-
answer: ["안녕이다냥?"],
12-
},
137
};
148

159
return NextResponse.json({ data: mockData });

src/app/api/v1/tarot/question/recommends/route.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,27 @@ import { NextResponse } from "next/server";
33

44
export async function GET() {
55
const mockData: TarotQuestionRecommendListResponse = {
6-
question: [
6+
questions: [
77
{
88
recommendQuestionId: 1,
99
question: "썸남 썸녀랑 잘 될까?",
1010
referenceCount: 1,
1111
},
1212
{
1313
recommendQuestionId: 2,
14-
question: "상반기에 취업할 수 있을까?",
14+
question: "상반기에 취업할 수 있을까? 상반기에 취업할 수 있을까? 상반기에 취업할 수 있을까?",
1515
referenceCount: 222,
1616
},
1717
{
1818
recommendQuestionId: 3,
1919
question: "그 사람은 내 생각하고 있을까?",
2020
referenceCount: 3333,
2121
},
22+
{
23+
recommendQuestionId: 4,
24+
question: "그 사람은 내 생각하고 있을까?",
25+
referenceCount: 3334,
26+
},
2227
],
2328
};
2429

src/app/page.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1-
import HeaderContent from "@/shared/components/HeaderContent";
2-
import MainContent from "@/shared/components/MainContent";
1+
import ChatOverview from "@/chat/components/ChatOverview";
2+
import { getTarotQuestionRecommends } from "@/tarot/apis/getTarotQuestionRecommends";
3+
import { dehydrate, HydrationBoundary, QueryClient } from "@tanstack/react-query";
4+
5+
export default async function HomePage() {
6+
const queryClient = new QueryClient();
7+
8+
await queryClient.prefetchQuery({
9+
queryKey: ["tarotQuestionRecommends"],
10+
queryFn: getTarotQuestionRecommends,
11+
});
312

4-
export default function HomePage() {
513
return (
6-
<>
7-
<HeaderContent>{null}</HeaderContent>
8-
<MainContent>{null}</MainContent>
9-
</>
14+
<HydrationBoundary state={dehydrate(queryClient)}>
15+
<ChatOverview />
16+
</HydrationBoundary>
1017
);
1118
}

src/chat/apis/createChatRoom.ts

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,12 @@
11
import apiClient from "@/shared/lib/axios/apiClient";
22
import { z } from "zod";
3-
import { MessageCategorySchema } from "../models/messageCategory";
4-
import { MessageSenderTypeSchema } from "../models/messageSender";
53

64
export type CreateChatRoomResponse = {
75
roomId: number;
8-
message: {
9-
messageId: number;
10-
type: string;
11-
sender: string;
12-
answer: string[];
13-
};
146
};
157

168
const schema = z.object({
179
roomId: z.number(),
18-
message: z.object({
19-
messageId: z.number(),
20-
type: z.literal(MessageCategorySchema.Enum.SYSTEM_NORMAL_REPLY),
21-
sender: z.literal(MessageSenderTypeSchema.Enum.SYSTEM),
22-
answer: z.array(z.string()),
23-
}),
2410
});
2511

2612
type CreateChatRoomData = z.infer<typeof schema>;
@@ -32,12 +18,10 @@ const validate = (data: CreateChatRoomResponse): CreateChatRoomData => {
3218

3319
export const createChatRoom = () => {
3420
return apiClient
35-
.post<CreateChatRoomResponse>(
36-
`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/v1/chat/room`,
37-
)
21+
.post<CreateChatRoomResponse>(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/v1/chat/room`)
3822
.then((res) => validate(res.data))
3923
.catch((error) => {
4024
console.error(error);
41-
return undefined;
25+
throw error;
4226
});
4327
};

src/chat/apis/getChatMessagesByRoomId.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,6 @@ export const getChatMessagesByRoomId = (roomId: number) => {
5050
.then((res) => validate(res.data))
5151
.catch((error) => {
5252
console.error(error);
53-
return undefined;
53+
throw error;
5454
});
5555
};

src/chat/apis/sendChatMessage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,6 @@ export const sendChatMessage = (request: SendChatMessageRequest) => {
4646
.then((res) => validate(res.data))
4747
.catch((error) => {
4848
console.error(error);
49-
return undefined;
49+
throw error;
5050
});
5151
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
'use client';
2+
3+
import QuickQuestionPickerBox from '@/chat/components/QuickQuestionPickerBox';
4+
import MainContent from '@/shared/components/MainContent';
5+
import { css } from 'styled-components';
6+
7+
export default function ChatOverview() {
8+
return (
9+
<MainContent>
10+
<h1
11+
css={css`
12+
margin-top: 170px;
13+
text-align: center;
14+
${(props) => props.theme.fonts.headline2}
15+
`}
16+
>
17+
AI 타로 술사, 타로냥에게
18+
<br /> 무엇이든 물어봐라냥
19+
</h1>
20+
<div
21+
css={css`
22+
margin-top: 32px;
23+
`}
24+
>
25+
<QuickQuestionPickerBox />
26+
</div>
27+
</MainContent>
28+
);
29+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { ColorsTypes } from '@/shared/lib/styledComponents/theme';
2+
import { css, useTheme } from 'styled-components';
3+
type Props = {
4+
question: string;
5+
onClick: () => void;
6+
selectedCount: number;
7+
color: keyof Pick<ColorsTypes, 'primary03' | 'primary01' | 'grey10' | 'grey60'>;
8+
};
9+
10+
export default function QuickQuestionPicker({ question, onClick, selectedCount, color }: Props) {
11+
const theme = useTheme();
12+
const formattedSelectedCount = selectedCount.toLocaleString();
13+
14+
const componentTheme = (() => {
15+
switch (color) {
16+
case 'primary03':
17+
case 'grey60':
18+
return {
19+
backgroundColor: theme.colors[color],
20+
titleColor: theme.colors.white,
21+
captionColor: theme.colors.grey10,
22+
};
23+
case 'primary01':
24+
case 'grey10':
25+
return {
26+
backgroundColor: theme.colors[color],
27+
titleColor: theme.colors.grey70,
28+
captionColor: theme.colors.grey60,
29+
};
30+
31+
default:
32+
const _exhausted: never = color;
33+
throw new Error(`처리되지 않은 색상 타입입니다. ${_exhausted}`);
34+
}
35+
})();
36+
37+
return (
38+
<button
39+
type="button"
40+
onClick={onClick}
41+
css={css`
42+
min-height: 94px;
43+
padding: 8px 12px;
44+
border: none;
45+
border-radius: 8px;
46+
background-color: ${componentTheme.backgroundColor};
47+
display: flex;
48+
flex-direction: column;
49+
justify-content: space-between;
50+
text-align: left;
51+
cursor: pointer;
52+
`}
53+
>
54+
<p
55+
css={css`
56+
${theme.fonts.subHead3}
57+
color: ${componentTheme.titleColor};
58+
`}
59+
>
60+
{question}
61+
</p>
62+
<p
63+
css={css`
64+
${theme.fonts.caption}
65+
color: ${componentTheme.captionColor};
66+
`}
67+
>{`${formattedSelectedCount}명이 질문 중`}</p>
68+
</button>
69+
);
70+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { createUserKeyCookie } from '@/auth/utils/createUserKeyCookie';
2+
import { useCreateChatRoom } from '@/chat/hooks/useCreateChatRoom';
3+
import { useSendChatMessage } from '@/chat/hooks/useSendChatMesasge';
4+
import { TarotQuestionRecommendListData } from '@/tarot/apis/getTarotQuestionRecommends';
5+
import { useTarotQuestionRecommends } from '@/tarot/hooks/useTarotQuestionRecommends';
6+
import { useRouter } from 'next/navigation';
7+
import { css } from 'styled-components';
8+
import QuickQuestionPicker from '../QuickQuestionPicker';
9+
import RefreshQuickQuestionButton from '../RefreshQuickQuestionButton';
10+
11+
export default function QuickQuestionPickerBox() {
12+
const { data } = useTarotQuestionRecommends();
13+
const { mutate: createChatRoom } = useCreateChatRoom();
14+
const { mutateAsync: sendChatMessage } = useSendChatMessage();
15+
const router = useRouter();
16+
17+
if (!data) return null;
18+
19+
const adaptQuestionRecommends = (data: TarotQuestionRecommendListData) => {
20+
const colors = ['primary03', 'grey10', 'primary01', 'grey60'] as const;
21+
return data.questions.map((question, i) => ({
22+
...question,
23+
color: colors[i],
24+
onClick: async () => {
25+
await createUserKeyCookie();
26+
createChatRoom(undefined, {
27+
onSuccess: (data) => {
28+
sendChatMessage(
29+
{
30+
roomId: data.roomId,
31+
message: question.question,
32+
intent: 'RECOMMEND_QUESTION',
33+
referenceQuestionId: question.recommendQuestionId,
34+
},
35+
{
36+
onSuccess: () => {
37+
router.push(`/chats/${data.roomId}`);
38+
},
39+
}
40+
);
41+
},
42+
});
43+
},
44+
}));
45+
};
46+
47+
return (
48+
<div>
49+
<div
50+
css={css`
51+
display: grid;
52+
grid-template-columns: repeat(2, 1fr);
53+
grid-template-rows: repeat(2, 1fr);
54+
gap: 8px;
55+
`}
56+
>
57+
{adaptQuestionRecommends(data).map((question) => (
58+
<QuickQuestionPicker
59+
key={question.recommendQuestionId}
60+
question={question.question}
61+
onClick={question.onClick}
62+
selectedCount={question.referenceCount}
63+
color={question.color}
64+
/>
65+
))}
66+
</div>
67+
<div
68+
css={css`
69+
width: fit-content;
70+
margin: 12px auto 0;
71+
`}
72+
>
73+
<RefreshQuickQuestionButton />
74+
</div>
75+
</div>
76+
);
77+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { useQueryClient } from '@tanstack/react-query';
2+
import { css } from 'styled-components';
3+
4+
export default function RefreshQuickQuestionButton() {
5+
const queryClient = useQueryClient();
6+
7+
const handleClick = () => {
8+
queryClient.invalidateQueries({ queryKey: ['tarotQuestionRecommends'] });
9+
};
10+
11+
return (
12+
<button
13+
type="button"
14+
onClick={handleClick}
15+
css={css`
16+
padding: 5px 8px;
17+
border: none;
18+
background-color: transparent;
19+
color: ${(props) => props.theme.colors.grey60};
20+
cursor: pointer;
21+
`}
22+
>
23+
<span
24+
css={css`
25+
${(props) => props.theme.fonts.body1};
26+
`}
27+
>
28+
추천 질문 변경
29+
</span>
30+
{/* TODO: 아이콘 추가 */}
31+
</button>
32+
);
33+
}

0 commit comments

Comments
 (0)