Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade react-router-dom and setup layout in routes #1666

Merged
merged 4 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"graphql": "^15.5.1",
"graphql-tag": "^2.12.6",
"graphql-ws": "^5.14.0",
"history": "^5.3.0",
"i18next": "^21.8.14",
"i18next-browser-languagedetector": "^6.1.4",
"i18next-http-backend": "^1.4.1",
Expand All @@ -45,7 +46,7 @@
"react-icons": "^4.12.0",
"react-infinite-scroll-component": "^6.1.0",
"react-redux": "^7.2.5",
"react-router-dom": "^5.2.0",
"react-router-dom": "^6.22.2",
"react-scripts": "5.0.1",
"react-toastify": "^9.0.3",
"redux": "^4.1.1",
Expand Down
134 changes: 57 additions & 77 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
/* eslint-disable */
import { useQuery } from '@apollo/client';
import { CHECK_AUTH } from 'GraphQl/Queries/Queries';
import AddOnStore from 'components/AddOn/core/AddOnStore/AddOnStore';
import Loader from 'components/Loader/Loader';
import SecuredRoute from 'components/SecuredRoute/SecuredRoute';
import SecuredRouteForUser from 'components/UserPortal/SecuredRouteForUser/SecuredRouteForUser';
import React from 'react';
import { Route, Routes } from 'react-router-dom';
import * as installedPlugins from 'components/plugins/index';
import React, { useEffect } from 'react';
import { Route, Switch } from 'react-router-dom';
import BlockUser from 'screens/BlockUser/BlockUser';
import EventDashboard from 'screens/EventDashboard/EventDashboard';
import ForgotPassword from 'screens/ForgotPassword/ForgotPassword';
import SecuredRoute from 'components/SecuredRoute/SecuredRoute';
import LoginPage from 'screens/LoginPage/LoginPage';
import MemberDetail from 'screens/MemberDetail/MemberDetail';
import OrganizationEvents from 'screens/OrganizationEvents/OrganizationEvents';
import OrganizationActionItems from 'screens/OrganizationActionItems/OrganizationActionItems';
import OrganizationPeople from 'screens/OrganizationPeople/OrganizationPeople';
import OrganizationFunds from 'screens/OrganizationFunds/OrganizationFunds';
import OrganizationDashboard from 'screens/OrganizationDashboard/OrganizationDashboard';
import OrgContribution from 'screens/OrgContribution/OrgContribution';
import OrgList from 'screens/OrgList/OrgList';
import OrgPost from 'screens/OrgPost/OrgPost';
import OrgSettings from 'screens/OrgSettings/OrgSettings';
import OrganizationActionItems from 'screens/OrganizationActionItems/OrganizationActionItems';
import OrganizationDashboard from 'screens/OrganizationDashboard/OrganizationDashboard';
import OrganizationEvents from 'screens/OrganizationEvents/OrganizationEvents';
import OrganizationFunds from 'screens/OrganizationFunds/OrganizationFunds';
import OrganizationPeople from 'screens/OrganizationPeople/OrganizationPeople';
import PageNotFound from 'screens/PageNotFound/PageNotFound';
import AddOnStore from 'components/AddOn/core/AddOnStore/AddOnStore';
import ForgotPassword from 'screens/ForgotPassword/ForgotPassword';
import Users from 'screens/Users/Users';
import BlockUser from 'screens/BlockUser/BlockUser';
import EventDashboard from 'screens/EventDashboard/EventDashboard';
import MemberDetail from 'screens/MemberDetail/MemberDetail';
import OrganizationScreen from 'components/OrganizationScreen/OrganizationScreen';
import SuperAdminScreen from 'components/SuperAdminScreen/SuperAdminScreen';

// User Portal Components
import Donate from 'screens/UserPortal/Donate/Donate';
Expand All @@ -35,9 +32,7 @@ import Settings from 'screens/UserPortal/Settings/Settings';
// import UserLoginPage from 'screens/UserPortal/UserLoginPage/UserLoginPage';
// import Chat from 'screens/UserPortal/Chat/Chat';
import Advertisements from 'components/Advertisements/Advertisements';
import useLocalStorage from 'utils/useLocalstorage';

const { setItem } = useLocalStorage();
import SecuredRouteForUser from 'components/UserPortal/SecuredRouteForUser/SecuredRouteForUser';

function app(): JSX.Element {
/*const { updatePluginLinks, updateInstalled } = bindActionCreators(
Expand Down Expand Up @@ -65,77 +60,62 @@ function app(): JSX.Element {

// TODO: Fetch Installed plugin extras and store for use within MainContent and Side Panel Components.

const { data, loading } = useQuery(CHECK_AUTH);

useEffect(() => {
if (data) {
setItem('name', `${data.checkAuth.firstName} ${data.checkAuth.lastName}`);
setItem('id', data.checkAuth._id);
setItem('email', data.checkAuth.email);
setItem('IsLoggedIn', 'TRUE');
setItem('UserType', data.checkAuth.userType);
setItem('FirstName', data.checkAuth.firstName);
setItem('LastName', data.checkAuth.lastName);
setItem('UserImage', data.checkAuth.image);
setItem('Email', data.checkAuth.email);
}
}, [data, loading]);

const extraRoutes = Object.entries(installedPlugins).map(
(plugin: any, index) => {
const extraComponent = plugin[1];
return (
<SecuredRoute
<Route
key={index}
path={`/plugin/${plugin[0].toLowerCase()}`}
component={extraComponent}
element={extraComponent}
/>
);
},
);

if (loading) {
return <Loader />;
}
return (
<>
<Switch>
<Route exact path="/" component={LoginPage} />
<SecuredRoute path="/orgdash" component={OrganizationDashboard} />
<SecuredRoute path="/orgpeople" component={OrganizationPeople} />
<SecuredRoute path="/orglist" component={OrgList} />
<SecuredRoute path="/member" component={MemberDetail} />
<SecuredRoute path="/orgevents" component={OrganizationEvents} />
<SecuredRoute
path="/orgactionitems"
component={OrganizationActionItems}
/>
<SecuredRoute path="/orgfunds" component={OrganizationFunds} />
<SecuredRoute path="/orgcontribution" component={OrgContribution} />
<SecuredRoute path="/orgpost" component={OrgPost} />
<SecuredRoute path="/orgsetting" component={OrgSettings} />
<SecuredRoute path="/orgstore" component={AddOnStore} />
<SecuredRoute path="/orgads" component={Advertisements} />
<SecuredRoute path="/users" component={Users} />
<SecuredRoute path="/blockuser" component={BlockUser} />
<SecuredRoute path="/event/:eventId" component={EventDashboard} />
{extraRoutes}
<Route exact path="/forgotPassword" component={ForgotPassword} />

<Routes>
<Route path="/" element={<LoginPage />} />
<Route element={<SecuredRoute />}>
<Route element={<SuperAdminScreen />}>
<Route path="/orglist" element={<OrgList />} />
<Route path="/member" element={<MemberDetail />} />
<Route path="/users" element={<Users />} />
</Route>
<Route element={<OrganizationScreen />}>
<Route path="/orgdash/:orgId" element={<OrganizationDashboard />} />
<Route path="/orgpeople/:orgId" element={<OrganizationPeople />} />
<Route path="/member/:orgId" element={<MemberDetail />} />
<Route path="/orgevents/:orgId" element={<OrganizationEvents />} />
<Route
path="/orgactionitems/:orgId"
element={<OrganizationActionItems />}
/>
<Route path="/orgfunds/:orgId" element={<OrganizationFunds />} />
<Route path="/orgcontribution" element={<OrgContribution />} />
<Route path="/orgpost/:orgId" element={<OrgPost />} />
<Route path="/orgsetting/:orgId" element={<OrgSettings />} />
<Route path="/orgstore/:orgId" element={<AddOnStore />} />
<Route path="/orgads/:orgId" element={<Advertisements />} />
<Route path="/blockuser/:orgId" element={<BlockUser />} />
{extraRoutes}
</Route>
</Route>
<Route path="/event/:eventId" element={<EventDashboard />} />
<Route path="/forgotPassword" element={<ForgotPassword />} />
{/* User Portal Routes */}
<SecuredRouteForUser
path="/user/organizations"
component={Organizations}
/>
<SecuredRouteForUser path="/user/organization" component={Home} />
<SecuredRouteForUser path="/user/people" component={People} />
<SecuredRouteForUser path="/user/settings" component={Settings} />
<SecuredRouteForUser path="/user/donate" component={Donate} />
<SecuredRouteForUser path="/user/events" component={Events} />
<Route element={<SecuredRouteForUser />}>
<Route path="/user/organizations" element={<Organizations />} />
<Route path="/user/organization/:orgId" element={<Home />} />
<Route path="/user/people/:orgId" element={<People />} />
<Route path="/user/settings" element={<Settings />} />
<Route path="/user/donate/:orgId" element={<Donate />} />
<Route path="/user/events/:orgId" element={<Events />} />
</Route>
{/* <SecuredRouteForUser path="/user/chat" component={Chat} /> */}

<Route exact path="*" component={PageNotFound} />
</Switch>
<Route path="*" element={<PageNotFound />} />
</Routes>
</>
);
}
Expand Down
4 changes: 4 additions & 0 deletions src/GraphQl/Mutations/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ export const LOGIN_MUTATION = gql`
_id
userType
adminApproved
firstName
lastName
email
image
}
accessToken
refreshToken
Expand Down
23 changes: 22 additions & 1 deletion src/components/AddOn/core/AddOnEntry/AddOnEntry.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ const client: ApolloClient<NormalizedCacheObject> = new ApolloClient({
cache: new InMemoryCache(),
link: ApolloLink.from([httpLink]),
});
let mockID: string | undefined = '1';
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: () => ({ orgId: mockID }),
}));

describe('Testing AddOnEntry', () => {
const props = {
Expand Down Expand Up @@ -122,7 +127,7 @@ describe('Testing AddOnEntry', () => {
return { sample: 'sample' };
},
};

mockID = 'undefined';
const { findByText, getByTestId } = render(
<MockedProvider addTypename={false} link={link}>
<Provider store={store}>
Expand Down Expand Up @@ -185,4 +190,20 @@ describe('Testing AddOnEntry', () => {
const btn = getByTestId('AddOnEntry_btn_install');
expect(btn.innerHTML).toMatch(/install/i);
});
test('should be redirected to /orglist if orgId is undefined', async () => {
mockID = undefined;
render(
<ApolloProvider client={client}>
<Provider store={store}>
<BrowserRouter>
<I18nextProvider i18n={i18nForTest}>
{<AddOnEntry uninstalledOrgs={[]} {...props} />}
</I18nextProvider>
</BrowserRouter>
</Provider>
</ApolloProvider>,
);
await wait(100);
expect(window.location.pathname).toEqual('/orglist');
});
});
6 changes: 5 additions & 1 deletion src/components/AddOn/core/AddOnEntry/AddOnEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { UPDATE_INSTALL_STATUS_PLUGIN_MUTATION } from 'GraphQl/Mutations/mutatio
import { useMutation } from '@apollo/client';
import { useTranslation } from 'react-i18next';
import { toast } from 'react-toastify';
import { Navigate, useParams } from 'react-router-dom';

interface InterfaceAddOnEntryProps {
id: string;
Expand All @@ -29,7 +30,10 @@ function addOnEntry({
}: InterfaceAddOnEntryProps): JSX.Element {
const { t } = useTranslation('translation', { keyPrefix: 'addOnEntry' });
//getting orgId from URL
const currentOrg = window.location.href.split('/id=')[1] + '';
const { orgId: currentOrg } = useParams();
if (!currentOrg) {
return <Navigate to={'/orglist'} />;
}
const [buttonLoading, setButtonLoading] = useState(false);
const [isInstalledLocal, setIsInstalledLocal] = useState(
uninstalledOrgs.includes(currentOrg),
Expand Down
42 changes: 25 additions & 17 deletions src/components/AddOn/core/AddOnRegister/AddOnRegister.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const mocks = [
pluginCreatedBy: 'Test Creator',
pluginDesc: 'Test Description',
pluginInstallStatus: false,
installedOrgs: [undefined],
installedOrgs: ['id'],
},
},
result: {
Expand Down Expand Up @@ -80,26 +80,19 @@ jest.mock('react-toastify', () => ({
},
}));

const mockNavigate = jest.fn();
let mockId: string | undefined = 'id';
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: () => ({ orgId: mockId }),
useNavigate: () => mockNavigate,
}));

describe('Testing AddOnRegister', () => {
const props = {
id: '6234d8bf6ud937ddk70ecc5c9',
};

const original = window.location;
beforeAll(() => {
Object.defineProperty(window, 'location', {
configurable: true,
value: { reload: jest.fn() },
});
});

afterAll(() => {
Object.defineProperty(window, 'location', {
configurable: true,
value: original,
});
});

test('should render modal and take info to add plugin for registered organization', async () => {
await act(async () => {
render(
Expand Down Expand Up @@ -187,7 +180,22 @@ describe('Testing AddOnRegister', () => {
userEvent.click(screen.getByTestId('addonregisterBtn'));

await wait(3000); // Waiting for 3 seconds to reload the page as timeout is set to 2 seconds in the component
expect(window.location.reload).toHaveBeenCalled();
expect(mockNavigate).toHaveBeenCalledWith(0);
});
});
test('should be redirected to /orglist if orgId is undefined', async () => {
mockId = undefined;
render(
<ApolloProvider client={client}>
<Provider store={store}>
<BrowserRouter>
<I18nextProvider i18n={i18nForTest}>
{<AddOnRegister {...props} />}
</I18nextProvider>
</BrowserRouter>
</Provider>
</ApolloProvider>,
);
expect(window.location.pathname).toEqual('/orglist');
});
});
10 changes: 8 additions & 2 deletions src/components/AddOn/core/AddOnRegister/AddOnRegister.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useMutation } from '@apollo/client';
import { ADD_PLUGIN_MUTATION } from 'GraphQl/Mutations/mutations';
import { useTranslation } from 'react-i18next';
import { toast } from 'react-toastify';
import { Navigate, useNavigate, useParams } from 'react-router-dom';

interface InterfaceFormStateTypes {
pluginName: string;
Expand All @@ -15,10 +16,15 @@ interface InterfaceFormStateTypes {
installedOrgs: [string] | [];
}

const currentUrl = window.location.href.split('=')[1];
function addOnRegister(): JSX.Element {
const { t } = useTranslation('translation', { keyPrefix: 'addOnRegister' });

const { orgId: currentUrl } = useParams();
const navigate = useNavigate();
if (!currentUrl) {
return <Navigate to={'/orglist'} />;
}

const [show, setShow] = useState(false);

const handleClose = (): void => setShow(false);
Expand Down Expand Up @@ -47,7 +53,7 @@ function addOnRegister(): JSX.Element {
if (data) {
toast.success('Plugin Added Successfully');
setTimeout(() => {
window.location.reload();
navigate(0);
}, 2000);
}
};
Expand Down
5 changes: 4 additions & 1 deletion src/components/AddOn/core/AddOnStore/AddOnStore.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ const PLUGIN_LOADING_MOCK = {
loading: true,
},
};

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: () => ({ orgId: 'undefined' }),
}));
const ORGANIZATIONS_LIST_MOCK = {
request: {
query: ORGANIZATIONS_LIST,
Expand Down
Loading
Loading