From d77e2c9622ec02ad9e71191e2a0d7faa533d6771 Mon Sep 17 00:00:00 2001 From: Logan4413 Date: Tue, 29 Oct 2024 19:47:32 -0400 Subject: [PATCH 1/3] Adding a timer input --- config/2024/config.json | 8 ++++ config/schema.json | 3 +- src/components/inputs/BaseInputProps.ts | 3 +- src/components/inputs/ConfigurableInput.tsx | 13 ++++++ src/components/inputs/TimerInput.tsx | 44 +++++++++++++++++++++ 5 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 src/components/inputs/TimerInput.tsx diff --git a/config/2024/config.json b/config/2024/config.json index b988699..53b36cf 100644 --- a/config/2024/config.json +++ b/config/2024/config.json @@ -73,6 +73,14 @@ "required": false, "code": "Mved" }, + { + "code": "timer", + "title": "Timer", + "type": "timer", + "defaultValue": 0, + "min": 0, + "required": false + }, { "code": "ausc", "title": "Speaker Scored", diff --git a/config/schema.json b/config/schema.json index ac96bb5..9f85202 100644 --- a/config/schema.json +++ b/config/schema.json @@ -99,7 +99,8 @@ "range", "select", "counter", - "image" + "image", + "timer" ] } } diff --git a/src/components/inputs/BaseInputProps.ts b/src/components/inputs/BaseInputProps.ts index ceae405..3a7f3f4 100644 --- a/src/components/inputs/BaseInputProps.ts +++ b/src/components/inputs/BaseInputProps.ts @@ -37,4 +37,5 @@ export type InputTypes = | 'range' | 'select' | 'counter' - | 'image'; + | 'image' + | 'timer'; diff --git a/src/components/inputs/ConfigurableInput.tsx b/src/components/inputs/ConfigurableInput.tsx index 7203b46..74c4436 100644 --- a/src/components/inputs/ConfigurableInput.tsx +++ b/src/components/inputs/ConfigurableInput.tsx @@ -5,6 +5,7 @@ import NumberInput from './NumberInput'; import RangeInput from './RangeInput'; import SelectInput from './SelectInput'; import StringInput from './StringInput'; +import TimerInput from './TimerInput'; export interface ConfigurableInputProps { section: string; @@ -85,6 +86,18 @@ export default function ConfigurableInput(props: ConfigurableInputProps) { section={props.section} /> ); + case 'timer': + return ( + + ) default: return (
diff --git a/src/components/inputs/TimerInput.tsx b/src/components/inputs/TimerInput.tsx new file mode 100644 index 0000000..6914a5d --- /dev/null +++ b/src/components/inputs/TimerInput.tsx @@ -0,0 +1,44 @@ +import BaseInputProps from './BaseInputProps'; + +export interface TimerInputProps extends BaseInputProps { + min?: number; + max?: number; + step?: number; + defaultValue?: number; +} + +export default function TimerInput(data: TimerInputProps) { + function handleChange(increment: number) { + const newVal = data.value + increment; + if (data.max !== undefined && newVal > data.max) { + // Don't fire the event if the new value would be greater than the max + return; + } + if (data.min !== undefined && newVal < data.min) { + // Don't fire the event if the new value would be less than the min + return; + } + + data.onChange(newVal); + } + + return ( +
+ +

{data.value}

+ +
+ ); +} From 7ca6d1934b752a9715f83a4ccf554b2d571ce612 Mon Sep 17 00:00:00 2001 From: Owen-Morgan825 Date: Tue, 12 Nov 2024 20:22:00 -0500 Subject: [PATCH 2/3] Make timer input actually a timer --- package-lock.json | 10 ++++ package.json | 1 + src/components/inputs/TimerInput.tsx | 86 +++++++++++++++++++--------- 3 files changed, 69 insertions(+), 28 deletions(-) diff --git a/package-lock.json b/package-lock.json index f4f0089..713c632 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "clsx": "^2.1.0", "immer": "^10.0.3", "lodash": "^4.17.21", + "lucide-react": "^0.456.0", "next-themes": "^0.2.1", "preact": "^10.19.3", "qrcode.react": "^3.1.0", @@ -2294,6 +2295,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "0.456.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.456.0.tgz", + "integrity": "sha512-DIIGJqTT5X05sbAsQ+OhA8OtJYyD4NsEMCA/HQW/Y6ToPQ7gwbtujIoeAaup4HpHzV35SQOarKAWH8LYglB6eA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, "node_modules/magic-string": { "version": "0.30.5", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", diff --git a/package.json b/package.json index ca3b38e..86a0a64 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "clsx": "^2.1.0", "immer": "^10.0.3", "lodash": "^4.17.21", + "lucide-react": "^0.456.0", "next-themes": "^0.2.1", "preact": "^10.19.3", "qrcode.react": "^3.1.0", diff --git a/src/components/inputs/TimerInput.tsx b/src/components/inputs/TimerInput.tsx index 6914a5d..fe56d5f 100644 --- a/src/components/inputs/TimerInput.tsx +++ b/src/components/inputs/TimerInput.tsx @@ -1,44 +1,74 @@ +import { Pause, Play, X } from 'lucide-react'; import BaseInputProps from './BaseInputProps'; - +import { useState, useEffect, useMemo } from 'react'; export interface TimerInputProps extends BaseInputProps { min?: number; max?: number; step?: number; defaultValue?: number; } - +function getAvg(array: any[]) { + let avg = 0; + array.forEach((num) => { + avg += num; + }); + return avg / array.length; +} export default function TimerInput(data: TimerInputProps) { - function handleChange(increment: number) { - const newVal = data.value + increment; - if (data.max !== undefined && newVal > data.max) { - // Don't fire the event if the new value would be greater than the max - return; + const [time, setTime] = useState(0); + const [isRunning, toggleTimer] = useState(false); + const [times, setTimes] = useState([]); + + console.log(data.value); + + function startStop() { + toggleTimer(!isRunning); + } + function clearTimer() { + setTime(0); + toggleTimer(false); + } + function updateTimes(newValue: number) { + setTimes((old) => ([...old, newValue])); + } + useEffect(() => { + let intervalId: number; + if (isRunning) { + intervalId = setInterval(() => setTime(time + (data.step || 1)), 10); } - if (data.min !== undefined && newVal < data.min) { - // Don't fire the event if the new value would be less than the min - return; + if (!isRunning && time !== 0) { + updateTimes(time / 100) } + return () => clearInterval(intervalId); + }, [isRunning, time]); - data.onChange(newVal); - } + const avg = useMemo(() => { + const avg2 = getAvg(times); + data.onChange(avg2); + return avg2; + }, [times]); return ( -
- -

{data.value}

- +
+

{times.map((t) => { return `${t}` }).join(',')}

+

{avg.toFixed(3)}

+

{(time / 100).toFixed(2)}

+
+ + +
); } From 1fbf97e1a574db3b78856bea1e8d46641970d692 Mon Sep 17 00:00:00 2001 From: Owen-Morgan825 Date: Tue, 26 Nov 2024 19:20:58 -0500 Subject: [PATCH 3/3] Add timer input type --- src/components/inputs/TimerInput.tsx | 43 ++++++++++++++++++---------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/components/inputs/TimerInput.tsx b/src/components/inputs/TimerInput.tsx index fe56d5f..13a2c43 100644 --- a/src/components/inputs/TimerInput.tsx +++ b/src/components/inputs/TimerInput.tsx @@ -1,4 +1,4 @@ -import { Pause, Play, X } from 'lucide-react'; +import { Pause, Play, TimerReset, Undo } from 'lucide-react'; import BaseInputProps from './BaseInputProps'; import { useState, useEffect, useMemo } from 'react'; export interface TimerInputProps extends BaseInputProps { @@ -8,6 +8,9 @@ export interface TimerInputProps extends BaseInputProps { defaultValue?: number; } function getAvg(array: any[]) { + if (array.length === 0) { + return 0; + } let avg = 0; array.forEach((num) => { avg += num; @@ -19,39 +22,42 @@ export default function TimerInput(data: TimerInputProps) { const [isRunning, toggleTimer] = useState(false); const [times, setTimes] = useState([]); - console.log(data.value); + useEffect(() => { + if (data.value === data.defaultValue && times.length > 0) { + clearTimer(); + setTimes([]); + } + }, [data.value, data.defaultValue, times]); function startStop() { toggleTimer(!isRunning); } - function clearTimer() { + + function clearTimer(update: boolean = false) { + if (update) { + updateTimes(time / 100); + } setTime(0); toggleTimer(false); } + function updateTimes(newValue: number) { + data.onChange(getAvg([...times, newValue])) setTimes((old) => ([...old, newValue])); } + useEffect(() => { let intervalId: number; if (isRunning) { intervalId = setInterval(() => setTime(time + (data.step || 1)), 10); } - if (!isRunning && time !== 0) { - updateTimes(time / 100) - } return () => clearInterval(intervalId); }, [isRunning, time]); - const avg = useMemo(() => { - const avg2 = getAvg(times); - data.onChange(avg2); - return avg2; - }, [times]); return (
-

{times.map((t) => { return `${t}` }).join(',')}

-

{avg.toFixed(3)}

+

{`${data.value.toFixed(3)} (${times.length})`}

{(time / 100).toFixed(2)}

+