diff --git a/index.html b/index.html index e846a5e..8a780af 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - Houston + Houston UI
diff --git a/src/Pages/Dashboard/partials/SearchResultsTable.tsx b/src/Pages/Dashboard/partials/SearchResultsTable.tsx index ebdd7fe..47cc42e 100644 --- a/src/Pages/Dashboard/partials/SearchResultsTable.tsx +++ b/src/Pages/Dashboard/partials/SearchResultsTable.tsx @@ -1,10 +1,12 @@ -import { FC } from 'react'; +import { FC, useState, useRef } from 'react'; import cx from 'classnames'; import { AgTable, Pagination } from '@navi/web-ui/lib/components'; -import { Tag } from '@navi/web-ui/lib/primitives'; +import { Tag, Drawer } from '@navi/web-ui/lib/primitives'; import { returnFormattedDate } from '@src/services/globalUtils'; +import DrawerMode from '@src/Pages/Incidents/DrawerMode/index'; + import styles from '../SearchResultsTable.module.scss'; import { useNavigate } from 'react-router-dom'; import { getSeverityColor } from '../constants'; @@ -31,7 +33,8 @@ const SearchResultsTable: FC = ({ handlePageSizeChange, }) => { const { pageNumber, totalElements } = pageDetails; - + const [drawerState, setDrawerState] = useState(false); + const incidentData = useRef({}); const navigate = useNavigate(); const rowData = currentPageData?.map((item: any, ind: number) => { @@ -52,19 +55,16 @@ const SearchResultsTable: FC = ({ createdAt: returnFormattedDate(item?.createdAt), updatedBy: item?.updatedBy, updatedAt: returnFormattedDate(item?.updatedAt), + slackChannel: item?.slackChannel, }; }); const columnData = [ - { - field: 'sNo', - suppressSizeToFit: true, - width: 90, - suppressMovable: true, - }, { field: 'id', headerName: 'Incident Id', + suppressSizeToFit: true, + width: 120, suppressMovable: true, }, { @@ -118,10 +118,23 @@ const SearchResultsTable: FC = ({ if (params?.api?.sizeColumnsToFit) params.api.sizeColumnsToFit(); }; - const handleRowClick = (event: any) => { - if (event?.data) { - navigate(`/incident/${event.data?.id}`); - } + // const handleRowClick = (event: any) => { + // if (event?.data) { + // navigate(`/incident/${event.data?.id}`); + // } + // }; + + const handleCloseDrawer = () => { + incidentData.current = {}; + setDrawerState(false); + }; + + const handleOpenDrawer = rowData => { + incidentData.current = { + incidentId: rowData?.data?.id, + slackChannel: rowData?.data?.slackChannel, + }; + setDrawerState(true); }; return ( @@ -152,10 +165,21 @@ const SearchResultsTable: FC = ({ suppressCellFocus defaultColDef={defaultColDef} onGridSizeChanged={onGridSizeChanged} - onRowClicked={handleRowClick} + onRowClicked={handleOpenDrawer} suppressColumnMoveAnimation detailRowAutoHeight={true} /> + + + ); }; diff --git a/src/Pages/Incidents/DrawerMode/DrawerMode.module.scss b/src/Pages/Incidents/DrawerMode/DrawerMode.module.scss new file mode 100644 index 0000000..e342314 --- /dev/null +++ b/src/Pages/Incidents/DrawerMode/DrawerMode.module.scss @@ -0,0 +1,45 @@ +.severity-details-wrapper { + display: flex; + align-items: center; + gap: 0 8px; + margin: 8px 0; +} + +.content-info { + display: flex; + align-items: center; + gap: 0 4px; +} + +.description-details { + display: flex; + align-items: flex-start; + gap: 0 4px; + margin: 12px 0 16px 0; + + .description { + margin-top: -2px; + line-height: 24px; + } +} + +.meta-info { + margin: 12px 0 16px 0; + + &__title { + margin-bottom: 8px; + } +} + +.participant-detail { + display: flex; + align-items: center; + gap: 4px; +} + +.team-details-wrapper { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 12px; +} diff --git a/src/Pages/Incidents/DrawerMode/index.tsx b/src/Pages/Incidents/DrawerMode/index.tsx new file mode 100644 index 0000000..e6b4e78 --- /dev/null +++ b/src/Pages/Incidents/DrawerMode/index.tsx @@ -0,0 +1,231 @@ +import { FC, useEffect, useState } from 'react'; + +import { Typography, Avatar } from '@navi/web-ui/lib/primitives'; +import Filter from '@navi/web-ui/lib/components/Filter'; +import { toast } from '@navi/web-ui/lib/primitives/Toast'; +import LoadingIcon from '@navi/web-ui/lib/icons/LoadingIcon'; + +import { ApiService } from '@src/services/api'; +import { + FETCH_HEADER_DETAILS, + FETCH_PARTICIPANTS_DATA, + FETCH_INCIDENT_DATA, + UPDATE_INCIDENT, + IncidentConstants, +} from '../constants'; +import styles from './DrawerMode.module.scss'; +import commonStyles from '../Incidents.module.scss'; + +interface DrawerModeProps { + incidentId: number; + slackChannel: string; +} + +const DrawerMode: FC = ({ incidentId, slackChannel }) => { + const [severity, setSeverity] = useState(); + const [status, setStatus] = useState(); + const [team, setTeam] = useState(); + const [headerData, setHeaderData] = useState({}); + const [incidentDetails, setIncidentDetails] = useState({}); + const [incidentParticipants, setIncidentParticipants] = useState([]); + const [isLoading, setIsLoading] = useState(false); + + const fetchHeaderDetails = (): void => { + const endPoint = FETCH_HEADER_DETAILS; + ApiService.get(endPoint) + .then(response => { + setHeaderData(response?.data?.data); + }) + .catch(error => { + const toastMessage = `${ + error?.response?.data?.error?.message + ? `${error?.response?.data?.error?.message},` + : '' + }`; + toast.error(toastMessage); + setHeaderData({}); + }); + }; + + const initFilters = (incidentDetails): void => { + const severity = headerData?.severities?.find( + item => item.value === incidentDetails?.severityId, + ); + const status = headerData?.incidentStatuses?.find( + item => item.value === incidentDetails?.status, + ); + const team = headerData?.teams?.find( + item => item.value === incidentDetails?.teamId, + ); + setSeverity(severity); + setStatus(status); + setTeam(team); + }; + + const fetchIncidentDetails = (): void => { + const endPoint = FETCH_INCIDENT_DATA(incidentId); + ApiService.get(endPoint) + .then(response => { + setIncidentDetails(response?.data?.data); + initFilters(response?.data?.data); + }) + .catch(error => { + const toastMessage = `${ + error?.response?.data?.error?.message + ? `${error?.response?.data?.error?.message},` + : '' + }`; + toast.error(toastMessage); + setIncidentDetails({}); + }); + }; + + const fetchParticipants = (): void => { + const endPoint = FETCH_PARTICIPANTS_DATA(slackChannel); + ApiService.get(endPoint) + .then(response => { + setIncidentParticipants(response?.data?.data); + }) + .catch(error => { + const toastMessage = `${ + error?.response?.data?.error?.message + ? `${error?.response?.data?.error?.message},` + : '' + }`; + toast.error(toastMessage); + setIncidentParticipants([]); + }); + }; + + useEffect(() => { + setIsLoading(true); + if (incidentId && slackChannel) { + fetchIncidentDetails(); + fetchHeaderDetails(); + fetchParticipants(); + } + }, [incidentId, slackChannel]); + + useEffect(() => { + if ( + Object.keys(incidentDetails).length && + Object.keys(headerData) && + incidentParticipants.length + ) { + setIsLoading(false); + } + }, [incidentDetails, headerData, incidentParticipants]); + + const updateIncident = () => { + const endPoint = UPDATE_INCIDENT; + ApiService.post(endPoint, { + id: incidentId, + teamId: team?.value, + status: status?.value, + severityId: severity?.value, + }) + .then(response => { + toast.success('Incident Updated Successfully'); + }) + .catch(error => { + const toastMessage = `${ + error?.response?.data?.error?.message + ? `${error?.response?.data?.error?.message},` + : '' + }`; + toast.error(toastMessage); + }); + }; + + const returnHeaderDetails = () => { + return ( +
+ Update Tags: +
+ Severity: + { + setSeverity(val); + updateIncident(); + }} + isSingleSelect + filterClass={styles['filter-wrapper']} + /> +
+
+ Status: + { + setStatus(val); + updateIncident(); + }} + isSingleSelect + filterClass={styles['filter-wrapper']} + /> +
+
+ Team: + { + setTeam(val); + updateIncident(); + }} + isSingleSelect + filterClass={styles['filter-wrapper']} + /> +
+
+ ); + }; + + const returnContent = () => { + return ( +
+
+ {IncidentConstants.title}: + {incidentDetails?.title} +
+
+ {IncidentConstants.description}: + + {incidentDetails?.description} + +
+
+ ); + }; + + const returnParticipants = () => { + return incidentParticipants?.map(participant => ( +
+
+ {' '} + {participant?.name} +
+
+ )); + }; + + if (isLoading) { + return ; + } + + return ( +
+ {returnContent()} +
+ {returnHeaderDetails()} +
+ Participants: + {returnParticipants()} +
+ ); +}; + +export default DrawerMode; diff --git a/src/Pages/Incidents/constants.ts b/src/Pages/Incidents/constants.ts index 6ee6a39..a597c87 100644 --- a/src/Pages/Incidents/constants.ts +++ b/src/Pages/Incidents/constants.ts @@ -11,12 +11,12 @@ export const IncidentConstants = { team: 'Team', }; -export const FETCH_SINGLE_INCIDENT_DATA = (payload: any): string => { +export const FETCH_INCIDENT_DATA = (payload: any): string => { return `${window?.config?.BASE_API_URL}/incidents/${payload}`; }; export const FETCH_PARTICIPANTS_DATA = (payload: string): string => { - return `${window?.config?.BASE_API_URL}/users?channelId=${payload}`; + return `${window?.config?.BASE_API_URL}/users?channel_id=${payload}`; }; export const FETCH_HEADER_DETAILS = `${window?.config?.BASE_API_URL}/incidents/header`; diff --git a/src/Pages/Incidents/index.tsx b/src/Pages/Incidents/index.tsx index 58cf65a..e50da90 100644 --- a/src/Pages/Incidents/index.tsx +++ b/src/Pages/Incidents/index.tsx @@ -8,7 +8,7 @@ import Content from './Content'; import Header from './Header'; import MetaInfo from './MetaInfo'; -import { FETCH_SINGLE_INCIDENT_DATA, IncidentConstants } from './constants'; +import { FETCH_INCIDENT_DATA, IncidentConstants } from './constants'; import { ApiService } from '@src/services/api'; import styles from './Incidents.module.scss'; @@ -24,7 +24,7 @@ const Incident: FC = () => { const incidentId = IncidentMatch?.params?.incidentId || ''; const startIncidentSearch = (): void => { - const endPoint = FETCH_SINGLE_INCIDENT_DATA(incidentId); + const endPoint = FETCH_INCIDENT_DATA(incidentId); ApiService.get(endPoint) .then(response => { setData(response?.data?.data); diff --git a/src/services/api.ts b/src/services/api.ts index 84c3aff..97a546a 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -9,12 +9,15 @@ export class ApiService { public static getInstance(): ApiService { if (!ApiService.instance) { ApiService.instance = new ApiService(); - // TODO: Uncomment this backend is sending Access-Control-Allow-Headers: x-session-token - // ApiService.instance.service.interceptors.request.use((req: any) => { - // req.headers['X-Session-Token'] = - // localStorage.getItem('react-token') || ''; - // return req; - // }); + const userData = localStorage.getItem('user-data'); + ApiService.instance.service.interceptors.request.use((req: any) => { + req.headers['X-Session-Token'] = + localStorage.getItem('react-token') || ''; + req.headers['X-User-Email'] = userData + ? JSON.parse(userData)?.emailId + : null; + return req; + }); } return ApiService.instance;