Skip to content

Commit

Permalink
Merge pull request #182 from woowacourse-teams/feat/#172
Browse files Browse the repository at this point in the history
채팅 레이아웃 구현 및 페이지 구현
  • Loading branch information
ss0526100 authored Aug 2, 2024
2 parents b86df08 + bd2de83 commit 053fe95
Show file tree
Hide file tree
Showing 16 changed files with 394 additions and 3 deletions.
2 changes: 2 additions & 0 deletions frontend/src/constants/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const ROUTES = {
detail: '/moim/:moimId',
participationComplete: '/moim/participation-complete',
login: '/login',
chat: '/chat',
chattingRoom: '/chatting-room/:moimId',
};

export default ROUTES;
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import type { Meta, StoryObj } from '@storybook/react';

import ChattingPreview from '@_components/ChattingPreview/ChattingPreview';
import ChattingPreviewContainer from './ChattingPreviewContainer';
import { Fragment } from 'react';

const meta: Meta<typeof ChattingPreviewContainer> = {
component: ChattingPreviewContainer,
};

export default meta;
type Story = StoryObj<typeof ChattingPreviewContainer>;

export const Default: Story = {
args: {
children: (
<Fragment>
<ChattingPreview
title="축구하실사람"
participants={[{ imageUrl: '' }, { imageUrl: '' }, { imageUrl: '' }]}
lastChat="마지막 메세지"
/>
<ChattingPreview
title="밥먹으실 사람"
participants={[{ imageUrl: '' }, { imageUrl: '' }, { imageUrl: '' }]}
/>
<ChattingPreview
title="밥먹으실 사람"
participants={[{ imageUrl: '' }, { imageUrl: '' }, { imageUrl: '' }]}
/>
<ChattingPreview
title="밥먹으실 사람"
participants={[{ imageUrl: '' }, { imageUrl: '' }, { imageUrl: '' }]}
/>
<ChattingPreview
title="밥먹으실 사람"
participants={[{ imageUrl: '' }, { imageUrl: '' }, { imageUrl: '' }]}
/>
<ChattingPreview
title="밥먹으실 사람"
participants={[{ imageUrl: '' }, { imageUrl: '' }, { imageUrl: '' }]}
/>
<ChattingPreview
title="밥먹으실 사람"
participants={[{ imageUrl: '' }, { imageUrl: '' }, { imageUrl: '' }]}
/>
</Fragment>
),
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Theme, css } from '@emotion/react';

export const Container = ({ theme }: { theme: Theme }) => css`
overflow-y: scroll;
display: flex;
flex-direction: column;
gap: 2rem;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
padding: 28px 22px;
background-color: ${theme.colorPalette.grey[100]};
&::-webkit-scrollbar {
display: none;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as S from './ChattingPreviewContainer.style';

import { PropsWithChildren } from 'react';
import { useTheme } from '@emotion/react';

export default function ChattingPreviewContainer(props: PropsWithChildren) {
const { children } = props;
const theme = useTheme();

return <div css={S.Container({ theme })}>{children}</div>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Theme, css } from '@emotion/react';

export const layoutStyle = ({ theme }: { theme: Theme }) => css`
display: flex;
flex-direction: column;
height: 100vh;
background-color: ${theme.colorPalette.grey[100]};
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as S from './ChattingPreviewLayout.style';

import ChattingPreviewContainer from './ChattingPreviewContainer/ChattingPreviewContainer';
import { PropsWithChildren } from 'react';
import StickyTriSectionHeader from '@_layouts/components/StickyTriSectionHeader/StickyTriSectionHeader';
import { useTheme } from '@emotion/react';

function ChattingPreviewLayout(props: PropsWithChildren) {
const { children } = props;
const theme = useTheme();

return <div css={S.layoutStyle({ theme })}>{children}</div>;
}

ChattingPreviewLayout.Header = StickyTriSectionHeader;
ChattingPreviewLayout.ContentContainer = ChattingPreviewContainer;

export default ChattingPreviewLayout;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { DISPLAY_MAX_WIDTH } from '@_constants/styles';
import { css } from '@emotion/react';

export const footer = css`
position: sticky;
bottom: 0;
max-width: ${DISPLAY_MAX_WIDTH};
padding: 0;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as S from './ChattingRoomFooter.style';

import { PropsWithChildren } from 'react';

function ChattingRoomFooter(props: PropsWithChildren) {
const { children } = props;

return <div css={S.footer}>{children}</div>;
}

export default ChattingRoomFooter;
119 changes: 119 additions & 0 deletions frontend/src/layouts/ChattingRoomLayout/ChattingRoomLayout.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import type { Meta, StoryObj } from '@storybook/react';

import ChatList from '@_components/ChatList/ChatList';
import ChattingFooter from '@_components/ChattingFooter/ChattingFooter';
import ChattingRoomLayout from './ChattingRoomLayout';

const meta: Meta<typeof ChattingRoomLayout> = {
component: ChattingRoomLayout,
};

export default meta;
type Story = StoryObj<typeof ChattingRoomLayout>;

const chats = [
{
sender: '상돌',
time: '14:00',
message: '안나야 공은 찰 줄 아냐',
isMyMessage: false,
},
{
sender: '안나',
time: '14:04',
message: '시비걸꺼면 나가라',
isMyMessage: true,
},
{
sender: '안나',
time: '14:04',
message: '지하돌아',
isMyMessage: true,
},
{
sender: '테바',
time: '14:06',
message: '여러분~ 싸우지 마세요',
isMyMessage: false,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
isMyMessage: false,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
isMyMessage: false,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
isMyMessage: false,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
isMyMessage: false,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
isMyMessage: false,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
isMyMessage: false,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
isMyMessage: false,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
isMyMessage: false,
},
];
export const Default: Story = {
args: {},

render: () => {
return (
<div style={{ width: '300px' }}>
<ChattingRoomLayout>
<ChattingRoomLayout.Header>
<ChattingRoomLayout.Header.Left>
<h1>왼쪽</h1>
</ChattingRoomLayout.Header.Left>
<ChattingRoomLayout.Header.Center>
제목
</ChattingRoomLayout.Header.Center>
</ChattingRoomLayout.Header>
<ChatList chats={chats} />
<ChattingRoomLayout.Footer>
<ChattingFooter onSubmit={() => {}} />
</ChattingRoomLayout.Footer>
</ChattingRoomLayout>
</div>
);
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { css } from '@emotion/react';

export const layoutStyle = css`
display: flex;
flex-direction: column;
width: 100%;
`;
16 changes: 16 additions & 0 deletions frontend/src/layouts/ChattingRoomLayout/ChattingRoomLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as S from './ChattingRoomLayout.style';

import ChattingRoomFooter from './ChattingRoomFooter/ChattingRoomFooter';
import { PropsWithChildren } from 'react';
import StickyTriSectionHeader from '@_layouts/components/StickyTriSectionHeader/StickyTriSectionHeader';

function ChattingRoomLayout(props: PropsWithChildren) {
const { children } = props;

return <div css={S.layoutStyle}>{children}</div>;
}

ChattingRoomLayout.Header = StickyTriSectionHeader;
ChattingRoomLayout.Footer = ChattingRoomFooter;

export default ChattingRoomLayout;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Theme, css } from '@emotion/react';

export const Header = ({ theme }: { theme: Theme }) => css`
position: sticky;
top: 0;
background-color: ${theme.colorPalette.white[100]};
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as S from './StickyTriSectionHeader.style';

import { PropsWithChildren } from 'react';
import TriSectionHeader from '@_layouts/components/TriSectionHeader/TriSectionHeader';
import { useTheme } from '@emotion/react';

function StickyTriSectionHeader(props: PropsWithChildren) {
const { children } = props;
const theme = useTheme();

return (
<div css={S.Header({ theme })}>
<TriSectionHeader>{children}</TriSectionHeader>
</div>
);
}

StickyTriSectionHeader.Left = TriSectionHeader.Left;
StickyTriSectionHeader.Center = TriSectionHeader.Center;
StickyTriSectionHeader.Right = TriSectionHeader.Right;

export default StickyTriSectionHeader;
28 changes: 28 additions & 0 deletions frontend/src/pages/ChatPage/ChatPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import ChattingPreview from '@_components/ChattingPreview/ChattingPreview';
import ChattingPreviewLayout from '@_layouts/ChattingPreviewLayout/ChattingPreviewLayout';
import { useTheme } from '@emotion/react';

export default function ChatPage() {
const theme = useTheme();
const dummy = new Array(30).fill(undefined).map(() => {
return {
title: '밥먹으실 사람',
participants: [{ imageUrl: '' }, { imageUrl: '' }, { imageUrl: '' }],
};
});

return (
<ChattingPreviewLayout>
<ChattingPreviewLayout.Header>
<ChattingPreviewLayout.Header.Left>
<h2 css={theme.typography.h5}>채팅</h2>
</ChattingPreviewLayout.Header.Left>
</ChattingPreviewLayout.Header>
<ChattingPreviewLayout.ContentContainer>
{dummy.map((dum, id) => (
<ChattingPreview {...dum} key={id} />
))}
</ChattingPreviewLayout.ContentContainer>
</ChattingPreviewLayout>
);
}
51 changes: 51 additions & 0 deletions frontend/src/pages/ChattingRoomPage/ChattingRoomPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useNavigate, useParams } from 'react-router-dom';

import Back from '@_common/assets/back.svg';
import ChatList from '@_components/ChatList/ChatList';
import ChattingFooter from '@_components/ChattingFooter/ChattingFooter';
import ChattingRoomLayout from '@_layouts/ChattingRoomLayout/ChattingRoomLayout';
import { useTheme } from '@emotion/react';

export default function ChattingRoomPage() {
const theme = useTheme();
const params = useParams();
const navigate = useNavigate();

const moimId = params.moimId;
const moimTitle = '모임 ' + moimId;
const chats = [
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
isMyMessage: false,
},
{
sender: '테바j',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
isMyMessage: true,
},
];

return (
<ChattingRoomLayout>
<ChattingRoomLayout.Header>
<ChattingRoomLayout.Header.Left>
<div onClick={() => navigate(-1)}>
<Back />
</div>
</ChattingRoomLayout.Header.Left>
<ChattingRoomLayout.Header.Center>
<h2 css={theme.typography.s1}>{moimTitle}</h2>
</ChattingRoomLayout.Header.Center>
</ChattingRoomLayout.Header>
<ChatList chats={chats} />
<ChattingRoomLayout.Footer>
<ChattingFooter onSubmit={() => {}} />
</ChattingRoomLayout.Footer>
</ChattingRoomLayout>
);
}
Loading

0 comments on commit 053fe95

Please sign in to comment.