From e7d08e7c26ee6b9252eca7eeeebfebedcca0a69a Mon Sep 17 00:00:00 2001 From: chakkun1121 <99847806+chakkun1121@users.noreply.github.com> Date: Mon, 22 Jan 2024 23:18:49 +0000 Subject: [PATCH] =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E5=87=A6?= =?UTF-8?q?=E7=90=86=E3=82=92=E3=82=AB=E3=82=B9=E3=82=BF=E3=83=A0=E3=83=95?= =?UTF-8?q?=E3=83=83=E3=82=AF=E3=81=AB=E5=88=87=E3=82=8A=E5=88=86=E3=81=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(app)/speaking/main.tsx | 34 ++----------- app/(app)/useFile.tsx | 96 +++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 30 deletions(-) create mode 100644 app/(app)/useFile.tsx diff --git a/app/(app)/speaking/main.tsx b/app/(app)/speaking/main.tsx index 0b29469..c0eae10 100644 --- a/app/(app)/speaking/main.tsx +++ b/app/(app)/speaking/main.tsx @@ -1,14 +1,10 @@ "use client"; -import { customSession } from "@/@types/customSession"; -import { fileType } from "@/@types/fileType"; -import { getFileInfo, getFileContent } from "@/googledrive"; import { useDocumentTitle } from "@uidotdev/usehooks"; -import { useSession } from "next-auth/react"; -import { useState, useEffect } from "react"; import Home from "./home"; import { speakingMode } from "@/@types/speakingMode"; import SpeakingPage from "./speaking"; +import { useFile } from "../useFile"; export default function Speaking({ fileId, @@ -17,34 +13,12 @@ export default function Speaking({ fileId: string; mode?: speakingMode; }) { - const [fileContent, setFileContent] = useState(); - const [title, setTitle] = useState(""); - const [loading, setLoading] = useState(true); - const { data: session }: { data: customSession | null } = - useSession() as unknown as { data: customSession }; - const token = session?.accessToken; - - // 初期読み込み - useEffect(() => { - (async () => { - if (!token) return; - try { - await Promise.all([ - setTitle((await getFileInfo(token, fileId)).name), - setFileContent(JSON.parse(await getFileContent(token, fileId))), - ]); - setLoading(false); - } catch (e: any) { - // 空ファイルでは "SyntaxError: Unexpected end of JSON input" を吐くが問題なし - if (e.message !== "Unexpected end of JSON input") console.error(e); - } - })(); - }, [token, fileId]); + const { fileContent, title, loading } = useFile(fileId); useDocumentTitle( - `${title + `${(title || "") .split(".") .slice(0, -1) - .join(".")} | スピーキング練習 | VocabPhrase | chakkun1121` + .join("")} | スピーキング練習 | VocabPhrase | chakkun1121` ); return ( <> diff --git a/app/(app)/useFile.tsx b/app/(app)/useFile.tsx new file mode 100644 index 0000000..7361a72 --- /dev/null +++ b/app/(app)/useFile.tsx @@ -0,0 +1,96 @@ +"use client"; +import { customSession } from "@/@types/customSession"; +import { fileType } from "@/@types/fileType"; +import { + getFileInfo, + getFileContent, + updateFileInfo, + uploadFile, +} from "@/googledrive"; +import { useSession } from "next-auth/react"; +import { useState, useEffect } from "react"; + +export function useFile(fileId: string): { + fileContent: fileType | undefined; + title: string; + updateFileContent: (content: fileType) => void; + updateTitle: (title: string) => void; + loading: boolean; + saving: boolean; +} { + const [fileContent, setFileContent] = useState(); + const [title, setTitle] = useState(""); + const [loading, setLoading] = useState(true); + const { data: session }: { data: customSession | null } = + useSession() as unknown as { data: customSession }; + const token = session?.accessToken; + useEffect(() => { + (async () => { + if (!token) return; + try { + await Promise.all([ + setTitle((await getFileInfo(token, fileId)).name), + setFileContent(JSON.parse(await getFileContent(token, fileId))), + ]); + setLoading(false); + } catch (e: any) { + // 空ファイルでは "SyntaxError: Unexpected end of JSON input" を吐くが問題なし + if (e.message !== "Unexpected end of JSON input") console.error(e); + } + })(); + }, [token, fileId]); + const [shouldSaveTitle, setShouldSaveTitle] = useState(false); // タイトルを保存する必要があるときはtrue + const [shouldSaveFileContent, setShouldSaveFileContent] = useState(false); // ファイル本体を保存する必要があるときはtrue + const [saving, setSaving] = useState(false); // 保存中はtrue + const [titleSaving, setTitleSaving] = useState(false); // タイトルを保存中はtrue + const [fileContentSaving, setFileContentSaving] = useState(false); // ファイル本体を保存中はtrue + + /** + * タイトルを更新します + * @returns + */ + async function updateTitle(title: string) { + if (!token) return; + if (title === "") return; + if (titleSaving) { + setShouldSaveTitle(true); + return; + } + setSaving(true); + setTitleSaving(true); + await updateFileInfo(token, fileId, { + name: title, + }); + if (shouldSaveTitle) updateTitle(title); + setSaving(false); + setTitleSaving(false); + setShouldSaveTitle(false); + } + /** + * ファイル本体を更新します + * @returns + */ + async function updateFileContent(fileContent: fileType) { + if (!token) return; + if (fileContent?.content?.length === 0) return; + if (fileContentSaving) { + setShouldSaveFileContent(true); + return; + } + setSaving(true); + setFileContentSaving(true); + await uploadFile(token, fileId, JSON.stringify(fileContent)); + if (shouldSaveFileContent) updateFileContent(fileContent); + setSaving(false); + setFileContentSaving(false); + setShouldSaveFileContent(false); + } + return { + fileContent, + title, + updateTitle, + updateFileContent, + loading, + saving, + }; +}