Skip to content

Commit

Permalink
Merge pull request #343 from Leets-Official/feat#332/기수-관련-ui
Browse files Browse the repository at this point in the history
#332 Feat:기수 관련 UI
  • Loading branch information
dalzzy authored Jan 30, 2025
2 parents b3072e8 + e44376d commit 2912d43
Show file tree
Hide file tree
Showing 19 changed files with 538 additions and 73 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"cSpell.words": ["Admincardinal"]
}
41 changes: 41 additions & 0 deletions src/components/Admin/AddCardinal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import theme from '@/styles/theme';
import styled from 'styled-components';
import plusIcon from '@/assets/images/ic_admin_plus.svg';
import { useState } from 'react';
import CardinalModal from '@/components/Admin/Modal/CardinalModal';

export const AddCardinalWrapper = styled.div`
width: 80px;
height: 164px;
box-sizing: border-box;
background-color: ${theme.color.gray[100]};
display: flex;
justify-content: center;
text-align: center;
align-items: center;
cursor: pointer;
`;

const AddCardinal: React.FC = () => {
const [isModalOpen, setIsModalOpen] = useState(false);

const handleOpenModal = () => {
setIsModalOpen(true);
};

const handleCloseModal = () => {
setIsModalOpen(false);
};

return (
<>
<AddCardinalWrapper onClick={handleOpenModal}>
<img src={plusIcon} alt="plus" />
</AddCardinalWrapper>

<CardinalModal isOpen={isModalOpen} onClose={handleCloseModal} />
</>
);
};

export default AddCardinal;
14 changes: 8 additions & 6 deletions src/components/Admin/CardinalInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import theme from '@/styles/theme';
import styled from 'styled-components';
import AddCardinal from '@/components/Admin/Modal/AddCardinal';
import AddCardinal from '@/components/Admin/AddCardinal';
import { BoxWrapper } from './TotalDues';
import Box from './Box';

const CardinalBoxWrapper = styled(BoxWrapper)`
padding: 30px 0 30px 0;
padding: 0 0 30px 0;
box-sizing: border-box;
`;

const boxData = [
{
id: 'cardinal-total',
Expand All @@ -18,28 +20,28 @@ const boxData = [
id: 'cardinal-4',
title: '24년 2학기(현재)',
description: '4기',
last: '동장 노정완 외 25명',
last: '노정완 외 25명',
color: `${theme.color.gray[65]}`,
},
{
id: 'cardinal-3',
title: '24년 1학기',
description: '3기',
last: '동장 김성민 외 25명',
last: '김성민 외 25명',
color: `${theme.color.gray[65]}`,
},
{
id: 'cardinal-2',
title: '23년 2학기',
description: '2기',
last: '동장 김성민 외 25명',
last: '김성민 외 25명',
color: `${theme.color.gray[65]}`,
},
{
id: 'cardinal-1',
title: '23년 1학기',
description: '1기',
last: '동장 김성민 외 25명',
last: '김성민 외 25명',
color: `${theme.color.gray[65]}`,
},
];
Expand Down
4 changes: 2 additions & 2 deletions src/components/Admin/MemberListTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ export const TableContainer = styled.div`
`;

const MemberListTable: React.FC<MemberListTableProps> = ({ columns }) => {
const { members } = useMemberContext();
const { filteredMembers } = useMemberContext();
return (
<TableContainer>
<StatusList />
<TableWrapper>
<table>
<MemberListTableHeader columns={columns} />
<tbody>
{members.map((row) => (
{filteredMembers.map((row) => (
<MemberListTableRow
key={row.studentId}
columns={columns}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Admin/MemberListTableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const StatusCell = styled.td<{ statusColor: string }>`
background-color: ${({ statusColor }) => statusColor};
`;

const SvgWrapper = styled.td`
export const SvgWrapper = styled.td`
padding: 10px;
text-align: center;
cursor: pointer;
Expand Down
27 changes: 0 additions & 27 deletions src/components/Admin/Modal/AddCardinal.tsx

This file was deleted.

101 changes: 101 additions & 0 deletions src/components/Admin/Modal/CardinalEditModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React, { useState } from 'react';
import Button from '@/components/Button/Button';
import * as S from '@/styles/admin/cardinal/AdminCardinal.styled';
import CommonCardinalModal from './CommonCardinalModal';

interface CardinalChangeModalProps {
isOpen: boolean;
onClose: () => void;
top?: string;
left?: string;
position?: 'center' | 'absolute' | 'fixed';
overlayColor?: string;
}

const CardinalEditModal: React.FC<CardinalChangeModalProps> = ({
isOpen,
onClose,
top = '100px',
left = '50%',
position = 'absolute',
overlayColor = 'transparent',
}) => {
const [cardinalNumber, setCardinalNumber] = useState('');
const [customInput, setCustomInput] = useState('');
const [error, setError] = useState('');

const handleSave = () => {
const inputValue = customInput || cardinalNumber;
if (!inputValue.trim()) {
setError('기수를 입력해주세요.');
return;
}
setError('');
alert(`새로운 기수: ${inputValue}`);
onClose();
};

return (
<CommonCardinalModal
isOpen={isOpen}
onClose={onClose}
title="기수 변경"
width="400px"
height="auto"
top={top}
left={left}
position={position}
overlayColor={overlayColor}
showCloseButton={false}
borderBottom
footer={
<S.FooterWrapper>
<Button
width="80px"
height="45px"
borderRadius="4px"
color="#2f2f2f"
onClick={onClose}
>
Cancel
</Button>
<Button
width="70px"
height="45px"
color="#2f2f2f"
borderRadius="4px"
onClick={handleSave}
>
저장
</Button>
</S.FooterWrapper>
}
>
<S.ModalContentWrapper>
<S.InputGroup>
<S.StyledInput
type="text"
placeholder="숫자만 입력"
value={cardinalNumber}
onChange={(e) => setCardinalNumber(e.target.value)}
flex={2}
maxWidth="65%"
/>
<S.StyledInput
type="text"
placeholder="직접 입력"
value={customInput}
onChange={(e) => setCustomInput(e.target.value)}
flex={1}
maxWidth="35%"
/>
</S.InputGroup>
<S.ErrorMessage>
*저장되지 않은 숫자는 새로운 기수로 추가됩니다.
</S.ErrorMessage>
</S.ModalContentWrapper>
</CommonCardinalModal>
);
};

export default CardinalEditModal;
66 changes: 66 additions & 0 deletions src/components/Admin/Modal/CardinalModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { useState } from 'react';
import styled from 'styled-components';
import Button from '@/components/Button/Button';
import CheckBox from '@/assets/images/ic_admin_checkbox.svg';
import UnCheckBox from '@/assets/images/ic_admin_uncheckbox.svg';
import * as S from '@/styles/admin/cardinal/AdminCardinal.styled';
import CommonCardinalModal from './CommonCardinalModal';

interface CardinalModalProps {
isOpen: boolean;
onClose: () => void;
}

export const ModalContentWrapper = styled.div`
padding: 20px;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 20px;
`;

const CardinalModal: React.FC<CardinalModalProps> = ({ isOpen, onClose }) => {
const [isChecked, setIsChecked] = useState(false);

const handleCheckBoxClick = () => {
setIsChecked((prev) => !prev);
};

return (
<CommonCardinalModal
isOpen={isOpen}
onClose={onClose}
width="400px"
height="auto"
top="20%"
left="40%"
position="absolute"
overlayColor="rgba(0,0,0,0.5)"
showCloseButton
footer={
<Button width="60px" height="48px" color="#323232" borderRadius="4px">
저장
</Button>
}
>
<ModalContentWrapper>
<S.Title>추가할 새로운 기수를 작성해주세요</S.Title>
<S.Input type="text" placeholder="기" />
<div>활동 시기</div>
<S.FlexRow>
<S.Input type="text" placeholder="년" />
<S.Input type="text" placeholder="학기" />
</S.FlexRow>
<S.SvgText onClick={handleCheckBoxClick}>
<img
src={isChecked ? CheckBox : UnCheckBox}
alt={isChecked ? 'checked' : 'unchecked'}
/>
<div> 현재 진행 중 </div>
</S.SvgText>
</ModalContentWrapper>
</CommonCardinalModal>
);
};

export default CardinalModal;
72 changes: 72 additions & 0 deletions src/components/Admin/Modal/CommonCardinalModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import Modal from 'react-modal';
import * as S from '@/styles/admin/cardinal/AdminCardinal.styled';
import closeIcon from '@/assets/images/ic_admin_close.svg';
import { CloseIcon } from './CommonModal';

interface CommonCardinalModalProps {
isOpen: boolean;
onClose: () => void;
title?: string;
children: React.ReactNode;
footer?: React.ReactNode;
width?: string;
height?: string;
top?: string;
left?: string;
overlayColor?: string;
showCloseButton?: boolean;
position: 'center' | 'absolute' | 'fixed';
borderBottom?: boolean;
}

const CommonCardinalModal: React.FC<CommonCardinalModalProps> = ({
isOpen,
onClose,
title,
children,
footer,
width = '500px',
height = 'auto',
top = '50%',
left = '50%',
overlayColor = 'rgba(0,0,0,0.5)',
showCloseButton = true,
position = 'center',
borderBottom = false,
}) => {
return (
<Modal
isOpen={isOpen}
onRequestClose={onClose}
style={{
overlay: { backgroundColor: 'transparent' },
content: { inset: 'unset' },
}}
>
<S.StyledModalOverlay overlayColor={overlayColor}>
<S.StyledModalContent
width={width}
height={height}
top={top}
left={left}
position={position}
>
<S.ModalContainer>
<S.TitleContainer borderBottom={borderBottom}>
<S.TitleText>{title}</S.TitleText>
{showCloseButton && (
<CloseIcon src={closeIcon} alt="close" onClick={onClose} />
)}
</S.TitleContainer>
<S.MainContent borderBottom={borderBottom}>
{children}
</S.MainContent>
<S.Footer>{footer}</S.Footer>
</S.ModalContainer>
</S.StyledModalContent>
</S.StyledModalOverlay>
</Modal>
);
};

export default CommonCardinalModal;
Loading

0 comments on commit 2912d43

Please sign in to comment.