INFRA-2867 | integrate product and assigner-responder api

This commit is contained in:
dhruvjoshi
2024-03-07 18:14:19 +05:30
parent 96a542fe73
commit 76373fd6b3
8 changed files with 287 additions and 131 deletions

View File

@@ -19,8 +19,8 @@ export const CREATE_INCIDENT = createURL('/houston/create-incident-v3');
export const PRODUCT_LIST = createURL('/houston/user/products');
export const FETCH_ASSIGNER_AND_RESPONDER = (payload: number[]) => {
console.log(payload, 'payload');
return `${URL_PREFIX}/product/assigner-responder?productIds=${payload}`;
const queryParams = payload.join('&productID=');
return `${URL_PREFIX}/product/assigner-and-responder?productID=${queryParams}`;
};
export const TimeSpan = [
@@ -89,6 +89,8 @@ export const actionTypes = {
export const initialState = {
open: false,
teams: [],
assigners: [],
responders: [],
title: '',
severity: [],
selectedSeverity: [],
@@ -100,6 +102,7 @@ export const initialState = {
isTitleValid: true,
isDescriptionValid: true,
};
export const reducer = (state, action) => {
switch (action.type) {
case actionTypes.SET_TEAMS:

View File

@@ -152,4 +152,7 @@
color: var(--navi-color-blue-base) !important;
}
}
}
.create-incident-single-selector{
width: 335px !important;
}

View File

@@ -25,12 +25,17 @@ import {
reducer,
} from '@src/Pages/Dashboard/constants';
import styles from './CreateIncident.module.scss';
import { Team } from '@src/Pages/Dashboard/type';
import { Product, Team } from '@src/Pages/Dashboard/type';
import useClickStream from '@src/services/clickStream';
import { CLICK_STREAM_EVENT_FACTORY } from '@src/services/clickStream/constants/values';
import ProductSelector from './ProductSelector';
import IncidentSingleSelector from './IncidentSingleSelector';
import {
updateFilterConfig,
updateProductList,
updateAssignerAndResponder,
} from './CreateIncidentHelper';
import useIncidentFormApi from '../useDashboardApi';
interface CreateIncidentFormProps {
startIncidentSearch: () => void;
handleDrawerClose: () => void;
@@ -42,10 +47,13 @@ const CreateIncidentForm: React.FC<CreateIncidentFormProps> = ({
const [state, dispatch] = useReducer(reducer, initialState);
const [loading, setIsLoading] = useState(false);
const { fireEvent } = useClickStream();
const { fetchFilterConfig, fetchProductList, fetchAssignerAndResponder } =
useIncidentFormApi();
const { EVENT_NAME, SCREEN_NAME } = CLICK_STREAM_EVENT_FACTORY;
const ref = useOutsideClick({
callback: handleClickOutside,
}) as MutableRefObject<HTMLDivElement>;
function handleClickOutside() {
dispatch({ type: actionTypes.SET_OPEN_SELECT, payload: false });
}
@@ -72,10 +80,11 @@ const CreateIncidentForm: React.FC<CreateIncidentFormProps> = ({
dispatch({ type: actionTypes.SET_TITLE, payload: inputValue });
validateTitle(inputValue);
};
const handleTeamChange = (
val: SelectPickerOptionProps | SelectPickerOptionProps[],
) => {
const handleTeamChange = (val: SelectPickerOptionProps[]) => {
dispatch({ type: actionTypes.SET_SELECTED_TEAM, payload: val });
if (val?.length === 0) return;
const productIds = val?.map(team => team.value as number);
fetchAssignerAndResponderData(productIds);
};
const handleAssignerChange = (val: SelectPickerValue) => {
dispatch({ type: actionTypes.SET_SELECTED_ASSIGNER, payload: val });
@@ -94,97 +103,104 @@ const CreateIncidentForm: React.FC<CreateIncidentFormProps> = ({
validateDescription(description);
};
const fetchData = async () => {
try {
const filterConfigResponse = await ApiService.get(FETCH_FILTER_CONFIG);
const filterConfigData = filterConfigResponse?.data?.data;
// const fetchAssignerAndResponder = (product: number[]) => {
// appDispatch(fetchAssignerAndResponderData(product))
// .unwrap()
// .then(assignerResponderResponse => {
// const assignerResponderData = assignerResponderResponse?.data;
if (!filterConfigData) {
toast.error(
'Something went wrong with filter config. Please try again later',
);
return;
}
// dispatch({
// type: actionTypes.SET_ASSIGNERS,
// payload: assignerResponderData?.assignerTeam?.teams || [],
// });
dispatch({
type: actionTypes.SET_SEVERITY,
payload: filterConfigData[1]?.filter_data || [],
});
// dispatch({
// type: actionTypes.SET_RESPONDERS,
// payload: assignerResponderData?.responderTeam?.teams || [],
// });
const productListResponse = await ApiService.get(PRODUCT_LIST);
const productListData = productListResponse?.data;
// dispatch({
// type: actionTypes.SET_SELECTED_ASSIGNER,
// payload: assignerResponderData?.assignerTeam?.defaultTeam?.id ?? '',
// });
dispatch({
type: actionTypes.SET_TEAMS,
payload: productListData?.products || [],
});
// dispatch({
// type: actionTypes.SET_SELECTED_RESPONDER,
// payload: assignerResponderData?.responderTeam?.defaultTeam?.id ?? '',
// });
// });
// };
dispatch({
type: actionTypes.SET_SELECTED_TEAM,
payload: [productListData?.defaultProduct] || [],
});
// useEffect(() => {
// appDispatch(fetchFilterConfigData())
// .unwrap()
// .then(filterConfigResponse => {
// const filterConfigData = filterConfigResponse?.data;
// if (!filterConfigData) {
// toast.error(
// 'Something went wrong with filter config. Please try again later',
// );
// return;
// }
// dispatch({
// type: actionTypes.SET_SEVERITY,
// payload: filterConfigData[1]?.filter_data || [],
// });
// });
await fetchAssignerAndResponder([
productListData?.defaultProduct?.product_id,
]);
} catch (error) {
toast.error('Something went wrong. Please try again later');
console.error(error);
}
// appDispatch(fetchProductListData())
// .unwrap()
// .then(productListResponse => {
// const productListData = productListResponse?.data;
// dispatch({
// type: actionTypes.SET_TEAMS,
// payload: productListData?.products || [],
// });
// dispatch({
// type: actionTypes.SET_SELECTED_TEAM,
// payload: [productListData?.defaultProduct] || [],
// });
// fetchAssignerAndResponder([
// productListData?.defaultProduct?.product_id,
// ]);
// });
// }, []);
const fetchAssignerAndResponderData = async (product: number[]) => {
const assignerResponderData = await fetchAssignerAndResponder(product);
updateAssignerAndResponder(assignerResponderData, dispatch);
};
const fetchAssignerAndResponder = async (product: number[]) => {
try {
const assignerResponderResponse = await ApiService.get(
FETCH_ASSIGNER_AND_RESPONDER(product),
);
const assignerResponderData = assignerResponderResponse?.data;
dispatch({
type: actionTypes.SET_ASSIGNERS,
payload: assignerResponderData?.assignerTeam?.teams || [],
});
dispatch({
type: actionTypes.SET_RESPONDERS,
payload: assignerResponderData?.responderTeam?.teams || [],
});
dispatch({
type: actionTypes.SET_SELECTED_ASSIGNER,
payload: assignerResponderData?.assignerTeam?.defaultTeam?.id ?? '',
});
dispatch({
type: actionTypes.SET_SELECTED_RESPONDER,
payload: assignerResponderData?.responderTeam?.defaultTeam?.id ?? '',
});
} catch (error) {
toast.error(
'Something went wrong with assigner and responder data. Please try again later',
);
console.error(error);
}
const fetchData = async () => {
setIsLoading(true);
const filterConfigData = await fetchFilterConfig();
const productListData = await fetchProductList();
updateFilterConfig(filterConfigData, dispatch);
updateProductList(productListData, dispatch);
fetchAssignerAndResponderData([
productListData?.defaultProduct?.product_id,
]);
setIsLoading(false);
};
useEffect(() => {
console.log('called');
fetchData();
console.log('fetchData');
}, []);
useEffect(() => {
if (state.selectedTeam?.product_id) {
console.log(state.selectedTeam);
fetchAssignerAndResponder(state.selectedTeam.product_id);
}
}, [state.selectedTeam]);
const getLabelValueOptions = (state: Team[]) => {
//TODO change contract to give label and value
const getLabelValueProducts = (state: Product[]) => {
return state?.map(team => ({
label: team?.product_name,
value: team?.product_id,
}));
};
const getLabelValueTeams = state => {
return state?.map(team => ({
label: team?.name,
value: team?.id,
}));
};
const clearDrawer = () => {
dispatch({ type: actionTypes.CLEAR_DRAWER });
handleDrawerClose();
@@ -271,7 +287,7 @@ const CreateIncidentForm: React.FC<CreateIncidentFormProps> = ({
<div className={styles['Team-wrapper']}>
<div className={styles['name-wrapper']}>Product</div>
<ProductSelector
options={getLabelValueOptions(state.teams)}
options={getLabelValueProducts(state.teams)}
handleSelectionChange={handleTeamChange}
selected={state.selectedTeam}
/>
@@ -279,7 +295,7 @@ const CreateIncidentForm: React.FC<CreateIncidentFormProps> = ({
<div className={styles['Team-wrapper']}>
<div className={styles['name-wrapper']}>Assigner</div>
<IncidentSingleSelector
options={getLabelValueOptions(state.assigner)}
options={getLabelValueTeams(state.assigners)}
handleSelectionChange={handleAssignerChange}
selected={state.assigner}
/>
@@ -287,7 +303,7 @@ const CreateIncidentForm: React.FC<CreateIncidentFormProps> = ({
<div className={styles['Team-wrapper']}>
<div className={styles['name-wrapper']}>Responder</div>
<IncidentSingleSelector
options={getLabelValueOptions(state.responder)}
options={getLabelValueTeams(state.responders)}
handleSelectionChange={handleResponderChange}
selected={state.responder}
/>

View File

@@ -0,0 +1,57 @@
import { actionTypes } from '../constants';
export const updateFilterConfig = (
filterConfigData: any,
dispatch: React.Dispatch<any>,
) => {
if (filterConfigData) {
dispatch({
type: actionTypes.SET_SEVERITY,
payload: filterConfigData[1]?.filter_data || [],
});
}
};
export const updateProductList = (
productListData: any,
dispatch: React.Dispatch<any>,
) => {
if (productListData) {
dispatch({
type: actionTypes.SET_TEAMS,
payload: productListData?.products || [],
});
dispatch({
type: actionTypes.SET_SELECTED_TEAM,
payload: [productListData?.defaultProduct] || [],
});
}
};
export const updateAssignerAndResponder = (
assignerResponderData: any,
dispatch: React.Dispatch<any>,
) => {
if (assignerResponderData) {
dispatch({
type: actionTypes.SET_ASSIGNERS,
payload: assignerResponderData?.assignerTeam?.teams,
});
dispatch({
type: actionTypes.SET_RESPONDERS,
payload: assignerResponderData?.responderTeam?.teams,
});
dispatch({
type: actionTypes.SET_SELECTED_ASSIGNER,
payload: assignerResponderData?.assignerTeam?.defaultTeam?.id ?? '',
});
dispatch({
type: actionTypes.SET_SELECTED_RESPONDER,
payload: assignerResponderData?.responderTeam?.defaultTeam?.id ?? '',
});
}
};

View File

@@ -3,6 +3,7 @@ import {
SelectPickerOptionProps,
SelectPickerValue,
} from '@navi/web-ui/lib/components/SelectPicker/types';
import styles from './CreateIncident.module.scss';
interface IncidentSingleSelectorProps {
options: SelectPickerOptionProps[];
@@ -22,6 +23,7 @@ const IncidentSingleSelector = (props: IncidentSingleSelectorProps) => {
updateClearAllCallback={handleClearCallback}
variant="bordered"
placeholder="Select Team"
containerClassName={styles['create-incident-single-selector']}
/>
);
};

View File

@@ -8,10 +8,20 @@ export interface filterItem {
filter_data: Team[] | null;
selection_config: SelectionType;
}
export interface Team {
product_id: string;
export interface FilterData{
label: string;
value: string;
}
export interface Product{
product_id: number;
product_name: string;
}
export interface Team {
label: string;
value: string;
}
// export
export interface FilterResult {
severity_ids: SelectPickerOptionProps[];
team_ids: SelectPickerOptionProps[];

View File

@@ -1,5 +1,7 @@
import { useDispatch } from 'react-redux';
import { AppDispatch } from '@src/store';
import { toast } from '@navi/web-ui/lib/primitives/Toast';
import {
fetchAssignerAndResponderData,
fetchFilterConfigData,
@@ -9,25 +11,48 @@ import {
const useIncidentFormApi = () => {
const dispatch = useDispatch<AppDispatch>();
const fetchFilterConfig = () => {
dispatch(fetchFilterConfigData());
const fetchFilterConfig = async () => {
try {
const response = await dispatch(fetchFilterConfigData()).unwrap();
return response?.data;
} catch (error) {
toast.error(
'Something went wrong with filter config. Please try again later',
);
console.error(error);
return null;
}
};
const fetchProductList = () => {
dispatch(fetchProductListData());
const fetchProductList = async () => {
try {
const response = await dispatch(fetchProductListData()).unwrap();
return response?.data;
} catch (error) {
toast.error(
'Something went wrong with fetching the product list. Please try again later',
);
console.error(error);
return null;
}
};
const fetchAssignerAndResponder = async (productList: any) => {
dispatch(fetchAssignerAndResponderData(productList));
};
const fetchData = async () => {
fetchFilterConfig();
fetchProductList();
const fetchAssignerAndResponder = async (product: number[]) => {
try {
const response = await dispatch(
fetchAssignerAndResponderData(product),
).unwrap();
return response?.data;
} catch (error) {
toast.error(
'Something went wrong with assigner and responder data. Please try again later',
);
console.error(error);
return null;
}
};
return {
fetchData,
fetchFilterConfig,
fetchProductList,
fetchAssignerAndResponder,

View File

@@ -2,23 +2,70 @@ import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { toast } from '@navi/web-ui/lib/primitives/Toast';
import { ApiService } from '@src/services/api';
import { RootState } from '@src/store';
import {
filterItem,
FilterData,
Team,
Product,
} from '@src/Pages/Dashboard/type';
import {
FETCH_ASSIGNER_AND_RESPONDER,
FETCH_FILTER_CONFIG,
PRODUCT_LIST,
} from '@src/Pages/Dashboard/constants';
interface FilterListResponse {
data: filterItem[];
}
// Interface for product item
// Interface for product list response
interface ProductListResponse {
data: {
defaultProduct: Product;
products: Product[];
};
}
// Interface for team item
interface TeamItem {
id: number;
name: string;
}
// Interface for assigner and responder response
interface Assigner {
defaultTeam: TeamItem;
teams: TeamItem[];
}
interface Responder {
defaultTeam: TeamItem;
teams: TeamItem[];
}
interface AssignerResponderResponse {
data: {
assignerTeam: Assigner;
responderTeam: Responder;
};
}
interface InitialState {
filterConfigData: FilterListResponse;
productListData: ProductListResponse;
assignerResponderData: AssignerResponderResponse;
error: string;
isFetching: boolean;
}
const initialState = {
incidentForm: {
filterConfigData: {},
productListData: {},
assignerResponderData: {},
error: '',
isFetching: false,
},
filterConfigData: {} as FilterListResponse,
productListData: {} as ProductListResponse,
assignerResponderData: {} as AssignerResponderResponse,
error: '',
isFetching: false,
};
// Define async thunk actions
export const fetchFilterConfigData = createAsyncThunk(
'incidentForm/fetchFilterConfigData',
async () => {
@@ -40,56 +87,49 @@ export const fetchAssignerAndResponderData = createAsyncThunk(
},
);
// Define slice
const incidentFormSlice = createSlice({
name: 'incidentForm',
initialState,
reducers: {
// Additional reducers can be defined here
},
reducers: {},
extraReducers: builder => {
builder
.addCase(fetchFilterConfigData.pending, state => {
state.incidentForm.isFetching = true;
state.incidentForm.error = '';
state.isFetching = true;
state.error = '';
})
.addCase(fetchFilterConfigData.fulfilled, (state, action) => {
state.incidentForm.isFetching = false;
state.incidentForm.filterConfigData = action.payload;
state.isFetching = false;
state.filterConfigData = action.payload;
})
.addCase(fetchFilterConfigData.rejected, (state, action) => {
state.incidentForm.isFetching = false;
state.incidentForm.error =
action.error.message ?? 'Something went wrong';
state.isFetching = false;
state.error = action.error.message ?? 'Something went wrong';
})
.addCase(fetchProductListData.pending, state => {
state.incidentForm.isFetching = true;
state.incidentForm.error = '';
state.isFetching = true;
state.error = '';
})
.addCase(fetchProductListData.fulfilled, (state, action) => {
state.incidentForm.isFetching = false;
state.incidentForm.productListData = action.payload;
state.isFetching = false;
state.productListData = action.payload;
})
.addCase(fetchProductListData.rejected, (state, action) => {
state.incidentForm.isFetching = false;
state.incidentForm.error =
action.error.message ?? 'Something went wrong';
state.isFetching = false;
state.error = action.error.message ?? 'Something went wrong';
})
.addCase(fetchAssignerAndResponderData.pending, state => {
state.incidentForm.isFetching = true;
state.incidentForm.error = '';
state.isFetching = true;
state.error = '';
})
.addCase(fetchAssignerAndResponderData.fulfilled, (state, action) => {
state.incidentForm.isFetching = false;
state.incidentForm.assignerResponderData = action.payload;
state.isFetching = false;
state.assignerResponderData = action.payload;
})
.addCase(fetchAssignerAndResponderData.rejected, (state, action) => {
state.incidentForm.isFetching = false;
state.incidentForm.error =
action.error.message ?? 'Something went wrong';
state.isFetching = false;
state.error = action.error.message ?? 'Something went wrong';
});
},
});
// Export reducer
export default incidentFormSlice.reducer;