frontend/src/providers/pond/interactionsAPI.tsx

306 lines
12 KiB
TypeScript

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<AxiosResponse<pond.AddInteractionResponse>>;
addMultiInteractions: (device: number, settings: pond.MultiInteractionSettings, otherTeam?: string) => Promise<AxiosResponse<pond.AddMultiInteractionsResponse>>;
addInteractionToComponents: (
fullComponentLocations: string[],
settings: pond.IInteractionSettings,
otherTeam?: string
) => Promise<AxiosResponse<pond.AddInteractionToComponentsResponse>>;
updateInteraction: (device: number, settings: pond.IInteractionSettings, otherTeam?: string) => Promise<AxiosResponse<pond.UpdateInteractionResponse>>;
updateInteractionPondSettings: (
device: number,
interaction: string,
settings: pond.IInteractionPondSettings,
otherTeam?: string
) => Promise<AxiosResponse<pond.UpdateInteractionPondSettingsResponse>>;
removeInteraction: (device: number, interaction: string, otherTeam?: string) => Promise<AxiosResponse<pond.RemoveInteractionResponse>>;
listInteractionsByDevice: (device: number | string, demo?: boolean, otherTeam?: string) => Promise<Interaction[]>;
listInteractionsByComponent: (
device: number,
component: quack.ComponentID,
demo?: boolean,
otherTeam?: string
) => Promise<Interaction[]>;
setAlertInteractions: (
alerts: pond.AlertData[],
otherTeam?: string
) => Promise<AxiosResponse<pond.SetAlertInteractionsResponse>>;
}
export const InteractionsAPIContext = createContext<IInteractionsAPIContext>(
{} 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<Props>) {
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<AxiosResponse<pond.AddInteractionResponse>>((resolve, reject) => {
post<pond.AddInteractionResponse>(
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<AxiosResponse<pond.AddInteractionToComponentsResponse>>((resolve, reject) => {
post<pond.AddInteractionToComponentsResponse>(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<AxiosResponse<pond.AddMultiInteractionsResponse>>((resolve, reject) => {
post<pond.AddMultiInteractionsResponse>(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<AxiosResponse<pond.UpdateInteractionResponse>>((resolve, reject) => {
put<pond.UpdateInteractionResponse>(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<AxiosResponse<pond.UpdateInteractionPondSettingsResponse>>((resolve, reject) => {
put<pond.UpdateInteractionPondSettingsResponse>(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<AxiosResponse<pond.RemoveInteractionResponse>>((resolve, reject) => {
del<pond.RemoveInteractionResponse>(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<Interaction[]> => {
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<Interaction[]> => {
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<AxiosResponse<pond.SetAlertInteractionsResponse>> => {
const view = otherTeam ? otherTeam : as
let url = pondURL("/interactions/setAlerts" + (view ? "?as=" + view : ""))
return new Promise<AxiosResponse<pond.SetAlertInteractionsResponse>>((resolve, reject) => {
post<pond.SetAlertInteractionsResponse>(url, { data: alerts }).then(resp => {
resp.data = pond.SetAlertInteractionsResponse.fromObject(resp.data)
return resolve(resp)
}).catch(err => {
return reject(err)
})
})
};
return (
<InteractionsAPIContext.Provider
value={{
addInteraction,
addMultiInteractions,
setAlertInteractions,
addInteractionToComponents,
updateInteraction,
updateInteractionPondSettings,
removeInteraction,
listInteractionsByDevice,
listInteractionsByComponent
}}>
{children}
</InteractionsAPIContext.Provider>
);
}
export const useInteractionsAPI = () => useContext(InteractionsAPIContext);