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

chore: revamp the frontend architecture #6598

Merged
merged 44 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
d383bee
feat: setup the app context to fetch users,licenses and feature flags
vikrantgupta25 Dec 5, 2024
b1bc70d
feat: added global event listeners for after_login event
vikrantgupta25 Dec 5, 2024
2f37f0e
feat: remove redux from app state and private route
vikrantgupta25 Dec 5, 2024
9f14088
feat: syncronize the approutes file
vikrantgupta25 Dec 5, 2024
43ec8e1
feat: cleanup the private routes
vikrantgupta25 Dec 5, 2024
e1b6dbb
feat: handle login and logout
vikrantgupta25 Dec 5, 2024
83f4b19
feat: cleanup the app layout file
vikrantgupta25 Dec 5, 2024
a8b1308
Merge remote-tracking branch 'origin' into cleanup-app-routes
vikrantgupta25 Dec 5, 2024
56ef96b
feat: cleanup and syncronize side nav item
vikrantgupta25 Dec 5, 2024
32906ba
fix: minor small re-render issue
vikrantgupta25 Dec 5, 2024
6ce5cf3
feat: parallel processing for sync calls for faster bootup of applica…
vikrantgupta25 Dec 6, 2024
c29cd45
feat: some refactoring for private routes
vikrantgupta25 Dec 6, 2024
63f188e
fix: entire application too much re-rendering
vikrantgupta25 Dec 6, 2024
bee1fba
fix: remove redux
vikrantgupta25 Dec 6, 2024
38f0312
feat: some more corrections
vikrantgupta25 Dec 6, 2024
b1d919c
feat: fix all the files except signup
vikrantgupta25 Dec 6, 2024
3dc695a
feat: add app provider to the test-utils
vikrantgupta25 Dec 6, 2024
54de01a
feat: should fix a lot of tests
vikrantgupta25 Dec 7, 2024
a651970
chore: fix more tests
vikrantgupta25 Dec 7, 2024
06bddd5
chore: fix more tests
vikrantgupta25 Dec 7, 2024
814a1e6
feat: fix some tests and corrected the redux mock
vikrantgupta25 Dec 7, 2024
9aba4fd
feat: delete snapshot
vikrantgupta25 Dec 7, 2024
a3ffdae
fix: test cases
vikrantgupta25 Dec 7, 2024
c424434
Merge remote-tracking branch 'origin' into cleanup-app-routes
vikrantgupta25 Dec 7, 2024
27230a7
Merge remote-tracking branch 'origin' into cleanup-app-routes
vikrantgupta25 Dec 9, 2024
d277279
fix: pipeline actions test cases
vikrantgupta25 Dec 9, 2024
e42e713
fix: billing test cases
vikrantgupta25 Dec 9, 2024
8b279a0
feat: update the signup API to accept isAnonymous and hasOptedUpdates
vikrantgupta25 Dec 10, 2024
dadee01
chore: cleanup the console logs
vikrantgupta25 Dec 10, 2024
59a48a0
fix: indefinite loading on manage licenses screen
vikrantgupta25 Dec 10, 2024
06de904
fix: better handling and route to something_went_wrong in case of qs …
vikrantgupta25 Dec 10, 2024
c526068
Merge remote-tracking branch 'origin' into cleanup-app-routes
vikrantgupta25 Dec 10, 2024
7c47c77
fix: signup for subsequent users
vikrantgupta25 Dec 10, 2024
566a594
chore: update test-utils
vikrantgupta25 Dec 10, 2024
6eeab69
Merge branch 'develop' into cleanup-app-routes
vikrantgupta25 Dec 11, 2024
4023a6c
chore: merge remote-tracking branch 'origin' into cleanup-app-routes
vikrantgupta25 Dec 16, 2024
08c4bd0
Merge branch 'develop' into cleanup-app-routes
vikrantgupta25 Dec 16, 2024
8763fe6
fix: jerky behaviour on entering the home page
vikrantgupta25 Dec 17, 2024
a95d218
feat: handle the retention for login context flow
vikrantgupta25 Dec 17, 2024
1c16916
Merge branch 'develop' into cleanup-app-routes
vikrantgupta25 Dec 17, 2024
22863c0
Merge branch 'develop' into cleanup-app-routes
vikrantgupta25 Dec 18, 2024
24417c8
Merge branch 'main' into cleanup-app-routes
vikrantgupta25 Dec 19, 2024
420915e
fix: do not let users workaround workspace blocked screen
vikrantgupta25 Dec 19, 2024
ba2cda0
Merge branch 'main' into cleanup-app-routes
vikrantgupta25 Dec 20, 2024
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
352 changes: 90 additions & 262 deletions frontend/src/AppRoutes/Private.tsx

Large diffs are not rendered by default.

467 changes: 212 additions & 255 deletions frontend/src/AppRoutes/index.tsx

Large diffs are not rendered by default.

96 changes: 16 additions & 80 deletions frontend/src/AppRoutes/utils.ts
Original file line number Diff line number Diff line change
@@ -1,92 +1,28 @@
import getLocalStorageApi from 'api/browser/localstorage/get';
import setLocalStorageApi from 'api/browser/localstorage/set';
import getUserApi from 'api/user/getUser';
import { Logout } from 'api/utils';
import { LOCALSTORAGE } from 'constants/localStorage';
import store from 'store';
import AppActions from 'types/actions';
import {
LOGGED_IN,
UPDATE_USER,
UPDATE_USER_ACCESS_REFRESH_ACCESS_TOKEN,
UPDATE_USER_IS_FETCH,
} from 'types/actions/app';
import { SuccessResponse } from 'types/api';
import { PayloadProps } from 'types/api/user/getUser';

const afterLogin = async (
const afterLogin = (
userId: string,
authToken: string,
refreshToken: string,
): Promise<SuccessResponse<PayloadProps> | undefined> => {
interceptorRejected?: boolean,
): void => {
setLocalStorageApi(LOCALSTORAGE.AUTH_TOKEN, authToken);
setLocalStorageApi(LOCALSTORAGE.REFRESH_AUTH_TOKEN, refreshToken);

store.dispatch<AppActions>({
type: UPDATE_USER_ACCESS_REFRESH_ACCESS_TOKEN,
payload: {
accessJwt: authToken,
refreshJwt: refreshToken,
},
});

const [getUserResponse] = await Promise.all([
getUserApi({
userId,
token: authToken,
}),
]);

if (getUserResponse.statusCode === 200 && getUserResponse.payload) {
store.dispatch<AppActions>({
type: LOGGED_IN,
payload: {
isLoggedIn: true,
},
});

const { payload } = getUserResponse;

store.dispatch<AppActions>({
type: UPDATE_USER,
payload: {
ROLE: payload.role,
email: payload.email,
name: payload.name,
orgName: payload.organization,
profilePictureURL: payload.profilePictureURL,
userId: payload.id,
orgId: payload.orgId,
userFlags: payload.flags,
},
});

const isLoggedInLocalStorage = getLocalStorageApi(LOCALSTORAGE.IS_LOGGED_IN);

if (isLoggedInLocalStorage === null) {
setLocalStorageApi(LOCALSTORAGE.IS_LOGGED_IN, 'true');
}

store.dispatch({
type: UPDATE_USER_IS_FETCH,
payload: {
isUserFetching: false,
},
});

return getUserResponse;
setLocalStorageApi(LOCALSTORAGE.USER_ID, userId);
setLocalStorageApi(LOCALSTORAGE.IS_LOGGED_IN, 'true');

if (!interceptorRejected) {
window.dispatchEvent(
new CustomEvent('AFTER_LOGIN', {
detail: {
accessJWT: authToken,
refreshJWT: refreshToken,
id: userId,
},
}),
);
}

store.dispatch({
type: UPDATE_USER_IS_FETCH,
payload: {
isUserFetching: false,
},
});

Logout();

return undefined;
};

export default afterLogin;
47 changes: 19 additions & 28 deletions frontend/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import afterLogin from 'AppRoutes/utils';
import axios, { AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import { ENVIRONMENT } from 'constants/env';
import { LOCALSTORAGE } from 'constants/localStorage';
import store from 'store';

import apiV1, {
apiAlertManager,
Expand All @@ -26,10 +25,7 @@ const interceptorsResponse = (
const interceptorsRequestResponse = (
value: InternalAxiosRequestConfig,
): InternalAxiosRequestConfig => {
const token =
store.getState().app.user?.accessJwt ||
getLocalStorageApi(LOCALSTORAGE.AUTH_TOKEN) ||
'';
const token = getLocalStorageApi(LOCALSTORAGE.AUTH_TOKEN) || '';

if (value && value.headers) {
value.headers.Authorization = token ? `Bearer ${token}` : '';
Expand All @@ -47,41 +43,36 @@ const interceptorRejected = async (
// reject the refresh token error
if (response.status === 401 && response.config.url !== '/login') {
const response = await loginApi({
refreshToken: store.getState().app.user?.refreshJwt,
refreshToken: getLocalStorageApi(LOCALSTORAGE.REFRESH_AUTH_TOKEN) || '',
});

if (response.statusCode === 200) {
const user = await afterLogin(
afterLogin(
response.payload.userId,
response.payload.accessJwt,
response.payload.refreshJwt,
true,
);

if (user) {
const reResponse = await axios(
`${value.config.baseURL}${value.config.url?.substring(1)}`,
{
method: value.config.method,
headers: {
...value.config.headers,
Authorization: `Bearer ${response.payload.accessJwt}`,
},
data: {
...JSON.parse(value.config.data || '{}'),
},
const reResponse = await axios(
`${value.config.baseURL}${value.config.url?.substring(1)}`,
{
method: value.config.method,
headers: {
...value.config.headers,
Authorization: `Bearer ${response.payload.accessJwt}`,
},
);

if (reResponse.status === 200) {
return await Promise.resolve(reResponse);
}
Logout();
data: {
...JSON.parse(value.config.data || '{}'),
},
},
);

return await Promise.reject(reResponse);
if (reResponse.status === 200) {
return await Promise.resolve(reResponse);
}
Logout();

return await Promise.reject(value);
return await Promise.reject(reResponse);
}
Logout();
}
Expand Down
20 changes: 7 additions & 13 deletions frontend/src/api/licenses/getAll.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
import { ApiV2Instance as axios } from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps } from 'types/api/licenses/getAll';

const getAll = async (): Promise<
SuccessResponse<PayloadProps> | ErrorResponse
> => {
try {
const response = await axios.get('/licenses');
const response = await axios.get('/licenses');

return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data.data,
};
};

export default getAll;
24 changes: 7 additions & 17 deletions frontend/src/api/user/getUser.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,18 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/user/getUser';

const getUser = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.get(`/user/${props.userId}`, {
headers: {
Authorization: `bearer ${props.token}`,
},
});
const response = await axios.get(`/user/${props.userId}`);

return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data,
};
};

export default getUser;
53 changes: 2 additions & 51 deletions frontend/src/api/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@ import deleteLocalStorageKey from 'api/browser/localstorage/remove';
import { LOCALSTORAGE } from 'constants/localStorage';
import ROUTES from 'constants/routes';
import history from 'lib/history';
import store from 'store';
import {
LOGGED_IN,
UPDATE_ORG,
UPDATE_USER,
UPDATE_USER_ACCESS_REFRESH_ACCESS_TOKEN,
UPDATE_USER_ORG_ROLE,
} from 'types/actions/app';

export const Logout = (): void => {
deleteLocalStorageKey(LOCALSTORAGE.AUTH_TOKEN);
Expand All @@ -19,50 +11,9 @@ export const Logout = (): void => {
deleteLocalStorageKey(LOCALSTORAGE.LOGGED_IN_USER_EMAIL);
deleteLocalStorageKey(LOCALSTORAGE.LOGGED_IN_USER_NAME);
deleteLocalStorageKey(LOCALSTORAGE.CHAT_SUPPORT);
deleteLocalStorageKey(LOCALSTORAGE.USER_ID);

store.dispatch({
type: LOGGED_IN,
payload: {
isLoggedIn: false,
},
});

store.dispatch({
type: UPDATE_USER_ORG_ROLE,
payload: {
org: null,
role: null,
},
});

store.dispatch({
type: UPDATE_USER,
payload: {
ROLE: 'VIEWER',
email: '',
name: '',
orgId: '',
orgName: '',
profilePictureURL: '',
userId: '',
userFlags: {},
},
});

store.dispatch({
type: UPDATE_USER_ACCESS_REFRESH_ACCESS_TOKEN,
payload: {
accessJwt: '',
refreshJwt: '',
},
});

store.dispatch({
type: UPDATE_ORG,
payload: {
org: [],
},
});
window.dispatchEvent(new CustomEvent('LOGOUT'));

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { Button, Modal, Typography } from 'antd';
import updateCreditCardApi from 'api/billing/checkout';
import logEvent from 'api/common/logEvent';
import { SOMETHING_WENT_WRONG } from 'constants/api';
import useLicense from 'hooks/useLicense';
import { useNotifications } from 'hooks/useNotifications';
import { CreditCard, X } from 'lucide-react';
import { useAppContext } from 'providers/App/App';
import { useEffect, useState } from 'react';
import { useMutation } from 'react-query';
import { useLocation } from 'react-router-dom';
Expand All @@ -20,16 +20,16 @@ export default function ChatSupportGateway(): JSX.Element {
false,
);

const { data: licenseData, isFetching } = useLicense();
const { licenses, isFetchingLicenses } = useAppContext();

useEffect(() => {
const activeValidLicense =
licenseData?.payload?.licenses?.find(
(license) => license.isCurrent === true,
) || null;
if (!isFetchingLicenses && licenses) {
const activeValidLicense =
licenses.licenses?.find((license) => license.isCurrent === true) || null;

setActiveLicense(activeValidLicense);
}, [licenseData, isFetching]);
setActiveLicense(activeValidLicense);
}
}, [licenses, isFetchingLicenses]);

const handleBillingOnSuccess = (
data: ErrorResponse | SuccessResponse<CheckoutSuccessPayloadProps, unknown>,
Expand Down
Loading
Loading