Skip to content

Commit

Permalink
Feature/#187 학습자료 생성모달 (#212)
Browse files Browse the repository at this point in the history
* feat : 제목, 소개, 공개범위

#187

* feat : 파일 삽입 기능 추가

#187

* design : 추가하기 버튼 그림자 추가

#187

* design : divider 위치 변경

#187

* design : minH : 40px 추가

#187
  • Loading branch information
jasper200207 authored May 16, 2024
1 parent 5249ed1 commit fe30cab
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/components/IconBox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { IconBoxProps } from './type';

const IconBox = ({ leftIcon, content, rightIcon, handleClick }: IconBoxProps) => {
return (
<Flex align="center" gap="1" w="100%" h="40px" color="white" bg="orange_light" borderRadius="2xl">
<Flex align="center" gap="1" w="100%" h="40px" minH="40px" color="white" bg="orange_light" borderRadius="2xl">
<IconButton as="div" flexShrink="0" aria-label="" icon={leftIcon} size="icon_md" variant="transparent" />
<Text textStyle="bold_md" flex="auto" cursor="default" isTruncated>
{content}
Expand Down
165 changes: 165 additions & 0 deletions src/containers/study/DocumentModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
'use client';

import { Divider, Flex, Input, Text, Textarea, Button } from '@chakra-ui/react';
import { ChangeEvent, useRef, useState } from 'react';
import { BiFile, BiImage, BiTrash } from 'react-icons/bi';
import { BsLink45Deg } from 'react-icons/bs';

import IconBox from '@/components/IconBox';
import ActionModal from '@/components/Modal/ActionModal';
import StyledRadio from '@/components/StyledRadio';
import StyledRadioGroup from '@/components/StyledRadioGroup';
import color from '@/constants/color';
import { DocumentModalProps, DocumentType, DocumentList } from '@/containers/study/DocumentModal/type';

const DocumentBoxIcon = {
img: <BiImage />,
file: <BiFile />,
url: <BsLink45Deg />,
};

const DocumentModal = ({ isOpen, onClose }: DocumentModalProps) => {
const [doctype, setDocType] = useState<DocumentType>('img');
const [docList, setDocList] = useState<DocumentList>({
img: [],
file: [],
url: [],
});
const imgInputRef = useRef<HTMLInputElement>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
const urlInputRef = useRef<HTMLInputElement>(null);

const onConfirmButtonClick = () => {
onClose();
};

const handleGetDoc = {
img: (e: ChangeEvent<HTMLInputElement>) => {
const imgs = Array.from(e.target.files || []);
setDocList((prev) => ({
...prev,
img: [
...prev.img,
...imgs.map((img) => ({
name: img.name,
content: img,
})),
],
}));
},
file: (e: ChangeEvent<HTMLInputElement>) => {
const files = Array.from(e.target.files || []);
setDocList((prev) => ({
...prev,
file: [
...prev.file,
...files.map((file) => ({
name: file.name,
content: file,
})),
],
}));
},
url: () => {
if (urlInputRef.current?.value) {
const url = urlInputRef.current.value;
setDocList((prev) => ({
...prev,
url: [
...prev.url,
{
name: url,
content: url,
},
],
}));
urlInputRef.current.value = '';
}
},
};

const handleAddDoc = {
img: () => {
imgInputRef.current?.click();
},
file: () => {
fileInputRef.current?.click();
},
url: () => {
handleGetDoc.url();
},
};

const handleRemoveDoc = (index: number) => {
setDocList((prev) => {
const newList = { ...prev };
newList[doctype] = newList[doctype].filter((_, idx) => idx !== index);
return newList;
});
};

return (
<ActionModal
isOpen={isOpen}
size="xl"
onClose={onClose}
title="학습자료 등록"
subButtonText="취소"
onSubButtonClick={onClose}
mainButtonText="등록"
onMainButtonClick={onConfirmButtonClick}
>
<Flex direction="column" gap="4">
<Text textStyle="bold_xl">학습자료 제목</Text>
<Input placeholder="학습자료 제목을 입력해주세요." />
<Text textStyle="bold_xl">학습자료 소개</Text>
<Textarea placeholder="학습자료 소개를 입력해주세요." />
<StyledRadioGroup title="파일 유형" value={doctype} onChange={(v) => setDocType(v as DocumentType)}>
<StyledRadio value="img">이미지</StyledRadio>
<StyledRadio value="file">파일</StyledRadio>
<StyledRadio value="url">URL 링크</StyledRadio>
</StyledRadioGroup>
<Flex justify="end" direction="row" gap="4" shrink="0">
<Input
ref={urlInputRef}
flex="1"
h="7"
shadow="md"
hidden={doctype !== 'url'}
placeholder="URL 링크를 입력해주세요."
/>
<Button w="28" h="7" shadow="md" onClick={() => handleAddDoc[doctype]()} variant="orange">
추가하기
</Button>
</Flex>
<Divider borderWidth="2px" borderColor={color.orange_dark} />
<input
hidden
type="file"
multiple
accept="image/jpg,image/png,image/jpeg,image/gif"
ref={imgInputRef}
onChange={handleGetDoc.img}
/>
<input hidden type="file" multiple ref={fileInputRef} onChange={handleGetDoc.file} />
<Flex direction="column" gap="4" overflow="scroll" maxH="52" shrink="0">
{docList[doctype].map((doc, index) => (
<IconBox
key={`${doc}`}
leftIcon={DocumentBoxIcon[doctype]}
content={doc.name}
rightIcon={<BiTrash />}
handleClick={() => handleRemoveDoc(index)}
/>
))}
</Flex>
<StyledRadioGroup title="공개 범위" defaultValue="all">
<StyledRadio value="all">전체 공개</StyledRadio>
<StyledRadio value="only_study">스터디 공개</StyledRadio>
</StyledRadioGroup>
</Flex>
</ActionModal>
);
};

export default DocumentModal;
15 changes: 15 additions & 0 deletions src/containers/study/DocumentModal/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export interface DocumentModalProps {
isOpen: boolean;
onClose: () => void;
}

export type DocumentType = 'img' | 'file' | 'url';

interface Document {
name: string;
content: string | File;
}

export type DocumentList = {
[key in DocumentType]: Array<Document>;
};

0 comments on commit fe30cab

Please sign in to comment.