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

[FE] 피드백 모아보기 페이지 웹 접근성 추가 (#690) #692

Merged
merged 5 commits into from
Oct 24, 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
@@ -1,5 +1,5 @@
import styled from "styled-components";
import { EllipsisText } from "@/styles/common";
import { EllipsisText, VisuallyHidden } from "@/styles/common";
import media from "@/styles/media";

export const FeedbackCardContainer = styled.div<{ $isTypeDevelop: boolean }>`
Expand Down Expand Up @@ -115,3 +115,7 @@ export const FeedbackDetail = styled.p`

${EllipsisText}
`;

export const ScreenReader = styled.div`
${VisuallyHidden}
`;
103 changes: 53 additions & 50 deletions frontend/src/components/feedback/feedbackCard/FeedbackCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,59 +21,62 @@ const FeedbackCard = ({
const feedbackTarget = selectedFeedbackType === "받은 피드백" ? "FROM" : "TO";

return (
<S.FeedbackCardContainer $isTypeDevelop={feedbackType === "develop"}>
<S.FeedbackHeader>
<HoverStyledLink to={`/profile/${feedbackCardData.username}`} tabIndex={-1}>
<S.FeedbackProfile>
<Profile imgSrc={feedbackCardData.profile} tabIndex={-1} />
<S.FeedbackTitle>{feedbackCardData.username}</S.FeedbackTitle>
</S.FeedbackProfile>
</HoverStyledLink>
<S.FeedbackType $isTypeDevelop={feedbackType === "develop"}>
{feedbackType === "develop" ? (
<>
개발 역량 피드백
<p>{feedbackTarget}. 나의 리뷰어</p>
</>
) : (
<>
소프트스킬 역량 피드백
<p>{feedbackTarget}. 나의 리뷰이</p>
</>
)}
</S.FeedbackType>
</S.FeedbackHeader>
<>
<S.ScreenReader>미션의 상세 피드백 내용입니다.</S.ScreenReader>
<S.FeedbackCardContainer $isTypeDevelop={feedbackType === "develop"}>
<S.FeedbackHeader>
<HoverStyledLink to={`/profile/${feedbackCardData.username}`} tabIndex={-1}>
<S.FeedbackProfile>
<Profile imgSrc={feedbackCardData.profile} tabIndex={-1} />
<S.FeedbackTitle>{feedbackCardData.username}</S.FeedbackTitle>
</S.FeedbackProfile>
</HoverStyledLink>
<S.FeedbackType $isTypeDevelop={feedbackType === "develop"}>
{feedbackType === "develop" ? (
<>
개발 역량 피드백
<p>{feedbackTarget}. 나의 리뷰어</p>
</>
) : (
<>
소프트스킬 역량 피드백
<p>{feedbackTarget}. 나의 리뷰이</p>
</>
)}
</S.FeedbackType>
</S.FeedbackHeader>

<S.FeedbackScoreContainer>
<S.FeedbackTitle>피드백 점수</S.FeedbackTitle>
<EvaluationPointBar
initialOptionId={feedbackCardData.evaluationPoint}
readonly={true}
color={feedbackType === "social" ? theme.COLOR.secondary : undefined}
isTabFocusable={false}
/>
</S.FeedbackScoreContainer>
<S.FeedbackScoreContainer>
<S.FeedbackTitle>피드백 점수</S.FeedbackTitle>
<EvaluationPointBar
initialOptionId={feedbackCardData.evaluationPoint}
readonly={true}
color={feedbackType === "social" ? theme.COLOR.secondary : undefined}
isTabFocusable={false}
/>
</S.FeedbackScoreContainer>

<S.FeedbackKeywordContainer>
<S.FeedbackTitle>피드백 키워드</S.FeedbackTitle>
<S.FeedbackKeywordWrapper>
{feedbackCardData.feedbackKeywords.map((keyword) => (
<S.FeedbackKeyword key={keyword}>{keyword}</S.FeedbackKeyword>
))}
</S.FeedbackKeywordWrapper>
</S.FeedbackKeywordContainer>
<S.FeedbackKeywordContainer>
<S.FeedbackTitle>피드백 키워드</S.FeedbackTitle>
<S.FeedbackKeywordWrapper>
{feedbackCardData.feedbackKeywords.map((keyword) => (
<S.FeedbackKeyword key={keyword}>{keyword}</S.FeedbackKeyword>
))}
</S.FeedbackKeywordWrapper>
</S.FeedbackKeywordContainer>

<S.FeedbackDetailContainer>
<S.FeedbackTitle>세부 피드백</S.FeedbackTitle>
<Textarea
rows={10}
maxLength={2000}
showCharCount={true}
value={feedbackCardData.feedbackText.length ? feedbackCardData.feedbackText : "없음"}
readOnly
/>
</S.FeedbackDetailContainer>
</S.FeedbackCardContainer>
<S.FeedbackDetailContainer>
<S.FeedbackTitle>세부 피드백</S.FeedbackTitle>
<Textarea
rows={10}
maxLength={2000}
showCharCount={true}
value={feedbackCardData.feedbackText.length ? feedbackCardData.feedbackText : "없음"}
readOnly
/>
</S.FeedbackDetailContainer>
</S.FeedbackCardContainer>
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import styled, { css, keyframes } from "styled-components";
import { VisuallyHidden } from "@/styles/common";
import media from "@/styles/media";

const fadeIn = keyframes`
Expand Down Expand Up @@ -131,3 +132,7 @@ export const NoKeywordText = styled.span`
font: ${({ theme }) => theme.TEXT.semiSmall};
color: ${({ theme }) => theme.COLOR.grey2};
`;

export const ScreenReader = styled.div`
${VisuallyHidden}
`;
146 changes: 87 additions & 59 deletions frontend/src/components/feedback/feedbackCardList/FeedbackCardList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,65 +42,93 @@ const FeedbackCardList = ({ selectedFeedbackType, feedbackData }: FeedbackCardLi
}

return (
<S.FeedbackCardContainer>
{feedbackData.map((feedback) => (
<React.Fragment key={feedback.roomId}>
<S.FeedbackMissionWrapper
$isSelected={selectedFeedback === feedback.roomId}
onClick={() => handleSelectedFeedback(feedback.roomId)}
>
<S.FeedbackMissionTitle>
<S.FeedbackMissionInfo>{feedback.title}</S.FeedbackMissionInfo>
<S.FeedbackCount>
({feedback.developFeedback.length + feedback.socialFeedback.length})
</S.FeedbackCount>
<S.FeedbackKeywordContainer>
{feedback.roomKeywords.filter((keyword) => keyword.trim() !== "").length > 0 ? (
feedback.roomKeywords.map(
(keyword) =>
keyword.trim() !== "" && (
<Label
key={keyword}
type="KEYWORD"
text={keyword}
backgroundColor={theme.COLOR.white}
/>
),
)
) : (
<S.NoKeywordText>지정된 키워드 없음</S.NoKeywordText>
)}
</S.FeedbackKeywordContainer>
</S.FeedbackMissionTitle>
<S.FeedbackMissionPrompt $isSelected={selectedFeedback === feedback.roomId}>
피드백을 보려면 클릭해주세요
</S.FeedbackMissionPrompt>
</S.FeedbackMissionWrapper>
<S.FeedbackInfoWrapper $isVisible={feedback.roomId === selectedFeedback}>
{feedback.roomId === selectedFeedback && (
<Carousel>
{feedback.developFeedback.map((developFeedback) => (
<FeedbackCard
key={developFeedback.feedbackId}
selectedFeedbackType={selectedFeedbackType}
feedbackCardData={developFeedback}
feedbackType="develop"
/>
))}
{feedback.socialFeedback.map((socialFeedback) => (
<FeedbackCard
key={socialFeedback.feedbackId}
selectedFeedbackType={selectedFeedbackType}
feedbackCardData={socialFeedback}
feedbackType="social"
/>
))}
</Carousel>
)}
</S.FeedbackInfoWrapper>
</React.Fragment>
))}
</S.FeedbackCardContainer>
<>
<S.ScreenReader>
{selectedFeedbackType} 리스트에 {feedbackData.length}개의 미션이 있습니다.
</S.ScreenReader>

<S.FeedbackCardContainer>
Comment on lines +45 to +50
Copy link
Contributor

Choose a reason for hiding this comment

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

Fragment 를 이용하기 보다 S.ScreenReader 를 FeedbackCardContainer 하위에 놔둬도 될거 같아요!

{feedbackData.map((feedback, index) => (
<React.Fragment key={feedback.roomId}>
<S.FeedbackMissionWrapper
$isSelected={selectedFeedback === feedback.roomId}
onClick={() => handleSelectedFeedback(feedback.roomId)}
role="listitem"
aria-expanded={selectedFeedback === feedback.roomId}
tabIndex={0}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
handleSelectedFeedback(feedback.roomId);
}
}}
aria-label={`${feedbackData.length}개의 미션 중 ${index + 1}번째 미션입니다.`}
>
<S.FeedbackMissionTitle>
<S.FeedbackMissionInfo>{feedback.title}</S.FeedbackMissionInfo>
<S.FeedbackCount
aria-label={`총 ${feedback.developFeedback.length + feedback.socialFeedback.length}개의 피드백`}
>
({feedback.developFeedback.length + feedback.socialFeedback.length})
</S.FeedbackCount>
<S.FeedbackKeywordContainer role="group" aria-label="피드백 키워드">
{feedback.roomKeywords.filter((keyword) => keyword.trim() !== "").length > 0 ? (
feedback.roomKeywords.map(
(keyword) =>
keyword.trim() !== "" && (
<Label
key={keyword}
type="KEYWORD"
text={keyword}
backgroundColor={theme.COLOR.white}
/>
),
)
) : (
<S.NoKeywordText role="note" aria-label="지정된 키워드가 없습니다">
지정된 키워드 없음
</S.NoKeywordText>
)}
</S.FeedbackKeywordContainer>
</S.FeedbackMissionTitle>
<S.FeedbackMissionPrompt
$isSelected={selectedFeedback === feedback.roomId}
aria-hidden={selectedFeedback === feedback.roomId}
>
피드백을 보려면 클릭해주세요
</S.FeedbackMissionPrompt>
</S.FeedbackMissionWrapper>
<S.FeedbackInfoWrapper
$isVisible={feedback.roomId === selectedFeedback}
aria-hidden={feedback.roomId !== selectedFeedback}
role="region"
aria-label={`${feedback.title}의 상세 피드백`}
>
{feedback.roomId === selectedFeedback && (
<Carousel>
{feedback.developFeedback.map((developFeedback) => (
<FeedbackCard
key={developFeedback.feedbackId}
selectedFeedbackType={selectedFeedbackType}
feedbackCardData={developFeedback}
feedbackType="develop"
/>
))}
{feedback.socialFeedback.map((socialFeedback) => (
<FeedbackCard
key={socialFeedback.feedbackId}
selectedFeedbackType={selectedFeedbackType}
feedbackCardData={socialFeedback}
feedbackType="social"
/>
))}
</Carousel>
)}
</S.FeedbackInfoWrapper>
</React.Fragment>
))}
</S.FeedbackCardContainer>
</>
);
};

Expand Down
Loading