Skip to content

Commit 1e1ec2e

Browse files
committed
feat: Dynamically fetch available presets from the backend
1 parent 45b74d3 commit 1e1ec2e

7 files changed

Lines changed: 88 additions & 594 deletions

File tree

custom_components/scene_presets/frontend/scene_presets_panel.js

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

custom_components/scene_presets/view.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ async def async_setup_view(hass):
77
PANEL_URL,
88
hass.config.path(f'{BASE_PATH}/frontend/scene_presets_panel.js'),
99
)
10+
11+
hass.http.register_static_path(
12+
f'/assets/{DOMAIN}/scene_presets.json',
13+
hass.config.path(f"{BASE_PATH}/presets.json"),
14+
)
1015

1116
await bind_preset_images(hass)
1217

js/App.tsx

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import React from "react";
1+
import React, {useEffect} from "react";
22
import {PresetApplyPage} from "./pages/PresetApplyPage";
3+
import {Category, Preset} from "./types";
4+
import {useSessionStorage} from "./hooks/useSessionStorage";
35

46
declare global {
57
namespace JSX {
@@ -27,6 +29,27 @@ export const App : React.FunctionComponent<{
2729
hass,
2830
narrow,
2931
}): JSX.Element => {
32+
const [categories, setCategories] = useSessionStorage<Array<Category>>("scene_presets_categories",[]);
33+
const [presets, setPresets] = useSessionStorage<Array<Preset>>("scene_presets_presets",[]);
34+
35+
useEffect(() => {
36+
const fetchData = async () => {
37+
try {
38+
const response = await fetch("/assets/scene_presets/scene_presets.json");
39+
const data = await response.json();
40+
41+
setCategories(data.categories);
42+
setPresets(data.presets);
43+
} catch (error) {
44+
console.error("Error fetching data:", error);
45+
}
46+
};
47+
48+
fetchData().then(() => {
49+
/* intentional */
50+
});
51+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
52+
3053
return (
3154
<>
3255
<ha-top-app-bar-fixed>
@@ -40,6 +63,9 @@ export const App : React.FunctionComponent<{
4063

4164
<PresetApplyPage
4265
hass={hass}
66+
67+
categories={categories}
68+
presets={presets}
4369
/>
4470
</>
4571
);

js/const.ts

Lines changed: 0 additions & 581 deletions
This file was deleted.

js/hooks/useSessionStorage.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import {useState} from "react";
2+
3+
export const useSessionStorage = <T>(key: string, initialValue: T): [T, (s: T) => void] => {
4+
const [storedValue, setStoredValue] = useState<T>(() => {
5+
try {
6+
const item = window.sessionStorage.getItem(key);
7+
return item ? JSON.parse(item) : initialValue;
8+
} catch (error) {
9+
console.warn(error);
10+
return initialValue;
11+
}
12+
});
13+
14+
const setValue = (value: T) => {
15+
try {
16+
const valueToStore = value instanceof Function ? value(storedValue) : value;
17+
setStoredValue(valueToStore);
18+
window.sessionStorage.setItem(key, JSON.stringify(valueToStore));
19+
} catch (error) {
20+
console.warn(error);
21+
return;
22+
}
23+
};
24+
25+
return [storedValue, setValue];
26+
};

js/pages/PresetApplyPage.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import React from "react";
2-
import data from "../../custom_components/scene_presets/presets.json";
32
import {Tile} from "../components/Tile";
43
import {useLocalStorage} from "../hooks/useLocalStorage";
54
import HaSwitch from "../components/hass/building_blocks/HaSwitch";
65
import {HaTargetSelector, HaTargetSelectorValue} from "../components/hass/selectors/HaTargetSelector";
76
import {HaNumberSelector} from "../components/hass/selectors/HaNumberSelector";
87
import HaIconButton from "../components/hass/building_blocks/HaIconButton";
8+
import {Category, Preset} from "../types";
99

1010
const DEFAULT_TUNABLE_SETTINGS = {
1111
shuffle: false,
@@ -17,9 +17,13 @@ const DEFAULT_TUNABLE_SETTINGS = {
1717
};
1818

1919
export const PresetApplyPage: React.FunctionComponent<{
20-
hass: any
20+
hass: any,
21+
categories: Array<Category>,
22+
presets: Array<Preset>,
2123
}> = ({
2224
hass,
25+
categories,
26+
presets
2327
}): JSX.Element => {
2428
const [targets, setTargets] = useLocalStorage<HaTargetSelectorValue>("scene_presets_apply_page_targets", {});
2529
const [shuffle, setShuffle] = useLocalStorage<boolean>("scene_presets_apply_page_shuffle", DEFAULT_TUNABLE_SETTINGS.shuffle);
@@ -57,19 +61,19 @@ export const PresetApplyPage: React.FunctionComponent<{
5761
const presetsByCategories = React.useMemo(() => {
5862
const out = {};
5963

60-
data.categories.forEach(category => {
61-
out[category.id] = data.presets.filter(p => p.categoryId === category.id);
64+
categories.forEach(category => {
65+
out[category.id] = presets.filter(p => p.categoryId === category.id);
6266
});
6367

6468
return out;
65-
}, []);
69+
}, [categories, presets]);
6670

6771

6872
const tiles = React.useMemo(() => {
6973
const allTiles: {[key: string] : JSX.Element} = {};
7074
const favoriteTiles: Array<string> = [];
7175

72-
data.presets.forEach((preset, i) => {
76+
presets.forEach((preset, i) => {
7377
const isFav = favoritePresets.includes(preset.id);
7478

7579
allTiles[preset.id] = <Tile
@@ -98,7 +102,7 @@ export const PresetApplyPage: React.FunctionComponent<{
98102
all: allTiles,
99103
favoriteIds: favoriteTiles,
100104
};
101-
}, [favoritePresets, applyPreset, setFavoritePresets]);
105+
}, [presets, favoritePresets, applyPreset, setFavoritePresets]);
102106

103107
return (
104108
<div
@@ -334,7 +338,7 @@ export const PresetApplyPage: React.FunctionComponent<{
334338
}
335339

336340
{
337-
data.categories.map(({name, id}) => {
341+
categories.map(({name, id}) => {
338342
return (
339343
<div
340344
key={"category_" + name}

js/types.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
export type Category = {
3+
id: string,
4+
name: string
5+
}
6+
7+
export type Preset = {
8+
id: string,
9+
categoryId: string,
10+
name: string,
11+
img: string,
12+
bri: number,
13+
lights: Array<{x: number, y: number}>
14+
}

0 commit comments

Comments
 (0)