From 2dfa86123e94068426d6fd7db1ffa4768fc2b099 Mon Sep 17 00:00:00 2001 From: yougyung Date: Mon, 26 Feb 2024 16:49:56 +0900 Subject: [PATCH 01/16] feat: implement upload-file component --- app/ui/view/molecule/upload-file.tsx | 64 ++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 app/ui/view/molecule/upload-file.tsx diff --git a/app/ui/view/molecule/upload-file.tsx b/app/ui/view/molecule/upload-file.tsx new file mode 100644 index 00000000..0344b9f2 --- /dev/null +++ b/app/ui/view/molecule/upload-file.tsx @@ -0,0 +1,64 @@ +'use client'; + +import React, { useState } from 'react'; +import Image from 'next/image'; +import { Button } from '@/app/ui/view/atom/button/button'; + +type FileType = File | null; + +interface UploadFileProps { + handleSubmit: (file: FileType) => void; +} + +function UploadFile({ handleSubmit }: UploadFileProps) { + const [file, setFile] = useState(null); + + const handleClickInputBox = (e: React.MouseEvent) => { + const fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.onchange = (event) => { + const { files } = event.target as HTMLInputElement; + if (!files) return alert('파일이없다는 처리'); + if (files[0].type !== 'application/pdf') { + alert('pdf가 아니라는 토스트? 모달? 안내'); + return; + } + setFile(files[0]); + }; + fileInput.click(); + }; + + const handleDrop = (event: React.DragEvent) => { + event.preventDefault(); + const droppedFile = event.dataTransfer.files[0]; + if (droppedFile.type !== 'application/pdf') { + alert('PDF 파일이 아닙니다.'); + return; + } + setFile(droppedFile); + }; + + const handleDragOver = (event: React.DragEvent) => { + event.preventDefault(); + }; + + return ( +
+
+ upload-button + + {file ? file.name : `마우스로 드래그 하거나 아이콘을 눌러 직접 추가해주세요.`} + +
+
+ ); +} + +export default UploadFile; From c3bc1ba3d15353fc17b9bffbc937d88a56a9ab8d Mon Sep 17 00:00:00 2001 From: yougyung Date: Sat, 2 Mar 2024 20:36:13 +0900 Subject: [PATCH 02/16] feat: implement file-upload manual --- .../file-upload/components/manual.tsx | 32 +++++++++++++++++++ app/(sub-page)/file-upload/page.tsx | 10 ++++-- 2 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 app/(sub-page)/file-upload/components/manual.tsx diff --git a/app/(sub-page)/file-upload/components/manual.tsx b/app/(sub-page)/file-upload/components/manual.tsx new file mode 100644 index 00000000..ebcd9199 --- /dev/null +++ b/app/(sub-page)/file-upload/components/manual.tsx @@ -0,0 +1,32 @@ +export default function Manual() { + return ( +
+
+

+ 한 번의 성적표 입력으로 +
맞춤형 결과를 확인하세요 ! +

+
+
+ 1. + + MyiWeb MSI + + 에 접속 후 로그인(PC환경 권장) +
+
2. 좌측 성적/졸업 메뉴 → 성적표(상담용,B4)클릭
+
3. 우측 상단 조회버튼 클릭 → 프린트 아이콘 클릭
+
4. 인쇄 정보의 대상(PDF로 저장) 설정 → 하단 저장 버튼 클릭
+
5. 저장한 파일 업로드
+
+ • 회원 가입한 학번과 일치하는 학번의 성적표를 입력해야 합니다. +
+
+
+
+ ); +} diff --git a/app/(sub-page)/file-upload/page.tsx b/app/(sub-page)/file-upload/page.tsx index 12983fe8..a6fc81d8 100644 --- a/app/(sub-page)/file-upload/page.tsx +++ b/app/(sub-page)/file-upload/page.tsx @@ -1,10 +1,14 @@ +import UploadFile from '@/app/ui/view/molecule/upload-file'; import ContentContainer from '../../ui/view/atom/content-container'; +import Manual from './components/manual'; export default function Page() { return ( - -
요소1
-
요소2
+ +
+ + +
); } From 8c375974c14e56f14315751af8cd34215e869898 Mon Sep 17 00:00:00 2001 From: yougyung Date: Sun, 3 Mar 2024 12:10:01 +0900 Subject: [PATCH 03/16] feat: implement useFile hook --- app/(sub-page)/file-upload/page.tsx | 16 +++++++-- app/hooks/useFile.ts | 19 +++++++++++ app/ui/view/molecule/upload-file.tsx | 49 +++++++++------------------- package-lock.json | 11 ++++++- package.json | 3 +- public/upload.svg | 5 +++ 6 files changed, 66 insertions(+), 37 deletions(-) create mode 100644 app/hooks/useFile.ts create mode 100644 public/upload.svg diff --git a/app/(sub-page)/file-upload/page.tsx b/app/(sub-page)/file-upload/page.tsx index a6fc81d8..a6bfa574 100644 --- a/app/(sub-page)/file-upload/page.tsx +++ b/app/(sub-page)/file-upload/page.tsx @@ -1,13 +1,25 @@ +'use client'; + import UploadFile from '@/app/ui/view/molecule/upload-file'; import ContentContainer from '../../ui/view/atom/content-container'; import Manual from './components/manual'; +import Button from '@/app/ui/view/atom/button/button'; +import useFile from '@/app/hooks/useFile'; export default function Page() { + const { file, changeFile } = useFile(); + + const handleClickSubmit = () => { + console.log('api 연결 (lamda, ec2)'); + console.log('전역 상태 변경 (isRegistered)'); + }; + return ( -
+
- + +
); diff --git a/app/hooks/useFile.ts b/app/hooks/useFile.ts new file mode 100644 index 00000000..cb443c63 --- /dev/null +++ b/app/hooks/useFile.ts @@ -0,0 +1,19 @@ +import { useState } from 'react'; +import { z } from 'zod'; + +export type FileType = File | null; + +export default function useFile() { + const [file, setFile] = useState(null); + + const changeFile = (file: File) => { + if (!validate.parse(file.name)) return; + setFile(file); + }; + + const validate = z.string().refine((value) => value.endsWith('.pdf'), { + message: 'File must be a PDF', + }); + + return { file, changeFile }; +} diff --git a/app/ui/view/molecule/upload-file.tsx b/app/ui/view/molecule/upload-file.tsx index 0344b9f2..f7527941 100644 --- a/app/ui/view/molecule/upload-file.tsx +++ b/app/ui/view/molecule/upload-file.tsx @@ -1,41 +1,27 @@ -'use client'; - -import React, { useState } from 'react'; import Image from 'next/image'; -import { Button } from '@/app/ui/view/atom/button/button'; - -type FileType = File | null; +import uploadBox from '@/public/upload.svg'; +import { FileType } from '@/app/hooks/useFile'; interface UploadFileProps { - handleSubmit: (file: FileType) => void; + file: FileType; + changeFile: (file: File) => void; } -function UploadFile({ handleSubmit }: UploadFileProps) { - const [file, setFile] = useState(null); - - const handleClickInputBox = (e: React.MouseEvent) => { - const fileInput = document.createElement('input'); - fileInput.type = 'file'; - fileInput.onchange = (event) => { +function UploadFile({ file, changeFile }: UploadFileProps) { + const handleClickInputBox = () => { + const $input = document.createElement('input'); + $input.type = 'file'; + $input.onchange = (event) => { const { files } = event.target as HTMLInputElement; - if (!files) return alert('파일이없다는 처리'); - if (files[0].type !== 'application/pdf') { - alert('pdf가 아니라는 토스트? 모달? 안내'); - return; - } - setFile(files[0]); + if (files) changeFile(files[0]); }; - fileInput.click(); + $input.click(); }; const handleDrop = (event: React.DragEvent) => { event.preventDefault(); - const droppedFile = event.dataTransfer.files[0]; - if (droppedFile.type !== 'application/pdf') { - alert('PDF 파일이 아닙니다.'); - return; - } - setFile(droppedFile); + const file = event.dataTransfer.files[0]; + changeFile(file); }; const handleDragOver = (event: React.DragEvent) => { @@ -49,14 +35,11 @@ function UploadFile({ handleSubmit }: UploadFileProps) { onDrop={handleDrop} onDragOver={handleDragOver} role="button" - className="p-2 m-auto w-1/2 flex flex-col justify-center items-center gap-2 border-dashed border-2 rounded-sm rounded-bl-xl border-light-blue-6 bg-light-blue-1 text-light-blue-6" + className="p-2 m-auto w-96 flex flex-col justify-center items-center gap-2 border-dashed border-2 rounded-sm rounded-bl-xl border-light-blue-6 bg-light-blue-1 text-light-blue-6" > - upload-button - - {file ? file.name : `마우스로 드래그 하거나 아이콘을 눌러 직접 추가해주세요.`} - + upload-button + {file ? file.name : `마우스로 드래그 하거나 아이콘을 눌러 추가해주세요.`}
-