Chore: Dissolve useFetchRole

This commit is contained in:
Gustav Hansen 2023-08-11 15:37:53 +02:00
parent f4ba1601a6
commit 6f37fbb69e
5 changed files with 30 additions and 195 deletions

View File

@ -1,64 +0,0 @@
import { useCallback, useEffect, useReducer, useRef } from 'react';
import { useFetchClient, useNotification } from '@strapi/helper-plugin';
import reducer, { initialState } from './reducer';
// TODO: Refactor to use react-query
export const useFetchRole = (id) => {
const [state, dispatch] = useReducer(reducer, initialState);
const toggleNotification = useNotification();
const isMounted = useRef(null);
const { get } = useFetchClient();
useEffect(() => {
isMounted.current = true;
if (id) {
fetchRole(id);
} else {
dispatch({
type: 'GET_DATA_SUCCEEDED',
role: {},
});
}
return () => (isMounted.current = false);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [id]);
const fetchRole = async (roleId) => {
try {
const {
data: { role },
} = await get(`/users-permissions/roles/${roleId}`);
// Prevent updating state on an unmounted component
if (isMounted.current) {
dispatch({
type: 'GET_DATA_SUCCEEDED',
role,
});
}
} catch (err) {
console.error(err);
dispatch({
type: 'GET_DATA_ERROR',
});
toggleNotification({
type: 'warning',
message: { id: 'notification.error' },
});
}
};
const handleSubmitSucceeded = useCallback((data) => {
dispatch({
type: 'ON_SUBMIT_SUCCEEDED',
...data,
});
}, []);
return { ...state, onSubmitSucceeded: handleSubmitSucceeded };
};

View File

@ -1,31 +0,0 @@
/* eslint-disable consistent-return */
import produce from 'immer';
export const initialState = {
role: {},
isLoading: true,
};
const reducer = (state, action) =>
produce(state, (draftState) => {
switch (action.type) {
case 'GET_DATA_SUCCEEDED': {
draftState.role = action.role;
draftState.isLoading = false;
break;
}
case 'GET_DATA_ERROR': {
draftState.isLoading = false;
break;
}
case 'ON_SUBMIT_SUCCEEDED': {
draftState.role.name = action.name;
draftState.role.description = action.description;
break;
}
default:
return draftState;
}
});
export default reducer;

View File

@ -1,90 +0,0 @@
import reducer from '../reducer';
describe('USERS PERMISSIONS | HOOKS | useFetchRole | reducer', () => {
describe('DEFAULT_ACTION', () => {
it('should return the initialState', () => {
const state = {
test: true,
};
expect(reducer(state, {})).toEqual(state);
});
});
describe('GET_DATA_ERROR', () => {
it('should set isLoading to false is an error occured', () => {
const action = {
type: 'GET_DATA_ERROR',
};
const initialState = {
role: {},
isLoading: true,
};
const expected = {
role: {},
isLoading: false,
};
expect(reducer(initialState, action)).toEqual(expected);
});
});
describe('GET_DATA_SUCCEEDED', () => {
it('should return the state with the data', () => {
const action = {
type: 'GET_DATA_SUCCEEDED',
role: {
id: 1,
name: 'Authenticated',
description: 'This is the Authenticated role',
permissions: {},
},
};
const initialState = {
role: {},
isLoading: true,
};
const expected = {
role: {
id: 1,
name: 'Authenticated',
description: 'This is the Authenticated role',
permissions: {},
},
isLoading: false,
};
expect(reducer(initialState, action)).toEqual(expected);
});
});
describe('ON_SUBMIT_SUCCEEDED', () => {
it("should set the role's name and description correctly", () => {
const state = {
role: {
id: 1,
name: 'Authenticated',
description: 'This is the Authenticated role',
permissions: {},
},
};
const action = {
type: 'ON_SUBMIT_SUCCEEDED',
name: 'Public',
description: 'test',
};
const expected = {
role: {
id: 1,
name: 'Public',
description: 'test',
permissions: {},
},
};
expect(reducer(state, action)).toEqual(expected);
});
});
});

View File

@ -22,17 +22,21 @@ export const usePlugins = () => {
{ {
queryKey: ['users-permissions', 'permissions'], queryKey: ['users-permissions', 'permissions'],
async queryFn() { async queryFn() {
const res = await get(`/users-permissions/permissions`); const {
data: { permissions },
} = await get(`/users-permissions/permissions`);
return res.data.permissions; return permissions;
}, },
}, },
{ {
queryKey: ['users-permissions', 'routes'], queryKey: ['users-permissions', 'routes'],
async queryFn() { async queryFn() {
const res = await get(`/users-permissions/routes`); const {
data: { routes },
} = await get(`/users-permissions/routes`);
return res.data.routes; return routes;
}, },
}, },
]); ]);
@ -62,8 +66,12 @@ export const usePlugins = () => {
const isLoading = isLoadingPermissions || isLoadingRoutes; const isLoading = isLoadingPermissions || isLoadingRoutes;
return { return {
// TODO: these return values need to be memoized, otherwise
// they will create infinite rendering loops when used as
// effect dependencies
permissions: permissions ? cleanPermissions(permissions) : {}, permissions: permissions ? cleanPermissions(permissions) : {},
routes: routes ?? {}, routes: routes ?? {},
getData: refetchQueries, getData: refetchQueries,
isLoading, isLoading,
}; };

View File

@ -13,23 +13,22 @@ import {
Grid, Grid,
} from '@strapi/design-system'; } from '@strapi/design-system';
import { import {
useFetchClient,
useOverlayBlocker, useOverlayBlocker,
SettingsPageTitle, SettingsPageTitle,
LoadingIndicatorPage, LoadingIndicatorPage,
Form, Form,
useAPIErrorHandler, useAPIErrorHandler,
useFetchClient,
useNotification, useNotification,
Link, Link,
} from '@strapi/helper-plugin'; } from '@strapi/helper-plugin';
import { ArrowLeft, Check } from '@strapi/icons'; import { ArrowLeft, Check } from '@strapi/icons';
import { Formik } from 'formik'; import { Formik } from 'formik';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { useMutation } from 'react-query'; import { useQuery, useMutation } from 'react-query';
import { useRouteMatch } from 'react-router-dom'; import { useRouteMatch } from 'react-router-dom';
import UsersPermissions from '../../../components/UsersPermissions'; import UsersPermissions from '../../../components/UsersPermissions';
import { useFetchRole } from '../../../hooks/useFetchRole';
import { usePlugins } from '../../../hooks/usePlugins'; import { usePlugins } from '../../../hooks/usePlugins';
import getTrad from '../../../utils/getTrad'; import getTrad from '../../../utils/getTrad';
import { createRoleSchema } from '../constants'; import { createRoleSchema } from '../constants';
@ -41,8 +40,21 @@ export const EditPage = () => {
const { const {
params: { id }, params: { id },
} = useRouteMatch(`/settings/users-permissions/roles/:id`); } = useRouteMatch(`/settings/users-permissions/roles/:id`);
const { get } = useFetchClient();
const { isLoading: isLoadingPlugins, routes } = usePlugins(); const { isLoading: isLoadingPlugins, routes } = usePlugins();
const { role, onSubmitSucceeded, isLoading: isLoadingRole } = useFetchRole(id); const {
data: role,
isLoading: isLoadingRole,
refetch: refetchRole,
} = useQuery(['users-permissions', 'role', id], async () => {
// TODO: why doesn't this endpoint follow the admin API conventions?
const {
data: { role },
} = await get(`/users-permissions/roles/${id}`);
return role;
});
const permissionsRef = React.useRef(); const permissionsRef = React.useRef();
const { put } = useFetchClient(); const { put } = useFetchClient();
const { formatAPIError } = useAPIErrorHandler(); const { formatAPIError } = useAPIErrorHandler();
@ -54,7 +66,7 @@ export const EditPage = () => {
}); });
}, },
onSuccess(data) { async onSuccess() {
toggleNotification({ toggleNotification({
type: 'success', type: 'success',
message: { message: {
@ -63,7 +75,7 @@ export const EditPage = () => {
}, },
}); });
onSubmitSucceeded({ name: data.name, description: data.description }); await refetchRole();
}, },
}); });