mirror of
https://github.com/remvze/moodist.git
synced 2025-12-17 00:44:14 +00:00
157 lines
3.9 KiB
TypeScript
157 lines
3.9 KiB
TypeScript
import { useEffect, useState, useRef, useMemo } from 'react';
|
|
|
|
import { Modal } from '@/components/modal';
|
|
import { Timer } from '@/components/timer';
|
|
import { dispatch } from '@/lib/event';
|
|
import { useSoundStore } from '@/store';
|
|
import { cn } from '@/helpers/styles';
|
|
import { FADE_OUT } from '@/constants/events';
|
|
|
|
import styles from './sleep-timer.module.css';
|
|
|
|
interface SleepTimerModalProps {
|
|
onClose: () => void;
|
|
show: boolean;
|
|
}
|
|
|
|
export function SleepTimerModal({ onClose, show }: SleepTimerModalProps) {
|
|
const [running, setRunning] = useState(false);
|
|
|
|
const [hours, setHours] = useState<string>('0');
|
|
const [minutes, setMinutes] = useState<string>('10');
|
|
|
|
const totalSeconds = useMemo(
|
|
() =>
|
|
(hours === '' ? 0 : parseInt(hours)) * 3600 +
|
|
(minutes === '' ? 0 : parseInt(minutes)) * 60,
|
|
[hours, minutes],
|
|
);
|
|
|
|
const [timeSpent, setTimeSpent] = useState(0);
|
|
|
|
const timeLeft = useMemo(
|
|
() => totalSeconds - timeSpent,
|
|
[totalSeconds, timeSpent],
|
|
);
|
|
|
|
const timerId = useRef<ReturnType<typeof setInterval>>();
|
|
|
|
const isPlaying = useSoundStore(state => state.isPlaying);
|
|
const play = useSoundStore(state => state.play);
|
|
const pause = useSoundStore(state => state.pause);
|
|
|
|
const handleStart = () => {
|
|
if (timerId.current) clearInterval(timerId.current);
|
|
if (!isPlaying) play();
|
|
|
|
if (totalSeconds > 0) {
|
|
setRunning(true);
|
|
|
|
const newTimerId = setInterval(() => {
|
|
setTimeSpent(prev => prev + 1);
|
|
}, 1000);
|
|
|
|
timerId.current = newTimerId;
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (timeLeft === 0) {
|
|
setRunning(false);
|
|
// pause();
|
|
dispatch(FADE_OUT, { duration: 1000 });
|
|
|
|
setTimeSpent(0);
|
|
|
|
if (timerId.current) clearInterval(timerId.current);
|
|
}
|
|
}, [timeLeft, pause]);
|
|
|
|
const handleReset = () => {
|
|
if (timerId.current) clearInterval(timerId.current);
|
|
setTimeSpent(0);
|
|
setHours('0');
|
|
setMinutes('10');
|
|
setRunning(false);
|
|
};
|
|
|
|
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
|
e.preventDefault();
|
|
|
|
handleStart();
|
|
};
|
|
|
|
return (
|
|
<Modal show={show} onClose={onClose}>
|
|
<header className={styles.header}>
|
|
<h2 className={styles.title}>Sleep Timer</h2>
|
|
<p className={styles.desc}>
|
|
Stop sounds after a certain amount of time.
|
|
</p>
|
|
</header>
|
|
|
|
<form onSubmit={handleSubmit}>
|
|
<div className={styles.controls}>
|
|
<div className={styles.inputs}>
|
|
{!running && (
|
|
<Field label="Hours" value={hours} onChange={setHours} />
|
|
)}
|
|
|
|
{!running && (
|
|
<Field label="Minutes" value={minutes} onChange={setMinutes} />
|
|
)}
|
|
</div>
|
|
|
|
{running ? <Timer displayHours={true} timer={timeLeft} /> : null}
|
|
|
|
<div className={styles.buttons}>
|
|
{running && (
|
|
<button
|
|
className={styles.button}
|
|
type="button"
|
|
onClick={handleReset}
|
|
>
|
|
Reset
|
|
</button>
|
|
)}
|
|
|
|
{!running && (
|
|
<button
|
|
className={cn(styles.button, styles.primary)}
|
|
type="submit"
|
|
>
|
|
Start
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</Modal>
|
|
);
|
|
}
|
|
|
|
interface FieldProps {
|
|
label: string;
|
|
onChange: (value: string) => void;
|
|
value: string;
|
|
}
|
|
|
|
function Field({ label, onChange, value }: FieldProps) {
|
|
return (
|
|
<div className={styles.field}>
|
|
<label className={styles.label} htmlFor={label.toLocaleLowerCase()}>
|
|
{label}
|
|
</label>
|
|
<input
|
|
className={styles.input}
|
|
id={label.toLocaleLowerCase()}
|
|
max="59"
|
|
min="0"
|
|
required
|
|
type="number"
|
|
value={value}
|
|
onChange={e => onChange(e.target.value === '' ? '' : e.target.value)}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|