refactor: data fetching for the public paste page

This includes changing routing to use createBrowserRouter and createRoutesFromElements which includes the use of the loader function.
This commit is contained in:
bjarneo 2024-01-28 10:03:47 +01:00
parent ec87692ff3
commit 5851a41fce
No known key found for this signature in database
GPG Key ID: AA3697C46F530672
9 changed files with 100 additions and 119 deletions

View File

@ -2,4 +2,5 @@ node_modules
.github .github
example_request_do.log example_request_do.log
bin/ bin/
.git .git
hemmelig.backup.db

3
.gitignore vendored
View File

@ -121,4 +121,5 @@ hemmelig.db*
prisma_test.js prisma_test.js
database/ database/
data/ data/
.vscode .vscode
hemmelig.backup.db

View File

@ -6,3 +6,4 @@ config/
public/ public/
.github/ .github/
tests/ tests/
hemmelig.backup.db

62
package-lock.json generated
View File

@ -40,6 +40,7 @@
"node-fetch": "^2.6.7", "node-fetch": "^2.6.7",
"pretty-bytes": "^4.0.2", "pretty-bytes": "^4.0.2",
"react-qr-code": "^2.0.8", "react-qr-code": "^2.0.8",
"react-router-dom": "^6.21.3",
"sanitize-filename": "^1.6.3", "sanitize-filename": "^1.6.3",
"tweetnacl": "^0.14.5", "tweetnacl": "^0.14.5",
"tweetnacl-util": "^0.15.1", "tweetnacl-util": "^0.15.1",
@ -75,7 +76,6 @@
"react-i18next": "^11.18.5", "react-i18next": "^11.18.5",
"react-quill": "^2.0.0", "react-quill": "^2.0.0",
"react-redux": "^7.2.5", "react-redux": "^7.2.5",
"react-router-dom": "^6.10.0",
"redux": "^4.1.1", "redux": "^4.1.1",
"vite": "^4.2.1" "vite": "^4.2.1"
} }
@ -2431,12 +2431,11 @@
} }
}, },
"node_modules/@remix-run/router": { "node_modules/@remix-run/router": {
"version": "1.5.0", "version": "1.14.2",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.2.tgz",
"integrity": "sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==", "integrity": "sha512-ACXpdMM9hmKZww21yEqWwiLws/UPLhNKvimN8RrYSqPSvB3ov7sLvAcfvaxePeLvccTQKGdkDIhLYApZVDFuKg==",
"dev": true,
"engines": { "engines": {
"node": ">=14" "node": ">=14.0.0"
} }
}, },
"node_modules/@smithy/abort-controller": { "node_modules/@smithy/abort-controller": {
@ -7084,31 +7083,29 @@
} }
}, },
"node_modules/react-router": { "node_modules/react-router": {
"version": "6.10.0", "version": "6.21.3",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.21.3.tgz",
"integrity": "sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==", "integrity": "sha512-a0H638ZXULv1OdkmiK6s6itNhoy33ywxmUFT/xtSoVyf9VnC7n7+VT4LjVzdIHSaF5TIh9ylUgxMXksHTgGrKg==",
"dev": true,
"dependencies": { "dependencies": {
"@remix-run/router": "1.5.0" "@remix-run/router": "1.14.2"
}, },
"engines": { "engines": {
"node": ">=14" "node": ">=14.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"react": ">=16.8" "react": ">=16.8"
} }
}, },
"node_modules/react-router-dom": { "node_modules/react-router-dom": {
"version": "6.10.0", "version": "6.21.3",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.21.3.tgz",
"integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==", "integrity": "sha512-kNzubk7n4YHSrErzjLK72j0B5i969GsuCGazRl3G6j1zqZBLjuSlYBdVdkDOgzGdPIffUOc9nmgiadTEVoq91g==",
"dev": true,
"dependencies": { "dependencies": {
"@remix-run/router": "1.5.0", "@remix-run/router": "1.14.2",
"react-router": "6.10.0" "react-router": "6.21.3"
}, },
"engines": { "engines": {
"node": ">=14" "node": ">=14.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"react": ">=16.8", "react": ">=16.8",
@ -10469,10 +10466,9 @@
} }
}, },
"@remix-run/router": { "@remix-run/router": {
"version": "1.5.0", "version": "1.14.2",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.2.tgz",
"integrity": "sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==", "integrity": "sha512-ACXpdMM9hmKZww21yEqWwiLws/UPLhNKvimN8RrYSqPSvB3ov7sLvAcfvaxePeLvccTQKGdkDIhLYApZVDFuKg=="
"dev": true
}, },
"@smithy/abort-controller": { "@smithy/abort-controller": {
"version": "2.0.13", "version": "2.0.13",
@ -13871,22 +13867,20 @@
} }
}, },
"react-router": { "react-router": {
"version": "6.10.0", "version": "6.21.3",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.21.3.tgz",
"integrity": "sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==", "integrity": "sha512-a0H638ZXULv1OdkmiK6s6itNhoy33ywxmUFT/xtSoVyf9VnC7n7+VT4LjVzdIHSaF5TIh9ylUgxMXksHTgGrKg==",
"dev": true,
"requires": { "requires": {
"@remix-run/router": "1.5.0" "@remix-run/router": "1.14.2"
} }
}, },
"react-router-dom": { "react-router-dom": {
"version": "6.10.0", "version": "6.21.3",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.21.3.tgz",
"integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==", "integrity": "sha512-kNzubk7n4YHSrErzjLK72j0B5i969GsuCGazRl3G6j1zqZBLjuSlYBdVdkDOgzGdPIffUOc9nmgiadTEVoq91g==",
"dev": true,
"requires": { "requires": {
"@remix-run/router": "1.5.0", "@remix-run/router": "1.14.2",
"react-router": "6.10.0" "react-router": "6.21.3"
} }
}, },
"react-style-singleton": { "react-style-singleton": {

View File

@ -65,6 +65,7 @@
"node-fetch": "^2.6.7", "node-fetch": "^2.6.7",
"pretty-bytes": "^4.0.2", "pretty-bytes": "^4.0.2",
"react-qr-code": "^2.0.8", "react-qr-code": "^2.0.8",
"react-router-dom": "^6.21.3",
"sanitize-filename": "^1.6.3", "sanitize-filename": "^1.6.3",
"tweetnacl": "^0.14.5", "tweetnacl": "^0.14.5",
"tweetnacl-util": "^0.15.1", "tweetnacl-util": "^0.15.1",
@ -97,7 +98,6 @@
"react-i18next": "^11.18.5", "react-i18next": "^11.18.5",
"react-quill": "^2.0.0", "react-quill": "^2.0.0",
"react-redux": "^7.2.5", "react-redux": "^7.2.5",
"react-router-dom": "^6.10.0",
"redux": "^4.1.1", "redux": "^4.1.1",
"vite": "^4.2.1" "vite": "^4.2.1"
}, },

View File

@ -1,54 +1,52 @@
import { MantineProvider } from '@mantine/core'; import { MantineProvider } from '@mantine/core';
import { ModalsProvider } from '@mantine/modals'; import { ModalsProvider } from '@mantine/modals';
import { BrowserRouter } from 'react-router-dom'; import { RouterProvider } from 'react-router-dom';
import AppRoutes from './routes.jsx'; import appRouter from './routes.jsx';
const HemmeligApplication = () => { const HemmeligApplication = () => {
return ( return (
<BrowserRouter> <MantineProvider
<MantineProvider withGlobalStyles
withGlobalStyles withNormalizeCSS
withNormalizeCSS theme={{
theme={{ colorScheme: 'dark',
colorScheme: 'dark', colors: {
colors: { hemmelig: [
hemmelig: [ '#ffffff',
'#ffffff', '#eaf5f4',
'#eaf5f4', '#d4ebe9',
'#d4ebe9', '#bfe2dd',
'#bfe2dd', '#aad8d2',
'#aad8d2', '#95cec7',
'#95cec7', '#7fc4bc',
'#7fc4bc', '#6abab1',
'#6abab1', '#55b1a5',
'#55b1a5', '#3fa79a',
'#3fa79a', '#2a9d8f',
'#2a9d8f', ],
], 'hemmelig-orange': [
'hemmelig-orange': [ '#ffffff',
'#ffffff', '#fff5f0',
'#fff5f0', '#ffeae1',
'#ffeae1', '#ffe0d2',
'#ffe0d2', '#ffd5c3',
'#ffd5c3', '#ffcbb4',
'#ffcbb4', '#ffc1a5',
'#ffc1a5', '#ffb696',
'#ffb696', '#ffac87',
'#ffac87', '#ffa178',
'#ffa178', '#ff9769',
'#ff9769', ],
], },
}, fontFamily: 'Inter, sans-serif',
fontFamily: 'Inter, sans-serif', fontFamilyMonospace: 'Inter, sans-serif',
fontFamilyMonospace: 'Inter, sans-serif', headings: { fontFamily: 'Inter, sans-serif' },
headings: { fontFamily: 'Inter, sans-serif' }, }}
}} >
> <ModalsProvider>
<ModalsProvider> <RouterProvider router={appRouter}></RouterProvider>
<AppRoutes /> </ModalsProvider>
</ModalsProvider> </MantineProvider>
</MantineProvider>
</BrowserRouter>
); );
}; };

View File

@ -1,5 +1,5 @@
import { lazy } from 'react'; import { lazy } from 'react';
import { Route, Routes } from 'react-router-dom'; import { Route, createBrowserRouter, createRoutesFromElements } from 'react-router-dom';
import AdminShell from './admin-shell.jsx'; import AdminShell from './admin-shell.jsx';
import ApplicationShell from './app-shell.jsx'; import ApplicationShell from './app-shell.jsx';
@ -18,21 +18,29 @@ const Settings = lazy(() => import('./routes/account/settings'));
const Users = lazy(() => import('./routes/account/users')); const Users = lazy(() => import('./routes/account/users'));
const UserAccount = lazy(() => import('./routes/account/account')); const UserAccount = lazy(() => import('./routes/account/account'));
const AppRoutes = () => { // loader: https://reactrouter.com/en/main/route/loader
return ( const appRouter = createBrowserRouter(
<Routes> createRoutesFromElements(
<>
<Route path="/" element={<ApplicationShell />}> <Route path="/" element={<ApplicationShell />}>
<Route index element={<Home />} /> <Route index element={<Home />} />
<Route path="secret/:encryptionKey/:secretId" element={<Secret />} /> <Route path="secret/:encryptionKey/:secretId" element={<Secret />} />
<Route path="secret/:secretId" element={<Secret />} /> <Route path="secret/:secretId" element={<Secret />} />
<Route path="public" element={<PublicSecrets />} /> <Route
element={<PublicSecrets />}
path="public"
loader={async () => {
const { getPublicSecrets } = await import('./api/secret');
return await getPublicSecrets();
}}
/>
<Route path="signin" element={<SignIn />} /> <Route path="signin" element={<SignIn />} />
<Route path="signup" element={<SignUp />} /> <Route path="signup" element={<SignUp />} />
<Route path="signout" element={<SignOut />} /> <Route path="signout" element={<SignOut />} />
<Route path="privacy" element={<Privacy />} /> <Route path="privacy" element={<Privacy />} />
<Route path="terms" element={<Terms />} /> <Route path="terms" element={<Terms />} />
</Route> </Route>
<Route path="/account" element={<AdminShell />}> <Route path="/account" element={<AdminShell />}>
<Route index element={<Account />} /> <Route index element={<Account />} />
<Route path="account" element={<Account />} /> <Route path="account" element={<Account />} />
@ -43,8 +51,8 @@ const AppRoutes = () => {
<Route path="privacy" element={<Privacy />} /> <Route path="privacy" element={<Privacy />} />
<Route path="terms" element={<Terms />} /> <Route path="terms" element={<Terms />} />
</Route> </Route>
</Routes> </>
); )
}; );
export default AppRoutes; export default appRouter;

View File

@ -1,29 +1,15 @@
import { Anchor, Container, Group, Loader, Stack, Table, Title } from '@mantine/core'; import { Anchor, Container, Group, Stack, Table, Title } from '@mantine/core';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime'; import relativeTime from 'dayjs/plugin/relativeTime';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom'; import { Link, useLoaderData } from 'react-router-dom';
import { getPublicSecrets } from '../../api/secret';
dayjs.extend(relativeTime); dayjs.extend(relativeTime);
const PublicSecrets = () => { const PublicSecrets = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const [secrets, setPublicSecrets] = useState([]); const secrets = useLoaderData();
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
(async () => {
const secrets = await getPublicSecrets();
setPublicSecrets(secrets);
setIsLoading(false);
})();
}, []);
const getTime = (expiresAt) => { const getTime = (expiresAt) => {
return dayjs().to(dayjs(expiresAt)); return dayjs().to(dayjs(expiresAt));
@ -46,14 +32,6 @@ const PublicSecrets = () => {
</tr> </tr>
)); ));
if (isLoading) {
return (
<Container>
<Loader color="teal" variant="bars" />
</Container>
);
}
return ( return (
<Container> <Container>
<Stack> <Stack>

View File

@ -236,7 +236,7 @@ async function secret(fastify) {
}); });
if (!data?.length) { if (!data?.length) {
return reply.code(404).send({ error: 'Public pastes not found' }); return reply.code(204).send([]);
} }
return data.map((secret) => ({ return data.map((secret) => ({