Skip to content

Commit 893fbe7

Browse files
authored
Merge pull request #520 from sparcs-kaist/feat/anony
Feat/anony
2 parents 895d24d + 46b3381 commit 893fbe7

File tree

20 files changed

+318
-92
lines changed

20 files changed

+318
-92
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterTable
2+
ALTER TABLE `chat` ADD COLUMN `is_anon` BOOLEAN NOT NULL DEFAULT false;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*
2+
Warnings:
3+
4+
- You are about to drop the column `is_anon` on the `chat` table. All the data in the column will be lost.
5+
6+
*/
7+
-- AlterTable
8+
ALTER TABLE `chat` DROP COLUMN `is_anon`,
9+
MODIFY `type` ENUM('message', 'notice', 'anonymous', 'adminnotice') NOT NULL;

packages/api/prisma/schema.prisma

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ datasource db {
1111
model Agenda {
1212
id Int @id @default(autoincrement())
1313
title String
14-
resolution String
1514
content String
1615
startAt DateTime? @map("start_at")
1716
endAt DateTime? @map("end_at")
1817
createdAt DateTime @default(now()) @map("created_at")
1918
updatedAt DateTime @updatedAt @map("updated_at")
2019
deletedAt DateTime? @map("deleted_at")
20+
resolution String
2121
choices Choice[]
2222
voters UserAgendaVotable[]
2323
@@ -26,35 +26,37 @@ model Agenda {
2626

2727
model User {
2828
id Int @id @default(autoincrement())
29-
username String @unique
30-
displayName String
3129
isAdmin Boolean @default(false) @map("is_admin")
30+
displayName String
31+
username String @unique
3232
chats Chat[]
33-
choices UserChoice[]
3433
agendas UserAgendaVotable[]
34+
choices UserChoice[]
3535
tags UserTag[]
3636
3737
@@map("user")
3838
}
3939

4040
model Choice {
4141
id Int @id @default(autoincrement())
42-
agenda Agenda @relation(fields: [agendaId], references: [id])
4342
agendaId Int @map("agenda_id")
4443
name String
44+
agenda Agenda @relation(fields: [agendaId], references: [id])
4545
users UserChoice[]
4646
47+
@@index([agendaId], map: "choice_agenda_id_fkey")
4748
@@map("choice")
4849
}
4950

5051
model Chat {
5152
id Int @id @default(autoincrement())
52-
user User @relation(fields: [userId], references: [id])
5353
userId Int @map("user_id")
5454
type ChatType
5555
message String @db.VarChar(500)
5656
createdAt DateTime @default(now()) @map("created_at")
57+
user User @relation(fields: [userId], references: [id])
5758
59+
@@index([userId], map: "chat_user_id_fkey")
5860
@@map("chat")
5961
}
6062

@@ -69,10 +71,11 @@ model Tag {
6971

7072
model TemplateChoice {
7173
id Int @id @default(autoincrement())
72-
template Template @relation(fields: [templateId], references: [id])
7374
templateId Int @map("template_id")
7475
name String
76+
template Template @relation(fields: [templateId], references: [id])
7577
78+
@@index([templateId], map: "template_choice_template_id_fkey")
7679
@@map("template_choice")
7780
}
7881

@@ -88,38 +91,42 @@ model Template {
8891
}
8992

9093
model UserChoice {
91-
user User @relation(fields: [userId], references: [id])
9294
userId Int @map("user_id")
93-
choice Choice @relation(fields: [choiceId], references: [id])
9495
choiceId Int @map("choice_id")
96+
choice Choice @relation(fields: [choiceId], references: [id])
97+
user User @relation(fields: [userId], references: [id])
9598
9699
@@id([userId, choiceId])
100+
@@index([choiceId], map: "user_choice_choice_id_fkey")
97101
@@map("user_choice")
98102
}
99103

100104
model UserAgendaVotable {
101-
user User @relation(fields: [userId], references: [id])
102105
userId Int @map("user_id")
103-
agenda Agenda @relation(fields: [agendaId], references: [id])
104106
agendaId Int @map("agenda_id")
107+
agenda Agenda @relation(fields: [agendaId], references: [id])
108+
user User @relation(fields: [userId], references: [id])
105109
106110
@@id([userId, agendaId])
111+
@@index([agendaId], map: "user_agenda_votable_agenda_id_fkey")
107112
@@map("user_agenda_votable")
108113
}
109114

110115
model UserTag {
111-
user User @relation(fields: [userId], references: [id])
112116
userId Int @map("user_id")
113-
tag Tag @relation(fields: [tagId], references: [id])
114117
tagId Int @map("tag_id")
118+
tag Tag @relation(fields: [tagId], references: [id])
119+
user User @relation(fields: [userId], references: [id])
115120
116121
@@id([userId, tagId])
122+
@@index([tagId], map: "user_tag_tag_id_fkey")
117123
@@map("user_tag")
118124
}
119125

120126
enum ChatType {
121127
message
122128
notice
123-
129+
anonymous
130+
adminnotice
124131
@@map("chat_type")
125132
}

packages/api/src/service/chat.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
import type { Prisma, User } from "@prisma/client";
22
import type * as schema from "@biseo/interface/chat";
33
import type { Agenda } from "@biseo/interface/agenda";
4-
54
import { prisma } from "@biseo/api/db/prisma";
65

76
export const createMessage = async (
8-
{ message }: schema.Send,
7+
{ message, type }: schema.Send,
98
user: User,
109
): Promise<schema.Message> => {
1110
const sendQuery: Prisma.ChatCreateInput = {
1211
user: { connect: user },
13-
type: "message",
12+
type,
1413
message,
1514
createdAt: new Date(),
1615
};
@@ -31,6 +30,13 @@ export const createMessage = async (
3130
},
3231
});
3332

33+
if (type === "anonymous") {
34+
createdMessage.user.id = 0;
35+
createdMessage.user.displayName = "익명";
36+
}
37+
38+
console.log(createdMessage);
39+
3440
return {
3541
...createdMessage,
3642
createdAt: createdAt.toISOString(),
@@ -92,8 +98,15 @@ export const retrieve = async ({
9298
},
9399
});
94100

95-
return messages.map(({ createdAt, ...message }) => ({
96-
...message,
97-
createdAt: createdAt.toISOString(),
98-
}));
101+
return messages.map(({ createdAt, ...message }) => {
102+
const displayMessage = message;
103+
if (message.type === "anonymous") {
104+
displayMessage.user.id = 0;
105+
displayMessage.user.displayName = "익명";
106+
}
107+
return {
108+
...displayMessage,
109+
createdAt: createdAt.toISOString(),
110+
};
111+
});
99112
};

packages/interface/src/chat/client.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
/* eslint-disable @typescript-eslint/no-redeclare -- A Zod schema name and type should have the same names */
22
import { z } from "zod";
3-
import { Message } from "./common";
3+
import { Message, MessageType } from "./common";
44

55
/**
66
* Send
77
* description
88
*/
99
export const Send = z.object({
1010
message: z.string().min(1).max(500),
11+
type: MessageType,
1112
});
1213
export type Send = z.infer<typeof Send>;
1314
export const SendCb = Message;

packages/interface/src/chat/common.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,18 @@ import { ChatUser } from "@/user";
66
* Message
77
* some description about message schema goes here
88
*/
9+
export const MessageType = z.enum([
10+
"message",
11+
"notice",
12+
"anonymous",
13+
"adminnotice",
14+
]);
15+
export type MessageType = z.infer<typeof MessageType>;
16+
917
export const Message = z.object({
1018
id: z.number(),
1119
user: ChatUser,
12-
type: z.enum(["message", "notice"]),
20+
type: MessageType,
1321
message: z.string().min(1).max(500),
1422
createdAt: z.string().datetime(),
1523
});

packages/web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"axios": "^1.4.0",
2020
"framer-motion": "^10.16.1",
2121
"immer": "^10.0.2",
22+
"lucide-react": "^0.456.0",
2223
"react": "^18.2.0",
2324
"react-dom": "^18.2.0",
2425
"react-intersection-observer": "^9.5.2",
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { bg, center, h, padding, round, text, w } from "@biseo/web/styles";
2+
import { css } from "@emotion/react";
3+
4+
export interface Props {
5+
label: string;
6+
position: "top" | "bottom";
7+
}
8+
9+
const BubbleStyle = css`
10+
${w("hug")}
11+
${h(24)}
12+
13+
${center}
14+
${padding.horizontal(10)}
15+
${bg.black}
16+
${round.md}
17+
18+
${text.option2}
19+
${text.white}
20+
21+
position: absolute;
22+
left: 50%;
23+
transform: translate(-50%, 0%);
24+
25+
white-space: nowrap;
26+
`;
27+
28+
export const Bubble: React.FC<Props> = ({ label, position }: Props) => (
29+
<div css={[BubbleStyle, position === "top" ? "bottom: 26px" : "top :26px"]}>
30+
{label}
31+
</div>
32+
);

packages/web/src/components/atoms/Scroll.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export const Scroll = styled.div<{ hide?: boolean }>`
2424
${props =>
2525
!props.hide &&
2626
css`
27-
background-color: ${props.theme.colors.gray400};
27+
background-color: ${props.theme.colors.gray300};
2828
`}
2929
border-radius: 100px;
3030
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React, { useState, type PropsWithChildren } from "react";
2+
import { center, h, w } from "@biseo/web/styles";
3+
import {
4+
Bubble,
5+
type Props as BubbleProps,
6+
} from "@biseo/web/components/atoms/Bubble";
7+
8+
interface Props extends BubbleProps, PropsWithChildren {}
9+
10+
export const BubbleItem: React.FC<Props> = ({
11+
label,
12+
position,
13+
children = null,
14+
}) => {
15+
const [hover, setHover] = useState<boolean>(false);
16+
17+
return (
18+
<div
19+
css={[center, w("hug"), h("hug"), "position: relative"]}
20+
onPointerEnter={() => {
21+
setHover(true);
22+
}}
23+
onPointerLeave={() => {
24+
setHover(false);
25+
}}
26+
>
27+
{hover && <Bubble label={label} position={position} />}
28+
{children}
29+
</div>
30+
);
31+
};
Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,54 @@
11
import React from "react";
2-
import styled from "@emotion/styled";
32
import { Text } from "@biseo/web/components/atoms";
3+
import { css } from "@emotion/react";
4+
import {
5+
align,
6+
bg,
7+
colors,
8+
h,
9+
justify,
10+
padding,
11+
row,
12+
w,
13+
} from "@biseo/web/styles";
14+
import { Megaphone } from "lucide-react";
415

516
interface Props {
617
title: string;
718
}
819

9-
const Container = styled.div`
20+
const containerStyle = css`
21+
${row}
22+
${w("fill")}
23+
${bg.gray100}
24+
${padding.horizontal(20)}
25+
${align.center}
26+
${justify.between}
1027
position: relative;
11-
display: flex;
12-
flex-direction: column;
13-
width: "100%";
1428
min-height: 42px;
15-
background-color: ${props => props.theme.colors.gray100};
16-
padding: 0 20px;
17-
justify-content: center;
29+
`;
30+
31+
const iconStyle = css`
32+
${row}
33+
${align.center}
34+
${justify.center}
35+
36+
${w(24)}
37+
${h(24)}
38+
39+
border-radius: 4px;
40+
cursor: pointer;
41+
42+
&:hover {
43+
${bg.gray200}
44+
}
1845
`;
1946

2047
export const ChatHeader: React.FC<Props> = ({ title }) => (
21-
<Container>
48+
<div css={containerStyle}>
2249
<Text variant="title2">{title}</Text>
23-
</Container>
50+
<div css={iconStyle}>
51+
<Megaphone size={20} color={colors.gray400} />
52+
</div>
53+
</div>
2454
);

0 commit comments

Comments
 (0)