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

채팅 입력 글자수 제한 #363

Merged
merged 6 commits into from
Sep 14, 2023
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
25 changes: 13 additions & 12 deletions client/src/components/atoms/TextArea.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,34 @@
import styled from "@emotion/styled";
import TextareaAutosize from "react-textarea-autosize";
import { w, h, text, padding } from "@/styles";

export const TextAreaFixedsize = styled.textarea`
width: 100%;
height: 100%;
padding: 10px 15px;
${w("fill")}
${h("fill")}
${padding.vertical(10)}
${padding.horizontal(15)}
resize: none;
border: none;
background: transparent;
font-size: 11px;
font-weight: 500;
color: ${props => props.theme.colors.black};
${text.subtitle}
${text.black}
::placeholder {
font-family: "Noto Sans KR", sans-serif;
color: ${props => props.theme.colors.gray300};
${text.gray300}
}
`;

export const TextAreaAutosize = styled(TextareaAutosize)`
width: 100%;
${w("fill")}
max-height: 100%;
outline: none;
resize: none;
border: none;
background: transparent;
font-size: 12px;
font-weight: 500;
color: ${props => props.theme.colors.black};
${text.body}
${text.black}
::placeholder {
font-family: "Noto Sans KR", sans-serif;
color: ${props => props.theme.colors.gray300};
${text.gray300}
}
`;
100 changes: 68 additions & 32 deletions client/src/components/molecules/ChatInput.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,49 @@
import React, { useCallback, useMemo } from "react";
import styled from "@emotion/styled";
import { css } from "@emotion/react";

import { EmoticonIcon, SendIcon } from "@/assets";
import { Box, Divider, TextAreaAutosize } from "@/components/atoms";
import { Divider, TextAreaAutosize } from "@/components/atoms";
import { useInput } from "@/common/hooks";
import {
w,
h,
padding,
scroll,
scrollBar,
bg,
justify,
align,
row,
gap,
border,
round,
} from "@/styles";

const InputForm = styled.form`
display: flex;
flex-direction: row;
gap: 10px;
width: 100%;
height: 100%;
padding: 10px 15px;
background-color: ${props => props.theme.colors.white};
border: solid 1px ${props => props.theme.colors.gray300};
border-radius: 5px;
const inputBoxStyle = css`
${w("fill")}
max-height: 30%;
${padding(10)}
${bg.white100}
${justify.start}
${align.start}
`;

const formStyle = css`
${row}
${gap(10)}
${w("fill")}
${h("fill")}
${padding.vertical(10)}
${padding.horizontal(15)}
${bg.white}
${border.gray300}
${round.md}
`;

const textAreaScrollStyle = css`
${scroll.y}
${scrollBar}
overflow-y: scroll;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overflow: scroll 대신 overflow: auto를 사용하면 스크롤바가 보일 때와 보이지 않을 때 텍스트 영역의 너비가 달라집니다.

`;

interface Props {
Expand All @@ -24,37 +53,44 @@ interface Props {
export const ChatInput: React.FC<Props> = ({ send }) => {
const { input, setValue } = useInput();

// TODO: disable send button based on `validated`
/** TODO: disable send button based on `validated` */
const validated = useMemo(() => input.value.trim().length > 0, [input.value]);

/** @constant 클라이언트와 서버에서 사용하는 채팅 메시지의 최대 길이를 지정합니다. */
const maxMessageLength = 500;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

서버, 클라이언트에서 모두 사용하는 값이라서 interface에 저장할 수 있으면 좋겠다고 생각했습니다!


const sendCurrent = useCallback(() => {
if (!validated) return;
send(input.value.trim());
setValue("");
}, [input.value, validated]);

return (
<Box w="fill" pad={10} bg="white100">
<InputForm>
<TextAreaAutosize
onKeyDown={e => {
if (
e.key === "Enter" &&
!e.shiftKey &&
!e.nativeEvent.isComposing
) {
e.preventDefault();
sendCurrent();
}
}}
value={input.value}
onChange={input.onChange}
/>
<Divider dir="vertical" />
<div css={inputBoxStyle}>
<form css={formStyle}>
<div css={[row, w("fill"), h("fill")]}>
<TextAreaAutosize
css={textAreaScrollStyle}
onKeyDown={e => {
if (
e.key === "Enter" &&
!e.shiftKey &&
!e.nativeEvent.isComposing
) {
e.preventDefault();
sendCurrent();
}
}}
value={input.value}
maxLength={maxMessageLength}
onChange={input.onChange}
/>
<Divider dir="vertical" />
</div>
<EmoticonIcon />
<SendIcon onClick={sendCurrent} />
{/* TODO: Replace with button / add hover, actove effect */}
</InputForm>
</Box>
</form>
</div>
);
};
8 changes: 4 additions & 4 deletions interface/src/admin/agenda/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ export type AdminAgenda = z.infer<typeof AdminAgenda>;
* some description about admin agenda create schema goes here
*/
export const AdminAgendaCreate = z.object({
title: z.string().min(1),
content: z.string().min(1),
resolution: z.string().min(1),
choices: z.array(z.string().min(1)).min(1),
title: z.string().min(1).max(255),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mysql에서 string 자료형의 길이는 [0, 255]입니다.
https://dev.mysql.com/doc/refman/8.0/en/string-type-syntax.html

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그래서 max 255였군용

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 처음 알았어요!

content: z.string().min(1).max(255),
resolution: z.string().min(1).max(255),
choices: z.array(z.string().min(1).max(255)).min(1),
voters: z.object({
total: z.array(z.number()),
}),
Expand Down
10 changes: 5 additions & 5 deletions interface/src/agenda/template/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ export type AgendaTemplate = z.infer<typeof AgendaTemplate>;
* some description about agenda template create schema goes here
*/
export const AgendaTemplateCreate = z.object({
templateName: z.string(),
title: z.string(),
content: z.string(),
resolution: z.string(),
choices: z.array(z.string()),
templateName: z.string().min(1).max(255),
title: z.string().min(1).max(255),
content: z.string().min(1).max(255),
resolution: z.string().min(1).max(255),
choices: z.array(z.string().min(1).max(255)),
Comment on lines +23 to +27
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

옹 이제 템플릿이랑 유저태그 만드는 모달 쪽 프론트 로직에도 요거 검증이 들어가야겠네
관련 이슈 없으면 만들어줄 수 있나요??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

우와 추가했습니다! 감사합니다!
#375

});
export type AgendaTemplateCreate = z.infer<typeof AgendaTemplateCreate>;

Expand Down
2 changes: 1 addition & 1 deletion interface/src/chat/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Message } from "./common";
* description
*/
export const Send = z.object({
message: z.string().min(1),
message: z.string().min(1).max(500),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

클라이언트가 채팅을 보내는 이벤트에서는 이 chat.Send 스키마에 따라 입력값 검증이 이루어집니다.

});
export type Send = z.infer<typeof Send>;
export const SendCb = Message;
Expand Down
4 changes: 2 additions & 2 deletions interface/src/user/tag/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export type UserTag = z.infer<typeof UserTag>;
* some description about user tag create schema goes here
*/
export const UserTagCreate = z.object({
title: z.string(),
description: z.string(),
title: z.string().min(1).max(255),
description: z.string().min(1).max(255),
users: z.array(z.number()),
});
export type UserTagCreate = z.infer<typeof UserTagCreate>;
Expand Down