diff --git a/src/api/index.ts b/src/api/index.ts index 3f7f26e..19ba57b 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -457,6 +457,16 @@ export const postLcr = (payload: Partial) => { return postFetch>(API_LCRS, payload); }; +export const postLcrCreateRoutes = ( + sid: string, + payload: Partial +) => { + return postFetch>( + `${API_LCRS}/${sid}/Routes`, + payload + ); +}; + export const postLcrRoute = (payload: Partial) => { return postFetch>(API_LCR_ROUTES, payload); }; @@ -607,6 +617,16 @@ export const putLcr = (sid: string, payload: Partial) => { return putFetch>(`${API_LCRS}/${sid}`, payload); }; +export const putLcrUpdateRoutes = ( + sid: string, + payload: Partial +) => { + return putFetch>( + `${API_LCRS}/${sid}/Routes`, + payload + ); +}; + export const putLcrRoutes = (sid: string, payload: Partial) => { return putFetch>( `${API_LCR_ROUTES}/${sid}`, diff --git a/src/api/types.ts b/src/api/types.ts index 0518482..e9a3219 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -504,7 +504,7 @@ export interface LcrRoute { lcr_route_sid?: null | string; lcr_sid: null | string; regex: null | string; - desciption?: null | string; + description?: null | string; priority: number; lcr_carrier_set_entries?: LcrCarrierSetEntry[]; } diff --git a/src/constants/index.tsx b/src/constants/index.tsx index 4ce8b45..b74fc0e 100644 --- a/src/constants/index.tsx +++ b/src/constants/index.tsx @@ -24,4 +24,3 @@ export const MSG_WEBHOOK_FIELDS = ( password fields are required. ); -export const NOT_AVAILABLE_PREFIX = "NotAvalable"; diff --git a/src/containers/internal/views/least-cost-routing/container.tsx b/src/containers/internal/views/least-cost-routing/container.tsx index 948e463..51a86e8 100644 --- a/src/containers/internal/views/least-cost-routing/container.tsx +++ b/src/containers/internal/views/least-cost-routing/container.tsx @@ -6,7 +6,6 @@ import update from "immutability-helper"; import { deleteLcrRoute } from "src/api"; import { toastError, toastSuccess } from "src/store"; import { SelectorOption } from "src/components/forms/selector"; -import { NOT_AVAILABLE_PREFIX } from "src/constants"; type ContainerProps = { lcrRoute: [LcrRoute[], React.Dispatch>]; @@ -61,11 +60,7 @@ export const Container = ({ }; const handleRouteDelete = (r: LcrRoute | undefined, index: number) => { - if ( - r && - r.lcr_route_sid && - !r.lcr_route_sid.startsWith(NOT_AVAILABLE_PREFIX) - ) { + if (r && r.lcr_route_sid) { deleteLcrRoute(r.lcr_route_sid) .then(() => { toastSuccess("Least cost routing rule successfully deleted"); @@ -82,7 +77,7 @@ export const Container = ({ {hasLength(lcrRoutes) && lcrRoutes.map((lr, i) => ( ; @@ -47,7 +43,7 @@ type LcrFormProps = { export const LcrForm = ({ lcrDataMap, lcrRouteDataMap }: LcrFormProps) => { const LCR_ROUTE_TEMPLATE: LcrRoute = { - lcr_route_sid: `${NOT_AVAILABLE_PREFIX}${v4()}`, + lcr_route_sid: "", regex: "", lcr_sid: "", priority: 0, @@ -68,7 +64,7 @@ export const LcrForm = ({ lcrDataMap, lcrRouteDataMap }: LcrFormProps) => { const [defaultLcrCarrier, setDefaultLcrCarrier] = useState(""); const [defaultLcrCarrierSetEntrySid, setDefaultLcrCarrierSetEntrySid] = useState(); - const [defaultLcrRouteSid, setDefaultLcrRouteSid] = useState(""); + const [defaultLcrRoute, setDefaultLcrRoute] = useState(null); const [defaultCarrier, setDefaultCarrier] = useState(""); const [apiUrl, setApiUrl] = useState(""); const [accountSid, setAccountSid] = useState(""); @@ -136,44 +132,53 @@ export const LcrForm = ({ lcrDataMap, lcrRouteDataMap }: LcrFormProps) => { setPreviousLcr(lcrDataMap.data); } - if ( - lcrRouteDataMap && - lcrRouteDataMap.data && - lcrRouteDataMap.data !== previousLcrRoutes - ) { - setPreviousLcrRoutes(lcrRouteDataMap.data); - // Find default carrier - lcrRouteDataMap.data.forEach((lr) => { - lr.lcr_carrier_set_entries?.forEach((entry) => { - if ( - entry.lcr_carrier_set_entry_sid === - lcrDataMap?.data?.default_carrier_set_entry_sid - ) { - setDefaultLcrCarrier(entry.voip_carrier_sid || defaultCarrier); - setDefaultLcrCarrierSetEntrySid( - entry.lcr_carrier_set_entry_sid || null - ); - setDefaultLcrRouteSid(entry.lcr_route_sid || ""); - } - }); - }); - } - useMemo(() => { + let default_lcr_route_sid = ""; + if ( + lcrRouteDataMap && + lcrRouteDataMap.data && + lcrRouteDataMap.data !== previousLcrRoutes + ) { + setPreviousLcrRoutes(lcrRouteDataMap.data); + // Find default carrier + lcrRouteDataMap.data.forEach((lr) => { + lr.lcr_carrier_set_entries?.forEach((entry) => { + if ( + entry.lcr_carrier_set_entry_sid === + lcrDataMap?.data?.default_carrier_set_entry_sid + ) { + setDefaultLcrCarrier(entry.voip_carrier_sid || defaultCarrier); + setDefaultLcrCarrierSetEntrySid( + entry.lcr_carrier_set_entry_sid || null + ); + default_lcr_route_sid = entry.lcr_route_sid || ""; + setDefaultLcrRoute(lr); + } + }); + }); + } + if (lcrRouteDataMap && lcrRouteDataMap.data) setLcrRoutes( lcrRouteDataMap.data.filter( - (route) => route.lcr_route_sid !== defaultLcrRouteSid + (route) => route.lcr_route_sid !== default_lcr_route_sid ) ); - }, [defaultLcrRouteSid]); + }, [lcrRouteDataMap?.data]); const addLcrRoutes = () => { + const newLcrRoute = LCR_ROUTE_TEMPLATE; const ls = [ ...lcrRoutes, { - ...LCR_ROUTE_TEMPLATE, + ...newLcrRoute, priority: lcrRoutes.length, + lcr_carrier_set_entries: newLcrRoute.lcr_carrier_set_entries?.map( + (r) => ({ + ...r, + voip_carrier_sid: defaultCarrier || carrierSelectorOptions[0].value, + }) + ), }, ]; setLcrRoutes(ls); @@ -194,11 +199,48 @@ export const LcrForm = ({ lcrDataMap, lcrRouteDataMap }: LcrFormProps) => { const lcrPayload: Lcr = getLcrPayload(); postLcr(lcrPayload) .then(({ json }) => { - Promise.all( - lcrRoutes.map((route, i) => handleLcrRoutePost(json.sid, route, i)) - ) + const lcrsPayload = lcrRoutes.map((l, i) => ({ + ...l, + lcr_carrier_set_entries: l.lcr_carrier_set_entries?.map((e) => ({ + ...e, + voip_carrier_sid: + e.voip_carrier_sid || + defaultCarrier || + carrierSelectorOptions[0]?.value, + })), + lcr_sid: json.sid, + priority: i, + })); + lcrsPayload.push({ + lcr_sid: json.sid, + regex: ".*", + description: "System Default Route", + priority: 9999, + lcr_carrier_set_entries: [ + { + lcr_route_sid: "", + voip_carrier_sid: + defaultLcrCarrier || carrierSelectorOptions[0]?.value, + priority: 0, + }, + ], + }); + postLcrCreateRoutes(json.sid, lcrsPayload) .then(() => { - handleLcrDefaultCarrierPost(json.sid); + if (lcrDataMap) { + toastSuccess("Least cost routing successfully updated"); + } else { + toastSuccess("Least cost routing successfully created"); + if (user?.access === Scope.admin) { + navigate(ROUTE_INTERNAL_LEST_COST_ROUTING); + } else { + navigate( + `${ROUTE_INTERNAL_LEST_COST_ROUTING}/${json.sid}/edit` + ); + } + // Update global state + dispatch({ type: "lcr" }); + } }) .catch(({ msg }) => { toastError(msg); @@ -209,209 +251,38 @@ export const LcrForm = ({ lcrDataMap, lcrRouteDataMap }: LcrFormProps) => { }); }; - const handleLcrDefaultCarrierPost = (lcr_sid: string) => { - const defaultRoute = { - lcr_sid: lcr_sid, - regex: ".*", - desciption: "System Default Route", - priority: 9999, - lcr_carrier_set_entries: [ - { - lcr_route_sid: "", - voip_carrier_sid: defaultLcrCarrier, - priority: 0, - }, - ], - }; - - handleLcrRoutePost(lcr_sid, defaultRoute, 9999).then((lcr_route_sid) => { - // There is small hack here to wait the data commited in bd for lcr entries - new Promise(async (r) => setTimeout(() => r(0), 300)).then(() => { - getLcrRoute(lcr_route_sid).then(({ json }) => { - if (json.lcr_carrier_set_entries?.length) { - const lcr_carrier_set_entry_sid = - json.lcr_carrier_set_entries[0].lcr_carrier_set_entry_sid; - putLcr(lcr_sid, { - default_carrier_set_entry_sid: lcr_carrier_set_entry_sid, - }) - .then(() => { - if (lcrDataMap) { - toastSuccess("Least cost routing successfully updated"); - } else { - toastSuccess("Least cost routing successfully created"); - if (user?.access === Scope.admin) { - navigate(ROUTE_INTERNAL_LEST_COST_ROUTING); - } else { - navigate( - `${ROUTE_INTERNAL_LEST_COST_ROUTING}/${lcr_sid}/edit` - ); - } - // Update global state - dispatch({ type: "lcr" }); - } - }) - .catch((error) => { - toastError(error); - }); - } - }); - }); - }); - }; - - const handleLcrRoutePost = ( - lcr_sid: string, - route: LcrRoute, - priority: number - ): Promise => { - return new Promise(async (resolve, reject) => { - const lcrRoutePayload: LcrRoute = { - lcr_sid, - regex: route.regex, - priority, - }; - postLcrRoute(lcrRoutePayload) - .then(({ json }) => { - if (route.lcr_carrier_set_entries) { - Promise.all( - route.lcr_carrier_set_entries.map((entry) => { - handleLcrCarrierSetEntryPost(json.sid, entry); - }) - ) - .then(() => { - resolve(json.sid); - }) - .catch((error) => { - reject(error); - }); - } - }) - .catch((error) => { - reject(error); - }); - }); - }; - - const handleLcrCarrierSetEntryPost = ( - lcr_route_sid: string, - entry: LcrCarrierSetEntry - ): Promise => { - const lcrCarrierSetEntryPayload: LcrCarrierSetEntry = { - ...entry, - voip_carrier_sid: entry.voip_carrier_sid || defaultCarrier, - lcr_route_sid, - }; - return new Promise(async (r, e) => { - postLcrCarrierSetEntry(lcrCarrierSetEntryPayload) - .then(({ json }) => r(json.sid)) - .catch((error) => e(error)); - }); - }; - const handleLcrPut = () => { if (lcrDataMap && lcrDataMap.data && lcrDataMap.data.lcr_sid) { // update LCR const lcrPayload: Lcr = getLcrPayload(); putLcr(lcrDataMap.data.lcr_sid, lcrPayload).then(() => { - Promise.all( - lcrRoutes.map((route, i) => { - if ( - route.lcr_route_sid && - !route.lcr_route_sid?.startsWith(NOT_AVAILABLE_PREFIX) - ) { - handleLcrRoutePut( - lcrDataMap.data?.lcr_sid || "", - route.lcr_route_sid, - route, - i - ); - } else { - handleLcrRoutePost(lcrDataMap.data?.lcr_sid || "", route, i); - } - }) - ) + putLcrUpdateRoutes(lcrDataMap.data?.lcr_sid || "", [ + ...lcrRoutes.map((r, i) => ({ + ...r, + priority: i, + })), + ...(hasValue(defaultLcrRoute) + ? [ + { + ...defaultLcrRoute, + lcr_carrier_set_entries: + defaultLcrRoute.lcr_carrier_set_entries?.map((r) => ({ + ...r, + voip_carrier_sid: + defaultLcrCarrier || + r.voip_carrier_sid || + carrierSelectorOptions[0].value, + })), + }, + ] + : []), + ]) .then(() => { - if (defaultLcrCarrierSetEntrySid) { - const defaultEntry: LcrCarrierSetEntry = { - lcr_route_sid: defaultLcrRouteSid, - voip_carrier_sid: defaultLcrCarrier, - priority: 0, - }; - - handleLcrCarrierEntryPut( - defaultLcrRouteSid, - defaultLcrCarrierSetEntrySid, - defaultEntry - ).then(() => { - toastSuccess("Least cost routing rule successfully updated"); - }); - } + toastSuccess("Least cost routing rule successfully updated"); }) .catch((error) => toastError(error)); }); } - - const handleLcrRoutePut = ( - lcr_sid: string, - lcr_route_sid: string, - route: LcrRoute, - priority: number - ): Promise => { - return new Promise(async (resolve, reject) => { - const lcrRoutePayload: LcrRoute = { - lcr_sid, - regex: route.regex, - priority, - }; - putLcrRoutes(lcr_route_sid, lcrRoutePayload).then(() => { - if ( - route.lcr_carrier_set_entries && - route.lcr_carrier_set_entries.length > 0 - ) { - Promise.all( - route.lcr_carrier_set_entries.map((entry) => { - if (entry.lcr_carrier_set_entry_sid) { - return handleLcrCarrierEntryPut( - entry.lcr_route_sid || lcr_route_sid, - entry.lcr_carrier_set_entry_sid, - entry - ); - } else { - return handleLcrCarrierSetEntryPost(lcr_route_sid, entry); - } - }) - ) - .then(() => { - resolve("Least cost routing rule successfully updated"); - }) - .catch((error) => { - reject(error); - }); - } - }); - }); - }; - - const handleLcrCarrierEntryPut = ( - lcr_route_sid: string, - lcr_carrier_set_entry_sid: string, - entry: LcrCarrierSetEntry - ): Promise => { - const lcrCarrierSetEntryPayload: LcrCarrierSetEntry = { - lcr_route_sid, - workload: entry.workload, - voip_carrier_sid: entry.voip_carrier_sid || defaultCarrier, - priority: entry.priority, - }; - return new Promise(async (r, e) => { - putLcrCarrierSetEntries( - lcr_carrier_set_entry_sid, - lcrCarrierSetEntryPayload - ) - .then(() => r("success")) - .catch((error) => e(error)); - }); - }; }; const handleSubmit = (e: React.FormEvent) => {