diff --git a/src/components/toolbox/countdown-timer/countdown-timer.tsx b/src/components/toolbox/countdown-timer/countdown-timer.tsx
index 613ca15..378066d 100644
--- a/src/components/toolbox/countdown-timer/countdown-timer.tsx
+++ b/src/components/toolbox/countdown-timer/countdown-timer.tsx
@@ -1,5 +1,7 @@
import { Modal } from '@/components/modal';
+import { Form } from './form';
+
interface TimerProps {
onClose: () => void;
show: boolean;
@@ -9,6 +11,7 @@ export function CountdownTimer({ onClose, show }: TimerProps) {
return (
Hello World
+
);
}
diff --git a/src/components/toolbox/countdown-timer/form/field/field.module.css b/src/components/toolbox/countdown-timer/form/field/field.module.css
new file mode 100644
index 0000000..585811f
--- /dev/null
+++ b/src/components/toolbox/countdown-timer/form/field/field.module.css
@@ -0,0 +1,27 @@
+.field {
+ flex-grow: 1;
+
+ & .label {
+ display: block;
+ margin-bottom: 8px;
+ font-size: var(--font-sm);
+ font-weight: 500;
+
+ & .optional {
+ font-weight: 400;
+ color: var(--color-foreground-subtle);
+ }
+ }
+
+ & .input {
+ width: 100%;
+ min-width: 0;
+ height: 40px;
+ padding: 0 16px;
+ color: var(--color-foreground);
+ background-color: var(--color-neutral-50);
+ border: 1px solid var(--color-neutral-200);
+ border-radius: 4px;
+ outline: none;
+ }
+}
diff --git a/src/components/toolbox/countdown-timer/form/field/field.tsx b/src/components/toolbox/countdown-timer/form/field/field.tsx
new file mode 100644
index 0000000..6b057a8
--- /dev/null
+++ b/src/components/toolbox/countdown-timer/form/field/field.tsx
@@ -0,0 +1,51 @@
+import styles from './field.module.css';
+
+interface FieldProps {
+ children?: React.ReactNode;
+ label: string;
+ onChange: (value: string | number) => void;
+ optional?: boolean;
+ type: 'text' | 'select';
+ value: string | number;
+}
+
+export function Field({
+ children,
+ label,
+ onChange,
+ optional,
+ type,
+ value,
+}: FieldProps) {
+ return (
+
+
+
+ {type === 'text' && (
+ onChange(e.target.value)}
+ />
+ )}
+
+ {type === 'select' && (
+
+ )}
+
+ );
+}
diff --git a/src/components/toolbox/countdown-timer/form/field/index.ts b/src/components/toolbox/countdown-timer/form/field/index.ts
new file mode 100644
index 0000000..497b3a7
--- /dev/null
+++ b/src/components/toolbox/countdown-timer/form/field/index.ts
@@ -0,0 +1 @@
+export { Field } from './field';
diff --git a/src/components/toolbox/countdown-timer/form/form.module.css b/src/components/toolbox/countdown-timer/form/form.module.css
new file mode 100644
index 0000000..b6a60ee
--- /dev/null
+++ b/src/components/toolbox/countdown-timer/form/form.module.css
@@ -0,0 +1,28 @@
+.form {
+ display: flex;
+ flex-direction: column;
+ row-gap: 28px;
+
+ & .button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 45px;
+ font-weight: 500;
+ color: var(--color-neutral-50);
+ cursor: pointer;
+ background-color: var(--color-neutral-950);
+ border: none;
+ border-radius: 8px;
+ outline: none;
+ box-shadow: inset 0 -3px 0 var(--color-neutral-700);
+ }
+}
+
+.timeFields {
+ display: flex;
+ column-gap: 12px;
+ align-items: flex-end;
+ justify-content: space-between;
+}
diff --git a/src/components/toolbox/countdown-timer/form/form.tsx b/src/components/toolbox/countdown-timer/form/form.tsx
new file mode 100644
index 0000000..066df86
--- /dev/null
+++ b/src/components/toolbox/countdown-timer/form/form.tsx
@@ -0,0 +1,97 @@
+import { useState, useMemo } from 'react';
+
+import { Field } from './field';
+
+import { useCountdownTimers } from '@/stores/countdown-timers';
+
+import styles from './form.module.css';
+
+export function Form() {
+ const [name, setName] = useState('');
+ const [hours, setHours] = useState(0);
+ const [minutes, setMinutes] = useState(10);
+ const [seconds, setSeconds] = useState(0);
+
+ const totalSeconds = useMemo(
+ () => hours * 60 * 60 + minutes * 60 + seconds,
+ [hours, minutes, seconds],
+ );
+
+ const add = useCountdownTimers(state => state.add);
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+
+ if (totalSeconds === 0) return;
+
+ add({
+ name,
+ total: totalSeconds,
+ });
+
+ setName('');
+ };
+
+ return (
+
+ );
+}
diff --git a/src/components/toolbox/countdown-timer/form/index.ts b/src/components/toolbox/countdown-timer/form/index.ts
new file mode 100644
index 0000000..9398c9e
--- /dev/null
+++ b/src/components/toolbox/countdown-timer/form/index.ts
@@ -0,0 +1 @@
+export { Form } from './form';
diff --git a/src/stores/countdown-timers/index.ts b/src/stores/countdown-timers/index.ts
new file mode 100644
index 0000000..0f44edf
--- /dev/null
+++ b/src/stores/countdown-timers/index.ts
@@ -0,0 +1,107 @@
+import { v4 as uuid } from 'uuid';
+import { create } from 'zustand';
+import { createJSONStorage, persist } from 'zustand/middleware';
+
+interface Timer {
+ id: string;
+ name: string;
+ spent: number;
+ total: number;
+}
+
+interface State {
+ spent: () => number;
+ timers: Array;
+ total: () => number;
+}
+
+interface Actions {
+ add: (timer: { name: string; total: number }) => void;
+ delete: (id: string) => void;
+ getTimer: (id: string) => Timer;
+ rename: (id: string, newName: string) => void;
+ reset: (id: string) => void;
+ tick: (id: string, amount?: number) => void;
+}
+
+export const useCountdownTimers = create()(
+ persist(
+ (set, get) => ({
+ add({ name, total }) {
+ set(state => ({
+ timers: [
+ {
+ id: uuid(),
+ name,
+ spent: 0,
+ total,
+ },
+ ...state.timers,
+ ],
+ }));
+ },
+
+ delete(id) {
+ set(state => ({
+ timers: state.timers.filter(timer => timer.id !== id),
+ }));
+ },
+
+ getTimer(id) {
+ return get().timers.filter(timer => timer.id === id)[0];
+ },
+
+ rename(id, newName) {
+ set(state => ({
+ timers: state.timers.map(timer => {
+ if (timer.id !== id) return timer;
+
+ return { ...timer, name: newName };
+ }),
+ }));
+ },
+
+ reset(id) {
+ set(state => ({
+ timers: state.timers.map(timer => {
+ if (timer.id !== id) return timer;
+
+ return { ...timer, spent: 0 };
+ }),
+ }));
+ },
+
+ spent() {
+ return get().timers.reduce((prev, curr) => prev + curr.spent, 0);
+ },
+
+ tick(id, amount = 1) {
+ set(state => ({
+ timers: state.timers.map(timer => {
+ if (timer.id !== id) return timer;
+
+ const updatedSpent =
+ timer.spent + amount > timer.total
+ ? timer.total
+ : timer.spent + amount;
+
+ return { ...timer, spent: updatedSpent };
+ }),
+ }));
+ },
+
+ timers: [],
+
+ total() {
+ return get().timers.reduce((prev, curr) => prev + curr.total, 0);
+ },
+ }),
+ {
+ name: 'moodist-countdown-timers',
+ partialize: state => ({ timers: state.timers }),
+ skipHydration: true,
+ storage: createJSONStorage(() => localStorage),
+ version: 0,
+ },
+ ),
+);