김재형

Implement file rename

...@@ -3,9 +3,11 @@ import { Popconfirm, Popover, Button, message } from "antd"; ...@@ -3,9 +3,11 @@ import { Popconfirm, Popover, Button, message } from "antd";
3 import { FileItem } from "./useFileList"; 3 import { FileItem } from "./useFileList";
4 import styles from "./FileItemActions.module.scss"; 4 import styles from "./FileItemActions.module.scss";
5 import { FileListPopover } from "./FileListPopover"; 5 import { FileListPopover } from "./FileListPopover";
6 +import { FileRenamePopover } from "./FileRenamePopover";
6 7
7 export type FileItemActionsProps = { 8 export type FileItemActionsProps = {
8 item: FileItem; 9 item: FileItem;
10 + onRename: (id: number, name: string) => void;
9 onMove: (id: number, to: number) => void; 11 onMove: (id: number, to: number) => void;
10 onCopy: (id: number, to: number) => void; 12 onCopy: (id: number, to: number) => void;
11 onDelete: (id: number) => void; 13 onDelete: (id: number) => void;
...@@ -13,18 +15,43 @@ export type FileItemActionsProps = { ...@@ -13,18 +15,43 @@ export type FileItemActionsProps = {
13 15
14 export function FileItemActions({ 16 export function FileItemActions({
15 item, 17 item,
18 + onRename,
16 onMove, 19 onMove,
17 onCopy, 20 onCopy,
18 onDelete, 21 onDelete,
19 }: FileItemActionsProps) { 22 }: FileItemActionsProps) {
23 + const [rename, setRename] = useState<boolean>(false);
20 const [move, setMove] = useState<boolean>(false); 24 const [move, setMove] = useState<boolean>(false);
21 const [copy, setCopy] = useState<boolean>(false); 25 const [copy, setCopy] = useState<boolean>(false);
22 26
23 return ( 27 return (
24 <div className={styles.actions}> 28 <div className={styles.actions}>
29 + <Popover
30 + title="변경할 이름을 입력하세요"
31 + content={
32 + <FileRenamePopover
33 + name={item.name}
34 + onRename={(name: string) => {
35 + if (name === item.name) {
36 + return message.error("동일한 이름으로는 변경할 수 없습니다");
37 + }
38 + if (!name) {
39 + return message.error("변경할 이름을 입력하세요");
40 + }
41 + onRename(item.id, name);
42 + setRename(false);
43 + }}
44 + onCancel={() => setRename(false)}
45 + />
46 + }
47 + trigger="click"
48 + visible={rename}
49 + onVisibleChange={setRename}
50 + >
25 <Button type="link" size="small"> 51 <Button type="link" size="small">
26 이름 변경 52 이름 변경
27 </Button> 53 </Button>
54 + </Popover>
28 <Button type="link" size="small"> 55 <Button type="link" size="small">
29 공유 56 공유
30 </Button> 57 </Button>
......
...@@ -17,6 +17,23 @@ export function FileList() { ...@@ -17,6 +17,23 @@ export function FileList() {
17 17
18 const api = useApi(); 18 const api = useApi();
19 19
20 + const handleRename = useCallback(
21 + async (id: number, name: string) => {
22 + try {
23 + const body = new URLSearchParams();
24 + body.set("name", name);
25 +
26 + await api.post(`/items/${id}/move/`, { body });
27 + await reload();
28 +
29 + message.info("이름이 변경되었습니다");
30 + } catch {
31 + message.error("이름 변경에 실패했습니다");
32 + }
33 + },
34 + [api, reload]
35 + );
36 +
20 const handleMove = useCallback( 37 const handleMove = useCallback(
21 async (id: number, to: number) => { 38 async (id: number, to: number) => {
22 try { 39 try {
...@@ -97,6 +114,7 @@ export function FileList() { ...@@ -97,6 +114,7 @@ export function FileList() {
97 <Table 114 <Table
98 rowKey="id" 115 rowKey="id"
99 columns={getColumns({ 116 columns={getColumns({
117 + handleRename,
100 handleMove, 118 handleMove,
101 handleCopy, 119 handleCopy,
102 handleDelete, 120 handleDelete,
...@@ -109,19 +127,21 @@ export function FileList() { ...@@ -109,19 +127,21 @@ export function FileList() {
109 } 127 }
110 128
111 type GetColumnsParams = { 129 type GetColumnsParams = {
130 + handleRename: (id: number, name: string) => void;
112 handleMove: (id: number, to: number) => void; 131 handleMove: (id: number, to: number) => void;
113 handleCopy: (id: number, to: number) => void; 132 handleCopy: (id: number, to: number) => void;
114 handleDelete: (id: number) => void; 133 handleDelete: (id: number) => void;
115 }; 134 };
116 135
117 function getColumns({ 136 function getColumns({
137 + handleRename,
118 handleMove, 138 handleMove,
119 handleCopy, 139 handleCopy,
120 handleDelete, 140 handleDelete,
121 }: GetColumnsParams): ColumnsType<FileItem> { 141 }: GetColumnsParams): ColumnsType<FileItem> {
122 return [ 142 return [
123 { 143 {
124 - title: "파일명", 144 + title: "이름",
125 key: "name", 145 key: "name",
126 dataIndex: "name", 146 dataIndex: "name",
127 render: (_name: string, item) => <FileListItem item={item} />, 147 render: (_name: string, item) => <FileListItem item={item} />,
...@@ -143,6 +163,7 @@ function getColumns({ ...@@ -143,6 +163,7 @@ function getColumns({
143 item.is_folder ? null : ( 163 item.is_folder ? null : (
144 <FileItemActions 164 <FileItemActions
145 item={item} 165 item={item}
166 + onRename={handleRename}
146 onMove={handleMove} 167 onMove={handleMove}
147 onCopy={handleCopy} 168 onCopy={handleCopy}
148 onDelete={handleDelete} 169 onDelete={handleDelete}
......
1 +import React, { useState } from "react";
2 +import { Button, Input } from "antd";
3 +
4 +export type FileRenamePopoverProps = {
5 + name: string;
6 + onRename: (name: string) => void;
7 + onCancel?: () => void;
8 +};
9 +
10 +export function FileRenamePopover({
11 + name: oldName,
12 + onRename,
13 + onCancel,
14 +}: FileRenamePopoverProps) {
15 + const [name, setName] = useState<string>(oldName);
16 + return (
17 + <div>
18 + <Input
19 + value={name}
20 + onChange={(event) => setName(event.target.value)}
21 + placeholder="이름"
22 + style={{ marginBottom: 10 }}
23 + />
24 + <div className="ant-popover-buttons">
25 + <Button size="small" onClick={onCancel}>
26 + 취소
27 + </Button>
28 + <Button type="primary" size="small" onClick={() => onRename(name)}>
29 + 변경
30 + </Button>
31 + </div>
32 + </div>
33 + );
34 +}