diff --git a/src/client/routes.jsx b/src/client/routes.jsx index b43943ac..37a0975b 100644 --- a/src/client/routes.jsx +++ b/src/client/routes.jsx @@ -51,12 +51,60 @@ const appRouter = createBrowserRouter( } /> }> - } /> - } /> - } /> - } /> - } /> - } /> + } + loader={async () => { + const { getUser } = await import('./api/account'); + + return await getUser(); + }} + /> + } + loader={async () => { + const { getUser } = await import('./api/account'); + + return await getUser(); + }} + /> + } + loader={async () => { + const { getSecrets } = await import('./api/secret'); + + return await getSecrets(); + }} + /> + } + loader={async () => { + const { getSettings } = await import('./api/settings'); + + return await getSettings(); + }} + /> + } + loader={async () => { + const { getUser } = await import('./api/account'); + + return await getUser(); + }} + /> + } + loader={async () => { + const { getUsers } = await import('./api/users'); + + return await getUsers(); + }} + /> } /> } /> diff --git a/src/client/routes/account/account.jsx b/src/client/routes/account/account.jsx index 7625ae51..5eebe020 100644 --- a/src/client/routes/account/account.jsx +++ b/src/client/routes/account/account.jsx @@ -1,70 +1,35 @@ -import { - Button, - Container, - Group, - Loader, - PasswordInput, - Stack, - Text, - TextInput, -} from '@mantine/core'; +import { Button, Group, PasswordInput, Stack, Text, TextInput } from '@mantine/core'; import { useForm } from '@mantine/form'; import { openConfirmModal } from '@mantine/modals'; import { IconAt, IconEdit, IconLock, IconTrash } from '@tabler/icons'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { Navigate } from 'react-router-dom'; +import { Navigate, useLoaderData } from 'react-router-dom'; import ErrorBox from '../../components/error-box'; import SuccessBox from '../../components/success-box'; import style from './account.module.css'; -import { deleteUser, getUser, updateUser } from '../../api/account'; +import { deleteUser, updateUser } from '../../api/account'; const Account = () => { const [success, setSuccess] = useState(false); const [error, setError] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const [userError, setUserError] = useState(null); const [successMessage, setSuccessMessage] = useState(null); const [deleted, setDeleted] = useState(false); const { t } = useTranslation(); + const userInfo = useLoaderData(); + const form = useForm({ - initialValues: { - currentPassword: '', - newPassword: '', - email: '', - confirmNewPassword: '', - }, + initialValues: userInfo?.user, validate: { confirmNewPassword: (value, values) => value !== values.newPassword ? t('account.account.passwords_does_not_match') : null, }, }); - useEffect(() => { - (async () => { - try { - const userInfo = await getUser(); - - if (userInfo.error || [401, 500].includes(userInfo.statusCode)) { - setUserError(userInfo.error ? userInfo.error : t('not_logged_in')); - - return; - } - - form.setValues(userInfo.user); - - setIsLoading(false); - setUserError(null); - } catch (err) { - setUserError(err); - } - })(); - }, []); - const onProfileUpdate = async (e) => { e.preventDefault(); @@ -78,7 +43,6 @@ const Account = () => { updatedUserInfo.message ? updatedUserInfo.message : t('account.account.can_not_update_profile') - ); return; @@ -152,15 +116,9 @@ const Account = () => { return ; } - if (isLoading && !userError) { - return ( - - - - ); - } + if (userInfo.error || [401, 500].includes(userInfo.statusCode)) { + const userError = userInfo.error ? userInfo.error : t('not_logged_in'); - if (userError) { return ( diff --git a/src/client/routes/account/index.jsx b/src/client/routes/account/index.jsx index e41909db..84a0ee59 100644 --- a/src/client/routes/account/index.jsx +++ b/src/client/routes/account/index.jsx @@ -1,40 +1,25 @@ import { Container, Loader, Stack, Text } from '@mantine/core'; -import { useEffect, useState } from 'react'; -import { Navigate } from 'react-router-dom'; +import { Navigate, useLoaderData } from 'react-router-dom'; import ErrorBox from '../../components/error-box'; import { useTranslation } from 'react-i18next'; -import { getUser } from '../../api/account'; const HomeAccount = () => { const { t } = useTranslation(); - const [user, setUser] = useState(null); - const [error, setError] = useState(null); - const [isLoading, setIsLoading] = useState(true); + const userInfo = useLoaderData(); - useEffect(() => { - (async () => { - try { - const userInfo = await getUser(); - - if (userInfo.error || [401, 500].includes(userInfo.statusCode)) { - setError(userInfo.error ? userInfo.error : t('not_logged_in')); - - return; - } - - setUser(userInfo.user); + if (userInfo?.error || [401, 500].includes(userInfo.statusCode)) { + return ( + + + + ); + } - setIsLoading(false); - setError(null); - } catch (err) { - setError(err); - } - })(); - }, []); + const { user = {} } = userInfo; - if (!user?.username && !isLoading) { + if (!user?.username) { return ; } @@ -46,14 +31,6 @@ const HomeAccount = () => { ); } - if (error) { - return ( - - - - ); - } - return ( {user?.generated && ( diff --git a/src/client/routes/account/secrets.jsx b/src/client/routes/account/secrets.jsx index c3d1097f..f1dd649d 100644 --- a/src/client/routes/account/secrets.jsx +++ b/src/client/routes/account/secrets.jsx @@ -1,15 +1,16 @@ -import { ActionIcon, Container, Group, Loader, Stack, Table, Text } from '@mantine/core'; +import { ActionIcon, Group, Stack, Table, Text } from '@mantine/core'; import { useForm } from '@mantine/form'; import { openConfirmModal } from '@mantine/modals'; import { IconTrash } from '@tabler/icons'; import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { useLoaderData } from 'react-router-dom'; import ErrorBox from '../../components/error-box'; import SuccessBox from '../../components/success-box'; -import { burnSecret, getSecrets } from '../../api/secret'; +import { burnSecret } from '../../api/secret'; dayjs.extend(relativeTime); @@ -28,10 +29,7 @@ const updateSecretList = (secrets, form, action = 'update') => { }; const Secrets = () => { - const [secrets, setSecrets] = useState([]); - const [error, setError] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const [userError, setUserError] = useState(null); + const [secrets, setSecrets] = useState(useLoaderData()); const [success, setSuccess] = useState(false); const { t } = useTranslation(); @@ -45,26 +43,15 @@ const Secrets = () => { initialValues: defaultValues, }); - useEffect(() => { - (async () => { - try { - const secrets = await getSecrets(); + if (secrets.error || [401, 500].includes(secrets.statusCode)) { + const error = secrets.error ? secrets.error : t('not_logged_in'); - if (secrets.error || [401, 500].includes(secrets.statusCode)) { - setUserError(secrets.error ? secrets.error : t('not_logged_in')); - - return; - } - - setSecrets(secrets); - - setIsLoading(false); - setUserError(null); - } catch (err) { - setUserError(err); - } - })(); - }, []); + return ( + + + + ); + } const onDeleteSecret = async (secret) => { try { @@ -121,25 +108,8 @@ const Secrets = () => { )); - if (isLoading && !userError) { - return ( - - - - ); - } - - if (userError) { - return ( - - - - ); - } - return ( - {error && } {success && } diff --git a/src/client/routes/account/settings.jsx b/src/client/routes/account/settings.jsx index 3ac67968..16575194 100644 --- a/src/client/routes/account/settings.jsx +++ b/src/client/routes/account/settings.jsx @@ -1,52 +1,26 @@ -import { Button, Checkbox, Container, Group, Input, Loader, Stack, Text } from '@mantine/core'; +import { Button, Checkbox, Group, Input, Stack, Text } from '@mantine/core'; import { useForm } from '@mantine/form'; import { IconAt, IconEdit } from '@tabler/icons'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { useLoaderData } from 'react-router-dom'; import ErrorBox from '../../components/error-box'; import SuccessBox from '../../components/success-box'; -import { getSettings, updateSettings } from '../../api/settings'; +import { updateSettings } from '../../api/settings'; const Settings = () => { const [success, setSuccess] = useState(false); const [error, setError] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const [userError, setUserError] = useState(null); const { t } = useTranslation(); + const adminSettings = useLoaderData(); + const form = useForm({ - initialValues: { - read_only: false, - disable_users: false, - disable_user_account_creation: false, - disable_file_upload: false, - restrict_organization_email: '', - }, + initialValues: adminSettings, }); - useEffect(() => { - (async () => { - try { - const adminSettings = await getSettings(); - - if (adminSettings.error || [401, 403, 500].includes(adminSettings.statusCode)) { - setUserError(adminSettings.error ? adminSettings.error : t('not_logged_in')); - - return; - } - - form.setValues(adminSettings[0]); - - setIsLoading(false); - setUserError(null); - } catch (err) { - setUserError(err); - } - })(); - }, []); - const onUpdateSettings = async (e) => { e.preventDefault(); @@ -79,18 +53,12 @@ const Settings = () => { } }; - if (isLoading && !userError) { - return ( - - - - ); - } + if (adminSettings.error || [401, 403, 500].includes(adminSettings.statusCode)) { + const error = adminSettings.error ? adminSettings.error : t('not_logged_in'); - if (userError) { return ( - + ); } diff --git a/src/client/routes/account/users.jsx b/src/client/routes/account/users.jsx index 6b2d50c9..9e2cbe41 100644 --- a/src/client/routes/account/users.jsx +++ b/src/client/routes/account/users.jsx @@ -4,7 +4,6 @@ import { Center, Container, Group, - Loader, Modal, PasswordInput, Select, @@ -17,8 +16,9 @@ import { useForm } from '@mantine/form'; import { useDisclosure } from '@mantine/hooks'; import { openConfirmModal } from '@mantine/modals'; import { IconAt, IconChefHat, IconEdit, IconPlus, IconTrash, IconUser } from '@tabler/icons'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { useLoaderData } from 'react-router-dom'; import { addUser, deleteUser, getUsers, updateUser } from '../../api/users'; import ErrorBox from '../../components/error-box'; @@ -50,56 +50,58 @@ const addUserList = (users, data) => { return updated; }; +const UserRows = ({ users, open, form, setModalState, openDeleteModal }) => { + return users.map((user) => ( + + + + + + + + )); +}; + const Users = () => { const [modalState, setModalState] = useState('add'); - const [users, setUsers] = useState([]); + const [users, setUsers] = useState(useLoaderData()); const [skip, setSkip] = useState(SKIP); const [showMore, setShowMore] = useState(true); const [success, setSuccess] = useState(false); const [error, setError] = useState(null); const [opened, { open, close }] = useDisclosure(false); - const [isLoading, setIsLoading] = useState(true); - const [userError, setUserError] = useState(null); const { t } = useTranslation(); const defaultValues = { username: '', email: '', - role: '', + role: 'user', password: '', }; const form = useForm({ - initialValues: defaultValues, + initialValues: users, }); - useEffect(() => { - (async () => { - try { - const users = await getUsers(); - - if (users.error || [401, 403, 500].includes(users.statusCode)) { - setUserError(users.error ? users.error : t('not_logged_in')); - - return; - } - - if (users?.length < SKIP) { - setShowMore(false); - } - - if (!users?.error) { - setUsers(users); - } - - setIsLoading(false); - setUserError(null); - } catch (err) { - setUserError(err); - } - })(); - }, []); + if (users?.length < SKIP) { + setShowMore(false); + } const onUpdateUser = async (event) => { event.preventDefault(); @@ -224,40 +226,9 @@ const Users = () => { close(event); }; - const rows = users.map((user) => ( - - - - - - - - )); + if (users.error || [401, 403, 500].includes(users?.statusCode)) { + const userError = users.error ? users.error : t('not_logged_in'); - if (isLoading && !userError) { - return ( - - - - ); - } - - if (userError) { return ( @@ -340,7 +311,15 @@ const Users = () => { - {rows} + + +
{user.username}{user.email}{user.role} + { + open(event); + form.setValues(user); + setModalState('update'); + }} + > + + + + openDeleteModal(user)}> + + +
{user.username}{user.email}{user.role} - { - open(event); - form.setValues(user); - setModalState('update'); - }} - > - - - - openDeleteModal(user)}> - - -
Delete
diff --git a/src/server/controllers/admin/settings.js b/src/server/controllers/admin/settings.js index 68d85c51..02ca7ff5 100644 --- a/src/server/controllers/admin/settings.js +++ b/src/server/controllers/admin/settings.js @@ -9,7 +9,7 @@ async function settings(fastify) { preValidation: [fastify.authenticate, fastify.admin], }, async () => { - const settings = await prisma.settings.findMany({ + const settings = await prisma.settings.findFirst({ where: { id: 'admin_settings', },