Skip to content

Commit

Permalink
Merge pull request #710 from woowacourse-teams/feature/#707
Browse files Browse the repository at this point in the history
모임 상세목록 접근성 개선
  • Loading branch information
jaeml06 authored Oct 23, 2024
2 parents a9b635b + 3ea7b80 commit b000df5
Show file tree
Hide file tree
Showing 15 changed files with 286 additions and 176 deletions.
7 changes: 4 additions & 3 deletions frontend/src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { HTMLAttributes, ReactNode } from 'react';
import {
Interpolation,
SerializedStyles,
Theme,
useTheme,
} from '@emotion/react';

import { ReactNode } from 'react';
import { shapes } from '@_components/Button/Button.style';

export interface ButtonProps {
export interface ButtonProps extends HTMLAttributes<HTMLButtonElement> {
shape: 'circle' | 'bar';
onClick?: () => void;
disabled?: boolean;
Expand All @@ -22,13 +22,14 @@ export interface ButtonProps {
}

export default function Button(props: ButtonProps) {
const { onClick, disabled, children, font } = props;
const { onClick, disabled, children, font, ...restProps } = props;
const theme = useTheme();
return (
<button
css={[shapes({ ...props, theme }), font]}
onClick={onClick}
disabled={disabled}
{...restProps}
>
{children}
</button>
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/Input/MessagInput/MessageInput.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as S from '@_components/Input/MessagInput/MessageInput.style';
import { useTheme } from '@emotion/react';

import { useState } from 'react';
import SubmitButton from '@_common/assets/submit_message_button.svg';
import { useState } from 'react';
import { useTheme } from '@emotion/react';

export interface MessageInputProps {
placeHolder: string;
Expand Down Expand Up @@ -36,6 +36,7 @@ export default function MessageInput(props: MessageInputProps) {
css={S.button({ theme })}
type="submit"
disabled={!message.trim() || disabled}
aria-label={`댓글쓰기 버튼 ${!message.trim() || disabled ? '댓글을 작성하여 버튼을 활성화하세요' : ''}`}
>
<SubmitButton />
</button>
Expand Down
12 changes: 10 additions & 2 deletions frontend/src/components/KebabMenu/KebabMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as S from '@_components/KebabMenu/KebabMenu.style';
import { useRef, useState, FocusEvent } from 'react';

import { FocusEvent, useRef, useState } from 'react';

import KebabButton from '@_common/assets/kebab_menu.svg';
import { useTheme } from '@emotion/react';

Expand Down Expand Up @@ -35,14 +37,20 @@ export default function KebabMenu(props: KebabMenuProps) {

return (
<div css={S.kebabContainer({ theme })}>
<button onClick={handleKebabToggle} onBlur={handleKebabClose}>
<button
onClick={handleKebabToggle}
onBlur={handleKebabClose}
aria-label="케밥 메뉴 활성화 버튼"
aria-checked={isKebabOpen}
>
<KebabButton />
</button>
{isKebabOpen && (
<div ref={optionsRef} css={S.optionBox({ theme })}>
{options.map((option) => {
return (
<button
aria-label={option.name}
key={option.name}
onClick={() => handleOptionClick(option.onClick)}
disabled={option.disabled}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Theme, css } from '@emotion/react';

export const explanationSection = ({ theme }: { theme: Theme }) => css`
margin: 0 5rem;
${theme.typography.s1}
`;
245 changes: 136 additions & 109 deletions frontend/src/pages/Moim/MoimDetailPage/MoimDetailPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { MoimInfo, Role } from '@_types/index';
import { useNavigate, useParams } from 'react-router-dom';

import BackLogo from '@_common/assets/back.svg';
import Button from '@_components/Button/Button';
import CommentList from './components/CommentList/CommentList';
import CommentListSkeleton from './components/CommentList/CommentListSkeleton';
Expand Down Expand Up @@ -28,7 +31,48 @@ import useOpenChat from '@_hooks/mutaions/useOpenChat';
import useReopenMoim from '@_hooks/mutaions/useReopenMoim';
import { useTheme } from '@emotion/react';
import useZzimMine from '@_hooks/queries/useZzimMine';
import BackArrowButton from '@_components/Button/BackArrowButton/BackArrowButton';

const getButtonMessage = (moim: MoimInfo, role: Role) => {
if (moim.status === 'CANCELED') return '취소된 모임이에요';

if (role === 'MOIMER') {
if (moim.status === 'MOIMING') return '모집 완료하기';
if (moim.status === 'COMPLETED') return '채팅방 열기(이동하기)';
return '';
}
if (role === 'NON_MOIMEE') {
if (moim.status === 'MOIMING') return '참여하기';
if (moim.status === 'COMPLETED') return '모집이 완료되었어요';
return '';
}
if (role === 'MOIMEE') {
if (moim.status === 'MOIMING') return '방장이 채팅방을 만들지 않았습니다';
if (moim.status === 'COMPLETED') return '채팅방으로 가기';
return '';
}
return '';
};

const getButtonDisabled = (moim: MoimInfo, role: Role) => {
if (moim.status === 'CANCELED') return true;

if (role === 'MOIMER') {
if (moim.status === 'MOIMING') return false;
if (moim.status === 'COMPLETED') return false;
return true;
}
if (role === 'NON_MOIMEE') {
if (moim.status === 'MOIMING') return false;
if (moim.status === 'COMPLETED') return true;
return true;
}
if (role === 'MOIMEE') {
if (moim.status === 'MOIMING') return true;
if (moim.status === 'COMPLETED') return false;
return true;
}
return true;
};

export default function MoimDetailPage() {
const navigate = useNavigate();
Expand All @@ -38,11 +82,11 @@ export default function MoimDetailPage() {
const moimId = Number(params.moimId);

const { moim, isLoading: isMoimLoading } = useMoim(moimId);
const { role, isChamyoMineLoading } = useChamyoMine(moimId);
const { role } = useChamyoMine(moimId);
const { isZzimed, isZzimMineLoading } = useZzimMine(moimId);
const { participants, chamyoAllIsLoading } = useChamyoAll(moimId);
const { mutate: changZzim } = useChangeZzim();
const { mutate, isPending: isPendingJoinMoim } = useJoinMoim(() => {
const { mutate: joinMoim } = useJoinMoim(() => {
navigate(GET_ROUTES.nowDarakbang.moimParticipateComplete());
});

Expand All @@ -51,49 +95,64 @@ export default function MoimDetailPage() {

const { mutate: ReopenMoim, isPending: isPendingReopenMoim } =
useReopenMoim();
const { mutate: completeMoim, isPending: isPendingCompleteMoim } =
useCompleteMoin();
const { mutate: completeMoim } = useCompleteMoin();
const { mutate: cancelChamyo, isPending: isPendingCancelChamyo } =
useCancelChamyo();
const { mutate: openChat, isPending: isPendingOpenChat } = useOpenChat(
(chatRoomId: number) =>
navigate(GET_ROUTES.nowDarakbang.chattingRoom(chatRoomId)),
const { mutate: openChat } = useOpenChat((chatRoomId: number) =>
navigate(GET_ROUTES.nowDarakbang.chattingRoom(chatRoomId)),
);

const kebabMenu = useMemo(() => {
return role === 'MOIMER' ? (
<KebabMenu
options={[
{
name: '모임 수정하기',
disabled: false,
onClick: () =>
navigate(GET_ROUTES.nowDarakbang.modify(moimId), {
state: {
...moim,
moimId,
},
}),
},
{
name: '모임 취소하기',
disabled: isPendingCancelMoim,
onClick: () => cancelMoim(moimId),
},
{
name: '모임 다시 열기',
disabled: isPendingReopenMoim,
onClick: () => ReopenMoim(moimId),
},
]}
/>
) : (
if (role === 'MOIMER') {
return (
<KebabMenu
options={[
{
name: '모임 수정하기',
disabled: false,
onClick: () =>
navigate(GET_ROUTES.nowDarakbang.modify(moimId), {
state: {
...moim,
moimId,
},
}),
},
{
name: '모임 취소하기',
disabled: isPendingCancelMoim,
onClick: () => cancelMoim(moimId),
},
{
name: '모임 다시 열기',
disabled: isPendingReopenMoim,
onClick: () => ReopenMoim(moimId),
},
]}
/>
);
}
if (role === 'MOIMEE') {
return (
<KebabMenu
options={[
{
name: '참여 취소하기',
disabled: isPendingCancelChamyo,
onClick: () => cancelChamyo(moimId),
},
]}
/>
);
}

return (
<KebabMenu
options={[
{
name: '참여 취소하기',
name: '사용할 수 있는 메뉴가 없습니다',
disabled: isPendingCancelChamyo,
onClick: () => cancelChamyo(moimId),
onClick: () => {},
},
]}
/>
Expand All @@ -111,89 +170,48 @@ export default function MoimDetailPage() {
role,
]);

const button = useMemo(() => {
return isChamyoMineLoading ? (
''
) : role === 'MOIMER' ? (
moim?.status === 'MOIMING' ? (
<Button
shape="bar"
disabled={false || isPendingCompleteMoim}
onClick={() => completeMoim(moimId)}
>
모집 완료하기
</Button>
) : moim?.status === 'CANCELED' ? (
<Button shape="bar" disabled={true}>
취소된 모임이예요
</Button>
) : (
<Button
shape="bar"
disabled={false || isPendingOpenChat}
onClick={() => openChat(moimId)}
>
채팅방 열기(이동하기)
</Button>
)
) : role === 'NON_MOIMEE' ? (
moim?.status === 'MOIMING' ? (
<Button
shape="bar"
disabled={false || isPendingJoinMoim}
onClick={() => mutate(moimId)}
>
참여하기
</Button>
) : moim?.status === 'COMPLETED' ? (
<Button shape="bar" disabled={true}>
모집이 완료되었어요
</Button>
) : (
<Button shape="bar" disabled={true}>
취소된 모임이예요
</Button>
)
) : moim?.status === 'MOIMING' ? (
<Button shape="bar" disabled={true}>
방장이 채팅방을 만들지 않았습니다
</Button>
) : (
<Button
shape="bar"
disabled={false}
onClick={() => navigate(GET_ROUTES.nowDarakbang.chattingRoom(moimId))}
>
채팅방으로 가기
</Button>
);
}, [
completeMoim,
isPendingCompleteMoim,
isPendingJoinMoim,
isPendingOpenChat,
moim?.status,
moimId,
navigate,
mutate,
openChat,
role,
isChamyoMineLoading,
]);
const buttonClickHandler = (moim: MoimInfo, role: Role) => {
if (moim.status === 'CANCELED') return;

if (role === 'MOIMER') {
if (moim.status === 'MOIMING') return completeMoim(moimId);
if (moim.status === 'COMPLETED') return openChat(moimId);
return;
}
if (role === 'NON_MOIMEE') {
if (moim.status === 'MOIMING') return joinMoim(moimId);
if (moim.status === 'COMPLETED') return;
return;
}
if (role === 'MOIMEE') {
if (moim.status === 'MOIMING') return;
if (moim.status === 'COMPLETED')
return navigate(GET_ROUTES.nowDarakbang.chattingRoom(moimId));
return;
}
return;
};

return (
<InformationLayout>
<InformationLayout.Header>
<InformationLayout.Header.Left>
<BackArrowButton
<div
role="button"
aria-label="뒤로가기"
onClick={() => navigate(GET_ROUTES.nowDarakbang.main())}
/>
>
<BackLogo />
</div>
</InformationLayout.Header.Left>
<InformationLayout.Header.Right>
{isZzimMineLoading && (
<ZzimButton isZzimed={false} onClick={() => {}} />
)}
{!isZzimMineLoading && (
<ZzimButton
aria-label={`찜 토글 버튼`}
aria-pressed={!!isZzimed}
isZzimed={!!isZzimed}
onClick={() => changZzim(moimId)}
/>
Expand Down Expand Up @@ -241,7 +259,16 @@ export default function MoimDetailPage() {
)}
</InformationLayout.ContentContainer>
<InformationLayout.BottomButtonWrapper>
{button}
{moim && role && (
<Button
shape="bar"
disabled={getButtonDisabled(moim, role)}
onClick={() => buttonClickHandler(moim, role)}
aria-label={getButtonMessage(moim, role)}
>
{getButtonMessage(moim, role)}
</Button>
)}
</InformationLayout.BottomButtonWrapper>
</InformationLayout>
);
Expand Down
Loading

0 comments on commit b000df5

Please sign in to comment.