import { AxiosResponse } from "axios"; import { useHTTP } from "hooks"; import { Interaction } from "models"; import { componentIDToString } from "pbHelpers/Component"; import { pond } from "protobuf-ts/pond"; import { quack } from "protobuf-ts/quack"; import { useGlobalState } from "providers/StateContainer"; import { createContext, PropsWithChildren, useContext } from "react"; import { has } from "utils/types"; import { pondURL } from "./pond"; export interface IInteractionsAPIContext { addInteraction: (device: number, settings: pond.IInteractionSettings, otherTeam?: string) => Promise>; addMultiInteractions: (device: number, settings: pond.MultiInteractionSettings, otherTeam?: string) => Promise>; addInteractionToComponents: ( fullComponentLocations: string[], settings: pond.IInteractionSettings, otherTeam?: string ) => Promise>; updateInteraction: (device: number, settings: pond.IInteractionSettings, otherTeam?: string) => Promise>; updateInteractionPondSettings: ( device: number, interaction: string, settings: pond.IInteractionPondSettings, otherTeam?: string ) => Promise>; removeInteraction: (device: number, interaction: string, otherTeam?: string) => Promise>; listInteractionsByDevice: (device: number | string, demo?: boolean, otherTeam?: string) => Promise; listInteractionsByComponent: ( device: number, component: quack.ComponentID, demo?: boolean, otherTeam?: string ) => Promise; setAlertInteractions: ( alerts: pond.AlertData[], otherTeam?: string ) => Promise>; } export const InteractionsAPIContext = createContext( {} as IInteractionsAPIContext ); interface Props {} //used to validate interaction fields before being sent outbound function sanitizeInteraction(interaction: pond.IInteractionSettings): pond.IInteractionSettings { let sanitizedInteraction = interaction; if (sanitizedInteraction.conditions) { sanitizedInteraction.conditions.forEach((condition, i) => { if (condition.value && sanitizedInteraction.conditions) { sanitizedInteraction.conditions[i].value = Math.round(condition.value); } }); } return sanitizedInteraction; } export default function InteractionProvider(props: PropsWithChildren) { const { children } = props; const { get, post, put, del } = useHTTP(); const [{ as }] = useGlobalState(); const addInteraction = (device: number, settings: pond.IInteractionSettings, otherTeam?: string) => { const view = otherTeam ? otherTeam : as return new Promise>((resolve, reject) => { post( pondURL("/devices/" + device + "/interactions" + (view ? "?as=" + view : "")), sanitizeInteraction(settings) ).then(resp => { resp.data = pond.AddInteractionResponse.fromObject(resp) return resolve(resp) }).catch(err => { return reject(err) }) }) }; /** * this function is intended for use to add a single interaction to multiple components by way of an object that they are linked to (bin, gate etc) * @param fullComponentLocations the full id of a component including the device ie: [4:9-5-12, 4:9-5-13, 3:9-5-12] * @param settings the settings of the interaction to add * @returns */ const addInteractionToComponents = ( fullComponentLocations: string[], settings: pond.IInteractionSettings, otherTeam?: string ) => { const view = otherTeam ? otherTeam : as let url = pondURL( "/interactions/forComponents?componentIds=" + fullComponentLocations.toString() + (view ? "&as=" + view : "") ) return new Promise>((resolve, reject) => { post(url,sanitizeInteraction(settings)).then(resp => { resp.data = pond.AddInteractionToComponentsResponse.fromObject(resp.data) return resolve(resp) }).catch(err => { return reject(err) }) }) }; const addMultiInteractions = (device: number, settings: pond.MultiInteractionSettings, otherTeam?: string) => { const view = otherTeam ? otherTeam : as let url = pondURL("/devices/" + device + "/interactions/multi" + (view ? "?as=" + view : "")) return new Promise>((resolve, reject) => { post(url,settings).then(resp => { resp.data = pond.AddMultiInteractionsResponse.fromObject(resp.data) return resolve(resp) }).catch(err => { return reject(err) }) }) }; const updateInteraction = (device: number, settings: pond.IInteractionSettings, otherTeam?: string) => { const view = otherTeam ? otherTeam : as let url = pondURL( "/devices/" + device + "/interactions?keys=" + [device] + "&types=" + ["device"] + (view ? "&as=" + view : "") ) return new Promise>((resolve, reject) => { put(url,sanitizeInteraction(settings)).then(resp => { resp.data = pond.UpdateInteractionResponse.fromObject(resp.data) return resolve(resp) }).catch(err => { return reject(err) }) }) }; const updateInteractionPondSettings = ( device: number, interaction: string, settings: pond.IInteractionPondSettings, otherTeam?: string ) => { const view = otherTeam ? otherTeam : as let url = pondURL( "/devices/" + device + "/interactions/" + interaction + "/interactionPondSettings?keys=" + [device] + "&types=" + ["device"] + (view ? "&as=" + view : "") ) return new Promise>((resolve, reject) => { put(url, sanitizeInteraction(settings)).then(resp => { resp.data = pond.UpdateInteractionPondSettingsResponse.fromObject(resp.data) return resolve(resp) }).catch(err => { return reject(err) }) }) }; const removeInteraction = (device: number, interaction: string, otherTeam?: string) => { const view = otherTeam ? otherTeam : as let url = pondURL("/devices/" + device + "/interactions/" + interaction + (view ? "?as=" + view : "")) return new Promise>((resolve, reject) => { del(url).then(resp => { resp.data = pond.RemoveInteractionResponse.fromObject(resp.data) return resolve(resp) }).catch(err => { return reject(err) }) }) }; const listInteractionsByDevice = ( device: number | string, demo: boolean = false, otherTeam?: string ): Promise => { const view = otherTeam ? otherTeam : as return new Promise((resolve, reject) => { get(pondURL("/devices/" + device + "/interactions" + (view ? "?as=" + view : ""), demo)) .then((response: any) => { if (!has(response, "data.interactions")) { return resolve([]); } let interactions: Interaction[] = []; response.data.interactions.forEach((interaction: Interaction) => { if ( interaction.settings.nodeOne > interaction.settings.nodeTwo && interaction.settings.nodeTwo !== 0 ) { //flip operator and send negative comparitor to save interaction.settings.conditions.forEach(condition => { //coming back from the backend as a string for some reason if (condition.comparison.toString() === "RELATIONAL_OPERATOR_GREATER_THAN") { condition.comparison = quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN; } else { condition.comparison = quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN; } condition.value = condition.value * -1; }); } interactions.push(Interaction.any(interaction)); }); return resolve(interactions); }) .catch((error: any) => { return reject(error); }); }); }; const listInteractionsByComponent = ( device: number, component: quack.ComponentID, demo: boolean = false, otherTeam?: string ): Promise => { const view = otherTeam ? otherTeam : as return new Promise((resolve, reject) => { get( pondURL( "/devices/" + device + "/components/" + componentIDToString(component) + "/interactions" + (view ? "?as=" + view : ""), demo ) ) .then((response: any) => { if (!has(response, "data.interactions")) { return resolve([]); } let interactions: Interaction[] = []; response.data.interactions.forEach((interaction: Interaction) => { if ( interaction.settings.nodeOne > interaction.settings.nodeTwo && interaction.settings.nodeTwo !== 0 ) { //flip operator and send negative comparitor to save interaction.settings.conditions.forEach(condition => { //coming back from the backend as a string for some reason if (condition.comparison.toString() === "RELATIONAL_OPERATOR_GREATER_THAN") { condition.comparison = quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN; } else { condition.comparison = quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN; } condition.value = condition.value * -1; }); } interactions.push(Interaction.any(interaction)); }); return resolve(interactions); }) .catch((error: any) => { return reject(error); }); }); }; const setAlertInteractions = ( alerts: pond.AlertData[], otherTeam?: string ): Promise> => { const view = otherTeam ? otherTeam : as let url = pondURL("/interactions/setAlerts" + (view ? "?as=" + view : "")) return new Promise>((resolve, reject) => { post(url, { data: alerts }).then(resp => { resp.data = pond.SetAlertInteractionsResponse.fromObject(resp.data) return resolve(resp) }).catch(err => { return reject(err) }) }) }; return ( {children} ); } export const useInteractionsAPI = () => useContext(InteractionsAPIContext);