commit 1d75dddd4cff1a529bc67be5e8c7c0fd0b6868ff
parent 1a98b23bc5891fcc1c14ef160b8ab06365141010
Author: 諒太 林 <ryouturn@gmail.com>
Date: Wed, 10 Jul 2024 18:10:43 +0900
add some code but it still not work
Diffstat:
4 files changed, 193 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
@@ -4,4 +4,7 @@
This app is creating for one-time image uploader in Pim.
## Design
-This app use nextjs. Also it mean that it using nodejs and react.-
\ No newline at end of file
+This app use nextjs. Also it mean that it using nodejs and react.
+
+### 参考文献
+https://tech.andpad.co.jp/entry/2023/12/10/100000+
\ No newline at end of file
diff --git a/image-uploader/package.json b/image-uploader/package.json
@@ -21,5 +21,6 @@
"eslint": "^9.6.0",
"eslint-config-next": "14.2.4",
"typescript": "^5.5.3"
- }
+ },
+ "packageManager": "pnpm@9.5.0+sha512.140036830124618d624a2187b50d04289d5a087f326c9edfc0ccd733d76c4f52c3a313d4fc148794a2a9d81553016004e6742e8cf850670268a7387fc220c903"
}
diff --git a/image-uploader/src/app/fileuploadform.tsx b/image-uploader/src/app/fileuploadform.tsx
@@ -0,0 +1,182 @@
+import type { NextPage } from "next";
+import React, { useState, useCallback } from "react";
+import { useDropzone } from "react-dropzone";
+import type { FileRejection } from "react-dropzone";
+
+const FileUploader: NextPage = () => {
+ const [currentShowFiles, setCurrentShowFiles] = useState<
+ { file: File; isUploaded: boolean }[]
+ >([]);
+
+ const onUploadFile = async (file: File) => {
+ try {
+ setCurrentShowFiles((prevFiles) => [
+ ...prevFiles,
+ { file, isUploaded: false },
+ ]);
+
+ const uploadTime = Math.random() * 9000 + 1000; // 1秒から10秒
+ await new Promise((resolve) => setTimeout(resolve, uploadTime));
+
+ setCurrentShowFiles((prevFiles) =>
+ prevFiles.map((f) =>
+ f.file.name === file.name ? { ...f, isUploaded: true } : f,
+ ),
+ );
+ } catch (error) {
+ // ↓ここでエラーに関するユーザーへの通知や処理を行う
+ alert(`アップロード中にエラーが発生しました: ${error}`);
+ }
+ };
+
+ const onDrop = useCallback(
+ async (acceptedFiles: File[]) => {
+ // ドロップしたファイルの中で、現在表示されているファイルと重複しているもの( filename と size が同じファイル)を除外する。
+ const filteringFiles = acceptedFiles.filter(
+ (file) =>
+ !currentShowFiles?.find(
+ (showFile) =>
+ file.name === showFile.file.name &&
+ file.size === showFile.file.size,
+ ),
+ );
+
+ // ドロップしたファイルと現在表示されているファイルの合計が 10 を超える場合、追加を許可しない。
+ if (filteringFiles.length + currentShowFiles.length > 10) {
+ alert("最大10ファイルまでアップロードできます。");
+ return;
+ }
+
+ // アップロード可能なファイルが存在する場合、アップロード中のスイッチを true にし、アップロードを開始する
+ if (filteringFiles.length) {
+ try {
+ await Promise.all(filteringFiles.map((file) => onUploadFile(file)));
+ // ↓すべてのファイルのアップロードが成功した後の処理を書く
+ } catch (error) {
+ // ↓ここでエラーに関するユーザーへの通知や処理を行う
+ alert(`アップロード中にエラーが発生しました: ${error}`);
+ }
+ }
+ },
+ [currentShowFiles],
+ );
+
+ const onDropRejected = useCallback((rejectedFiles: FileRejection[]) => {
+ rejectedFiles.forEach(({ file, errors }) => {
+ errors.forEach(({ code }) => {
+ let message = "エラーが発生しました。";
+ switch (code) {
+ case "file-too-large":
+ message = `${file.name} のファイルサイズが大きすぎます。50MB以下のファイルをアップロードしてください。`;
+ break;
+ case "file-invalid-type":
+ message = `${file.name} のファイル形式が許可されていません。許可されているファイル形式は jpg, png, pdf, doc, docx, xls, xlsx, ppt, pptx です。`;
+ break;
+ default:
+ break;
+ }
+ alert(message);
+ });
+ });
+ }, []);
+
+ const { getRootProps, getInputProps, isDragAccept, isDragReject } =
+ useDropzone({
+ onDrop,
+ onDropRejected,
+ accept: {
+ "image/jpeg": [],
+ "image/png": [],
+ "application/pdf": [],
+ },
+ maxSize: 50 * 1024 * 1024, // 50MB
+ });
+
+ // ドラッグ中のスタイルを設定
+ const setDropZoneStyle = () => {
+ if (isDragAccept) {
+ return styles.is_drag_accept;
+ } else if (isDragReject) {
+ return styles.is_drag_reject;
+ } else {
+ return "";
+ }
+ };
+
+ const removeFile = (index: number) => {
+ const filteringFiles = currentShowFiles.filter(
+ (_, i) => i !== index,
+ );
+ setCurrentShowFiles(filteringFiles);
+ };
+
+ return (
+ <div>
+ <div>
+ <div
+ {...getRootProps()}
+ >
+ <input {...getInputProps()} />
+ <p>
+ {isDragAccept
+ ? "ファイルをアップロードします。"
+ : isDragReject
+ ? "エラー"
+ : "ファイルを登録してください。"}
+ </p>
+ <p>
+ {isDragReject
+ ? "このファイル形式のアップロードは許可されていません。"
+ : "ファイルを選択するか、ドラッグアンドドロップしてください。"}
+ </p>
+ <button disabled={isDragReject}>ファイルを選択</button>
+ </div>
+ <p>
+ 複数のファイルを選択できます。pdf, png, jpg, jpeg
+ ファイルを選択できます。
+ </p>
+ <p>※1ファイルの最大サイズは50MBです</p>
+ </div>
+ {currentShowFiles && (
+ <aside>
+ <ul>
+ {currentShowFiles.map((item, index) => (
+ <li key={index}>
+ {item.isUploaded ? (
+ <div>
+ <div>
+ <span>
+ </span>
+ </div>
+ <div>
+ <p>{item.file.name}</p>
+ </div>
+ <button
+ type="button"
+ onClick={() => {
+ removeFile(index);
+ }}
+ >
+ <span>
+ </span>
+ </button>
+ </div>
+ ) : (
+ <div>
+ <div>
+ <p>
+ {item.file.name}をアップロードしています…
+ </p>
+ </div>
+ </div>
+ )}
+ </li>
+ ))}
+ </ul>
+ </aside>
+ )}
+ </div>
+ );
+};
+
+export default FileUploader;+
\ No newline at end of file
diff --git a/image-uploader/src/app/page.tsx b/image-uploader/src/app/page.tsx
@@ -1,4 +1,5 @@
'use client'
+import FileUploader from "./fileuploadform";
import styles from "./page.module.css";
import { useDropzone } from "react-dropzone";
@@ -17,9 +18,8 @@ export default function Home() {
<h3>Attention</h3>
<p>Files posted here will be deleted after a set period of time.</p>
</div>
- <div {...getRootProps()} style={{ border: "1px solid #ff7f50", width: 200, height: 150 }}>
- <input {...getInputProps()} />
- <button>upload</button>
+ <div>
+ <FileUploader/>
</div>
<div>
<h4>URL</h4>