import { createStore } from "redux"; import { RemoteService } from "./remote"; import { createDispatchHook } from "react-redux"; import actions from "./storeActions"; const initialToken = localStorage.getItem("token"); const initialState = { login: { loggedIn: false, token: initialToken ? initialToken : null, }, userInfo: null, /** @type {[integer]Room} */ rooms: {}, /** @type {[integer]Device} */ devices: {}, }; function reducer(previousState, action) { let newState = Object.assign({}, previousState); const createOrUpdateRoom = (room) => { if (!(room.id in newState.rooms)) { newState.rooms[room.id] = room; newState.rooms[room.id].devices = new Set(); } else { newState.rooms[room.id].name = room.name; newState.rooms[room.id].image = room.image; newState.rooms[room.id].icon = room.icon; } }; switch (action.type) { case "LOGIN_UPDATE": newState.login = action.login; delete newState.errors.login; break; case "USER_INFO_UPDATE": newState.user = action.user; delete newState.errors.userInfo; break; case "ROOMS_UPDATE": for (const room of action.rooms) { createOrUpdateRoom(room); } delete newState.errors.rooms; break; case "DEVICES_UPDATE": // if room is given, delete all devices in that room // and remove any join between that room and deleted // devices if (action.roomId) { const room = newState.rooms[action.roomId]; for (const deviceId of room.devices) { delete newState.devices[deviceId]; } room.devices = []; } else if (action.partial) { // if the update is partial and caused by an operation on an input // device (like /switch/operate), iteratively remove deleted // devices and their join with their corresponding room. for (const device of action.devices) { const room = newState.rooms[newState.devices[device.id].roomId]; room.devices.delete(device.id); delete newState.devices[device.id]; } } else { // otherwise, just delete all devices and all joins // between rooms and devices newState.devices = {}; for (const room of newState.rooms) { room.devices = []; } } for (const device of action.devices) { newState.devices[device.id] = device; if (device.roomId in newState.rooms) { newState.rooms[device.roomId].devices.add(device.id); } else { console.warn( "Cannot join device", device, `in room ${device.roomId} since that room has not been fetched` ); } } delete newState.errors.devices; break; case "ROOM_SAVE": createOrUpdateRoom(action.room); break; case "ROOM_DELETE": if (!(actions.roomId in newState.rooms)) { console.warn(`Room to delete ${actions.roomId} does not exist`); break; } // This update does not ensure the consistent update of switchId/dimmerId properties // on output devices connected to an input device in this room. Please manually request // all devices again if consistent update is desired for (const id of newState.rooms[action.roomId].devices) { delete newState.devices[id]; } delete newState.rooms[action.roomId]; break; case "DEVICE_DELETE": if (!(actions.deviceId in newState.devices)) { console.warn(`Device to delete ${actions.deviceId} does not exist`); break; } newState.rooms[newState.devices[actions.deviceId].roomId].devices.delete( actions.deviceId ); delete newState.devices[actions.deviceId]; break; case "LOGOUT": newState.login = { token: null, loggedIn: false }; newState.rooms = []; newState.devices = []; delete newState.errors.login; break; default: console.warn(`Action type ${action.type} unknown`, action); } return newState; } const smartHutStore = createStore(reducer, initialState); export default smartHutStore;