-
Notifications
You must be signed in to change notification settings - Fork 1
Suu/add night light button #23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -13,9 +13,12 @@ export interface ScenesState { | |||||
| lastExecutedSceneId: string | null; | ||||||
| sceneOrder: string[]; | ||||||
| sceneOrderLoaded: boolean; | ||||||
| nightLightSceneMap: Record<string, string | undefined>; | ||||||
| nightLightScenesLoaded: boolean; | ||||||
| } | ||||||
|
|
||||||
| const SCENE_ORDER_STORAGE_KEY = "sceneOrder"; | ||||||
| const NIGHT_LIGHT_SCENE_STORAGE_KEY = "nightLightSceneAssignments"; | ||||||
|
|
||||||
| const persistSceneOrder = (order: string[]) => { | ||||||
| try { | ||||||
|
|
@@ -25,6 +28,14 @@ const persistSceneOrder = (order: string[]) => { | |||||
| } | ||||||
| }; | ||||||
|
|
||||||
| const persistNightLightScenes = (map: Record<string, string | undefined>) => { | ||||||
| try { | ||||||
| void window.electronStore.set(NIGHT_LIGHT_SCENE_STORAGE_KEY, map); | ||||||
| } catch (error) { | ||||||
| console.error("Failed to persist night-light scene assignments:", error); | ||||||
| } | ||||||
| }; | ||||||
|
|
||||||
| const initialState: ScenesState = { | ||||||
| scenes: [], | ||||||
| isLoading: false, | ||||||
|
|
@@ -35,6 +46,8 @@ const initialState: ScenesState = { | |||||
| lastExecutedSceneId: null, | ||||||
| sceneOrder: [], | ||||||
| sceneOrderLoaded: false, | ||||||
| nightLightSceneMap: {}, | ||||||
| nightLightScenesLoaded: false, | ||||||
| }; | ||||||
|
|
||||||
| export const loadSceneOrder = createAsyncThunk("scenes/loadSceneOrder", async () => { | ||||||
|
|
@@ -49,6 +62,27 @@ export const loadSceneOrder = createAsyncThunk("scenes/loadSceneOrder", async () | |||||
| return []; | ||||||
| }); | ||||||
|
|
||||||
| export const loadNightLightSceneAssignments = createAsyncThunk( | ||||||
| "scenes/loadNightLightSceneAssignments", | ||||||
| async () => { | ||||||
| try { | ||||||
| const stored = await window.electronStore.get(NIGHT_LIGHT_SCENE_STORAGE_KEY); | ||||||
| if (stored && typeof stored === "object") { | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The check
Suggested change
|
||||||
| const map: Record<string, string> = {}; | ||||||
| Object.entries(stored as Record<string, unknown>).forEach(([deviceId, sceneId]) => { | ||||||
| if (typeof deviceId === "string" && typeof sceneId === "string") { | ||||||
| map[deviceId] = sceneId; | ||||||
| } | ||||||
| }); | ||||||
| return map; | ||||||
| } | ||||||
| } catch (error) { | ||||||
| console.error("Failed to load night-light scene assignments:", error); | ||||||
| } | ||||||
| return {}; | ||||||
| } | ||||||
| ); | ||||||
|
|
||||||
| export const fetchScenes = createAsyncThunk("scenes/fetchScenes", async (_, { getState, rejectWithValue }) => { | ||||||
| const { settings } = getState() as RootState; | ||||||
| if (!settings.apiToken || !settings.isTokenValidated) { | ||||||
|
|
@@ -109,6 +143,15 @@ const scenesSlice = createSlice({ | |||||
| state.sceneOrderLoaded = true; | ||||||
| persistSceneOrder(state.sceneOrder); | ||||||
| }, | ||||||
| setNightLightSceneForDevice: (state, action: PayloadAction<{ deviceId: string; sceneId: string | null }>) => { | ||||||
| const { deviceId, sceneId } = action.payload; | ||||||
| if (sceneId) { | ||||||
| state.nightLightSceneMap[deviceId] = sceneId; | ||||||
| } else { | ||||||
| delete state.nightLightSceneMap[deviceId]; | ||||||
| } | ||||||
| persistNightLightScenes(state.nightLightSceneMap); | ||||||
| }, | ||||||
| }, | ||||||
| extraReducers: (builder) => { | ||||||
| builder | ||||||
|
|
@@ -159,11 +202,24 @@ const scenesSlice = createSlice({ | |||||
| }) | ||||||
| .addCase(loadSceneOrder.rejected, (state) => { | ||||||
| state.sceneOrderLoaded = true; | ||||||
| }) | ||||||
| .addCase(loadNightLightSceneAssignments.fulfilled, (state, action: PayloadAction<Record<string, string>>) => { | ||||||
| state.nightLightScenesLoaded = true; | ||||||
| state.nightLightSceneMap = action.payload; | ||||||
| }) | ||||||
| .addCase(loadNightLightSceneAssignments.rejected, (state) => { | ||||||
| state.nightLightScenesLoaded = true; | ||||||
| }); | ||||||
| }, | ||||||
| }); | ||||||
|
|
||||||
| export const { clearSceneErrors, clearSceneExecutionError, clearScenesState, setSceneOrder } = scenesSlice.actions; | ||||||
| export const { | ||||||
| clearSceneErrors, | ||||||
| clearSceneExecutionError, | ||||||
| clearScenesState, | ||||||
| setSceneOrder, | ||||||
| setNightLightSceneForDevice | ||||||
| } = scenesSlice.actions; | ||||||
|
|
||||||
| export const selectScenes = (state: RootState) => state.scenes.scenes; | ||||||
| export const selectScenesLoading = (state: RootState) => state.scenes.isLoading; | ||||||
|
|
@@ -174,5 +230,8 @@ export const selectSceneExecutionError = (state: RootState, sceneId: string) => | |||||
| export const selectLastExecutedSceneId = (state: RootState) => state.scenes.lastExecutedSceneId; | ||||||
| export const selectSceneOrderLoaded = (state: RootState) => state.scenes.sceneOrderLoaded; | ||||||
| export const selectSceneOrder = (state: RootState) => state.scenes.sceneOrder; | ||||||
| export const selectNightLightSceneForDevice = (state: RootState, deviceId: string) => | ||||||
| state.scenes.nightLightSceneMap[deviceId]; | ||||||
| export const selectNightLightScenesLoaded = (state: RootState) => state.scenes.nightLightScenesLoaded; | ||||||
|
|
||||||
| export default scenesSlice.reducer; | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These consecutive
useSelectorhooks, where some depend on the output of others from the previous render, can lead to stale data and unnecessary re-renders. It's a best practice to derive all related state within a singleuseSelectorhook. This ensures data consistency for a single render and can be more performant, especially when providing a custom equality check to prevent re-renders if the derived data hasn't functionally changed.