From 0f0e624ebc7cc96017f4667fcd8025fe2b03d798 Mon Sep 17 00:00:00 2001 From: melvinchia3636 Date: Sun, 14 Apr 2024 09:53:38 +0800 Subject: [PATCH] 24w15 Former-commit-id: 9df4dbc3772273d29024452577f63b8cfa111347 [formerly 29dc4d2e9a85edffbf207e8ee3af21306722c634] [formerly ff49ec6aaef41900de3ac62d321c6af55e17acb5 [formerly 865d23809a689fb95a94210df62ee972fdbf821f]] Former-commit-id: d45f51f4f143edbddbe17c3d8cf1cb03ffc9d220 [formerly 0db73af8405bc86e7bfc8b42ba046b56145a606b] Former-commit-id: 4d40862c144b50a0c513d536d9c4814aceb30613 --- .eslintrc.cjs | 12 +- keys/cert.pem | 24 +++ keys/key.pem | 28 +++ keys/keytmp.pem | 30 +++ package.json | 6 +- src/App.tsx | 8 +- src/MainApplication.tsx | 2 +- src/Router.tsx | 6 +- src/auth/components/AuthForm.tsx | 129 +++++++++++-- src/auth/components/AuthSignInButtons.tsx | 29 +-- src/components/Header.tsx | 4 +- .../Sidebar/components/SidebarHeader.tsx | 2 +- .../Sidebar/components/SidebarItem.tsx | 2 +- .../Sidebar/components/SidebarItems.tsx | 6 +- src/components/Sidebar/index.tsx | 2 +- .../general/CreateOrModifyButton.tsx | 2 +- src/modules/Calendar/index.tsx | 4 +- .../LogItem/components/LogItemContent.tsx | 7 +- .../LogItem/components/LogItemHeader.tsx | 22 +-- .../Changelog/components/LogItem/index.tsx | 2 +- src/modules/Changelog/index.tsx | 14 +- .../components/CodeTimeActivityCalendar.tsx | 8 +- .../components/CodeTimeMostProjects.tsx | 115 ------------ .../components/CodeTimeStatistics.tsx | 4 +- ...stLanguages.tsx => CodeTimeTopEntries.tsx} | 52 ++--- src/modules/CodeTime/index.tsx | 17 +- src/modules/Dashboard/index.tsx | 6 +- src/modules/Flashcards/components/CardSet.tsx | 10 +- .../Flashcards/components/EditCardModal.tsx | 4 +- src/modules/Flashcards/components/Sidebar.tsx | 12 +- src/modules/Flashcards/index.tsx | 18 +- .../Containers/components/ContainerItem.tsx | 4 +- .../components/ModifyContainerModal.tsx | 14 +- .../Ideas/components/ContainerHeader.tsx | 8 +- .../Ideas/components/EntryContextMenu.tsx | 2 +- .../Ideas/components/IdeaEntry/EntryLink.tsx | 2 +- .../components/ModifyIdeaModal/index.tsx | 6 +- .../IdeaBox/components/Ideas/index.tsx | 8 +- src/modules/IdeaBox/index.tsx | 14 +- src/modules/Modules/ModuleItem.tsx | 2 +- src/modules/Modules/index.tsx | 10 +- src/modules/Notes/FIle/index.tsx | 13 +- .../Directory/components/DirectoryHeader.tsx | 6 +- .../EntryItem/components/EntryMenu.tsx | 4 +- .../Subject/components/ModifyFolderModal.tsx | 6 +- src/modules/Notes/Subject/index.tsx | 8 +- .../components/ModifySubjectModal.tsx | 10 +- .../Workspace/components/SubjectItem.tsx | 4 +- src/modules/Notes/Workspace/index.tsx | 12 +- src/modules/Notes/index.tsx | 10 +- src/modules/Passwords/CreatePassword.tsx | 6 +- src/modules/Passwords/CreatePasswordModal.tsx | 12 +- src/modules/Passwords/PasswordEntryItem.tsx | 4 +- src/modules/Passwords/index.tsx | 14 +- .../components/BgTempSelector.tsx | 2 +- .../components/ThemeColorSelector.tsx | 2 +- .../components/ThemeSelector.tsx | 2 +- src/modules/Personalization/index.tsx | 4 +- src/modules/Photos/components/ImageObject.tsx | 6 +- .../Photos/components/PhotosSidebar.tsx | 10 +- .../modals/AddPhotosToAlbumModal.tsx | 6 +- .../modals/DeletePhotosConfirmationModal.tsx | 4 +- .../components/modals/ModifyAlbumModal.tsx | 6 +- ...vePhotosFromAlbumConfirmationModal.tsx.tsx | 4 +- .../Photos/pages/AlbumGallery/index.tsx | 12 +- .../pages/AlbumList/components/AlbumItem.tsx | 4 +- .../AlbumList/components/AlbumListHeader.tsx | 2 +- src/modules/Photos/pages/AlbumList/index.tsx | 12 +- .../Photos/pages/FavouritesGallery/index.tsx | 12 +- .../pages/MainGallery/Gallery/DateGroup.tsx | 2 +- .../pages/MainGallery/Gallery/Gallery.tsx | 4 +- .../MainGallery/Gallery/GalleryContainer.tsx | 4 +- .../MainGallery/Gallery/GalleryHeader.tsx | 8 +- .../Scrollbars/MobileSlidingScrollbar.tsx | 2 +- .../Scrollbars/TimelineScrollbar.tsx | 2 +- .../Photos/pages/MainGallery/index.tsx | 6 +- src/modules/PomodoroTimer/index.tsx | 4 +- .../ProjectsK/pages/ProjectEntry/index.tsx | 6 +- .../ProjectEntry/sections/ProjectFiles.tsx | 10 +- .../ProjectEntry/sections/ProjectProgress.tsx | 6 +- .../components/CreateProjectModal.tsx | 10 +- .../pages/ProjectList/components/Sidebar.tsx | 8 +- .../ProjectsK/pages/ProjectList/index.tsx | 14 +- src/modules/ProjectsM/components/Kanban.tsx | 4 +- src/modules/ProjectsM/index.tsx | 12 +- src/modules/ReferenceBooks/index.tsx | 12 +- src/modules/ServerStatus/index.tsx | 8 +- src/modules/Spotify/WebPlayback.tsx | 4 +- src/modules/Spotify/index.tsx | 6 +- .../TodoList/components/ModifyListModal.tsx | 14 +- .../TodoList/components/ModifyTagModal.tsx | 6 +- .../components/ModifyTaskWindow/index.tsx | 8 +- src/modules/TodoList/components/Sidebar.tsx | 8 +- src/modules/TodoList/index.tsx | 12 +- src/providers/AuthProvider.tsx | 177 ++++++++---------- src/providers/GlobalStateProvider.tsx | 22 +-- src/providers/PhotosProvider.tsx | 2 +- tsconfig.json | 9 +- tsconfig.node.json | 7 +- vite.config.ts | 15 +- 100 files changed, 669 insertions(+), 597 deletions(-) create mode 100644 keys/cert.pem create mode 100644 keys/key.pem create mode 100644 keys/keytmp.pem delete mode 100644 src/modules/CodeTime/components/CodeTimeMostProjects.tsx rename src/modules/CodeTime/components/{CodeTimeMostLanguages.tsx => CodeTimeTopEntries.tsx} (73%) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 26a1a7f38..8b466e7ef 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -44,8 +44,18 @@ module.exports = { ".ts", ".tsx", ".d.ts" - ] + ], + "moduleDirectory": ["node_modules", "src/"] }, + "alias": { + "extensions": [".js", ".jsx", ".ts", ".tsx", ".d.ts"], + "map": [ + ['@components', './src/components/general/'], + ['@providers', './src/providers/'], + ['@hooks', './src/hooks/'], + ['@sidebar', './src/components/Sidebar/'], + ], + } }, "react": { "version": "detect" diff --git a/keys/cert.pem b/keys/cert.pem new file mode 100644 index 000000000..72b42bbd4 --- /dev/null +++ b/keys/cert.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIUNXnBYQb9NkWTygrQz59+iVwTP4gwDQYJKoZIhvcNAQEL +BQAwgYYxCzAJBgNVBAYTAk1ZMQ4wDAYDVQQIDAVKb2hvcjEUMBIGA1UEBwwLSm9o +b3IgQmFocnUxETAPBgNVBAoMCENvZGVibG9nMRMwEQYDVQQDDApNRUxWSU5DSElB +MSkwJwYJKoZIhvcNAQkBFhptZWx2aW5jaGlhNjIzNjAwQGdtYWlsLmNvbTAeFw0y +NDA0MTMwODMzNTlaFw0yNTA0MTMwODMzNTlaMIGGMQswCQYDVQQGEwJNWTEOMAwG +A1UECAwFSm9ob3IxFDASBgNVBAcMC0pvaG9yIEJhaHJ1MREwDwYDVQQKDAhDb2Rl +YmxvZzETMBEGA1UEAwwKTUVMVklOQ0hJQTEpMCcGCSqGSIb3DQEJARYabWVsdmlu +Y2hpYTYyMzYwMEBnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCsrWnnNFEeMYoxdsWDdDyMv9WRLczSrKVdW4qdl6ooJSQQ5sRNnm/HbvTv +NnfZzHSYaLIGGZRv81XnQB1WQVkA6izxx9Jc23ZxqyRMSt3NyWFHP+n4SIOQNVBL +OD/0Ite+4qfiHBAjy2E8xWe6UL+sQ1fvZTHXdsGLZimBnkT4nNp68ygsRiRMAeIl +e1SbRxUoJ5/4N2Iicxyq5xUqfbXKI3F0HsYAxpWd1UX89Eh845jG87ImxoXrXBLR +DtskHGxFHPylIl3CoEcIxek8Uw7HfEPE4otGLNpOaM9For3bpOogkMoLChjiCWcY +MOcX5DDQnY0380pntniM2IaNZNKtAgMBAAGjUzBRMB0GA1UdDgQWBBREnrYHXvTb ++IkUaAjjaDIHb0aUGDAfBgNVHSMEGDAWgBREnrYHXvTb+IkUaAjjaDIHb0aUGDAP +BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAOY//lNrQjFH/dj2ta +Wvj2NqVKWWGX7NZy8kNpzwisfOhs0hkf1WGzUj4uTEthk+SZCgmgi5x9G/QJ7E9Y +gnuVvsa10CJ2rAnlCC83IEx6TO9vkoOWKYwltNTaAXit5o7aajU1eiIBJ1Z6+sUq ++Z1bBGLIHb0csGa5wVYkRhSBaA6wiRGo8KekITG0VXP/f2rQWmTjkMZpBQVNB487 +xNs8O4DnRE2mjiWM2EaNeD6zWG18xckUK7Wace9hGDBYCfRR5ANt67I6P/Tj7axp +pbMF5SAUZ9W4RJ0asr1LxGcsAip4vRTD1NgSayCDmU8wQ/tQsOpxHxJIZmFkayhi +SVPx +-----END CERTIFICATE----- diff --git a/keys/key.pem b/keys/key.pem new file mode 100644 index 000000000..87711e3ad --- /dev/null +++ b/keys/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCsrWnnNFEeMYox +dsWDdDyMv9WRLczSrKVdW4qdl6ooJSQQ5sRNnm/HbvTvNnfZzHSYaLIGGZRv81Xn +QB1WQVkA6izxx9Jc23ZxqyRMSt3NyWFHP+n4SIOQNVBLOD/0Ite+4qfiHBAjy2E8 +xWe6UL+sQ1fvZTHXdsGLZimBnkT4nNp68ygsRiRMAeIle1SbRxUoJ5/4N2Iicxyq +5xUqfbXKI3F0HsYAxpWd1UX89Eh845jG87ImxoXrXBLRDtskHGxFHPylIl3CoEcI +xek8Uw7HfEPE4otGLNpOaM9For3bpOogkMoLChjiCWcYMOcX5DDQnY0380pntniM +2IaNZNKtAgMBAAECggEAC3XlqH21azlDKxiZ7/6VTODSjjR++qCQx8sdPmu5fw6a +qoXWaNxnc3zEGY2rk14ELbVifhB75JjpjlPtXoiEcrttc41H7ffMOwEZLfhuE4wW +aRcvMoEFklr80vE5yryhRb8KAMd3XsN51wG3FQuU8nGfHXlsPxkCVtEsrLinao9K +ZJfxWM+B6FkPlUr4VXrQNnuYE28de+UKwsaMkQHT2Q6AgntM5lKqKM9m0i9xNS37 +rH4GYHUG6/Rw5uChv22Qi2V7OlJf9VecRL2UpRtnCwEZ3W5Q1fbNV6fluMYcHwNj +AR3fjbZw2mx6twXWpCke2rx9zm3TgPwIlRCYQyOllQKBgQDuKo7CPbOuSp9Yp7jM +OuAcjo9yhVs0WNPcCbwS7kwABFzTdlsODJeDlCyPr0C+MyqGMrbg50gAF8tBGegd +NeWc56TJFSnZGpxpOZkUJoKS+8mp2IPKx0ezoVnf1+VaoQ7C1txHjOQ6F0egborO +G6CJHhPD+OdXwye7r+shku9hbwKBgQC5m326nomrPRDZq5hWAmbpJJUQh5DZY4lR +3X7vgY+mu2qX5BNdxVJV46oba9bZh3hmQztBb8pdWtUjhl5IsAt0fsKn1RcMKEkk +ZSWSDEvz5R1VNUfriqDrhPG9lAFpIHHRuOO7HblY8aP8uJDAwv4gb+7jB4xfokoZ +VpIDMkxHowKBgQDdZR5UHnt7V88M4Mz+vPQ8V6GteZ4w6Sn4b+wvROnNUkDgKjO2 +uanXHNTXtLhglru/CEHMi/L4cyX0nJqTHNkXpJYgftXqBbzEbFCK1MmozPrIModA +50MWDrW3ScDhILrSEF2w/Z3jCmUBFAFgW3o+PIFvOWAEy1uSM5RGH4r7bQKBgGWp +PRxSaaVZNTmEO1QgzK02VE9RcY0gb75fS39zv3LbhG7dhZ3+zjItGKccUfmjsdaR +TIty56xqbAOhPVMi2aNdKtEybgVCq407uXBdO9zCyWY6YMIqlClsD9x+jKdAFheA +5Xs/tJ16/Q8XKHHsW7T4mifPoptfEKcAO8l0a0NxAoGAAW5PkDeLAZIvh0kp+FB4 ++I2/ZF9MXBzsmHvHjL183Dp1L8uPKvLJfsiqM1TuT+8CjQU0o9LeaWP2Gl9KBW4y +RONsiJ8RmF8StjYaqiMuQwkeS9duTWC6hdcjc4WHoT+9HJ/fvy9sd21HtFYRplOj +PPn4imkWznFC4DzeUHRJQfg= +-----END PRIVATE KEY----- diff --git a/keys/keytmp.pem b/keys/keytmp.pem new file mode 100644 index 000000000..b872e59e9 --- /dev/null +++ b/keys/keytmp.pem @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFJDBWBgkqhkiG9w0BBQ0wSTAxBgkqhkiG9w0BBQwwJAQQ4x3R3RfiB8csIoHc +ggVb6wICCAAwDAYIKoZIhvcNAgkFADAUBggqhkiG9w0DBwQIaf/S8DLOO7sEggTI +3CcHFPYtq4VixpEMMS3td2qMYc/9JpINOlIOEH3b+qVGdGQVzUY26EpTyVi3nd19 +m/RlSwxLdRxOgiFx95FHP7KmarE63AY694SAHItzX6noH5ieqtswDsKKsuaY6m+8 +EBhAbMys4f1Rx/qZ5cOKH6YpbMhvKktg4VPLXmY/TwlABIMEquj+U93/UDM5tKXE +6oUux7eBjheQnpmUSkFhwMKaV7m26D/9GA1+ybS2hgomY2uFUcPGChQBJKsaXIjM +j7Ngo2FXVzklqbmmgiIWGnkGTdq/zlKsWPHsr+Nu5cx6pPSKN7eDdvYACpJAo7Hw +rkk9sNsVVRSx8ghOh9wsPZEI+zCl7+YFM9MsTUmV/TSl6M8KgG9l7nj53X59eVl4 +zJx5YseuMi47epmb6BQYn9U2p6famJlcdIdry2EMfCp1myemE5JYbLw9zbhDyAy5 +VGHZjAskGKkZTdgwP2EDSL12yVMgvcCZOf1BzJLekzJV5BnprHY5vqu/9tn4cI/1 +YEukO7ayEObwS+0QD82R91ZHwNLC52/HpkIqfpaTMJWTnLccg5IvtHPMDzv3r2Pa +HjCOWeWhNoaBWwOGK6ldBe2PM+20TS9ExpNnoSQNR62kO/wEOcu6EaBLGdI56kmD +8c2xJEKTza+bbADTBS5PLd6SDYJRPae8ExVIOTrgUomE8LVoL/Ux5D32057GFE/z +TPtcx1A/5XAZbIpW598AZr763hElqi/paEDRsxFnlpY3nF7pJ6aU/gWW4xgYhuug +2o10nSNMm6Fg34vYXsouK5vMEZZlcb4Jst0k8vZMNCSO48nKNuxUaeHmsYL5JVFC +mEfdWY6quwQ1OU78kceGmasz0T3U0OLqY+ytjwAkcWhF4v3STDRVuZMLJ+7dByPC +sYU2i8JOksG6yeuQasv8toQ34QEhixzYJp64j06KgmrgVUyUMrzQV7Sh2gkZPd4Z +BQ+82dDK0p99vBEpCp5oDzHDIxNG/p83Y0cgY6D3Dl4hwrpxcuHmJFF4Wk9bdY/y +s7wgmQrqALI9FaEwkPctpAkXoobw5JRiJHw65a+wCGH05H9vhWiKh6qiPez0sSqa +WzkmDtGvkxcsT8Cs3RZG21wij3M3uQqEkqlEXzZv9YDSffwuuXEwJEfSiEjT2bW4 +OprTdTnfeM4M+VtEqTqtK+JTHLoO3X8VvGkciE6qUG4V9/bvVcytEmwfYWoP5JSq +v+JruxLE9HPNKFWuVUv5UZYVckN4DYV0EawHVoOuubOmw1K0vRIvks3vPl146VrO +MoFdy09ZG8RSOS+hdTE39aHE/0H3yWzlv66ZcvQBsNO+L0wPqeZf7uPW9cHMvCR3 +TyDVa+kGUE/0Lyq+sm0EjjEVt/aZW7ZPLXBEuhvCDiZMgH4BbyMfiPWIxjmc/AkB +URbR2GNAq3q1+z1VXYj8oTVLyXsQ12AG4gpHDwIAt/KQq3jBsCmMHGCf5iYHnolw +t/vq3xwnxdS7W6qeC2uQpP2ESVc73NXtKYKOcq3C/cVqA6QoPVQmOnywUKkQWejq +ltG3MGHg18VlvpY3yodo3emSGGN7qeSX05lfQm3axcrQbHd5fUII9ZkTDrB4ezTC +5qvopDwCAyJIBKhVFoJluyXpxt/O4Lmu +-----END ENCRYPTED PRIVATE KEY----- diff --git a/package.json b/package.json index 208482e65..d6a88bcfc 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@headlessui/react": "^1.7.17", "@iconify/collections": "^1.0.375", "@iconify/react": "^4.1.1", + "@passwordless-id/webauthn": "^1.5.0", "@react-pdf-viewer/core": "3.12.0", "@types/react-custom-scrollbars": "^4.0.12", "@types/react-helmet": "^6.1.11", @@ -31,6 +32,7 @@ "cors": "^2.8.5", "daisyui": "^4.4.14", "moment": "^2.30.1", + "path": "^0.12.7", "pdfjs-dist": "3.4.120", "pocketbase": "^0.19.0", "postcss": "^8.4.31", @@ -64,6 +66,7 @@ "@vitejs/plugin-react": "^4.2.0", "eslint": "^8.0.1", "eslint-config-standard-with-typescript": "^40.0.0", + "eslint-import-resolver-alias": "^1.1.2", "eslint-plugin-import": "^2.29.0", "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", "eslint-plugin-promise": "^6.0.0", @@ -72,6 +75,7 @@ "eslint-plugin-react-refresh": "^0.4.4", "eslint-plugin-tailwindcss": "^3.14.3", "typescript": "*", - "vite": "^5.0.0" + "vite": "^5.0.0", + "vite-plugin-mkcert": "^1.17.5" } } diff --git a/src/App.tsx b/src/App.tsx index c03549c92..0d2a5ebe8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,11 +4,11 @@ import React from 'react' import { BrowserRouter } from 'react-router-dom' import AppRouter from './Router' -import GlobalStateProvider from './providers/GlobalStateProvider' +import GlobalStateProvider from '@providers/GlobalStateProvider' import { ToastContainer } from 'react-toastify' -import AuthProvider from './providers/AuthProvider' -import PersonalizationProvider from './providers/PersonalizationProvider' -import SpotifyProvider from './providers/SpotifyProvider' +import AuthProvider from '@providers/AuthProvider' +import PersonalizationProvider from '@providers/PersonalizationProvider' +import SpotifyProvider from '@providers/SpotifyProvider' function App(): React.ReactElement { return ( diff --git a/src/MainApplication.tsx b/src/MainApplication.tsx index ad7ebc01f..bda43a553 100644 --- a/src/MainApplication.tsx +++ b/src/MainApplication.tsx @@ -1,5 +1,5 @@ import React from 'react' -import Sidebar from './components/Sidebar' +import Sidebar from '@sidebar' import Header from './components/Header' import { Outlet } from 'react-router' diff --git a/src/Router.tsx b/src/Router.tsx index 82be49440..71c881a65 100644 --- a/src/Router.tsx +++ b/src/Router.tsx @@ -2,9 +2,9 @@ /* eslint-disable @typescript-eslint/strict-boolean-expressions */ import React, { Suspense, lazy, useContext, useMemo } from 'react' import { Route, Routes, useLocation, useNavigate } from 'react-router-dom' -import { AuthContext } from './providers/AuthProvider' -import { titleToPath } from './components/Sidebar/components/SidebarItem' -import Loading from './components/general/Loading' +import { AuthContext } from '@providers/AuthProvider' +import { titleToPath } from '@sidebar/components/SidebarItem' +import Loading from '@components/Loading' import PhotosFavouritesGallery from './modules/Photos/pages/FavouritesGallery' const PhotosProvider = lazy( diff --git a/src/auth/components/AuthForm.tsx b/src/auth/components/AuthForm.tsx index 6548b945b..a8b25bc8e 100644 --- a/src/auth/components/AuthForm.tsx +++ b/src/auth/components/AuthForm.tsx @@ -1,9 +1,10 @@ import React, { useContext, useState } from 'react' -import Input from '../../components/general/Input' +import Input from '@components/Input' import AuthSignInButton from './AuthSignInButtons' -import { AuthContext } from '../../providers/AuthProvider' +import { AuthContext } from '@providers/AuthProvider' import { toast } from 'react-toastify' import { AUTH_ERROR_MESSAGES } from '../../constants/auth' +import * as webauthn from '@passwordless-id/webauthn' function AuthForm(): React.ReactElement { const [emailOrUsername, setEmail] = useState('') @@ -11,11 +12,37 @@ function AuthForm(): React.ReactElement { const [loading, setLoading] = useState(false) const { + setAuth, + setUserData, authenticate, - authWithOauth, - loginQuota: { quota, dismissQuota } + loginQuota: { quota, dismissQuota }, + verifyToken } = useContext(AuthContext) + async function fetchPassKeyChallenge(): Promise { + return await fetch( + `${import.meta.env.VITE_API_HOST}/user/passkey/challenge`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ) + .then(async res => { + const data = await res.json() + if (res.ok && data.state === 'success') { + return data.data + } else { + throw new Error(data.message) + } + }) + .catch(err => { + toast.error('Couldn’t fetch the challenge. Please try again.') + console.error(err) + }) + } + function signIn(): void { if (emailOrUsername.length === 0 || password.length === 0) { toast.error(AUTH_ERROR_MESSAGES.EMPTY_FIELDS) @@ -43,19 +70,91 @@ function AuthForm(): React.ReactElement { }) } - function signInWithGithub(): void { - setLoading(true) - authWithOauth('github') - .then(res => { - if (!res.startsWith('success')) { - toast.error(res) + async function registerWithPasskey(): Promise { + const res = await webauthn.client.register( + 'melvinchia623600@gmail.com', + '20e47b44-293a-417a-8559-d7f32affd8b4', + { + authenticatorType: 'both', + userVerification: 'required', + discoverable: 'preferred', + timeout: 60000, + attestation: true + } + ) + + await fetch(`${import.meta.env.VITE_API_HOST}/user/passkey/register`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(res) + }) + .then(async res => { + const data = await res.json() + if (res.ok && data.state === 'success') { + toast.success('Passkey created successfully') } else { - toast.success('Welcome back, ' + res.split(' ').slice(1).join(' ')) + throw new Error(data.message) } + }) + .catch(err => { + toast.error("Couldn't create the passkey. Please try again.") + console.error(err) + }) + .finally(() => { setLoading(false) }) - .catch(() => { - toast.error(AUTH_ERROR_MESSAGES.UNKNOWN_ERROR) + } + + async function signInWithPasskey(): Promise { + setLoading(true) + const challenge = await fetchPassKeyChallenge() + + const res = await webauthn.client.authenticate([], challenge) + + await fetch(`${import.meta.env.VITE_API_HOST}/user/passkey/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(res) + }) + .then(async res => { + const data = await res.json() + + if (res.ok && data.state === 'success') { + document.cookie = `token=${data.token}; path=/; expires=${new Date( + Date.now() + 7 * 24 * 60 * 60 * 1000 + ).toUTCString()}` + + verifyToken(data.token) + .then(async ({ success, userData }) => { + if (success) { + setUserData(userData) + setAuth(true) + + toast.success(`Welcome back, ${userData.name}!`) + } + }) + .catch(() => { + setAuth(false) + }) + .finally(() => { + setLoading(false) + }) + } else { + throw new Error(data.message) + } + }) + .catch(err => { + toast.error( + 'Failed to authenticate with the passkey. Please try again.' + ) + console.error(err) + }) + .finally(() => { + setLoading(false) }) } @@ -82,6 +181,7 @@ function AuthForm(): React.ReactElement { signIn() } }} + darker /> ) diff --git a/src/auth/components/AuthSignInButtons.tsx b/src/auth/components/AuthSignInButtons.tsx index 831f4b2d4..e29aaff49 100644 --- a/src/auth/components/AuthSignInButtons.tsx +++ b/src/auth/components/AuthSignInButtons.tsx @@ -1,5 +1,5 @@ import React, { useContext } from 'react' -import { AuthContext } from '../../providers/AuthProvider' +import { AuthContext } from '@providers/AuthProvider' import { Icon } from '@iconify/react/dist/iconify.js' function AuthSignInButton({ @@ -7,13 +7,13 @@ function AuthSignInButton({ password, loading, signIn, - signInWithGithub + signInWithPasskey }: { emailOrUsername: string password: string loading: boolean signIn: () => void - signInWithGithub: () => void + signInWithPasskey: () => void }): React.ReactElement { const { auth } = useContext(AuthContext) @@ -31,14 +31,21 @@ function AuthSignInButton({ > {loading ? : 'Sign In'} - +
+
+
Or Sign In With
+
+
+
+ +
) } diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 9a0ae91de..2547464a0 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,7 +1,7 @@ import React, { Fragment, useContext } from 'react' import { Icon } from '@iconify/react' -import { GlobalStateContext } from '../providers/GlobalStateProvider' -import { AuthContext } from '../providers/AuthProvider' +import { GlobalStateContext } from '@providers/GlobalStateProvider' +import { AuthContext } from '@providers/AuthProvider' import { Menu, Transition } from '@headlessui/react' import { toast } from 'react-toastify' import MenuItem from './general/HamburgerMenu/MenuItem' diff --git a/src/components/Sidebar/components/SidebarHeader.tsx b/src/components/Sidebar/components/SidebarHeader.tsx index 2bf307902..49a54e17c 100644 --- a/src/components/Sidebar/components/SidebarHeader.tsx +++ b/src/components/Sidebar/components/SidebarHeader.tsx @@ -1,5 +1,5 @@ import React, { useContext } from 'react' -import { GlobalStateContext } from '../../../providers/GlobalStateProvider' +import { GlobalStateContext } from '@providers/GlobalStateProvider' import { Icon } from '@iconify/react' function SidebarHeader(): React.ReactElement { diff --git a/src/components/Sidebar/components/SidebarItem.tsx b/src/components/Sidebar/components/SidebarItem.tsx index 8d8579770..e3aa5ff1a 100644 --- a/src/components/Sidebar/components/SidebarItem.tsx +++ b/src/components/Sidebar/components/SidebarItem.tsx @@ -2,7 +2,7 @@ /* eslint-disable multiline-ternary */ import { Icon } from '@iconify/react' import React, { useContext, useEffect, useState } from 'react' -import { GlobalStateContext } from '../../../providers/GlobalStateProvider' +import { GlobalStateContext } from '@providers/GlobalStateProvider' import { useLocation } from 'react-router' import { Link } from 'react-router-dom' diff --git a/src/components/Sidebar/components/SidebarItems.tsx b/src/components/Sidebar/components/SidebarItems.tsx index 64c0d8600..7bc32f69a 100644 --- a/src/components/Sidebar/components/SidebarItems.tsx +++ b/src/components/Sidebar/components/SidebarItems.tsx @@ -3,13 +3,13 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable multiline-ternary */ import React, { useContext, useEffect, useState } from 'react' -import { GlobalStateContext } from '../../../providers/GlobalStateProvider' +import { GlobalStateContext } from '@providers/GlobalStateProvider' import SidebarItem, { titleToPath } from './SidebarItem' import SidebarTitle from './SidebarTitle' import SidebarDivider from './SidebarDivider' import { type INotesWorkspace } from '../../../modules/Notes' -import useFetch from '../../../hooks/useFetch' -import { AuthContext } from '../../../providers/AuthProvider' +import useFetch from '@hooks/useFetch' +import { AuthContext } from '@providers/AuthProvider' import { ROUTES } from '../../../Router' function SidebarItems(): React.ReactElement { diff --git a/src/components/Sidebar/index.tsx b/src/components/Sidebar/index.tsx index b3259e7de..92768b01b 100644 --- a/src/components/Sidebar/index.tsx +++ b/src/components/Sidebar/index.tsx @@ -1,6 +1,6 @@ /* eslint-disable multiline-ternary */ import React, { useContext } from 'react' -import { GlobalStateContext } from '../../providers/GlobalStateProvider' +import { GlobalStateContext } from '@providers/GlobalStateProvider' import SidebarItems from './components/SidebarItems' import SidebarHeader from './components/SidebarHeader' diff --git a/src/components/general/CreateOrModifyButton.tsx b/src/components/general/CreateOrModifyButton.tsx index 3816369c9..7b69418db 100644 --- a/src/components/general/CreateOrModifyButton.tsx +++ b/src/components/general/CreateOrModifyButton.tsx @@ -2,7 +2,7 @@ /* eslint-disable multiline-ternary */ import { Icon } from '@iconify/react/dist/iconify.js' import React, { useContext } from 'react' -import { PersonalizationContext } from '../../providers/PersonalizationProvider' +import { PersonalizationContext } from '@providers/PersonalizationProvider' function CreateOrModifyButton({ type, diff --git a/src/modules/Calendar/index.tsx b/src/modules/Calendar/index.tsx index 5b978e75d..4b8bd53db 100644 --- a/src/modules/Calendar/index.tsx +++ b/src/modules/Calendar/index.tsx @@ -1,9 +1,9 @@ /* eslint-disable multiline-ternary */ /* eslint-disable @typescript-eslint/indent */ import React from 'react' -import ModuleHeader from '../../components/general/ModuleHeader' +import ModuleHeader from '@components/ModuleHeader' import { Icon } from '@iconify/react' -import ModuleWrapper from '../../components/general/ModuleWrapper' +import ModuleWrapper from '@components/ModuleWrapper' function Calendar(): React.ReactElement { return ( diff --git a/src/modules/Changelog/components/LogItem/components/LogItemContent.tsx b/src/modules/Changelog/components/LogItem/components/LogItemContent.tsx index 4b14bf2f1..fc98a097a 100644 --- a/src/modules/Changelog/components/LogItem/components/LogItemContent.tsx +++ b/src/modules/Changelog/components/LogItem/components/LogItemContent.tsx @@ -7,15 +7,14 @@ function LogItemContent({ entry: IChangeLogVersion }): React.ReactElement { return ( -
    +
      {entry.entries .sort((a, b) => a.feature.localeCompare(b.feature)) .map(subEntry => (
    • - - {subEntry.feature}: - {' '} + {subEntry.feature}:{' '} (.*?)<\/code>/g, diff --git a/src/modules/Changelog/components/LogItem/components/LogItemHeader.tsx b/src/modules/Changelog/components/LogItem/components/LogItemHeader.tsx index 161805aa7..82b9d7889 100644 --- a/src/modules/Changelog/components/LogItem/components/LogItemHeader.tsx +++ b/src/modules/Changelog/components/LogItem/components/LogItemHeader.tsx @@ -9,19 +9,17 @@ function LogItemHeader({ return (

      Ver. {entry.version}{' '} - + ( - {new Date(entry.date_range[0]).toLocaleDateString('en-US', { - year: 'numeric', - month: 'short', - day: 'numeric' - })}{' '} - -{' '} - {new Date(entry.date_range[1]).toLocaleDateString('en-US', { - year: 'numeric', - month: 'short', - day: 'numeric' - })} + {entry.date_range + .map(date => + new Date(date).toLocaleDateString('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric' + }) + ) + .join(' - ')} )

      diff --git a/src/modules/Changelog/components/LogItem/index.tsx b/src/modules/Changelog/components/LogItem/index.tsx index 01619e9cb..70293a92c 100644 --- a/src/modules/Changelog/components/LogItem/index.tsx +++ b/src/modules/Changelog/components/LogItem/index.tsx @@ -7,7 +7,7 @@ function LogItem({ entry }: { entry: IChangeLogVersion }): React.ReactElement { return (
    • diff --git a/src/modules/Changelog/index.tsx b/src/modules/Changelog/index.tsx index 93d45fb83..1c39882d8 100644 --- a/src/modules/Changelog/index.tsx +++ b/src/modules/Changelog/index.tsx @@ -2,13 +2,13 @@ /* eslint-disable @typescript-eslint/no-throw-literal */ /* eslint-disable @typescript-eslint/indent */ import React, { useEffect, useState } from 'react' -import ModuleHeader from '../../components/general/ModuleHeader' -import useFetch from '../../hooks/useFetch' +import ModuleHeader from '@components/ModuleHeader' +import useFetch from '@hooks/useFetch' import LogItem from './components/LogItem' -import APIComponentWithFallback from '../../components/general/APIComponentWithFallback' -import ModuleWrapper from '../../components/general/ModuleWrapper' -import EmptyStateScreen from '../../components/general/EmptyStateScreen' -import SearchInput from '../../components/general/SearchInput' +import APIComponentWithFallback from '@components/APIComponentWithFallback' +import ModuleWrapper from '@components/ModuleWrapper' +import EmptyStateScreen from '@components/EmptyStateScreen' +import SearchInput from '@components/SearchInput' export interface IChangeLogVersion { version: string @@ -66,7 +66,7 @@ function Changelog(): React.ReactElement { stuffToSearch="features" /> -
        +
          {typeof data !== 'string' && (filteredData.length > 0 ? ( filteredData.map(entry => ( diff --git a/src/modules/CodeTime/components/CodeTimeActivityCalendar.tsx b/src/modules/CodeTime/components/CodeTimeActivityCalendar.tsx index 6c936ae97..26a40bc24 100644 --- a/src/modules/CodeTime/components/CodeTimeActivityCalendar.tsx +++ b/src/modules/CodeTime/components/CodeTimeActivityCalendar.tsx @@ -4,7 +4,7 @@ import { Icon } from '@iconify/react/dist/iconify.js' import React, { useContext, useEffect, useState } from 'react' import ActivityCalendar from 'react-activity-calendar' import THEME_COLOR_HEX from '../../../constants/theme_color_hex' -import { PersonalizationContext } from '../../../providers/PersonalizationProvider' +import { PersonalizationContext } from '@providers/PersonalizationProvider' import { Tooltip } from 'react-tooltip' function CodeTimeActivityCalendar(): React.ReactElement { @@ -43,8 +43,8 @@ function CodeTimeActivityCalendar(): React.ReactElement { }, []) return ( -
          -

          +
          +

          Activities Calendar

          @@ -120,7 +120,7 @@ function CodeTimeActivityCalendar(): React.ReactElement {
          {firstYear && ( -
          +
          {Array(new Date().getFullYear() - firstYear + 1) .fill(0) .map((_, index) => ( diff --git a/src/modules/CodeTime/components/CodeTimeMostProjects.tsx b/src/modules/CodeTime/components/CodeTimeMostProjects.tsx deleted file mode 100644 index 992ce7eb2..000000000 --- a/src/modules/CodeTime/components/CodeTimeMostProjects.tsx +++ /dev/null @@ -1,115 +0,0 @@ -/* eslint-disable @typescript-eslint/restrict-plus-operands */ -/* eslint-disable @typescript-eslint/indent */ -import { Icon } from '@iconify/react/dist/iconify.js' -import React, { useState } from 'react' -import HoursAndMinutesFromSeconds from './HoursAndMinutesFromSeconds' -import useFetch from '../../../hooks/useFetch' -import APIComponentWithFallback from '../../../components/general/APIComponentWithFallback' - -function CodeTimeMostProjects(): React.ReactElement { - const [lastForProjects, setLastForProjects] = useState< - '24 hours' | '7 days' | '30 days' - >('24 hours') - const [topProjects] = useFetch>( - `code-time/projects?last=${lastForProjects}` - ) - - return ( -
          -
          -

          - - - Projects You've Spent Most Time Doing - -

          -
          -

          in the last

          -
          - {['24 hours', '7 days', '30 days'].map((last, index) => ( - - ))} -
          -
          -
          - - -
          - {typeof topProjects !== 'string' && - Object.keys(topProjects).length > 0 && - Object.entries(topProjects) - .slice(0, 5) - .map(([key, value], index) => ( -
          a + b[1], 0)) * - 100 - )}%` - }} - >
          - ))} -
          -
            - {topProjects !== null && - Object.keys(topProjects).length > 0 && - Object.entries(topProjects) - .slice(0, 5) - .map(([key, value], index) => ( -
          • -
            -
            - {key} -
            -
            - -
            -
          • - ))} -
          -
          -
          - ) -} - -export default CodeTimeMostProjects diff --git a/src/modules/CodeTime/components/CodeTimeStatistics.tsx b/src/modules/CodeTime/components/CodeTimeStatistics.tsx index 43c63f586..cc6b13e11 100644 --- a/src/modules/CodeTime/components/CodeTimeStatistics.tsx +++ b/src/modules/CodeTime/components/CodeTimeStatistics.tsx @@ -5,8 +5,8 @@ import { Icon } from '@iconify/react/dist/iconify.js' import React from 'react' import HoursAndMinutesFromSeconds from './HoursAndMinutesFromSeconds' -import useFetch from '../../../hooks/useFetch' -import APIComponentWithFallback from '../../../components/general/APIComponentWithFallback' +import useFetch from '@hooks/useFetch' +import APIComponentWithFallback from '@components/APIComponentWithFallback' function CodeTimeStatistics(): React.ReactElement { const [stats] = useFetch>('code-time/statistics') diff --git a/src/modules/CodeTime/components/CodeTimeMostLanguages.tsx b/src/modules/CodeTime/components/CodeTimeTopEntries.tsx similarity index 73% rename from src/modules/CodeTime/components/CodeTimeMostLanguages.tsx rename to src/modules/CodeTime/components/CodeTimeTopEntries.tsx index 0fd6498bb..b44f46704 100644 --- a/src/modules/CodeTime/components/CodeTimeMostLanguages.tsx +++ b/src/modules/CodeTime/components/CodeTimeTopEntries.tsx @@ -2,25 +2,30 @@ import { Icon } from '@iconify/react/dist/iconify.js' import React, { useState } from 'react' import HoursAndMinutesFromSeconds from './HoursAndMinutesFromSeconds' -import useFetch from '../../../hooks/useFetch' -import APIComponentWithFallback from '../../../components/general/APIComponentWithFallback' +import useFetch from '@hooks/useFetch' +import APIComponentWithFallback from '@components/APIComponentWithFallback' -function CodeTimeMostLanguages(): React.ReactElement { - const [lastForLanguages, setLastForLanguages] = useState< - '24 hours' | '7 days' | '30 days' - >('24 hours') +function CodeTimeTopEntries({ + type +}: { + type: 'languages' | 'projects' +}): React.ReactElement { + const [lastFor, setLastFor] = useState<'24 hours' | '7 days' | '30 days'>( + '24 hours' + ) - const [topLanguages] = useFetch>( - `code-time/languages?last=${lastForLanguages}` + const [topEntries] = useFetch>( + `code-time/${type}?last=${lastFor}` ) return ( -
          -
          +
          +

          - Languages You've Spent Most Time Using + {type[0].toUpperCase()} + {type.slice(1)} You've Spent Most Time Using

          @@ -30,10 +35,10 @@ function CodeTimeMostLanguages(): React.ReactElement {
          - +
          - {typeof topLanguages !== 'string' && - Object.keys(topLanguages).length > 0 && - Object.entries(topLanguages) + {typeof topEntries !== 'string' && + Object.keys(topEntries).length > 0 && + Object.entries(topEntries) .slice(0, 5) .map(([key, value], index) => (
          a + b[1], 0)) * 100 @@ -77,9 +83,9 @@ function CodeTimeMostLanguages(): React.ReactElement { ))}
            - {topLanguages !== null && - Object.keys(topLanguages).length > 0 && - Object.entries(topLanguages) + {topEntries !== null && + Object.keys(topEntries).length > 0 && + Object.entries(topEntries) .slice(0, 5) .map(([key, value], index) => (
          • -
            +
            - - + {['projects', 'languages'].map(type => ( + + ))}
            ) diff --git a/src/modules/Dashboard/index.tsx b/src/modules/Dashboard/index.tsx index e1ed9df9a..e87c20590 100644 --- a/src/modules/Dashboard/index.tsx +++ b/src/modules/Dashboard/index.tsx @@ -19,9 +19,9 @@ import { Title, Filler } from 'chart.js' -import ModuleHeader from '../../components/general/ModuleHeader' -import { AuthContext } from '../../providers/AuthProvider' -import ModuleWrapper from '../../components/general/ModuleWrapper' +import ModuleHeader from '@components/ModuleHeader' +import { AuthContext } from '@providers/AuthProvider' +import ModuleWrapper from '@components/ModuleWrapper' ChartJS.register( ArcElement, diff --git a/src/modules/Flashcards/components/CardSet.tsx b/src/modules/Flashcards/components/CardSet.tsx index c298a3ea4..64c05305b 100644 --- a/src/modules/Flashcards/components/CardSet.tsx +++ b/src/modules/Flashcards/components/CardSet.tsx @@ -1,12 +1,12 @@ import { Icon } from '@iconify/react/dist/iconify.js' import React, { useEffect, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' -import GoBackButton from '../../../components/general/GoBackButton' -import useFetch from '../../../hooks/useFetch' +import GoBackButton from '@components/GoBackButton' +import useFetch from '@hooks/useFetch' import { type IFlashcardDeck } from '..' -import APIComponentWithFallback from '../../../components/general/APIComponentWithFallback' -import HamburgerMenu from '../../../components/general/HamburgerMenu' -import MenuItem from '../../../components/general/HamburgerMenu/MenuItem' +import APIComponentWithFallback from '@components/APIComponentWithFallback' +import HamburgerMenu from '@components/HamburgerMenu' +import MenuItem from '@components/HamburgerMenu/MenuItem' import EditCardModal from './EditCardModal' // Generated by https://quicktype.io diff --git a/src/modules/Flashcards/components/EditCardModal.tsx b/src/modules/Flashcards/components/EditCardModal.tsx index 0d259181c..b60155b07 100644 --- a/src/modules/Flashcards/components/EditCardModal.tsx +++ b/src/modules/Flashcards/components/EditCardModal.tsx @@ -1,10 +1,10 @@ /* eslint-disable @typescript-eslint/indent */ /* eslint-disable multiline-ternary */ import React, { useEffect, useState } from 'react' -import Modal from '../../../components/general/Modal' +import Modal from '@components/Modal' import { Icon } from '@iconify/react/dist/iconify.js' import { type IFlashcardCard } from './CardSet' -import CreateOrModifyButton from '../../../components/general/CreateOrModifyButton' +import CreateOrModifyButton from '@components/CreateOrModifyButton' import { toast } from 'react-toastify' import { cookieParse } from 'pocketbase' diff --git a/src/modules/Flashcards/components/Sidebar.tsx b/src/modules/Flashcards/components/Sidebar.tsx index a70c8fbf8..0f4a63016 100644 --- a/src/modules/Flashcards/components/Sidebar.tsx +++ b/src/modules/Flashcards/components/Sidebar.tsx @@ -1,13 +1,13 @@ /* eslint-disable @typescript-eslint/strict-boolean-expressions */ /* eslint-disable @typescript-eslint/indent */ import React from 'react' -import SidebarDivider from '../../../components/Sidebar/components/SidebarDivider' -import SidebarTitle from '../../../components/Sidebar/components/SidebarTitle' +import SidebarDivider from '@sidebar/components/SidebarDivider' +import SidebarTitle from '@sidebar/components/SidebarTitle' import { Icon } from '@iconify/react' -import GoBackButton from '../../../components/general/GoBackButton' -import SidebarItem from '../../../components/Sidebar/components/SidebarItem' -import useFetch from '../../../hooks/useFetch' -import APIComponentWithFallback from '../../../components/general/APIComponentWithFallback' +import GoBackButton from '@components/GoBackButton' +import SidebarItem from '@sidebar/components/SidebarItem' +import useFetch from '@hooks/useFetch' +import APIComponentWithFallback from '@components/APIComponentWithFallback' export interface IFlashcardTag { amount: number diff --git a/src/modules/Flashcards/index.tsx b/src/modules/Flashcards/index.tsx index 7de38e5cc..2f4a963b3 100644 --- a/src/modules/Flashcards/index.tsx +++ b/src/modules/Flashcards/index.tsx @@ -2,12 +2,12 @@ import { faker } from '@faker-js/faker' import { Icon } from '@iconify/react/dist/iconify.js' import React, { useState } from 'react' import { Link } from 'react-router-dom' -import ModuleHeader from '../../components/general/ModuleHeader' -import ModuleWrapper from '../../components/general/ModuleWrapper' -import SearchInput from '../../components/general/SearchInput' -import Sidebar, { type IFlashcardTag } from './components/Sidebar' -import useFetch from '../../hooks/useFetch' -import APIComponentWithFallback from '../../components/general/APIComponentWithFallback' +import ModuleHeader from '@components/ModuleHeader' +import ModuleWrapper from '@components/ModuleWrapper' +import SearchInput from '@components/SearchInput' +import Sidebar, { type IFlashcardTag } from '@sidebar' +import useFetch from '@hooks/useFetch' +import APIComponentWithFallback from '@components/APIComponentWithFallback' export interface IFlashcardDeck { card_amount: number @@ -73,7 +73,7 @@ export default function Flashcards(): React.ReactElement { key={deck.id} className="group relative flex flex-col justify-start gap-6 rounded-lg bg-bg-50 p-8 shadow-[4px_4px_10px_0px_rgba(0,0,0,0.05)] hover:bg-bg-200/50 dark:bg-bg-900 dark:hover:bg-bg-800" > -
            +
            {deck.tag !== '' && (
            -
            +
            -
            +

            {faker.datatype.number(100)} cards

            diff --git a/src/modules/IdeaBox/components/Containers/components/ContainerItem.tsx b/src/modules/IdeaBox/components/Containers/components/ContainerItem.tsx index 506c1f0c2..fc498ba37 100644 --- a/src/modules/IdeaBox/components/Containers/components/ContainerItem.tsx +++ b/src/modules/IdeaBox/components/Containers/components/ContainerItem.tsx @@ -3,8 +3,8 @@ import { Icon } from '@iconify/react/dist/iconify.js' import React from 'react' import { Link } from 'react-router-dom' import { type IIdeaBoxContainer } from '../../..' -import HamburgerMenu from '../../../../../components/general/HamburgerMenu' -import MenuItem from '../../../../../components/general/HamburgerMenu/MenuItem' +import HamburgerMenu from '@components/HamburgerMenu' +import MenuItem from '@components/HamburgerMenu/MenuItem' function ContainerItem({ container, diff --git a/src/modules/IdeaBox/components/Containers/components/ModifyContainerModal.tsx b/src/modules/IdeaBox/components/Containers/components/ModifyContainerModal.tsx index a14a5ed38..fee8ca018 100644 --- a/src/modules/IdeaBox/components/Containers/components/ModifyContainerModal.tsx +++ b/src/modules/IdeaBox/components/Containers/components/ModifyContainerModal.tsx @@ -1,17 +1,17 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable multiline-ternary */ import React, { useEffect, useState } from 'react' -import Modal from '../../../../../components/general/Modal' +import Modal from '@components/Modal' import { Icon } from '@iconify/react/dist/iconify.js' -import ColorPickerModal from '../../../../../components/general/ColorPicker/ColorPickerModal' +import ColorPickerModal from '@components/ColorPicker/ColorPickerModal' import { toast } from 'react-toastify' import { type IIdeaBoxContainer } from '../../..' import { useDebounce } from '@uidotdev/usehooks' -import IconInput from '../../../../../components/general/IconSelector/IconInput' -import Input from '../../../../../components/general/Input' -import IconSelector from '../../../../../components/general/IconSelector' -import CreateOrModifyButton from '../../../../../components/general/CreateOrModifyButton' -import ColorInput from '../../../../../components/general/ColorPicker/ColorInput' +import IconInput from '@components/IconSelector/IconInput' +import Input from '@components/Input' +import IconSelector from '@components/IconSelector' +import CreateOrModifyButton from '@components/CreateOrModifyButton' +import ColorInput from '@components/ColorPicker/ColorInput' import { cookieParse } from 'pocketbase' function ModifyContainerModal({ diff --git a/src/modules/IdeaBox/components/Ideas/components/ContainerHeader.tsx b/src/modules/IdeaBox/components/Ideas/components/ContainerHeader.tsx index 9af326977..7e2bc71c9 100644 --- a/src/modules/IdeaBox/components/Ideas/components/ContainerHeader.tsx +++ b/src/modules/IdeaBox/components/Ideas/components/ContainerHeader.tsx @@ -3,10 +3,10 @@ import { Icon } from '@iconify/react/dist/iconify.js' import React from 'react' import { useNavigate } from 'react-router-dom' import { type IIdeaBoxContainer } from '../../..' -import GoBackButton from '../../../../../components/general/GoBackButton' -import useFetch from '../../../../../hooks/useFetch' -import HamburgerMenu from '../../../../../components/general/HamburgerMenu' -import MenuItem from '../../../../../components/general/HamburgerMenu/MenuItem' +import GoBackButton from '@components/GoBackButton' +import useFetch from '@hooks/useFetch' +import HamburgerMenu from '@components/HamburgerMenu' +import MenuItem from '@components/HamburgerMenu/MenuItem' function ContainerHeader({ id, diff --git a/src/modules/IdeaBox/components/Ideas/components/EntryContextMenu.tsx b/src/modules/IdeaBox/components/Ideas/components/EntryContextMenu.tsx index bca1a0222..100edbff2 100644 --- a/src/modules/IdeaBox/components/Ideas/components/EntryContextMenu.tsx +++ b/src/modules/IdeaBox/components/Ideas/components/EntryContextMenu.tsx @@ -4,7 +4,7 @@ import { Icon } from '@iconify/react/dist/iconify.js' import React from 'react' import { type IIdeaBoxEntry } from '..' import { toast } from 'react-toastify' -import MenuItem from '../../../../../components/general/HamburgerMenu/MenuItem' +import MenuItem from '@components/HamburgerMenu/MenuItem' import { cookieParse } from 'pocketbase' function EntryContextMenu({ diff --git a/src/modules/IdeaBox/components/Ideas/components/IdeaEntry/EntryLink.tsx b/src/modules/IdeaBox/components/Ideas/components/IdeaEntry/EntryLink.tsx index a88e0b350..bc9560b41 100644 --- a/src/modules/IdeaBox/components/Ideas/components/IdeaEntry/EntryLink.tsx +++ b/src/modules/IdeaBox/components/Ideas/components/IdeaEntry/EntryLink.tsx @@ -24,7 +24,7 @@ function EntryLink({ updateIdeaList: () => void }): React.ReactElement { return ( -
            +
            {entry.pinned && ( () @@ -53,10 +53,7 @@ function NotesFile(): React.ReactElement {
            diff --git a/src/modules/Notes/Subject/components/Directory/components/DirectoryHeader.tsx b/src/modules/Notes/Subject/components/Directory/components/DirectoryHeader.tsx index aea26ac4d..aedbe1360 100644 --- a/src/modules/Notes/Subject/components/Directory/components/DirectoryHeader.tsx +++ b/src/modules/Notes/Subject/components/Directory/components/DirectoryHeader.tsx @@ -5,11 +5,11 @@ import { Menu, Transition } from '@headlessui/react' import { Icon } from '@iconify/react/dist/iconify.js' import React from 'react' import { Link, useNavigate, useParams } from 'react-router-dom' -import GoBackButton from '../../../../../../components/general/GoBackButton' -import MenuItem from '../../../../../../components/general/HamburgerMenu/MenuItem' +import GoBackButton from '@components/GoBackButton' +import MenuItem from '@components/HamburgerMenu/MenuItem' import { type INotesEntry, type INotesPath } from '../../..' import { toast } from 'react-toastify' -import useFetch from '../../../../../../hooks/useFetch' +import useFetch from '@hooks/useFetch' import { cookieParse } from 'pocketbase' function DirectoryHeader({ diff --git a/src/modules/Notes/Subject/components/Directory/components/EntryItem/components/EntryMenu.tsx b/src/modules/Notes/Subject/components/Directory/components/EntryItem/components/EntryMenu.tsx index 2657b7b15..c56c7d4b9 100644 --- a/src/modules/Notes/Subject/components/Directory/components/EntryItem/components/EntryMenu.tsx +++ b/src/modules/Notes/Subject/components/Directory/components/EntryItem/components/EntryMenu.tsx @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/indent */ import React from 'react' -import HamburgerMenu from '../../../../../../../../components/general/HamburgerMenu' -import MenuItem from '../../../../../../../../components/general/HamburgerMenu/MenuItem' +import HamburgerMenu from '@components/HamburgerMenu' +import MenuItem from '@components/HamburgerMenu/MenuItem' import { type INotesEntry } from '../../../../..' function EntryMenu({ diff --git a/src/modules/Notes/Subject/components/ModifyFolderModal.tsx b/src/modules/Notes/Subject/components/ModifyFolderModal.tsx index 1729c02ec..8ac598174 100644 --- a/src/modules/Notes/Subject/components/ModifyFolderModal.tsx +++ b/src/modules/Notes/Subject/components/ModifyFolderModal.tsx @@ -4,11 +4,11 @@ import React, { useEffect, useState } from 'react' import { Icon } from '@iconify/react/dist/iconify.js' import { toast } from 'react-toastify' import { useDebounce } from '@uidotdev/usehooks' -import Modal from '../../../../components/general/Modal' +import Modal from '@components/Modal' import { useParams } from 'react-router' import { type INotesEntry } from '..' -import Input from '../../../../components/general/Input' -import CreateOrModifyButton from '../../../../components/general/CreateOrModifyButton' +import Input from '@components/Input' +import CreateOrModifyButton from '@components/CreateOrModifyButton' import { cookieParse } from 'pocketbase' function ModifyFolderModal({ diff --git a/src/modules/Notes/Subject/index.tsx b/src/modules/Notes/Subject/index.tsx index 15a79d19e..ef5c5f3ab 100644 --- a/src/modules/Notes/Subject/index.tsx +++ b/src/modules/Notes/Subject/index.tsx @@ -6,13 +6,13 @@ /* eslint-disable @typescript-eslint/indent */ import React, { useEffect, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' -import EmptyStateScreen from '../../../components/general/EmptyStateScreen' +import EmptyStateScreen from '@components/EmptyStateScreen' import ModifyFolderModal from './components/ModifyFolderModal' import DirectoryHeader from './components/Directory/components/DirectoryHeader' import Directory from './components/Directory' -import DeleteConfirmationModal from '../../../components/general/DeleteConfirmationModal' -import useFetch from '../../../hooks/useFetch' -import APIComponentWithFallback from '../../../components/general/APIComponentWithFallback' +import DeleteConfirmationModal from '@components/DeleteConfirmationModal' +import useFetch from '@hooks/useFetch' +import APIComponentWithFallback from '@components/APIComponentWithFallback' // Generated by https://quicktype.io diff --git a/src/modules/Notes/Workspace/components/ModifySubjectModal.tsx b/src/modules/Notes/Workspace/components/ModifySubjectModal.tsx index cb5a3fc9e..87aaf0b21 100644 --- a/src/modules/Notes/Workspace/components/ModifySubjectModal.tsx +++ b/src/modules/Notes/Workspace/components/ModifySubjectModal.tsx @@ -4,13 +4,13 @@ import React, { useEffect, useState } from 'react' import { Icon } from '@iconify/react/dist/iconify.js' import { toast } from 'react-toastify' import { useDebounce } from '@uidotdev/usehooks' -import Modal from '../../../../components/general/Modal' +import Modal from '@components/Modal' import { useParams } from 'react-router' -import Input from '../../../../components/general/Input' -import IconInput from '../../../../components/general/IconSelector/IconInput' +import Input from '@components/Input' +import IconInput from '@components/IconSelector/IconInput' import { type INotesSubject } from './SubjectItem' -import IconSelector from '../../../../components/general/IconSelector' -import CreateOrModifyButton from '../../../../components/general/CreateOrModifyButton' +import IconSelector from '@components/IconSelector' +import CreateOrModifyButton from '@components/CreateOrModifyButton' import { cookieParse } from 'pocketbase' function ModifySubjectModal({ diff --git a/src/modules/Notes/Workspace/components/SubjectItem.tsx b/src/modules/Notes/Workspace/components/SubjectItem.tsx index b1d5e114a..2d0a835af 100644 --- a/src/modules/Notes/Workspace/components/SubjectItem.tsx +++ b/src/modules/Notes/Workspace/components/SubjectItem.tsx @@ -2,8 +2,8 @@ import { Icon } from '@iconify/react/dist/iconify.js' import React from 'react' import { Link, useParams } from 'react-router-dom' -import HamburgerMenu from '../../../../components/general/HamburgerMenu' -import MenuItem from '../../../../components/general/HamburgerMenu/MenuItem' +import HamburgerMenu from '@components/HamburgerMenu' +import MenuItem from '@components/HamburgerMenu/MenuItem' export interface INotesSubject { workspace: string diff --git a/src/modules/Notes/Workspace/index.tsx b/src/modules/Notes/Workspace/index.tsx index 130d5932f..17b0ab2e0 100644 --- a/src/modules/Notes/Workspace/index.tsx +++ b/src/modules/Notes/Workspace/index.tsx @@ -1,18 +1,18 @@ /* eslint-disable @typescript-eslint/indent */ /* eslint-disable multiline-ternary */ import React, { useEffect, useState } from 'react' -import ModuleHeader from '../../../components/general/ModuleHeader' +import ModuleHeader from '@components/ModuleHeader' import { Icon } from '@iconify/react/dist/iconify.js' import { useNavigate, useParams } from 'react-router' import { type INotesWorkspace } from '..' -import EmptyStateScreen from '../../../components/general/EmptyStateScreen' +import EmptyStateScreen from '@components/EmptyStateScreen' import ModifySubjectModal from './components/ModifySubjectModal' -import GoBackButton from '../../../components/general/GoBackButton' +import GoBackButton from '@components/GoBackButton' import SubjectItem, { type INotesSubject } from './components/SubjectItem' import CreateSubjectButton from './components/CreateSubjectButton' -import DeleteConfirmationModal from '../../../components/general/DeleteConfirmationModal' -import useFetch from '../../../hooks/useFetch' -import APIComponentWithFallback from '../../../components/general/APIComponentWithFallback' +import DeleteConfirmationModal from '@components/DeleteConfirmationModal' +import useFetch from '@hooks/useFetch' +import APIComponentWithFallback from '@components/APIComponentWithFallback' function NotesCategory(): React.ReactElement { const { workspace } = useParams<{ workspace: string }>() diff --git a/src/modules/Notes/index.tsx b/src/modules/Notes/index.tsx index dbdf52bad..7bc0f95dc 100644 --- a/src/modules/Notes/index.tsx +++ b/src/modules/Notes/index.tsx @@ -1,11 +1,11 @@ import React, { useEffect, useState } from 'react' -import ModuleHeader from '../../components/general/ModuleHeader' -import Loading from '../../components/general/Loading' -import Error from '../../components/general/Error' +import ModuleHeader from '@components/ModuleHeader' +import Loading from '@components/Loading' +import Error from '@components/Error' import { Icon } from '@iconify/react/dist/iconify.js' import { Link } from 'react-router-dom' -import useFetch from '../../hooks/useFetch' -import ModuleWrapper from '../../components/general/ModuleWrapper' +import useFetch from '@hooks/useFetch' +import ModuleWrapper from '@components/ModuleWrapper' export interface INotesWorkspace { collectionId: string diff --git a/src/modules/Passwords/CreatePassword.tsx b/src/modules/Passwords/CreatePassword.tsx index e133c26fa..f51156f54 100644 --- a/src/modules/Passwords/CreatePassword.tsx +++ b/src/modules/Passwords/CreatePassword.tsx @@ -1,11 +1,11 @@ /* eslint-disable multiline-ternary */ import React, { useContext, useRef, useState } from 'react' -import Input from '../../components/general/Input' +import Input from '@components/Input' import { Icon } from '@iconify/react/dist/iconify.js' import { toast } from 'react-toastify' import { cookieParse } from 'pocketbase' -import { AuthContext } from '../../providers/AuthProvider' -import Modal from '../../components/general/Modal' +import { AuthContext } from '@providers/AuthProvider' +import Modal from '@components/Modal' function CreatePassword(): React.ReactElement { const { setUserData, userData } = useContext(AuthContext) diff --git a/src/modules/Passwords/CreatePasswordModal.tsx b/src/modules/Passwords/CreatePasswordModal.tsx index 2f48e9151..e1c5b462a 100644 --- a/src/modules/Passwords/CreatePasswordModal.tsx +++ b/src/modules/Passwords/CreatePasswordModal.tsx @@ -1,12 +1,12 @@ /* eslint-disable multiline-ternary */ import React, { useEffect, useState } from 'react' -import Modal from '../../components/general/Modal' +import Modal from '@components/Modal' import { Icon } from '@iconify/react/dist/iconify.js' -import Input from '../../components/general/Input' -import IconInput from '../../components/general/IconSelector/IconInput' -import IconSelector from '../../components/general/IconSelector' -import ColorInput from '../../components/general/ColorPicker/ColorInput' -import ColorPickerModal from '../../components/general/ColorPicker/ColorPickerModal' +import Input from '@components/Input' +import IconInput from '@components/IconSelector/IconInput' +import IconSelector from '@components/IconSelector' +import ColorInput from '@components/ColorPicker/ColorInput' +import ColorPickerModal from '@components/ColorPicker/ColorPickerModal' import { toast } from 'react-toastify' import { cookieParse } from 'pocketbase' diff --git a/src/modules/Passwords/PasswordEntryItem.tsx b/src/modules/Passwords/PasswordEntryItem.tsx index c15d20496..e8381368a 100644 --- a/src/modules/Passwords/PasswordEntryItem.tsx +++ b/src/modules/Passwords/PasswordEntryItem.tsx @@ -5,8 +5,8 @@ import { type IPasswordEntry } from '.' import { Icon } from '@iconify/react/dist/iconify.js' import { cookieParse } from 'pocketbase' import { toast } from 'react-toastify' -import HamburgerMenu from '../../components/general/HamburgerMenu' -import MenuItem from '../../components/general/HamburgerMenu/MenuItem' +import HamburgerMenu from '@components/HamburgerMenu' +import MenuItem from '@components/HamburgerMenu/MenuItem' function PasswordEntryITem({ password, diff --git a/src/modules/Passwords/index.tsx b/src/modules/Passwords/index.tsx index 711436b24..1d299fb6b 100644 --- a/src/modules/Passwords/index.tsx +++ b/src/modules/Passwords/index.tsx @@ -1,18 +1,18 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable multiline-ternary */ import React, { useContext, useState } from 'react' -import ModuleWrapper from '../../components/general/ModuleWrapper' -import ModuleHeader from '../../components/general/ModuleHeader' -import Input from '../../components/general/Input' +import ModuleWrapper from '@components/ModuleWrapper' +import ModuleHeader from '@components/ModuleHeader' +import Input from '@components/Input' import { Icon } from '@iconify/react/dist/iconify.js' -import { AuthContext } from '../../providers/AuthProvider' +import { AuthContext } from '@providers/AuthProvider' import CreatePassword from './CreatePassword' import { toast } from 'react-toastify' import { cookieParse } from 'pocketbase' import CreatePasswordModal from './CreatePasswordModal' -import EmptyStateScreen from '../../components/general/EmptyStateScreen' -import useFetch from '../../hooks/useFetch' -import APIComponentWithFallback from '../../components/general/APIComponentWithFallback' +import EmptyStateScreen from '@components/EmptyStateScreen' +import useFetch from '@hooks/useFetch' +import APIComponentWithFallback from '@components/APIComponentWithFallback' import PasswordEntryITem from './PasswordEntryITem' export interface IPasswordEntry { diff --git a/src/modules/Personalization/components/BgTempSelector.tsx b/src/modules/Personalization/components/BgTempSelector.tsx index 7aa9fe86b..68c65267c 100644 --- a/src/modules/Personalization/components/BgTempSelector.tsx +++ b/src/modules/Personalization/components/BgTempSelector.tsx @@ -1,5 +1,5 @@ import React, { useContext } from 'react' -import { PersonalizationContext } from '../../../providers/PersonalizationProvider' +import { PersonalizationContext } from '@providers/PersonalizationProvider' const COLORS = ['bg-slate', 'bg-gray', 'bg-zinc', 'bg-neutral', 'bg-stone'] diff --git a/src/modules/Personalization/components/ThemeColorSelector.tsx b/src/modules/Personalization/components/ThemeColorSelector.tsx index b9598fc91..c4385f263 100644 --- a/src/modules/Personalization/components/ThemeColorSelector.tsx +++ b/src/modules/Personalization/components/ThemeColorSelector.tsx @@ -1,5 +1,5 @@ import React, { Fragment, useContext } from 'react' -import { PersonalizationContext } from '../../../providers/PersonalizationProvider' +import { PersonalizationContext } from '@providers/PersonalizationProvider' import { Listbox, Transition } from '@headlessui/react' import { Icon } from '@iconify/react/dist/iconify.js' diff --git a/src/modules/Personalization/components/ThemeSelector.tsx b/src/modules/Personalization/components/ThemeSelector.tsx index 59e9fabfb..f81ab818b 100644 --- a/src/modules/Personalization/components/ThemeSelector.tsx +++ b/src/modules/Personalization/components/ThemeSelector.tsx @@ -1,5 +1,5 @@ import React, { useContext } from 'react' -import { PersonalizationContext } from '../../../providers/PersonalizationProvider' +import { PersonalizationContext } from '@providers/PersonalizationProvider' import { Icon } from '@iconify/react/dist/iconify.js' function ThemeSelector(): React.ReactElement { diff --git a/src/modules/Personalization/index.tsx b/src/modules/Personalization/index.tsx index cacf9dc28..ecf08c786 100644 --- a/src/modules/Personalization/index.tsx +++ b/src/modules/Personalization/index.tsx @@ -1,9 +1,9 @@ import React from 'react' -import ModuleHeader from '../../components/general/ModuleHeader' +import ModuleHeader from '@components/ModuleHeader' import ThemeSelector from './components/ThemeSelector' import ThemeColorSelector from './components/ThemeColorSelector' import BgTempSelector from './components/BgTempSelector' -import ModuleWrapper from '../../components/general/ModuleWrapper' +import ModuleWrapper from '@components/ModuleWrapper' function Personalization(): React.ReactElement { return ( diff --git a/src/modules/Photos/components/ImageObject.tsx b/src/modules/Photos/components/ImageObject.tsx index 7f3054589..e3a989ca3 100644 --- a/src/modules/Photos/components/ImageObject.tsx +++ b/src/modules/Photos/components/ImageObject.tsx @@ -7,12 +7,12 @@ import { import { LazyLoadImage } from 'react-lazy-load-image-component' import { Icon } from '@iconify/react/dist/iconify.js' import Zoom from 'react-medium-image-zoom' -import HamburgerMenu from '../../../components/general/HamburgerMenu' -import MenuItem from '../../../components/general/HamburgerMenu/MenuItem' +import HamburgerMenu from '@components/HamburgerMenu' +import MenuItem from '@components/HamburgerMenu/MenuItem' import { cookieParse } from 'pocketbase' import { toast } from 'react-toastify' import { useParams } from 'react-router' -import useFetch from '../../../hooks/useFetch' +import useFetch from '@hooks/useFetch' function forceDown(url: string, filename: string): void { fetch(url) diff --git a/src/modules/Photos/components/PhotosSidebar.tsx b/src/modules/Photos/components/PhotosSidebar.tsx index d126a74d9..9646e5f1c 100644 --- a/src/modules/Photos/components/PhotosSidebar.tsx +++ b/src/modules/Photos/components/PhotosSidebar.tsx @@ -1,13 +1,13 @@ /* eslint-disable multiline-ternary */ /* eslint-disable @typescript-eslint/indent */ import React, { useContext } from 'react' -import SidebarItem from '../../../components/Sidebar/components/SidebarItem' -import SidebarDivider from '../../../components/Sidebar/components/SidebarDivider' -import SidebarTitle from '../../../components/Sidebar/components/SidebarTitle' +import SidebarItem from '@sidebar/components/SidebarItem' +import SidebarDivider from '@sidebar/components/SidebarDivider' +import SidebarTitle from '@sidebar/components/SidebarTitle' import { Icon } from '@iconify/react/dist/iconify.js' -import APIComponentWithFallback from '../../../components/general/APIComponentWithFallback' +import APIComponentWithFallback from '@components/APIComponentWithFallback' import { Link, useNavigate } from 'react-router-dom' -import { PhotosContext } from '../../../providers/PhotosProvider' +import { PhotosContext } from '@providers/PhotosProvider' function PhotosSidebar(): React.ReactElement { const { diff --git a/src/modules/Photos/components/modals/AddPhotosToAlbumModal.tsx b/src/modules/Photos/components/modals/AddPhotosToAlbumModal.tsx index 6ecaeefc1..c989b87f8 100644 --- a/src/modules/Photos/components/modals/AddPhotosToAlbumModal.tsx +++ b/src/modules/Photos/components/modals/AddPhotosToAlbumModal.tsx @@ -1,9 +1,9 @@ /* eslint-disable multiline-ternary */ import React, { useContext, useEffect, useState } from 'react' -import Modal from '../../../../components/general/Modal' +import Modal from '@components/Modal' import { Icon } from '@iconify/react/dist/iconify.js' -import { PhotosContext } from '../../../../providers/PhotosProvider' -import APIComponentWithFallback from '../../../../components/general/APIComponentWithFallback' +import { PhotosContext } from '@providers/PhotosProvider' +import APIComponentWithFallback from '@components/APIComponentWithFallback' import { cookieParse } from 'pocketbase' import { toast } from 'react-toastify' diff --git a/src/modules/Photos/components/modals/DeletePhotosConfirmationModal.tsx b/src/modules/Photos/components/modals/DeletePhotosConfirmationModal.tsx index b5bfaf404..7594a8384 100644 --- a/src/modules/Photos/components/modals/DeletePhotosConfirmationModal.tsx +++ b/src/modules/Photos/components/modals/DeletePhotosConfirmationModal.tsx @@ -4,8 +4,8 @@ import React, { useContext, useState } from 'react' import { toast } from 'react-toastify' import { Icon } from '@iconify/react/dist/iconify.js' import { cookieParse } from 'pocketbase' -import Modal from '../../../../components/general/Modal' -import { PhotosContext } from '../../../../providers/PhotosProvider' +import Modal from '@components/Modal' +import { PhotosContext } from '@providers/PhotosProvider' function DeletePhotosConfirmationModal({ refreshPhotos, diff --git a/src/modules/Photos/components/modals/ModifyAlbumModal.tsx b/src/modules/Photos/components/modals/ModifyAlbumModal.tsx index 741f989bd..a9b8ae7f3 100644 --- a/src/modules/Photos/components/modals/ModifyAlbumModal.tsx +++ b/src/modules/Photos/components/modals/ModifyAlbumModal.tsx @@ -1,8 +1,8 @@ import React, { useContext, useEffect, useRef, useState } from 'react' -import Modal from '../../../../components/general/Modal' +import Modal from '@components/Modal' import { Icon } from '@iconify/react/dist/iconify.js' -import Input from '../../../../components/general/Input' -import CreateOrModifyButton from '../../../../components/general/CreateOrModifyButton' +import Input from '@components/Input' +import CreateOrModifyButton from '@components/CreateOrModifyButton' import { toast } from 'react-toastify' import { cookieParse } from 'pocketbase' import { diff --git a/src/modules/Photos/components/modals/RemovePhotosFromAlbumConfirmationModal.tsx.tsx b/src/modules/Photos/components/modals/RemovePhotosFromAlbumConfirmationModal.tsx.tsx index c7b896477..891973402 100644 --- a/src/modules/Photos/components/modals/RemovePhotosFromAlbumConfirmationModal.tsx.tsx +++ b/src/modules/Photos/components/modals/RemovePhotosFromAlbumConfirmationModal.tsx.tsx @@ -4,8 +4,8 @@ import React, { useContext, useState } from 'react' import { toast } from 'react-toastify' import { Icon } from '@iconify/react/dist/iconify.js' import { cookieParse } from 'pocketbase' -import Modal from '../../../../components/general/Modal' -import { PhotosContext } from '../../../../providers/PhotosProvider' +import Modal from '@components/Modal' +import { PhotosContext } from '@providers/PhotosProvider' function RemovePhotosFromAlbumConfirmationModal({ refreshPhotos, diff --git a/src/modules/Photos/pages/AlbumGallery/index.tsx b/src/modules/Photos/pages/AlbumGallery/index.tsx index 34703036e..0a33d767c 100644 --- a/src/modules/Photos/pages/AlbumGallery/index.tsx +++ b/src/modules/Photos/pages/AlbumGallery/index.tsx @@ -2,12 +2,12 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable multiline-ternary */ import React, { useContext, useEffect } from 'react' -import ModuleWrapper from '../../../../components/general/ModuleWrapper' +import ModuleWrapper from '@components/ModuleWrapper' import { Icon } from '@iconify/react/dist/iconify.js' import { useNavigate, useParams } from 'react-router' -import GoBackButton from '../../../../components/general/GoBackButton' -import useFetch from '../../../../hooks/useFetch' -import APIComponentWithFallback from '../../../../components/general/APIComponentWithFallback' +import GoBackButton from '@components/GoBackButton' +import useFetch from '@hooks/useFetch' +import APIComponentWithFallback from '@components/APIComponentWithFallback' import { type IPhotosEntryDimensionsItem, type IPhotosAlbum, @@ -19,8 +19,8 @@ import moment from 'moment' import BottomBar from '../../components/BottomBar' import DeletePhotosConfirmationModal from '../../components/modals/DeletePhotosConfirmationModal.tsx' import RemovePhotosFromAlbumConfirmationModal from '../../components/modals/RemovePhotosFromAlbumConfirmationModal.tsx.tsx' -import HamburgerMenu from '../../../../components/general/HamburgerMenu/index.tsx' -import MenuItem from '../../../../components/general/HamburgerMenu/MenuItem.tsx' +import HamburgerMenu from '@components/HamburgerMenu/index.tsx' +import MenuItem from '@components/HamburgerMenu/MenuItem.tsx' import ModifyAlbumModal from '../../components/modals/ModifyAlbumModal.tsx' export interface IPhotoAlbumEntryItem extends IPhotosEntryDimensionsItem { diff --git a/src/modules/Photos/pages/AlbumList/components/AlbumItem.tsx b/src/modules/Photos/pages/AlbumList/components/AlbumItem.tsx index ca2f8cb06..ad969b72d 100644 --- a/src/modules/Photos/pages/AlbumList/components/AlbumItem.tsx +++ b/src/modules/Photos/pages/AlbumList/components/AlbumItem.tsx @@ -2,8 +2,8 @@ import { Icon } from '@iconify/react/dist/iconify.js' import React, { useContext } from 'react' import { Link } from 'react-router-dom' -import HamburgerMenu from '../../../../../components/general/HamburgerMenu' -import MenuItem from '../../../../../components/general/HamburgerMenu/MenuItem' +import HamburgerMenu from '@components/HamburgerMenu' +import MenuItem from '@components/HamburgerMenu/MenuItem' import { PhotosContext, type IPhotosAlbum diff --git a/src/modules/Photos/pages/AlbumList/components/AlbumListHeader.tsx b/src/modules/Photos/pages/AlbumList/components/AlbumListHeader.tsx index 725d7df4c..bbd83c670 100644 --- a/src/modules/Photos/pages/AlbumList/components/AlbumListHeader.tsx +++ b/src/modules/Photos/pages/AlbumList/components/AlbumListHeader.tsx @@ -1,5 +1,5 @@ import React, { useContext } from 'react' -import { PhotosContext } from '../../../../../providers/PhotosProvider' +import { PhotosContext } from '@providers/PhotosProvider' import { Icon } from '@iconify/react/dist/iconify.js' function AlbumListHeader(): React.ReactElement { diff --git a/src/modules/Photos/pages/AlbumList/index.tsx b/src/modules/Photos/pages/AlbumList/index.tsx index dc7ce7941..53d439d6c 100644 --- a/src/modules/Photos/pages/AlbumList/index.tsx +++ b/src/modules/Photos/pages/AlbumList/index.tsx @@ -1,21 +1,21 @@ /* eslint-disable multiline-ternary */ /* eslint-disable @typescript-eslint/indent */ import React, { useContext, useEffect, useState } from 'react' -import ModuleWrapper from '../../../../components/general/ModuleWrapper' -import ModuleHeader from '../../../../components/general/ModuleHeader' +import ModuleWrapper from '@components/ModuleWrapper' +import ModuleHeader from '@components/ModuleHeader' import PhotosSidebar from '../../components/PhotosSidebar' import { type IPhotosAlbum, PhotosContext } from '../../../../providers/PhotosProvider' -import APIComponentWithFallback from '../../../../components/general/APIComponentWithFallback' +import APIComponentWithFallback from '@components/APIComponentWithFallback' import ModifyAlbumModal from '../../components/modals/ModifyAlbumModal' -import DeleteConfirmationModal from '../../../../components/general/DeleteConfirmationModal' +import DeleteConfirmationModal from '@components/DeleteConfirmationModal' import AlbumItem from './components/AlbumItem' import AlbumListHeader from './components/AlbumListHeader' -import SearchInput from '../../../../components/general/SearchInput' +import SearchInput from '@components/SearchInput' import { useDebounce } from '@uidotdev/usehooks' -import EmptyStateScreen from '../../../../components/general/EmptyStateScreen' +import EmptyStateScreen from '@components/EmptyStateScreen' function PhotosAlbumList(): React.ReactElement { const { albumList, refreshAlbumList, refreshPhotos } = diff --git a/src/modules/Photos/pages/FavouritesGallery/index.tsx b/src/modules/Photos/pages/FavouritesGallery/index.tsx index d1a59d734..01e8c6ecb 100644 --- a/src/modules/Photos/pages/FavouritesGallery/index.tsx +++ b/src/modules/Photos/pages/FavouritesGallery/index.tsx @@ -2,12 +2,12 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable multiline-ternary */ import React, { useContext, useEffect } from 'react' -import ModuleWrapper from '../../../../components/general/ModuleWrapper.tsx' +import ModuleWrapper from '@components/ModuleWrapper.tsx' import { Icon } from '@iconify/react/dist/iconify.js' import { useNavigate, useParams } from 'react-router' -import GoBackButton from '../../../../components/general/GoBackButton.tsx' -import useFetch from '../../../../hooks/useFetch.ts' -import APIComponentWithFallback from '../../../../components/general/APIComponentWithFallback.tsx' +import GoBackButton from '@components/GoBackButton.tsx' +import useFetch from '@hooks/useFetch.ts' +import APIComponentWithFallback from '@components/APIComponentWithFallback.tsx' import { type IPhotosEntryDimensionsItem, PhotosContext @@ -15,8 +15,8 @@ import { import Gallery from 'react-photo-gallery' import ImageObject from '../../components/ImageObject.tsx' import BottomBar from '../../components/BottomBar.tsx' -import HamburgerMenu from '../../../../components/general/HamburgerMenu/index.tsx' -import MenuItem from '../../../../components/general/HamburgerMenu/MenuItem.tsx' +import HamburgerMenu from '@components/HamburgerMenu/index.tsx' +import MenuItem from '@components/HamburgerMenu/MenuItem.tsx' export interface IPhotoAlbumEntryItem extends IPhotosEntryDimensionsItem { collectionId: string diff --git a/src/modules/Photos/pages/MainGallery/Gallery/DateGroup.tsx b/src/modules/Photos/pages/MainGallery/Gallery/DateGroup.tsx index 1b7818af1..3e94ae734 100644 --- a/src/modules/Photos/pages/MainGallery/Gallery/DateGroup.tsx +++ b/src/modules/Photos/pages/MainGallery/Gallery/DateGroup.tsx @@ -11,7 +11,7 @@ import { PhotosContext, type IPhotosEntry } from '../../../../../providers/PhotosProvider' -import useOnScreen from '../../../../../hooks/useOnScreen' +import useOnScreen from '@hooks/useOnScreen' import { cookieParse } from 'pocketbase' import { toast } from 'react-toastify' diff --git a/src/modules/Photos/pages/MainGallery/Gallery/Gallery.tsx b/src/modules/Photos/pages/MainGallery/Gallery/Gallery.tsx index cb94da637..d35739ed8 100644 --- a/src/modules/Photos/pages/MainGallery/Gallery/Gallery.tsx +++ b/src/modules/Photos/pages/MainGallery/Gallery/Gallery.tsx @@ -2,9 +2,9 @@ /* eslint-disable @typescript-eslint/indent */ import React, { useContext, useEffect } from 'react' import DateGroup from './DateGroup' -import { PhotosContext } from '../../../../../providers/PhotosProvider' +import { PhotosContext } from '@providers/PhotosProvider' import BottomBar from '../../../components/BottomBar' -import EmptyStateScreen from '../../../../../components/general/EmptyStateScreen' +import EmptyStateScreen from '@components/EmptyStateScreen' function Gallery(): React.ReactElement { const { photos, selectedPhotos, setSelectedPhotos } = diff --git a/src/modules/Photos/pages/MainGallery/Gallery/GalleryContainer.tsx b/src/modules/Photos/pages/MainGallery/Gallery/GalleryContainer.tsx index 9b028355b..c62fa2671 100644 --- a/src/modules/Photos/pages/MainGallery/Gallery/GalleryContainer.tsx +++ b/src/modules/Photos/pages/MainGallery/Gallery/GalleryContainer.tsx @@ -2,11 +2,11 @@ /* eslint-disable @typescript-eslint/indent */ import React, { useContext } from 'react' import moment from 'moment' -import APIComponentWithFallback from '../../../../../components/general/APIComponentWithFallback' +import APIComponentWithFallback from '@components/APIComponentWithFallback' import MobileSlidingScrollbar from '../Scrollbars/MobileSlidingScrollbar' import TimelineScrollbar from '../Scrollbars/TimelineScrollbar' import Gallery from './Gallery' -import { PhotosContext } from '../../../../../providers/PhotosProvider' +import { PhotosContext } from '@providers/PhotosProvider' function GalleryContainer(): React.ReactElement { const { diff --git a/src/modules/Photos/pages/MainGallery/Gallery/GalleryHeader.tsx b/src/modules/Photos/pages/MainGallery/Gallery/GalleryHeader.tsx index 03427f772..020665461 100644 --- a/src/modules/Photos/pages/MainGallery/Gallery/GalleryHeader.tsx +++ b/src/modules/Photos/pages/MainGallery/Gallery/GalleryHeader.tsx @@ -3,12 +3,12 @@ /* eslint-disable react/jsx-no-undef */ import { Icon } from '@iconify/react/dist/iconify.js' import React, { useContext, useEffect, useState } from 'react' -import { PhotosContext } from '../../../../../providers/PhotosProvider' -import useFetch from '../../../../../hooks/useFetch' +import { PhotosContext } from '@providers/PhotosProvider' +import useFetch from '@hooks/useFetch' import { cookieParse } from 'pocketbase' import { toast } from 'react-toastify' -import HamburgerMenu from '../../../../../components/general/HamburgerMenu' -import MenuItem from '../../../../../components/general/HamburgerMenu/MenuItem' +import HamburgerMenu from '@components/HamburgerMenu' +import MenuItem from '@components/HamburgerMenu/MenuItem' function GalleryHeader(): React.ReactElement { const { refreshPhotos, hidePhotosInAlbum, setHidePhotosInAlbum, setReady } = diff --git a/src/modules/Photos/pages/MainGallery/Scrollbars/MobileSlidingScrollbar.tsx b/src/modules/Photos/pages/MainGallery/Scrollbars/MobileSlidingScrollbar.tsx index 5b4d9b8d0..129a55169 100644 --- a/src/modules/Photos/pages/MainGallery/Scrollbars/MobileSlidingScrollbar.tsx +++ b/src/modules/Photos/pages/MainGallery/Scrollbars/MobileSlidingScrollbar.tsx @@ -3,7 +3,7 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import { Icon } from '@iconify/react/dist/iconify.js' import React, { useContext } from 'react' -import { PhotosContext } from '../../../../../providers/PhotosProvider' +import { PhotosContext } from '@providers/PhotosProvider' function MobileSlidingScrollbar(): React.ReactElement { const { galleryWrapperRef, sideSliderRef, mobileDateDisplayRef, photos } = diff --git a/src/modules/Photos/pages/MainGallery/Scrollbars/TimelineScrollbar.tsx b/src/modules/Photos/pages/MainGallery/Scrollbars/TimelineScrollbar.tsx index 76017af1a..8df35d6ab 100644 --- a/src/modules/Photos/pages/MainGallery/Scrollbars/TimelineScrollbar.tsx +++ b/src/modules/Photos/pages/MainGallery/Scrollbars/TimelineScrollbar.tsx @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import moment from 'moment' import React, { useContext, useRef } from 'react' -import { PhotosContext } from '../../../../../providers/PhotosProvider' +import { PhotosContext } from '@providers/PhotosProvider' function TimelineScrollbar(): React.ReactElement { const { diff --git a/src/modules/Photos/pages/MainGallery/index.tsx b/src/modules/Photos/pages/MainGallery/index.tsx index 99cf44065..e2a7303b3 100644 --- a/src/modules/Photos/pages/MainGallery/index.tsx +++ b/src/modules/Photos/pages/MainGallery/index.tsx @@ -1,14 +1,14 @@ /* eslint-disable multiline-ternary */ import React, { useContext, useEffect, useState } from 'react' -import ModuleHeader from '../../../../components/general/ModuleHeader' +import ModuleHeader from '@components/ModuleHeader' import GalleryHeader from './Gallery/GalleryHeader' import PhotosSidebar from '../../components/PhotosSidebar' import GalleryContainer from './Gallery/GalleryContainer' import ModifyAlbumModal from '../../components/modals/ModifyAlbumModal' import AddPhotosToAlbumModal from '../../components/modals/AddPhotosToAlbumModal' import DeletePhotosConfirmationModal from '../../components/modals/DeletePhotosConfirmationModal' -import { PhotosContext } from '../../../../providers/PhotosProvider' -import { GlobalStateContext } from '../../../../providers/GlobalStateProvider' +import { PhotosContext } from '@providers/PhotosProvider' +import { GlobalStateContext } from '@providers/GlobalStateProvider' function PhotosMainGallery(): React.ReactElement { const { sidebarExpanded } = useContext(GlobalStateContext) diff --git a/src/modules/PomodoroTimer/index.tsx b/src/modules/PomodoroTimer/index.tsx index dea14030a..b96f3d197 100644 --- a/src/modules/PomodoroTimer/index.tsx +++ b/src/modules/PomodoroTimer/index.tsx @@ -1,9 +1,9 @@ /* eslint-disable multiline-ternary */ import React from 'react' -import ModuleHeader from '../../components/general/ModuleHeader' +import ModuleHeader from '@components/ModuleHeader' import { Icon } from '@iconify/react/dist/iconify.js' import Timer from './components/Timer' -import ModuleWrapper from '../../components/general/ModuleWrapper' +import ModuleWrapper from '@components/ModuleWrapper' export default function PomodoroTimer(): React.ReactElement { return ( diff --git a/src/modules/ProjectsK/pages/ProjectEntry/index.tsx b/src/modules/ProjectsK/pages/ProjectEntry/index.tsx index 633f76092..55d7a3f4c 100644 --- a/src/modules/ProjectsK/pages/ProjectEntry/index.tsx +++ b/src/modules/ProjectsK/pages/ProjectEntry/index.tsx @@ -3,15 +3,15 @@ import React, { Fragment, useEffect } from 'react' import { Icon } from '@iconify/react' import { useLocation, useNavigate, useParams } from 'react-router-dom' -import GoBackButton from '../../../../components/general/GoBackButton' +import GoBackButton from '@components/GoBackButton' import { PROJECT_STATUS, type IProjectsKEntry } from '../ProjectList' -import useFetch from '../../../../hooks/useFetch' +import useFetch from '@hooks/useFetch' import ProjectProgress from './sections/ProjectProgress' import ProjectFiles from './sections/ProjectFiles' import { Listbox, Transition } from '@headlessui/react' import { toast } from 'react-toastify' import { cookieParse } from 'pocketbase' -import APIComponentWithFallback from '../../../../components/general/APIComponentWithFallback' +import APIComponentWithFallback from '@components/APIComponentWithFallback' export interface IProjectsKVersion { collectionId: string diff --git a/src/modules/ProjectsK/pages/ProjectEntry/sections/ProjectFiles.tsx b/src/modules/ProjectsK/pages/ProjectEntry/sections/ProjectFiles.tsx index 857c9653a..f189dfe20 100644 --- a/src/modules/ProjectsK/pages/ProjectEntry/sections/ProjectFiles.tsx +++ b/src/modules/ProjectsK/pages/ProjectEntry/sections/ProjectFiles.tsx @@ -4,15 +4,15 @@ /* eslint-disable multiline-ternary */ import React, { useState } from 'react' import { type IProjectsKEntry } from '../../ProjectList' -import APIComponentWithFallback from '../../../../../components/general/APIComponentWithFallback' +import APIComponentWithFallback from '@components/APIComponentWithFallback' import { Icon } from '@iconify/react/dist/iconify.js' -import EmptyStateScreen from '../../../../../components/general/EmptyStateScreen' +import EmptyStateScreen from '@components/EmptyStateScreen' import { toast } from 'react-toastify' import { cookieParse } from 'pocketbase' import FILE_ICONS from '../../../../../constants/file_icons' -import useFetch from '../../../../../hooks/useFetch' -import HamburgerMenu from '../../../../../components/general/HamburgerMenu' -import MenuItem from '../../../../../components/general/HamburgerMenu/MenuItem' +import useFetch from '@hooks/useFetch' +import HamburgerMenu from '@components/HamburgerMenu' +import MenuItem from '@components/HamburgerMenu/MenuItem' export default function ProjectFiles({ projectData, diff --git a/src/modules/ProjectsK/pages/ProjectEntry/sections/ProjectProgress.tsx b/src/modules/ProjectsK/pages/ProjectEntry/sections/ProjectProgress.tsx index ba83de71b..cec093708 100644 --- a/src/modules/ProjectsK/pages/ProjectEntry/sections/ProjectProgress.tsx +++ b/src/modules/ProjectsK/pages/ProjectEntry/sections/ProjectProgress.tsx @@ -2,8 +2,8 @@ import React from 'react' import { Icon } from '@iconify/react/dist/iconify.js' import { type IProjectsKEntry } from '../../ProjectList' -import APIComponentWithFallback from '../../../../../components/general/APIComponentWithFallback' -import useFetch from '../../../../../hooks/useFetch' +import APIComponentWithFallback from '@components/APIComponentWithFallback' +import useFetch from '@hooks/useFetch' import { toast } from 'react-toastify' import { cookieParse } from 'pocketbase' @@ -96,7 +96,7 @@ export default function ProjectProgress({

            -
              +
                {progress.steps.map((id: string, index: number) => (
            -
              +
                {Array(Math.floor(Math.random() * 10)) .fill(0) .map((_, index) => ( diff --git a/src/modules/ProjectsM/index.tsx b/src/modules/ProjectsM/index.tsx index b54f1c11f..9f5c5840f 100644 --- a/src/modules/ProjectsM/index.tsx +++ b/src/modules/ProjectsM/index.tsx @@ -1,15 +1,15 @@ /* eslint-disable multiline-ternary */ /* eslint-disable @typescript-eslint/indent */ import React, { useEffect, useState } from 'react' -import ModuleHeader from '../../components/general/ModuleHeader' -import SidebarTitle from '../../components/Sidebar/components/SidebarTitle' -import SidebarDivider from '../../components/Sidebar/components/SidebarDivider' +import ModuleHeader from '@components/ModuleHeader' +import SidebarTitle from '@sidebar/components/SidebarTitle' +import SidebarDivider from '@sidebar/components/SidebarDivider' import { Icon } from '@iconify/react' import { Link } from 'react-router-dom' -import SidebarItem from '../../components/Sidebar/components/SidebarItem' +import SidebarItem from '@sidebar/components/SidebarItem' import { faker } from '@faker-js/faker' -import ModuleWrapper from '../../components/general/ModuleWrapper' -import SearchInput from '../../components/general/SearchInput' +import ModuleWrapper from '@components/ModuleWrapper' +import SearchInput from '@components/SearchInput' function shuffle(array: any[]): any[] { let currentIndex = array.length diff --git a/src/modules/ReferenceBooks/index.tsx b/src/modules/ReferenceBooks/index.tsx index 25024e9a5..dd89cc974 100644 --- a/src/modules/ReferenceBooks/index.tsx +++ b/src/modules/ReferenceBooks/index.tsx @@ -1,12 +1,12 @@ import { faker } from '@faker-js/faker' import { Icon } from '@iconify/react/dist/iconify.js' import React, { useState } from 'react' -import ModuleHeader from '../../components/general/ModuleHeader' -import SidebarDivider from '../../components/Sidebar/components/SidebarDivider' -import SidebarItem from '../../components/Sidebar/components/SidebarItem' -import SidebarTitle from '../../components/Sidebar/components/SidebarTitle' -import ModuleWrapper from '../../components/general/ModuleWrapper' -import SearchInput from '../../components/general/SearchInput' +import ModuleHeader from '@components/ModuleHeader' +import SidebarDivider from '@sidebar/components/SidebarDivider' +import SidebarItem from '@sidebar/components/SidebarItem' +import SidebarTitle from '@sidebar/components/SidebarTitle' +import ModuleWrapper from '@components/ModuleWrapper' +import SearchInput from '@components/SearchInput' function ReferenceBooks(): React.ReactElement { const [searchQuery, setSearchQuery] = useState('') diff --git a/src/modules/ServerStatus/index.tsx b/src/modules/ServerStatus/index.tsx index 2c3c0ff3e..e55658426 100644 --- a/src/modules/ServerStatus/index.tsx +++ b/src/modules/ServerStatus/index.tsx @@ -3,11 +3,11 @@ /* eslint-disable multiline-ternary */ /* eslint-disable @typescript-eslint/strict-boolean-expressions */ import React, { useEffect } from 'react' -import ModuleHeader from '../../components/general/ModuleHeader' +import ModuleHeader from '@components/ModuleHeader' import { Icon } from '@iconify/react/dist/iconify.js' -import useFetch from '../../hooks/useFetch' -import APIComponentWithFallback from '../../components/general/APIComponentWithFallback' -import ModuleWrapper from '../../components/general/ModuleWrapper' +import useFetch from '@hooks/useFetch' +import APIComponentWithFallback from '@components/APIComponentWithFallback' +import ModuleWrapper from '@components/ModuleWrapper' import GaugeComponent from 'react-gauge-component' import moment from 'moment' diff --git a/src/modules/Spotify/WebPlayback.tsx b/src/modules/Spotify/WebPlayback.tsx index 34a1356b6..05659a34b 100644 --- a/src/modules/Spotify/WebPlayback.tsx +++ b/src/modules/Spotify/WebPlayback.tsx @@ -3,8 +3,8 @@ /* eslint-disable @typescript-eslint/naming-convention */ import React, { useContext, useEffect, useState } from 'react' import { Icon } from '@iconify/react/dist/iconify.js' -import { SpotifyContext } from '../../providers/SpotifyProvider' -import EmptyStateScreen from '../../components/general/EmptyStateScreen' +import { SpotifyContext } from '@providers/SpotifyProvider' +import EmptyStateScreen from '@components/EmptyStateScreen' function WebPlayback(): React.ReactElement { const { player, isPaused, isActive, currentTrack } = diff --git a/src/modules/Spotify/index.tsx b/src/modules/Spotify/index.tsx index bba30c7d9..3e15facc8 100644 --- a/src/modules/Spotify/index.tsx +++ b/src/modules/Spotify/index.tsx @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/strict-boolean-expressions */ /* eslint-disable multiline-ternary */ import React, { useContext } from 'react' -import ModuleHeader from '../../components/general/ModuleHeader' -import { AuthContext } from '../../providers/AuthProvider' +import ModuleHeader from '@components/ModuleHeader' +import { AuthContext } from '@providers/AuthProvider' import { Icon } from '@iconify/react/dist/iconify.js' import WebPlayback from './WebPlayback' -import ModuleWrapper from '../../components/general/ModuleWrapper' +import ModuleWrapper from '@components/ModuleWrapper' function Spotify(): React.ReactElement { const { userData } = useContext(AuthContext) diff --git a/src/modules/TodoList/components/ModifyListModal.tsx b/src/modules/TodoList/components/ModifyListModal.tsx index a03a3bc64..739197016 100644 --- a/src/modules/TodoList/components/ModifyListModal.tsx +++ b/src/modules/TodoList/components/ModifyListModal.tsx @@ -4,14 +4,14 @@ import React, { useEffect, useState } from 'react' import { Icon } from '@iconify/react/dist/iconify.js' import { toast } from 'react-toastify' import { useDebounce } from '@uidotdev/usehooks' -import Modal from '../../../components/general/Modal' -import ColorPickerModal from '../../../components/general/ColorPicker/ColorPickerModal' +import Modal from '@components/Modal' +import ColorPickerModal from '@components/ColorPicker/ColorPickerModal' import { type ITodoListList } from './Sidebar' -import CreateOrModifyButton from '../../../components/general/CreateOrModifyButton' -import IconSelector from '../../../components/general/IconSelector' -import Input from '../../../components/general/Input' -import IconInput from '../../../components/general/IconSelector/IconInput' -import ColorInput from '../../../components/general/ColorPicker/ColorInput' +import CreateOrModifyButton from '@components/CreateOrModifyButton' +import IconSelector from '@components/IconSelector' +import Input from '@components/Input' +import IconInput from '@components/IconSelector/IconInput' +import ColorInput from '@components/ColorPicker/ColorInput' import { cookieParse } from 'pocketbase' function ModifyListModal({ diff --git a/src/modules/TodoList/components/ModifyTagModal.tsx b/src/modules/TodoList/components/ModifyTagModal.tsx index ef145cbe0..3b3aec6db 100644 --- a/src/modules/TodoList/components/ModifyTagModal.tsx +++ b/src/modules/TodoList/components/ModifyTagModal.tsx @@ -4,9 +4,9 @@ import React, { useEffect, useState } from 'react' import { Icon } from '@iconify/react/dist/iconify.js' import { toast } from 'react-toastify' import { useDebounce } from '@uidotdev/usehooks' -import Modal from '../../../components/general/Modal' -import CreateOrModifyButton from '../../../components/general/CreateOrModifyButton' -import Input from '../../../components/general/Input' +import Modal from '@components/Modal' +import CreateOrModifyButton from '@components/CreateOrModifyButton' +import Input from '@components/Input' import { type ITodoListTag } from './Sidebar' import { cookieParse } from 'pocketbase' diff --git a/src/modules/TodoList/components/ModifyTaskWindow/index.tsx b/src/modules/TodoList/components/ModifyTaskWindow/index.tsx index d0eae7d31..fba747c4f 100644 --- a/src/modules/TodoList/components/ModifyTaskWindow/index.tsx +++ b/src/modules/TodoList/components/ModifyTaskWindow/index.tsx @@ -3,14 +3,14 @@ /* eslint-disable multiline-ternary */ import { Icon } from '@iconify/react/dist/iconify.js' import React, { useEffect, useRef, useState } from 'react' -import Input from '../../../../components/general/Input' +import Input from '@components/Input' import { type ITodoListTag, type ITodoListList } from '../Sidebar' import { type ITodoListEntryItem } from '../..' -import HamburgerMenu from '../../../../components/general/HamburgerMenu' -import MenuItem from '../../../../components/general/HamburgerMenu/MenuItem' +import HamburgerMenu from '@components/HamburgerMenu' +import MenuItem from '@components/HamburgerMenu/MenuItem' import { toast } from 'react-toastify' import { cookieParse } from 'pocketbase' -import CreateOrModifyButton from '../../../../components/general/CreateOrModifyButton' +import CreateOrModifyButton from '@components/CreateOrModifyButton' import PrioritySelector from './components/PrioritySelector' import ListSelector from './components/ListSelector' import TagsSelector from './components/TagsSelector' diff --git a/src/modules/TodoList/components/Sidebar.tsx b/src/modules/TodoList/components/Sidebar.tsx index 208825855..f5cb85d79 100644 --- a/src/modules/TodoList/components/Sidebar.tsx +++ b/src/modules/TodoList/components/Sidebar.tsx @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/strict-boolean-expressions */ /* eslint-disable @typescript-eslint/indent */ import React, { useEffect, useState } from 'react' -import SidebarDivider from '../../../components/Sidebar/components/SidebarDivider' -import SidebarTitle from '../../../components/Sidebar/components/SidebarTitle' +import SidebarDivider from '@sidebar/components/SidebarDivider' +import SidebarTitle from '@sidebar/components/SidebarTitle' import { Icon } from '@iconify/react' -import APIComponentWithFallback from '../../../components/general/APIComponentWithFallback' -import GoBackButton from '../../../components/general/GoBackButton' +import APIComponentWithFallback from '@components/APIComponentWithFallback' +import GoBackButton from '@components/GoBackButton' import ModifyListModal from './ModifyListModal' import ModifyTagModal from './ModifyTagModal' diff --git a/src/modules/TodoList/index.tsx b/src/modules/TodoList/index.tsx index f1ba94ba2..9f58b656f 100644 --- a/src/modules/TodoList/index.tsx +++ b/src/modules/TodoList/index.tsx @@ -6,14 +6,14 @@ import Sidebar, { type ITodoListTag, type ITodoListList } from './components/Sidebar' -import ModuleHeader from '../../components/general/ModuleHeader' -import useFetch from '../../hooks/useFetch' -import APIComponentWithFallback from '../../components/general/APIComponentWithFallback' +import ModuleHeader from '@components/ModuleHeader' +import useFetch from '@hooks/useFetch' +import APIComponentWithFallback from '@components/APIComponentWithFallback' import TaskItem from './components/TaskItem' import ModifyTaskWindow from './components/ModifyTaskWindow' -import ModuleWrapper from '../../components/general/ModuleWrapper' -import SearchInput from '../../components/general/SearchInput' -import DeleteConfirmationModal from '../../components/general/DeleteConfirmationModal' +import ModuleWrapper from '@components/ModuleWrapper' +import SearchInput from '@components/SearchInput' +import DeleteConfirmationModal from '@components/DeleteConfirmationModal' export interface ITodoListEntryItem { collectionId: string diff --git a/src/providers/AuthProvider.tsx b/src/providers/AuthProvider.tsx index b0b74f999..e230b6e6f 100644 --- a/src/providers/AuthProvider.tsx +++ b/src/providers/AuthProvider.tsx @@ -1,12 +1,12 @@ /* eslint-disable @typescript-eslint/strict-boolean-expressions */ /* eslint-disable @typescript-eslint/member-delimiter-style */ -import React, { createContext, useContext, useEffect, useState } from 'react' -import { GlobalStateContext } from './GlobalStateProvider' +import React, { createContext, useEffect, useState } from 'react' import { AUTH_ERROR_MESSAGES } from '../constants/auth' import { toast } from 'react-toastify' const AUTH_DATA: { auth: boolean + setAuth: React.Dispatch> authenticate: ({ email, password @@ -14,7 +14,7 @@ const AUTH_DATA: { email: string password: string }) => Promise - authWithOauth: (provider: string) => Promise + verifyToken: (token: string) => Promise<{ success: boolean; userData: any }> logout: () => void loginQuota: { quota: number @@ -26,8 +26,9 @@ const AUTH_DATA: { getAvatarURL: () => string } = { auth: false, + setAuth: () => {}, authenticate: async () => '', - authWithOauth: async () => '', + verifyToken: async () => ({ success: false, userData: null }), logout: () => {}, loginQuota: { quota: 5, @@ -50,9 +51,6 @@ export default function AuthProvider({ const [userData, setUserData] = useState(null) const [quota, setQuota] = useState(5) const [authLoading, setAuthLoading] = useState(true) - const { - pocketbase: { pocketbase, loading, error } - } = useContext(GlobalStateContext) function updateQuota(): number { const storedQuota = window.localStorage.getItem('quota') @@ -97,6 +95,29 @@ export default function AuthProvider({ toast.error(AUTH_ERROR_MESSAGES.QUOTA_EXCEEDED) } + async function verifyToken(token: string): Promise<{ + success: boolean + userData: any + }> { + return await fetch(`${import.meta.env.VITE_API_HOST}/user/auth/verify`, { + method: 'POST', + headers: { + Authorization: `Bearer ${token}` + } + }) + .then(async res => { + const data = await res.json() + if (res.ok && data.state === 'success') { + return { success: true, userData: data.userData } + } else { + return { success: false, userData: null } + } + }) + .catch(() => { + return { success: false, userData: null } + }) + } + async function authenticate({ email, password @@ -104,109 +125,65 @@ export default function AuthProvider({ email: string password: string }): Promise { - if (!loading && pocketbase !== null && error === null) { - try { - await pocketbase - .collection('users') - .authWithPassword(email, password) - .catch(e => { - throw e.message - }) + const res = fetch(`${import.meta.env.VITE_API_HOST}/user/auth/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ email, password }) + }) + .then(async res => { + const data = await res.json() + if (res.ok && data.state === 'success') { + window.localStorage.setItem('quota', '5') + window.localStorage.removeItem('lastQuotaExceeded') - window.localStorage.setItem('quota', '5') - window.localStorage.removeItem('lastQuotaExceeded') + document.cookie = `token=${data.token}; path=/; expires=${new Date( + Date.now() + 7 * 24 * 60 * 60 * 1000 + ).toUTCString()}` - document.cookie = `token=${ - pocketbase.authStore.token - }; path=/; expires=${new Date( - Date.now() + 7 * 24 * 60 * 60 * 1000 - ).toUTCString()}` + setUserData(data.userData) + setAuth(true) - setUserData(pocketbase.authStore.model) - setAuth(pocketbase.authStore.isValid) - - return 'success: ' + pocketbase.authStore.model?.name - } catch (error) { - switch (error) { + return 'success: ' + data.userData.name + } else { + throw new Error(data.message) + } + }) + .catch(err => { + switch (err) { case 'Failed to authenticate.': return AUTH_ERROR_MESSAGES.INVALID_CREDENTIALS default: return AUTH_ERROR_MESSAGES.UNKNOWN_ERROR } - } - } else { - return AUTH_ERROR_MESSAGES.DATABASE_NOT_READY - } - } + }) - async function authWithOauth(provider: string): Promise { - if (!loading && pocketbase !== null && error === null) { - try { - const w = window.open() - - await pocketbase - .collection('users') - .authWithOAuth2({ - provider, - urlCallback: url => { - if (w !== null) { - w.location.href = url - } - } - }) - .catch(e => { - throw e.message - }) - - window.localStorage.setItem('quota', '5') - window.localStorage.removeItem('lastQuotaExceeded') - - document.cookie = `token=${ - pocketbase.authStore.token - }; path=/; expires=${new Date( - Date.now() + 7 * 24 * 60 * 60 * 1000 - ).toUTCString()}` - - setUserData(pocketbase.authStore.model) - - return 'success: ' + pocketbase.authStore.model?.name - } catch (error) { - switch (error) { - case 'Failed to authenticate.': - return AUTH_ERROR_MESSAGES.INVALID_CREDENTIALS - default: - return AUTH_ERROR_MESSAGES.UNKNOWN_ERROR - } - } finally { - setAuth(pocketbase.authStore.isValid) - } - } else { - return AUTH_ERROR_MESSAGES.DATABASE_NOT_READY - } + return await res } function logout(): void { - if (!loading && pocketbase !== null) { - pocketbase.authStore.clear() - setAuth(false) - document.cookie = `token=; path=/; expires=${new Date( - Date.now() + 7 * 24 * 60 * 60 * 1000 - ).toUTCString()}` - setUserData(null) + setAuth(false) + document.cookie = `token=; path=/; expires=${new Date( + Date.now() + 7 * 24 * 60 * 60 * 1000 + ).toUTCString()}` + setUserData(null) - window.localStorage.setItem('quota', '5') - window.localStorage.removeItem('lastQuotaExceeded') - } + window.localStorage.setItem('quota', '5') + window.localStorage.removeItem('lastQuotaExceeded') } useEffect(() => { setAuthLoading(true) - if (!loading && pocketbase !== null && document.cookie.includes('token')) { - ;(async () => { - await pocketbase.collection('users').authRefresh() - setAuth(pocketbase.authStore.isValid) - setUserData(pocketbase.authStore.model) - })() + updateQuota() + if (document.cookie.includes('token')) { + verifyToken(document.cookie.split('=')[1]) + .then(async ({ success, userData }) => { + if (success) { + setUserData(userData) + setAuth(true) + } + }) .catch(() => { setAuth(false) }) @@ -216,18 +193,13 @@ export default function AuthProvider({ } else { setAuthLoading(false) } - }, [loading]) - - useEffect(() => { - updateQuota() }, []) function getAvatarURL(): string { - const _userData = pocketbase?.authStore.model - if (_userData) { + if (userData) { return `${import.meta.env.VITE_POCKETBASE_ENDPOINT}/api/files/${ - _userData.collectionId - }/${_userData.id}/${_userData.avatar}` + userData.collectionId + }/${userData.id}/${userData.avatar}` } return '' } @@ -236,8 +208,9 @@ export default function AuthProvider({ void - pocketbase: { - pocketbase: Pocketbase | null - loading: boolean - error: any - } } = { sidebarExpanded: true, - toggleSidebar: () => {}, - pocketbase: { - pocketbase: null, - loading: false, - error: null - } + toggleSidebar: () => {} } export const GlobalStateContext = createContext(GLOBAL_STATE) @@ -28,7 +16,6 @@ export default function GlobalStateProvider({ children: React.ReactNode }): React.ReactElement { const [navbarExpanded, setNavbarExpanded] = useState(true) - const { pocketbase, loading, error } = usePocketbase() function toggleNavbarExpanded(): void { setNavbarExpanded(!navbarExpanded) @@ -44,12 +31,7 @@ export default function GlobalStateProvider({ {children} diff --git a/src/providers/PhotosProvider.tsx b/src/providers/PhotosProvider.tsx index 68c9493a1..176a3c585 100644 --- a/src/providers/PhotosProvider.tsx +++ b/src/providers/PhotosProvider.tsx @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/indent */ import moment from 'moment' import React, { createContext, useEffect, useRef, useState } from 'react' -import useFetch from '../hooks/useFetch' +import useFetch from '@hooks/useFetch' import { Outlet } from 'react-router' export interface IPhotosEntryDimensionsItem { diff --git a/tsconfig.json b/tsconfig.json index d04033baf..9d4a208a9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,14 @@ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + + "paths": { + "@components/*": ["./src/components/general/*"], + "@providers/*": ["./src/providers/*"], + "@hooks/*": ["./src/hooks/*"], + "@sidebar/*": ["./src/components/Sidebar/*"] + } }, "include": ["src"], "references": [{ "path": "./tsconfig.node.json" }] diff --git a/tsconfig.node.json b/tsconfig.node.json index 42872c59f..d3fbed10e 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -4,7 +4,12 @@ "skipLibCheck": true, "module": "ESNext", "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true + "allowSyntheticDefaultImports": true, + + "paths": { + "@components/*": ["./src/components/general/*"], + "@providers/*": ["./src/providers/*"] + } }, "include": ["vite.config.ts"] } diff --git a/vite.config.ts b/vite.config.ts index 5a33944a9..c28fb1259 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,20 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' +import mkcert from 'vite-plugin-mkcert' +import path from 'path' // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react()], + plugins: [react(), mkcert()], + server: { + https: false + }, + resolve: { + alias: { + '@components': path.resolve(__dirname, './src/components/general'), + '@providers': path.resolve(__dirname, './src/providers'), + '@hooks': path.resolve(__dirname, './src/hooks'), + '@sidebar': path.resolve(__dirname, './src/components/Sidebar') + } + } })