Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add timer settings #47

Merged
merged 7 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
},
},
});