From 2ba5da4b736d0e5fc393d25e1a978ffdb6a62e13 Mon Sep 17 00:00:00 2001 From: Khairul Hidayat Date: Thu, 4 Apr 2024 06:40:16 +0700 Subject: [PATCH] feat: update file manager --- backend/routes/files/delete.ts | 22 ++++++++ backend/routes/files/index.ts | 4 +- src/app/apps/files.tsx | 52 +++++++++++++++++-- .../containers/AudioPlayerProvider.tsx | 33 ++++++++---- src/components/pages/files/FileMenu.tsx | 27 +++++++++- src/components/pages/music/AudioPlayer.tsx | 1 - src/components/pages/music/MiniPlayer.tsx | 35 +++++++++---- src/components/ui/Button.tsx | 4 ++ src/components/ui/Input.tsx | 27 +++++++--- src/hooks/useDisclosure.ts | 17 ++++++ src/stores/audioPlayerStore.ts | 13 ++++- 11 files changed, 199 insertions(+), 36 deletions(-) create mode 100644 backend/routes/files/delete.ts create mode 100644 src/hooks/useDisclosure.ts diff --git a/backend/routes/files/delete.ts b/backend/routes/files/delete.ts new file mode 100644 index 0000000..cbb5244 --- /dev/null +++ b/backend/routes/files/delete.ts @@ -0,0 +1,22 @@ +import type { Context } from "hono"; +import { z } from "zod"; +import { getFilePath } from "./utils"; +import fs from "fs"; +import { HTTPException } from "hono/http-exception"; + +const schema = z.object({ + path: z.string().min(1), +}); + +export const deleteFile = async (c: Context) => { + const data = schema.parse(await c.req.json()); + const { path } = getFilePath(data.path); + + if (!fs.existsSync(path)) { + throw new HTTPException(404, { message: "File not found!" }); + } + + await fs.promises.unlink(path); + + return c.json({ result: true }); +}; diff --git a/backend/routes/files/index.ts b/backend/routes/files/index.ts index 24c2b4a..c96f0ac 100644 --- a/backend/routes/files/index.ts +++ b/backend/routes/files/index.ts @@ -6,6 +6,7 @@ import { download } from "./download"; import { getYtdl, ytdl } from "./ytdl"; import cache from "../../middlewares/cache"; import { getId3Tags, getId3Image } from "./id3Tags"; +import { deleteFile } from "./delete"; const cacheFile = cache({ ttl: 86400 }); @@ -16,6 +17,7 @@ const route = new Hono() .get("/ytdl/:id", getYtdl) .get("/download/*", cacheFile, download) .get("/id3-tags/*", cacheFile, getId3Tags) - .get("/id3-img/*", cacheFile, getId3Image); + .get("/id3-img/*", cacheFile, getId3Image) + .delete("/delete", deleteFile); export default route; diff --git a/src/app/apps/files.tsx b/src/app/apps/files.tsx index 2ca94e5..dbb9995 100644 --- a/src/app/apps/files.tsx +++ b/src/app/apps/files.tsx @@ -5,7 +5,7 @@ import { useAuth } from "@/stores/authStore"; import BackButton from "@ui/BackButton"; import Input from "@ui/Input"; import { Stack } from "expo-router"; -import React, { useState } from "react"; +import React, { useMemo, useState } from "react"; import { useMutation, useQuery } from "react-query"; import FileDrop from "@/components/pages/files/FileDrop"; import { showToast } from "@/stores/toastStore"; @@ -28,6 +28,9 @@ const FilesPage = () => { path: "", }); const [viewFile, setViewFile] = useState(null); + const [isSearching, setSearching] = useState(false); + const [search, setSearch] = useState(""); + const parentPath = params.path.length > 0 ? params.path.split("/").slice(0, -1).join("/") @@ -65,6 +68,18 @@ const FilesPage = () => { } }; + const files = useMemo(() => { + let items = [...(data || [])].map((item, idx) => ({ ...item, idx })); + + if (search) { + items = items.filter((item) => + item.name.toLowerCase().includes(search.toLowerCase()) + ); + } + + return items; + }, [data, search]); + if (!isLoggedIn) { return null; } @@ -81,7 +96,34 @@ const FilesPage = () => { > , title: "Files" }} + options={{ + headerLeft: () => , + title: "Files", + headerRight: () => ( +