Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/anony #520

Merged
merged 20 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE `chat` ADD COLUMN `is_anon` BOOLEAN NOT NULL DEFAULT false;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
Warnings:

- You are about to drop the column `is_anon` on the `chat` table. All the data in the column will be lost.

*/
-- AlterTable
ALTER TABLE `chat` DROP COLUMN `is_anon`,
MODIFY `type` ENUM('message', 'notice', 'anonymous', 'adminnotice') NOT NULL;
35 changes: 21 additions & 14 deletions packages/api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ datasource db {
model Agenda {
id Int @id @default(autoincrement())
title String
resolution String
content String
startAt DateTime? @map("start_at")
endAt DateTime? @map("end_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")
resolution String
choices Choice[]
voters UserAgendaVotable[]

Expand All @@ -26,35 +26,37 @@ model Agenda {

model User {
id Int @id @default(autoincrement())
username String @unique
displayName String
isAdmin Boolean @default(false) @map("is_admin")
displayName String
username String @unique
chats Chat[]
choices UserChoice[]
agendas UserAgendaVotable[]
choices UserChoice[]
tags UserTag[]

@@map("user")
}

model Choice {
id Int @id @default(autoincrement())
agenda Agenda @relation(fields: [agendaId], references: [id])
agendaId Int @map("agenda_id")
name String
agenda Agenda @relation(fields: [agendaId], references: [id])
users UserChoice[]

@@index([agendaId], map: "choice_agenda_id_fkey")
@@map("choice")
}

model Chat {
id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [id])
userId Int @map("user_id")
type ChatType
message String @db.VarChar(500)
createdAt DateTime @default(now()) @map("created_at")
user User @relation(fields: [userId], references: [id])

@@index([userId], map: "chat_user_id_fkey")
@@map("chat")
}

Expand All @@ -69,10 +71,11 @@ model Tag {

model TemplateChoice {
id Int @id @default(autoincrement())
template Template @relation(fields: [templateId], references: [id])
templateId Int @map("template_id")
name String
template Template @relation(fields: [templateId], references: [id])

@@index([templateId], map: "template_choice_template_id_fkey")
@@map("template_choice")
}

Expand All @@ -88,38 +91,42 @@ model Template {
}

model UserChoice {
user User @relation(fields: [userId], references: [id])
userId Int @map("user_id")
choice Choice @relation(fields: [choiceId], references: [id])
choiceId Int @map("choice_id")
choice Choice @relation(fields: [choiceId], references: [id])
user User @relation(fields: [userId], references: [id])

@@id([userId, choiceId])
@@index([choiceId], map: "user_choice_choice_id_fkey")
@@map("user_choice")
}

model UserAgendaVotable {
user User @relation(fields: [userId], references: [id])
userId Int @map("user_id")
agenda Agenda @relation(fields: [agendaId], references: [id])
agendaId Int @map("agenda_id")
agenda Agenda @relation(fields: [agendaId], references: [id])
user User @relation(fields: [userId], references: [id])

@@id([userId, agendaId])
@@index([agendaId], map: "user_agenda_votable_agenda_id_fkey")
@@map("user_agenda_votable")
}

model UserTag {
user User @relation(fields: [userId], references: [id])
userId Int @map("user_id")
tag Tag @relation(fields: [tagId], references: [id])
tagId Int @map("tag_id")
tag Tag @relation(fields: [tagId], references: [id])
user User @relation(fields: [userId], references: [id])

@@id([userId, tagId])
@@index([tagId], map: "user_tag_tag_id_fkey")
@@map("user_tag")
}

enum ChatType {
message
notice

anonymous
adminnotice
@@map("chat_type")
}
27 changes: 20 additions & 7 deletions packages/api/src/service/chat.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import type { Prisma, User } from "@prisma/client";
import type * as schema from "@biseo/interface/chat";
import type { Agenda } from "@biseo/interface/agenda";

import { prisma } from "@biseo/api/db/prisma";

export const createMessage = async (
{ message }: schema.Send,
{ message, type }: schema.Send,
user: User,
): Promise<schema.Message> => {
const sendQuery: Prisma.ChatCreateInput = {
user: { connect: user },
type: "message",
type,
message,
createdAt: new Date(),
};
Expand All @@ -31,6 +30,13 @@
},
});

if (type === "anonymous") {
createdMessage.user.id = 0;
createdMessage.user.displayName = "익명";
}

console.log(createdMessage);

Check warning on line 38 in packages/api/src/service/chat.ts

View workflow job for this annotation

GitHub Actions / Lint and Format (18.x, 8.x)

Unexpected console statement

return {
...createdMessage,
createdAt: createdAt.toISOString(),
Expand Down Expand Up @@ -92,8 +98,15 @@
},
});

return messages.map(({ createdAt, ...message }) => ({
...message,
createdAt: createdAt.toISOString(),
}));
return messages.map(({ createdAt, ...message }) => {
const displayMessage = message;
if (message.type === "anonymous") {
displayMessage.user.id = 0;
displayMessage.user.displayName = "익명";
}
return {
...displayMessage,
createdAt: createdAt.toISOString(),
};
});
};
3 changes: 2 additions & 1 deletion packages/interface/src/chat/client.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
/* eslint-disable @typescript-eslint/no-redeclare -- A Zod schema name and type should have the same names */
import { z } from "zod";
import { Message } from "./common";
import { Message, MessageType } from "./common";

/**
* Send
* description
*/
export const Send = z.object({
message: z.string().min(1).max(500),
type: MessageType,
});
export type Send = z.infer<typeof Send>;
export const SendCb = Message;
Expand Down
10 changes: 9 additions & 1 deletion packages/interface/src/chat/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@ import { ChatUser } from "@/user";
* Message
* some description about message schema goes here
*/
export const MessageType = z.enum([
"message",
"notice",
"anonymous",
"adminnotice",
]);
export type MessageType = z.infer<typeof MessageType>;

export const Message = z.object({
id: z.number(),
user: ChatUser,
type: z.enum(["message", "notice"]),
type: MessageType,
message: z.string().min(1).max(500),
createdAt: z.string().datetime(),
});
Expand Down
1 change: 1 addition & 0 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"axios": "^1.4.0",
"framer-motion": "^10.16.1",
"immer": "^10.0.2",
"lucide-react": "^0.456.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-intersection-observer": "^9.5.2",
Expand Down
32 changes: 32 additions & 0 deletions packages/web/src/components/atoms/Bubble.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { bg, center, h, padding, round, text, w } from "@biseo/web/styles";
import { css } from "@emotion/react";

export interface Props {
label: string;
position: "top" | "bottom";
}

const BubbleStyle = css`
${w("hug")}
${h(24)}

${center}
${padding.horizontal(10)}
${bg.black}
${round.md}

${text.option2}
${text.white}

position: absolute;
left: 50%;
transform: translate(-50%, 0%);

white-space: nowrap;
`;

export const Bubble: React.FC<Props> = ({ label, position }: Props) => (
<div css={[BubbleStyle, position === "top" ? "bottom: 26px" : "top :26px"]}>
{label}
</div>
);
2 changes: 1 addition & 1 deletion packages/web/src/components/atoms/Scroll.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const Scroll = styled.div<{ hide?: boolean }>`
${props =>
!props.hide &&
css`
background-color: ${props.theme.colors.gray400};
background-color: ${props.theme.colors.gray300};
`}
border-radius: 100px;
}
Expand Down
31 changes: 31 additions & 0 deletions packages/web/src/components/molecules/BubbleItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React, { useState, type PropsWithChildren } from "react";
import { center, h, w } from "@biseo/web/styles";
import {
Bubble,
type Props as BubbleProps,
} from "@biseo/web/components/atoms/Bubble";

interface Props extends BubbleProps, PropsWithChildren {}

export const BubbleItem: React.FC<Props> = ({
label,
position,
children = null,
}) => {
const [hover, setHover] = useState<boolean>(false);

return (
<div
css={[center, w("hug"), h("hug"), "position: relative"]}
onPointerEnter={() => {
setHover(true);
}}
onPointerLeave={() => {
setHover(false);
}}
>
{hover && <Bubble label={label} position={position} />}
{children}
</div>
);
};
50 changes: 40 additions & 10 deletions packages/web/src/components/molecules/ChatHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,54 @@
import React from "react";
import styled from "@emotion/styled";
import { Text } from "@biseo/web/components/atoms";
import { css } from "@emotion/react";
import {
align,
bg,
colors,
h,
justify,
padding,
row,
w,
} from "@biseo/web/styles";
import { Megaphone } from "lucide-react";

interface Props {
title: string;
}

const Container = styled.div`
const containerStyle = css`
${row}
${w("fill")}
${bg.gray100}
${padding.horizontal(20)}
${align.center}
${justify.between}
position: relative;
display: flex;
flex-direction: column;
width: "100%";
min-height: 42px;
background-color: ${props => props.theme.colors.gray100};
padding: 0 20px;
justify-content: center;
`;

const iconStyle = css`
${row}
${align.center}
${justify.center}

${w(24)}
${h(24)}

border-radius: 4px;
cursor: pointer;

&:hover {
${bg.gray200}
}
`;

export const ChatHeader: React.FC<Props> = ({ title }) => (
<Container>
<div css={containerStyle}>
<Text variant="title2">{title}</Text>
</Container>
<div css={iconStyle}>
<Megaphone size={20} color={colors.gray400} />
</div>
</div>
);
Loading
Loading