diff --git a/.gitignore b/.gitignore index 5e899e5..3c5e2a2 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,6 @@ next-env.d.ts /data /.*/ /src/_app -/src/_pages +/src/_page /src/utils/_legacy /src/components/_legacy diff --git a/src/_pages/404.tsx b/src/_pages/404.tsx deleted file mode 100644 index b262bd5..0000000 --- a/src/_pages/404.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import Button from "components/Button"; -import LoaderLayout from "components/Layout/Loader"; -import Link from "next/link"; - -export default function NotFoundPage() { - return ( - -
-
- Page not found -
- -
- - The page you are trying to access is not found. - - Please check the URL or go back to the homepage. - -
- - - -
-
-
-
- ); -} diff --git a/src/_pages/[...path]/index.tsx b/src/_pages/[...path]/index.tsx deleted file mode 100644 index 7ac9bf4..0000000 --- a/src/_pages/[...path]/index.tsx +++ /dev/null @@ -1,303 +0,0 @@ -import axios from "axios"; -import ExplorerLayout from "components/Layout/Explorer"; -import LoaderLayout from "components/Layout/Loader"; -import PasswordLayout from "components/Layout/Password"; -import PreviewLayout from "components/Layout/Preview"; -import gIndexConfig from "config"; -import { GetServerSidePropsContext } from "next"; -import { useRouter } from "next/router"; -import { useEffect, useState } from "react"; -import { IGDriveFiles } from "types/api/files"; -import { - APIGetFileResponse, - APIGetPasswordResponse, - APIGetReadmeResponse, -} from "types/api/response"; -import { Constant } from "types/constant"; -import { decryptData, encryptData } from "utils/encryptionHelper/hash"; -import { gdriveFilesList } from "utils/gdrive"; -import gdrive from "utils/gdriveInstance"; -import { addNewPassword, checkPathPassword } from "utils/passwordHelper"; - -interface FilePathPageProps { - mappedEncryptedPath: Record<"name" | "id" | "mimeType", string>[]; -} -interface StateDataProps { - file: IGDriveFiles | null; - files: IGDriveFiles[]; - folders: IGDriveFiles[]; - pageToken: string | null; -} -export default function FilePathPage(props: FilePathPageProps) { - const router = useRouter(); - const [data, setData] = useState({ - file: null, - files: [], - folders: [], - pageToken: null, - }); - const [readmeFile, setReadmeFile] = useState(null); - const [isProtected, setIsProtected] = useState(false); - const [nearestProtected, setNearestProtected] = useState(""); - const [isFileProtected, setIsFileProtected] = useState(false); - const [isFile, setIsFile] = useState(false); - const [isLoadingData, setIsLoadingData] = useState(true); - useEffect(() => { - setIsLoadingData(true); - - const lastPathMimeType = - props.mappedEncryptedPath[(props.mappedEncryptedPath.length ?? 1) - 1] - .mimeType; - let isLastPathFile = false; - if (lastPathMimeType === "application/vnd.google-apps.folder") { - isLastPathFile = false; - setIsFile(false); - } else { - isLastPathFile = true; - setIsFile(true); - } - - const _getPassword = axios.get("/api/getPassword", { - params: { - path: encryptData(JSON.stringify(props.mappedEncryptedPath)), - }, - }); - const _getData = axios.get("/api/getData", { - params: { - encryptedId: - props.mappedEncryptedPath[props.mappedEncryptedPath.length - 1].id, - isFile: isLastPathFile ? "1" : undefined, - }, - }); - const _getReadme = axios.get("/api/getReadme", { - params: { - encryptedId: - props.mappedEncryptedPath[props.mappedEncryptedPath.length - 1].id, - }, - }); - - Promise.all([_getPassword, _getData, _getReadme]) - .then(async ([passwordData, fileData, readmeData]) => { - // Check password - if (passwordData.data.data && passwordData.data.data.length) { - let isPathProtected = true; - const savedPasswordCookie = - document.cookie - .split(";") - .find((cookie) => - cookie.startsWith(`${Constant.cookies_SitePassword}=`), - ) ?? undefined; - const savedPasswordValue = - savedPasswordCookie?.split("=")[1] ?? undefined; - - if (savedPasswordValue) { - // Check only nearest path - const nearestPassword = - passwordData.data.data[passwordData.data.data.length - 1]; - setNearestProtected(nearestPassword.relativePath); - const isPasswordValid = checkPathPassword( - nearestPassword.relativePath, - savedPasswordValue, - decryptData(nearestPassword.password), - ); - if (isPasswordValid) { - isPathProtected = false; - } - } - - setIsProtected(isPathProtected); - setIsFileProtected(true); - } - - // Assign files - setData(fileData.data.data); - - // Fetch readme - setReadmeFile(readmeData.data.data); - }) - .catch((err) => { - console.error(err); - throw new Error(err); - }) - .finally(() => { - setIsLoadingData(false); - }); - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.mappedEncryptedPath]); - - return ( - - {isLoadingData ? ( -
-
-
- {gIndexConfig.siteConfig.siteName} -
-
- Fetching {isFile ? "file info" : "folder contents"}... -
-
- ) : ( - <> - {isProtected ? ( - { - const cookie = - document.cookie - .split(";") - .find((cookie) => - cookie.startsWith(`${Constant.cookies_SitePassword}=`), - ) ?? undefined; - addNewPassword( - decodeURIComponent(nearestProtected), - password, - cookie?.split("=")[1] ?? undefined, - ); - router.reload(); - }} - /> - ) : ( - <> - {isFile ? ( - - ) : ( - - )} - - )} - - )} - - ); -} - -export async function getServerSideProps(context: GetServerSidePropsContext) { - const { path } = context.params as { path: string[] }; - - const fetchRootId = gdrive.files.get({ - fileId: gIndexConfig.apiConfig.rootFolder, - fields: "id", - supportsAllDrives: gIndexConfig.apiConfig.isTeamDrive, - }); - const fetchPathId = path.map(async (path) => { - const query = ["trashed = false", `name = '${path}'`]; - const fetchFolderContents = await gdriveFilesList({ - q: `${query.join(" and ")}`, - fields: "files(id, name, mimeType, parents)", - }); - - if (!fetchFolderContents.data.files?.length) { - return { - path, - data: [], - }; - } - - return { - path, - data: fetchFolderContents.data.files.map((file) => ({ - id: file.id, - parents: file.parents?.[0], - mimeType: file.mimeType, - })), - }; - }); - - const [rootId, pathId] = await Promise.all([ - fetchRootId, - Promise.all(fetchPathId), - ]); - - if (pathId.some((path) => !path.data.length)) { - return { - notFound: true, - }; - } - - const selectedPath: string[] = []; - const mappedPath: Record<"name" | "id" | "mimeType", string>[] = []; - const rejectedPath: string[] = []; - - // Check path validity - pathId.forEach((path, index) => { - let checkPath = - index === 0 - ? path.data.find((file) => file.parents === rootId.data.id) - : path.data.find((file) => file.parents === selectedPath[index - 1]); - if (!checkPath) { - rejectedPath.push(path.path); - return; - } - selectedPath.push(checkPath.id as string); - mappedPath.push({ - name: path.path, - id: checkPath.id as string, - mimeType: checkPath.mimeType as string, - }); - }); - if (rejectedPath.length) { - return { - notFound: true, - }; - } - - return { - props: { - mappedEncryptedPath: mappedPath.map((path) => ({ - name: path.name, - id: encryptData(path.id), - mimeType: path.mimeType, - })), - }, - }; -} diff --git a/src/_pages/_app.tsx b/src/_pages/_app.tsx deleted file mode 100644 index 2af49fc..0000000 --- a/src/_pages/_app.tsx +++ /dev/null @@ -1,352 +0,0 @@ -import { Icon } from "@iconify/react"; -import Button from "components/Button"; -import ButtonGroup from "components/ButtonGroup"; -import ButtonIcon from "components/ButtonIcon"; -import ClickAway from "components/ClickAway"; -import Modal from "components/Modal"; -import Tooltip from "components/Tooltip"; -import gIndexConfig from "config"; -import { DefaultSeo } from "next-seo"; -import { AppProps } from "next/app"; -import { JetBrains_Mono, Kanit, Poppins } from "next/font/google"; -import Link from "next/link"; -import { useRouter } from "next/router"; -import { useEffect, useState } from "react"; -import { ToastContainer } from "react-toastify"; -import "react-toastify/dist/ReactToastify.css"; -import "styles/globals.css"; -import { twMerge } from "tailwind-merge"; -import twColor from "tailwindcss/colors"; -import hexToRgb from "utils/hexToRGB"; -import { removeAllPassword } from "utils/passwordHelper"; - -const kanit = Kanit({ - display: "auto", - weight: ["300", "400", "500", "600", "700", "800", "900"], - subsets: ["latin-ext", "latin"], - preload: true, -}); -export const poppins = Poppins({ - display: "auto", - weight: ["300", "400", "500", "600", "700", "800", "900"], - subsets: ["latin-ext", "latin"], - preload: true, -}); -export const jetbrainsMono = JetBrains_Mono({ - display: "auto", - weight: ["300", "400", "500", "600", "700", "800"], - subsets: ["latin-ext", "latin"], - style: ["normal", "italic"], - preload: true, -}); - -export default function App({ Component, pageProps }: AppProps) { - const router = useRouter(); - - const [accentColor] = useState( - gIndexConfig.siteConfig.defaultAccentColor as keyof typeof twColor, - ); - - const [showToTopButton, setShowToTopButton] = useState(false); - const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); - const [clearPasswordModalOpen, setClearPasswordModalOpen] = - useState(false); - - useEffect(() => { - const handleScroll = () => { - if (window.scrollY > 150) { - setShowToTopButton(true); - } else { - setShowToTopButton(false); - } - }; - window.addEventListener("scroll", handleScroll); - return () => window.removeEventListener("scroll", handleScroll); - }, []); - - const handleClearPassword = () => { - removeAllPassword(); - setClearPasswordModalOpen(false); - router.reload(); - }; - - useEffect(() => { - const colorObject = twColor[accentColor]; - Object.keys(colorObject).forEach((key) => { - document.documentElement.style.setProperty( - `--accent-${key}`, - hexToRgb(colorObject[key as keyof typeof colorObject]), - ); - }); - }, [accentColor]); - - return ( -
- - - -
-
- -
- -
- - Powered by{" "} - - next-gdrive-index - - -
-
- - - - {/* To the top */} - window.scrollTo({ top: 0, behavior: "smooth" })} - /> - - {/* Clear password */} - setClearPasswordModalOpen(false)} - title='Clear password' - > -
-
- - Are you sure you want to clear your password? - - - You will need to re-enter your password to access protected - folders / files. - -
- - - - -
-
-
- ); -} diff --git a/src/_pages/_document.tsx b/src/_pages/_document.tsx deleted file mode 100644 index 97f5e1e..0000000 --- a/src/_pages/_document.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import gIndexConfig from "config"; -import { Head, Html, Main, NextScript } from "next/document"; - -export default function Document() { - return ( - - - - - -
- - - - ); -} diff --git a/src/_pages/index.tsx b/src/_pages/index.tsx deleted file mode 100644 index f2c0c15..0000000 --- a/src/_pages/index.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import axios from "axios"; -import ExplorerLayout from "components/Layout/Explorer"; -import LoaderLayout from "components/Layout/Loader"; -import gIndexConfig from "config"; -import { useRouter } from "next/router"; -import { useEffect, useState } from "react"; -import { IGDriveFiles } from "types/api/files"; -import { APIGetFileResponse, APIGetReadmeResponse } from "types/api/response"; - -interface StateDataProps { - file: IGDriveFiles | null; - files: IGDriveFiles[]; - folders: IGDriveFiles[]; - pageToken: string | null; -} -export default function RootPage() { - const router = useRouter(); - const [data, setData] = useState({ - file: null, - files: [], - folders: [], - pageToken: null, - }); - const [readmeFile, setReadmeFile] = useState(null); - const [isLoadingData, setIsLoadingData] = useState(true); - - useEffect(() => { - setIsLoadingData(true); - const _getData = axios.get("/api/getData"); - const _getReadme = axios.get("/api/getReadme"); - - Promise.all([_getData, _getReadme]) - .then(([fileData, readmeData]) => { - // Assign files - setData(fileData.data.data); - - // Fetch readme - setReadmeFile(readmeData.data.data); - }) - .catch((err) => { - console.error(err); - throw new Error(err); - }) - .finally(() => { - setIsLoadingData(false); - }); - }, []); - - return ( - - {isLoadingData ? ( -
-
-
- {gIndexConfig.siteConfig.siteName} -
-
- Fetching folder contents... -
-
- ) : ( - - )} - - ); -}