Skip to content

Commit

Permalink
feat-fe: 지원자 카드 컴포넌트의 UI 개선 적용 (#808)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Seongjin Hong <[email protected]>
  • Loading branch information
github-actions[bot] and seongjinme authored Oct 15, 2024
1 parent 66e2076 commit 0c2585d
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ export const ApplicantCardDefault: Story = {
averageScore: 3.86,
isRejected: false,
popOverMenuItems,
isSelectMode: false,
isSelected: false,
onCardClick: () => console.log('지원자 카드가 클릭되었습니다.'),
onSelectApplicant: () => console.log('지원자 선택 체크박스가 클릭되었습니다.'),
},
};

Expand All @@ -107,6 +110,9 @@ export const RejectedApplicantCard: Story = {
averageScore: 2.23,
isRejected: true,
popOverMenuItems,
isSelectMode: false,
isSelected: false,
onCardClick: () => console.log('지원자 카드가 클릭되었습니다.'),
onSelectApplicant: () => console.log('지원자 선택 체크박스가 클릭되었습니다.'),
},
};
70 changes: 47 additions & 23 deletions frontend/src/components/dashboard/ApplicantCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useDropdown } from '@contexts/DropdownContext';

import type { DropdownItemType } from '@components/_common/molecules/DropdownItemRenderer';
import DropdownItemRenderer from '@components/_common/molecules/DropdownItemRenderer';
import CheckBox from '@components/_common/atoms/CheckBox';
import S from './style';

interface ApplicantCardProps {
Expand All @@ -20,7 +21,10 @@ interface ApplicantCardProps {
evaluationCount: number;
averageScore: number;
popOverMenuItems: DropdownItemType[];
isSelectMode: boolean;
isSelected: boolean;
onCardClick: () => void;
onSelectApplicant: (isChecked: boolean) => void;
}

export default function ApplicantCard({
Expand All @@ -30,12 +34,15 @@ export default function ApplicantCard({
evaluationCount,
averageScore,
popOverMenuItems,
isSelectMode,
isSelected,
onCardClick,
onSelectApplicant,
}: ApplicantCardProps) {
const { isOpen, open, close } = useDropdown();
const optionButtonWrapperRef = useRef<HTMLDivElement>(null);

const evaluationString = averageScore ? `★ ${averageScore.toFixed(1)}` : '평가 대기 중';
const evaluationString = evaluationCount > 0 ? averageScore.toFixed(1) : '';

const handleClickPopOverButton = (event: React.MouseEvent) => {
event.stopPropagation();
Expand All @@ -58,6 +65,10 @@ export default function ApplicantCard({

const cardClickHandler = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
if (isSelectMode) {
onSelectApplicant(!isSelected);
return;
}
onCardClick();
};

Expand All @@ -78,13 +89,16 @@ export default function ApplicantCard({
>
<S.CardDetail>
<S.CardHeader>{name}</S.CardHeader>
<S.CardEvaluationFlag
averageScore={averageScore}
evaluationCount={evaluationCount}
>
{evaluationString}
</S.CardEvaluationFlag>
<S.CardInfoContainer>
<S.CardEvaluationFlag
averageScore={averageScore}
isScoreExists={evaluationCount > 0}
>
<S.CardEvaluationFlagScore isScoreExists={evaluationCount > 0}>
{evaluationString}
</S.CardEvaluationFlagScore>
</S.CardEvaluationFlag>
<S.CardInfo>
<HiOutlineClock size="1.2rem" />
{formatDate(createdAt)}
Expand All @@ -99,23 +113,33 @@ export default function ApplicantCard({

<S.OptionButtonWrapper>
<div ref={optionButtonWrapperRef}>
<IconButton
type="button"
outline={false}
onClick={handleClickPopOverButton}
disabled={isRejected}
>
<HiEllipsisVertical />
</IconButton>
<PopOverMenu
isOpen={isOpen}
popOverPosition="3.5rem 0 0 -6rem"
>
<DropdownItemRenderer
items={popOverMenuItems}
subContentPlacement="left"
{isSelectMode && (
<CheckBox
isChecked={isSelected}
onToggle={() => {}}
/>
</PopOverMenu>
)}
{!isSelectMode && (
<>
<IconButton
type="button"
outline={false}
onClick={handleClickPopOverButton}
disabled={isRejected}
>
<HiEllipsisVertical />
</IconButton>
<PopOverMenu
isOpen={isOpen}
popOverPosition="3.5rem 0 0 -6rem"
>
<DropdownItemRenderer
items={popOverMenuItems}
subContentPlacement="left"
/>
</PopOverMenu>
</>
)}
</div>
</S.OptionButtonWrapper>
</S.CardContainer>
Expand Down
24 changes: 19 additions & 5 deletions frontend/src/components/dashboard/ApplicantCard/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,25 @@ const CardHeader = styled.h3`
margin-bottom: 0;
`;

const CardEvaluationFlag = styled.div<{ averageScore: number; evaluationCount: number }>`
width: fit-content;
const CardEvaluationFlag = styled.div<{ averageScore: number; isScoreExists: boolean }>`
width: 4rem;
display: flex;
flex-direction: row;
justify-content: space-between;
border-radius: 0.4rem;
padding: 0.3rem 0.4rem;
margin-left: -0.1rem;
${({ theme }) => theme.colors.text.block};
${({ theme, averageScore }) => {
${({ theme, averageScore, isScoreExists }) => {
if (!isScoreExists) {
return css`
background: ${theme.baseColors.grayscale[300]};
color: ${theme.colors.text.block};
`;
}
if (averageScore >= 1 && averageScore < 2) {
return css`
color: ${theme.baseColors.redscale[500]};
Expand Down Expand Up @@ -77,15 +87,18 @@ const CardEvaluationFlag = styled.div<{ averageScore: number; evaluationCount: n
return css`
background: ${theme.baseColors.grayscale[300]};
color: ${theme.colors.text.default};
`;
}}
`;

const CardEvaluationFlagScore = styled.span<{ isScoreExists: boolean }>`
padding-right: ${({ isScoreExists }) => (isScoreExists ? '0' : '0.2rem')};
`;

const CardInfoContainer = styled.div`
display: flex;
flex-direction: row;
gap: 2.4rem;
gap: 1.6rem;
${({ theme }) => theme.typography.common.small};
color: ${({ theme }) => theme.baseColors.grayscale[800]};
Expand All @@ -108,6 +121,7 @@ const S = {
CardDetail,
CardHeader,
CardEvaluationFlag,
CardEvaluationFlagScore,
CardInfoContainer,
CardInfo,
OptionButtonWrapper,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import type { Meta, StoryObj } from '@storybook/react';
import { reactRouterParameters, withRouter } from 'storybook-addon-remix-react-router';
import { SpecificApplicantIdProvider } from '@contexts/SpecificApplicnatIdContext';
import { SpecificProcessIdProvider } from '@contexts/SpecificProcessIdContext';
import { FloatingEmailFormProvider } from '@contexts/FloatingEmailFormContext';
import { MultiApplicantContextProvider } from '@contexts/MultiApplicantContext';
import ProcessColumn from './index';

const meta: Meta<typeof ProcessColumn> = {
Expand Down Expand Up @@ -36,7 +38,11 @@ const meta: Meta<typeof ProcessColumn> = {
(Child) => (
<SpecificApplicantIdProvider>
<SpecificProcessIdProvider>
<Child />
<FloatingEmailFormProvider>
<MultiApplicantContextProvider>
<Child />
</MultiApplicantContextProvider>
</FloatingEmailFormProvider>
</SpecificProcessIdProvider>
</SpecificApplicantIdProvider>
),
Expand Down
26 changes: 20 additions & 6 deletions frontend/src/components/dashboard/ProcessColumn/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { useParams } from 'react-router-dom';

import { useSpecificApplicantId } from '@contexts/SpecificApplicnatIdContext';
import { useSpecificProcessId } from '@contexts/SpecificProcessIdContext';
import { Process } from '@customTypes/process';
import { DropdownItemType } from '@components/_common/molecules/DropdownItemRenderer';

import useProcess from '@hooks/useProcess';
import useApplicant from '@hooks/useApplicant';
import { useModal } from '@contexts/ModalContext';
import specificApplicant from '@hooks/useSpecificApplicant';

import { useSpecificApplicantId } from '@contexts/SpecificApplicnatIdContext';
import { useSpecificProcessId } from '@contexts/SpecificProcessIdContext';
import { useModal } from '@contexts/ModalContext';
import { DropdownProvider } from '@contexts/DropdownContext';

import { DropdownItemType } from '@components/_common/molecules/DropdownItemRenderer';
import specificApplicant from '@hooks/useSpecificApplicant';
import { useFloatingEmailForm } from '@contexts/FloatingEmailFormContext';
import { useMultiApplicant } from '@contexts/MultiApplicantContext';

import ApplicantCard from '../ApplicantCard';
import ProcessDescription from './ProcessDescription';
import S from './style';
Expand All @@ -32,6 +34,7 @@ export default function ProcessColumn({ process, showRejectedApplicant, isPassed
const { setProcessId } = useSpecificProcessId();
const { open } = useModal();
const { open: sideEmailFormOpen } = useFloatingEmailForm();
const { isMultiType, applicants, addApplicant, removeApplicant } = useMultiApplicant();

const menuItemsList = ({ applicantId }: { applicantId: number }) => {
const menuItems: DropdownItemType[] = [
Expand Down Expand Up @@ -73,6 +76,14 @@ export default function ProcessColumn({ process, showRejectedApplicant, isPassed
return menuItems;
};

const applicantSelectHandler = (id: number, isChecked: boolean) => {
if (isChecked) {
addApplicant(id);
} else {
removeApplicant(id);
}
};

const cardClickHandler = (id: number) => {
setApplicantId(id);
setProcessId(process.processId);
Expand All @@ -97,7 +108,10 @@ export default function ProcessColumn({ process, showRejectedApplicant, isPassed
evaluationCount={evaluationCount}
averageScore={averageScore}
popOverMenuItems={menuItemsList({ applicantId })}
isSelectMode={isMultiType}
isSelected={applicants.includes(applicantId)}
onCardClick={() => cardClickHandler(applicantId)}
onSelectApplicant={(isChecked: boolean) => applicantSelectHandler(applicantId, isChecked)}
/>
</DropdownProvider>
))}
Expand Down

0 comments on commit 0c2585d

Please sign in to comment.