Skip to content

Commit

Permalink
Add timer settings (#47)
Browse files Browse the repository at this point in the history
* Move pomodoro-status file location

* Add shadcn input component

* Update input source classes

* Add pomodoro timer setting

* Fixed tailwind class order

* WIP: Introduce redux to timer settings

* Handle updating values
* Add reducer
* Handle data in settings modal

* Complete implemention of redux

* Remove unwanted commented out code
  • Loading branch information
Evomatic authored Jan 24, 2024
1 parent edc7701 commit 831a190
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Pomodoro from '@/components/pomodoro/pomodoro';
import Logo from '../components/logo';
import PomodoroStatus from '@/components/pomodoro-status';
import PomodoroStatus from '@/components/pomodoro/pomodoro-status';

export default function Home() {
return (
Expand Down
12 changes: 10 additions & 2 deletions src/components/pomodoro/pomodoro-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@ import { ReactElement, useState } from 'react';
import Image from 'next/image';
import PomodoroColourSettings from '@/components/pomodoro/pomodoro-colour-settings';
import PomodoroFontSettings from '@/components/pomodoro/pomodoro-font-settings';
import PomodoroTimerSettings, { PomodoroTimerData } from './pomodoro-timer-settings';
import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { pomodoroSettingsSlice } from '@/lib/redux/slices/pomodoroSettingsSlice';
import { useDispatch, useSelector } from '@/lib/redux/store';

export default function PomodoroSettings(): ReactElement {
const dispatch = useDispatch();
const { colour, font } = useSelector((state) => state.pomodoroSettings);
const { colour, font, time } = useSelector((state) => state.pomodoroSettings);

const [selectedFont, setSelectedFont] = useState<string>(font);
const [selectedColour, setSelectedColour] = useState<string>(colour);
const [selectedTime, setSelectedTime] = useState<PomodoroTimerData>(time);
const [open, setOpen] = useState<boolean>(false);

const handleFontChange = (font: string) => {
Expand All @@ -26,10 +28,15 @@ export default function PomodoroSettings(): ReactElement {
setSelectedColour(colour);
};

const handleTimeChange = (time: PomodoroTimerData) => {
setSelectedTime(time)
}

const handleApplyNewSettings = () => {
const settings = {
font: selectedFont,
colour: selectedColour,
time: selectedTime
};
dispatch(pomodoroSettingsSlice.actions.updateAllSettings(settings));
setOpen(false);
Expand All @@ -40,10 +47,11 @@ export default function PomodoroSettings(): ReactElement {
<DialogTrigger className="">
<Image src="/icon-settings.svg" width={28} height={28} alt="settings" className="cursor-pointer" />
</DialogTrigger>
<DialogContent className="flex h-[575px] w-[327px] flex-col justify-between dark:bg-settings-background md:h-[540px] md:w-[490px]">
<DialogContent className="flex h-[575px] w-[327px] flex-col justify-between md:h-[540px] md:w-[490px] dark:bg-settings-background">
<DialogHeader>
<DialogTitle>Edit profile</DialogTitle>
</DialogHeader>
<PomodoroTimerSettings onTimerChange={handleTimeChange} />
<PomodoroColourSettings onColourChange={handleColourChange} />
<PomodoroFontSettings onFontChange={handleFontChange} />
<Button onClick={handleApplyNewSettings}>Apply</Button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use client';

import { ReactElement } from 'react';
import { Label } from './ui/label';
import { RadioGroup, RadioGroupItem } from './ui/radio-group';
import { Label } from '../ui/label';
import { RadioGroup, RadioGroupItem } from '../ui/radio-group';
import { PomodoroStatus } from '@/lib/redux/slices/pomodoroStatusSlice';
import { pomodoroStatusSlice } from '@/lib/redux/slices/pomodoroStatusSlice';
import { useSelector, useDispatch, ReduxState } from '@/lib/redux/store';
Expand Down
100 changes: 100 additions & 0 deletions src/components/pomodoro/pomodoro-timer-settings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { ChangeEvent, useState } from 'react';
import { Colours } from '@/lib/colours';
import { ReduxState, useSelector } from '@/lib/redux/store';
import { Input } from '../ui/input';
import { Label } from '../ui/label';

export interface PomodoroTimerData {
pomodoro: number;
shortBreak: number;
longBreak: number;
}

interface PomodoroTimerSettingsProps {
onTimerChange: (updatedTimerData: PomodoroTimerData) => void;
}

export default function PomodoroTimerSettings({ onTimerChange }: PomodoroTimerSettingsProps) {
const { colour, time } = useSelector((state: ReduxState) => state.pomodoroSettings);
const [selectedTime, setSelectedTime] = useState<PomodoroTimerData>(time);
const inputRules = {
min: 5,
max: 60,
step: 5,
};

const updateTimeValues = (callback: (prevSelectedTime: PomodoroTimerData) => Partial<PomodoroTimerData>) => {
const updatedProperties = callback(selectedTime);

setSelectedTime((prevSelectedTime) => ({
...prevSelectedTime,
...updatedProperties,
}));

onTimerChange({ ...selectedTime, ...updatedProperties });
};

const handleTimeChange = (event: ChangeEvent<HTMLInputElement>) => {
const { name, value } = event.target;
updateTimeValues(() => ({ [name]: value }));
};

function setRingOffsetColor(colour: string) {
switch (colour) {
case Colours.SecondaryAqua:
return 'focus:border-secondary-aqua';
case Colours.SecondaryPurple:
return 'focus:border-secondary-purple';
}
return 'focus:border-secondary-peach';
}

return (
<div className="flex flex-col gap-2">
<Label className="pb-3 text-center text-xs font-bold uppercase tracking-[0.4em] md:self-start">
Time (Minutes)
</Label>
<div className="flex flex-col items-center gap-2 md:flex-row">
<div className="flex w-full items-center justify-between md:flex-col md:items-start md:gap-2">
<Label className="text-xs font-bold text-gray-400">pomodoro</Label>
<Input
name="pomodoro"
className={`font-bold ${setRingOffsetColor(colour)}`}
type="number"
onChange={handleTimeChange}
value={selectedTime.pomodoro}
min={inputRules.min}
max={inputRules.max}
step={inputRules.step}
/>
</div>
<div className="flex w-full items-center justify-between md:flex-col md:items-start md:gap-2">
<Label className="text-xs font-bold text-gray-400">short break</Label>
<Input
name="shortBreak"
className={`font-bold ${setRingOffsetColor(colour)}`}
type="number"
onChange={handleTimeChange}
value={selectedTime.shortBreak}
min={inputRules.min}
max={inputRules.max}
step={inputRules.step}
/>
</div>
<div className="flex w-full items-center justify-between md:flex-col md:items-start md:gap-2">
<Label className="text-xs font-bold text-gray-400">long break</Label>
<Input
name="longBreak"
className={`font-bold ${setRingOffsetColor(colour)}`}
type="number"
onChange={handleTimeChange}
value={selectedTime.longBreak}
min={inputRules.min}
max={inputRules.max}
step={inputRules.step}
/>
</div>
</div>
</div>
);
}
12 changes: 6 additions & 6 deletions src/components/pomodoro/pomodoro-timer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import { CircularTimer } from './circular-progress';

export default function PomodoroTimer(): ReactElement {
const { status } = useSelector((state: ReduxState) => state.pomodoroStatus);
const { colour } = useSelector((state: ReduxState) => state.pomodoroSettings);
const { colour, time } = useSelector((state: ReduxState) => state.pomodoroSettings);
const dispatch = useDispatch();

const pomodoroTime = 1500;
const shortBreakTime = 300;
const longBreakTime = 900;
const pomodoroTime = time.pomodoro * 60;
const shortBreakTime = time.shortBreak * 60;
const longBreakTime = time.longBreak * 60;

const intervalId = useRef<number | null>(null);
const [pomodoroCount, setPomodoroCount] = useState<number>(1);
Expand Down Expand Up @@ -76,14 +76,14 @@ import { CircularTimer } from './circular-progress';
setTimeRemaining(longBreakTime);
setIsFocusTime(false);
}
}, [status]);
}, [longBreakTime, pomodoroTime, shortBreakTime, status]);

useEffect(() => {
if (timeRemaining === 0) {
if (intervalId.current !== null) {
clearInterval(intervalId.current);
}
// clearInterval(intervalId.current);

intervalId.current = null;
if (isFocusTime && pomodoroCount == 4) {
dispatch(pomodoroStatusSlice.actions.selectedTimer('long'));
Expand Down
25 changes: 25 additions & 0 deletions src/components/ui/input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as React from "react"

import { cn } from "@/lib/utils"

export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}

const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-10 w-[140px] rounded-lg border bg-on-light-background px-3 py-2 text-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-slate-500 focus-visible:outline-none focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:h-12",
className
)}
ref={ref}
{...props}
/>
)
}
)
Input.displayName = "Input"

export { Input }
4 changes: 4 additions & 0 deletions src/lib/redux/slices/pomodoroSettingsSlice.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { Colours } from '@/lib/colours';
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { PomodoroTimerData } from '@/components/pomodoro/pomodoro-timer-settings';

interface PomodoroSettingsSliceState {
font: string;
colour: string;
time: PomodoroTimerData;
}

const InitialSettingsState: PomodoroSettingsSliceState = {
font: 'font-kumbh',
colour: Colours.SecondaryPeach,
time: { pomodoro: 25, shortBreak: 5, longBreak: 15 }
};

export const pomodoroSettingsSlice = createSlice({
Expand All @@ -24,6 +27,7 @@ export const pomodoroSettingsSlice = createSlice({
updateAllSettings: (state, action: PayloadAction<PomodoroSettingsSliceState>) => {
state.font = action.payload.font;
state.colour = action.payload.colour;
state.time = action.payload.time;
},
},
});

0 comments on commit 831a190

Please sign in to comment.