김재형

Implement FileList component

...@@ -7965,10 +7965,9 @@ ...@@ -7965,10 +7965,9 @@
7965 "optional": true 7965 "optional": true
7966 }, 7966 },
7967 "filesize": { 7967 "filesize": {
7968 - "version": "6.0.1", 7968 + "version": "6.1.0",
7969 - "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.0.1.tgz", 7969 + "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
7970 - "integrity": "sha512-u4AYWPgbI5GBhs6id1KdImZWn5yfyFrrQ8OWZdN7ZMfA8Bf4HcO0BGo9bmUIEV8yrp8I1xVfJ/dn90GtFNNJcg==", 7970 + "integrity": "sha512-LpCHtPQ3sFx67z+uh2HnSyWSLLu5Jxo21795uRDuar/EOuYWXib5EmPaGIBuSnRqH2IODiKA2k5re/K9OnN/Yg=="
7971 - "dev": true
7972 }, 7971 },
7973 "fill-range": { 7972 "fill-range": {
7974 "version": "7.0.1", 7973 "version": "7.0.1",
...@@ -17053,6 +17052,12 @@ ...@@ -17053,6 +17052,12 @@
17053 "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", 17052 "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
17054 "dev": true 17053 "dev": true
17055 }, 17054 },
17055 + "filesize": {
17056 + "version": "6.0.1",
17057 + "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.0.1.tgz",
17058 + "integrity": "sha512-u4AYWPgbI5GBhs6id1KdImZWn5yfyFrrQ8OWZdN7ZMfA8Bf4HcO0BGo9bmUIEV8yrp8I1xVfJ/dn90GtFNNJcg==",
17059 + "dev": true
17060 + },
17056 "has-flag": { 17061 "has-flag": {
17057 "version": "3.0.0", 17062 "version": "3.0.0",
17058 "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 17063 "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
7 "@ant-design/icons": "^4.2.1", 7 "@ant-design/icons": "^4.2.1",
8 "antd": "^4.3.3", 8 "antd": "^4.3.3",
9 "classnames": "^2.2.6", 9 "classnames": "^2.2.6",
10 + "filesize": "^6.1.0",
10 "ky": "^0.20.0", 11 "ky": "^0.20.0",
11 "miragejs": "^0.1.40", 12 "miragejs": "^0.1.40",
12 "react": "^16.13.1", 13 "react": "^16.13.1",
......
1 +.actions {
2 + a {
3 + margin: 0 4px;
4 + }
5 +}
1 import React from "react"; 1 import React from "react";
2 +import { Table } from "antd";
3 +import { ColumnsType } from "antd/lib/table";
4 +import filesize from "filesize";
5 +
2 import { useParams } from "react-router-dom"; 6 import { useParams } from "react-router-dom";
3 -import { useFileList } from "./useFileList"; 7 +import { useFileList, FileItem } from "./useFileList";
8 +import { FileListItem } from "./FileListItem";
9 +
10 +import styles from "./FileList.module.scss";
11 +
12 +const columns: ColumnsType<FileItem> = [
13 + {
14 + title: "파일명",
15 + dataIndex: "name",
16 + render: (_name: string, item) => <FileListItem item={item} />,
17 + },
18 + {
19 + title: "크기",
20 + dataIndex: "size",
21 + width: 120,
22 + render: (bytes: number, item) =>
23 + item.is_folder ? "" : filesize(bytes, { round: 0 }),
24 + },
25 + {
26 + title: "",
27 + dataIndex: "",
28 + width: 200,
29 + render: (__: any, item) =>
30 + item.is_folder ? null : (
31 + <div className={styles.actions}>
32 + <a>공유</a>
33 + <a>이동</a>
34 + <a>복사</a>
35 + <a>삭제</a>
36 + </div>
37 + ),
38 + },
39 +];
4 40
5 export function FileList() { 41 export function FileList() {
6 const id = useParams<{ id: string }>().id; 42 const id = useParams<{ id: string }>().id;
7 const { data } = useFileList(id); 43 const { data } = useFileList(id);
8 44
9 - return <div>{JSON.stringify(data, null, 2)}</div>; 45 + if (data && data.parent !== null) {
46 + data.list.unshift(({
47 + id: data.parent,
48 + is_folder: true,
49 + name: "..",
50 + file_type: "folder",
51 + } as unknown) as FileItem);
52 + }
53 +
54 + return data && <Table columns={columns} dataSource={data.list} />;
10 } 55 }
......
1 +import React, { Fragment } from "react";
2 +import { FileItem } from "./useFileList";
3 +
4 +export function FileListItem({ item }: { item: FileItem }) {
5 + return <Fragment>{item.name}</Fragment>;
6 +}
1 import { useState, useCallback, useEffect } from "react"; 1 import { useState, useCallback, useEffect } from "react";
2 import ky from "ky"; 2 import ky from "ky";
3 3
4 -interface FileListResponse { 4 +interface FileListData extends FileItem {
5 - data: FileItem & {
6 list: FileItem[]; 5 list: FileItem[];
7 - };
8 } 6 }
9 7
10 -interface FileItem { 8 +interface FileListResponse {
9 + data: FileListData;
10 +}
11 +
12 +export interface FileItem {
11 is_folder: boolean; 13 is_folder: boolean;
12 name: string; 14 name: string;
13 file_type: "folder" | "file"; 15 file_type: "folder" | "file";
...@@ -22,29 +24,15 @@ interface FileItem { ...@@ -22,29 +24,15 @@ interface FileItem {
22 id: number; 24 id: number;
23 } 25 }
24 26
25 -interface Token {
26 - accessToken: string;
27 - refreshToken: string;
28 - expiration: Date;
29 - user: {
30 - id: number;
31 - username: string;
32 - name: string;
33 - totalSize: number;
34 - currentSize: number;
35 - rootFolder: number;
36 - };
37 -}
38 -
39 export function useFileList(id: string) { 27 export function useFileList(id: string) {
40 - const [data, setData] = useState<FileListResponse | null>(null); 28 + const [data, setData] = useState<FileListData | null>(null);
41 29
42 const reload = useCallback(async () => { 30 const reload = useCallback(async () => {
43 const response = await ky 31 const response = await ky
44 .get(`/items/${id}/children/`) 32 .get(`/items/${id}/children/`)
45 .json<FileListResponse>(); 33 .json<FileListResponse>();
46 34
47 - setData(response); 35 + setData(response.data);
48 }, [id]); 36 }, [id]);
49 37
50 useEffect(() => { 38 useEffect(() => {
......