Skip to content

Commit

Permalink
refactor: use react router loader to fetch data to eliminate the use …
Browse files Browse the repository at this point in the history
…of useEffect (#283)

* refactor: get user from the route and not in use effect

* refactor: get user from the route and not in use effect

* refactor: get user from the route and not in use effect

* refactor: get user from the route and not in use effect

* refactor: get user from the route and not in use effect

* refactor: get user from the route and not in use effect

* fix: sonar lint
  • Loading branch information
bjarneo authored Mar 10, 2024
1 parent dc00d84 commit b20c472
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 244 deletions.
60 changes: 54 additions & 6 deletions src/client/routes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,60 @@ const appRouter = createBrowserRouter(
<Route path="terms" element={<Terms />} />
</Route>
<Route path="/account" element={<AdminShell />}>
<Route index element={<Account />} />
<Route path="account" element={<Account />} />
<Route path="secrets" element={<Secrets />} />
<Route path="instance-settings" element={<Settings />} />
<Route path="account-settings" element={<UserAccount />} />
<Route path="users" element={<Users />} />
<Route
index
element={<Account />}
loader={async () => {
const { getUser } = await import('./api/account');

return await getUser();
}}
/>
<Route
path="account"
element={<Account />}
loader={async () => {
const { getUser } = await import('./api/account');

return await getUser();
}}
/>
<Route
path="secrets"
element={<Secrets />}
loader={async () => {
const { getSecrets } = await import('./api/secret');

return await getSecrets();
}}
/>
<Route
path="instance-settings"
element={<Settings />}
loader={async () => {
const { getSettings } = await import('./api/settings');

return await getSettings();
}}
/>
<Route
path="account-settings"
element={<UserAccount />}
loader={async () => {
const { getUser } = await import('./api/account');

return await getUser();
}}
/>
<Route
path="users"
element={<Users />}
loader={async () => {
const { getUsers } = await import('./api/users');

return await getUsers();
}}
/>
<Route path="privacy" element={<Privacy />} />
<Route path="terms" element={<Terms />} />
</Route>
Expand Down
60 changes: 9 additions & 51 deletions src/client/routes/account/account.jsx
Original file line number Diff line number Diff line change
@@ -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();

Expand All @@ -78,7 +43,6 @@ const Account = () => {
updatedUserInfo.message
? updatedUserInfo.message
: t('account.account.can_not_update_profile')

);

return;
Expand Down Expand Up @@ -152,15 +116,9 @@ const Account = () => {
return <Navigate to="/signout" />;
}

if (isLoading && !userError) {
return (
<Container>
<Loader color="teal" variant="bars" />
</Container>
);
}
if (userInfo.error || [401, 500].includes(userInfo.statusCode)) {
const userError = userInfo.error ? userInfo.error : t('not_logged_in');

if (userError) {
return (
<Stack>
<ErrorBox message={userError} />
Expand Down
45 changes: 11 additions & 34 deletions src/client/routes/account/index.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<Stack>
<ErrorBox message={userInfo.error ? userInfo.error : t('not_logged_in')} />
</Stack>
);
}

setIsLoading(false);
setError(null);
} catch (err) {
setError(err);
}
})();
}, []);
const { user = {} } = userInfo;

if (!user?.username && !isLoading) {
if (!user?.username) {
return <Navigate replace to="/signin" />;
}

Expand All @@ -46,14 +31,6 @@ const HomeAccount = () => {
);
}

if (error) {
return (
<Stack>
<ErrorBox message={error} />
</Stack>
);
}

return (
<Stack>
{user?.generated && (
Expand Down
56 changes: 13 additions & 43 deletions src/client/routes/account/secrets.jsx
Original file line number Diff line number Diff line change
@@ -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);

Expand All @@ -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();
Expand All @@ -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 (
<Stack>
<ErrorBox message={error} />
</Stack>
);
}

const onDeleteSecret = async (secret) => {
try {
Expand Down Expand Up @@ -121,25 +108,8 @@ const Secrets = () => {
</tr>
));

if (isLoading && !userError) {
return (
<Container>
<Loader color="teal" variant="bars" />
</Container>
);
}

if (userError) {
return (
<Stack>
<ErrorBox message={userError} />
</Stack>
);
}

return (
<Stack>
{error && <ErrorBox message={error} />}
{success && <SuccessBox message={'secrets.deleted'} />}
<Group position="left">
<Table horizontalSpacing="sm" highlightOnHover>
Expand Down
Loading

0 comments on commit b20c472

Please sign in to comment.