diff options
Diffstat (limited to 'src/components/Timer.tsx')
| -rw-r--r-- | src/components/Timer.tsx | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/src/components/Timer.tsx b/src/components/Timer.tsx new file mode 100644 index 0000000..61a98f5 --- /dev/null +++ b/src/components/Timer.tsx @@ -0,0 +1,178 @@ +import { createSignal, For, Match, Show, Switch } from "solid-js"; +import styles from "./Timer.module.css"; + +export const TIME_UNITS = ["s", "m", "h", "d"] as const; +export type Timer = { + title: string; + options: { + time: number; + unit: (typeof TIME_UNITS)[number]; + }[]; + backgroundColor: string; + onTill: number | null; + secondsLeftText: string; + extraStopActions: { title: string }[]; +}; + +export default function Timer(props: Timer) { + const [onTill, setOnTill] = createSignal(props.onTill); + const [unit, setUnit] = createSignal<(typeof TIME_UNITS)[number]>( + TIME_UNITS[1], + ); + const [formattedTime, setFormattedTime] = createSignal(""); + const [disabled, setDisabled] = createSignal(onTill() !== null); + const [customValue, setCustomValue] = createSignal<number | "">(""); + + let _intervalId = null; + function toggleAutoUpdate() { + if (_intervalId === null) { + updateTime(); + _intervalId = setInterval(updateTime, 1000); + } else { + clearInterval(_intervalId); + _intervalId = null; + } + } + if (props.onTill !== null) { + toggleAutoUpdate(); + } + function updateTime() { + const s = Math.floor(onTill() - Date.now() / 1000); + const days = Math.floor(s / (24 * 3600)); + const hours = Math.floor((s % (24 * 3600)) / 3600); + const minutes = Math.floor((s % 3600) / 60); + const seconds = s % 60; + + let text = ""; + if (days > 0) { + text += days + "d : "; + } + if (hours > 0 || text.length > 0) { + text += hours + "h : "; + } + if (minutes > 0 || text.length > 0) { + text += minutes + "m : "; + } + if (seconds > 0 || text.length > 0) { + text += seconds + "s"; + } + setFormattedTime(text); + } + function startStopClick() { + const val = customValue(); + if (disabled() === false && val !== "") { + optionClick({ time: val, unit: unit() }); + } else if (disabled() === true) { + setDisabled(false); + setOnTill(null); + toggleAutoUpdate(); + } + } + + function optionClick(option: Timer["options"][number]) { + setDisabled(true); + let newOnTill = Math.floor(Date.now() / 1000); + if (option.unit === "s") { + newOnTill += option.time; + } else if (option.unit === "m") { + newOnTill += option.time * 60; + } else if (option.unit === "h") { + newOnTill += option.time * 3600; + } else { + newOnTill += option.time * 3600 * 24; + } + setOnTill(newOnTill); + toggleAutoUpdate(); + } + + function extraStopClick(act: Timer["extraStopActions"][number]) { + // Some api call for the extra + startStopClick(); + } + return ( + <div class={styles.cont}> + <h2>{props.title}</h2> + + <div class={styles.customOption}> + <input + type="number" + value={customValue()} + on:input={(e) => + setCustomValue(e.target.value ? parseFloat(e.target.value) : "") + } + disabled={disabled()} + min="1" + /> + <div class={styles.units}> + <For each={TIME_UNITS}> + {(u) => ( + <span + on:click={() => (disabled() ? null : setUnit(u))} + classList={{ + [styles.selectedUnit]: unit() === u, + [styles.notSelectedUnit]: unit() !== u, + [styles.darkgray]: disabled() === true, + }} + > + {u} + </span> + )} + </For> + </div> + <button + class={styles.customOptionBtn} + on:click={startStopClick} + disabled={ + disabled() + ? false + : customValue() === "" || (customValue() as number) <= 0 + } + style={{ "background-color": disabled() ? "red" : "green" }} + > + {disabled() ? "Wyłącz" : "Włącz"} + </button> + {/*<Show when={disabled() === true}>*/} + <For each={props.extraStopActions}> + {(act) => ( + <button + disabled={disabled() === false} + on:click={[extraStopClick, act]} + class={styles.extraStopBtn} + > + {act.title} + </button> + )} + </For> + {/*</Show>*/} + </div> + + <div class={styles.timeLeft}> + <Switch> + <Match when={onTill() === null}> + <span>Wyłączone</span> + <h2> </h2> + </Match> + <Match when={onTill() > 0}> + <span>{props.secondsLeftText} </span> + <h2>{formattedTime()}</h2> + </Match> + </Switch> + </div> + + <div class={styles.options}> + <For each={props.options}> + {(option) => ( + <button + class={styles.option} + on:click={[optionClick, option]} + style={{ "background-color": props.backgroundColor }} + disabled={disabled()} + > + {option.time} {option.unit} + </button> + )} + </For> + </div> + </div> + ); +} |
