Skip to content

Commit ecc75a1

Browse files
committed
Chore: refactor and explain
1 parent 2c158fe commit ecc75a1

File tree

3 files changed

+73
-143
lines changed

3 files changed

+73
-143
lines changed

web/src/routes/manage/[id]/+page.svelte

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,23 @@
1111
faPlay,
1212
faRefresh
1313
} from '@fortawesome/free-solid-svg-icons';
14-
import { calculateNewStartAt, updateTimer, type TimerAction } from './helpers';
14+
import {
15+
updateTimer,
16+
calculateStartTimeAfterResume,
17+
calculateStartTimeAfterSkip
18+
} from './helpers';
1519
import type { Timer } from 'types/timer';
1620
import { ProgressRadial } from '@skeletonlabs/skeleton';
1721
1822
export let data: PageData;
1923
let { timerData } = data;
2024
let submitResult: Promise<Timer | void> = Promise.resolve();
2125
22-
const handleButton = (action: TimerAction) => {
23-
console.log('button submit', action);
24-
const start_at = calculateNewStartAt(timerData.segments, timerData, action);
25-
const stop_at = action === 'stop' ? new Date().getTime() : undefined;
26+
const _updateTimer = (start_at?: number, stop_at?: number) => {
27+
if (!start_at) {
28+
start_at = timerData.start_at;
29+
}
30+
2631
const newTimer = {
2732
...timerData,
2833
start_at: start_at,
@@ -35,6 +40,22 @@
3540
});
3641
};
3742
43+
const restartTimer = () => {
44+
_updateTimer(new Date().getTime());
45+
};
46+
47+
const stopTimer = () => {
48+
_updateTimer(undefined, new Date().getTime());
49+
};
50+
51+
const resumeTimer = () => {
52+
_updateTimer(calculateStartTimeAfterResume(timerData), undefined);
53+
};
54+
55+
const skipCurrentSegment = () => {
56+
_updateTimer(calculateStartTimeAfterSkip(timerData));
57+
};
58+
3859
$: timerData = data.timerData;
3960
</script>
4061

@@ -47,35 +68,22 @@
4768
<div class="flex items-center justify-center">
4869
<ProgressRadial class="w-10" />
4970
</div>
50-
{:then result}
51-
{#if result}
52-
<aside class="alert variant-ghost-success">
53-
<Fa icon={faCircleCheck} class="text-2xl" />
54-
<h3 class="alert-message">Success</h3>
55-
<button
56-
class="btn-icon"
57-
on:click={() => {
58-
submitResult = Promise.resolve();
59-
}}><Fa icon={faClose} /></button
60-
>
61-
</aside>
62-
{/if}
63-
71+
{:then}
6472
<div class="grid grid-cols-1 md:grid-cols-3 gap-3 pb-4">
65-
<button class="btn variant-filled-primary p-4" on:click={() => handleButton('restart')}>
73+
<button class="btn variant-filled-primary p-4" on:click={restartTimer}>
6674
<span><Fa icon={faRefresh} /></span><span>Restart</span>
6775
</button>
6876

69-
<button class="btn variant-filled-primary p-4" on:click={() => handleButton('skip')}>
77+
<button class="btn variant-filled-primary p-4" on:click={skipCurrentSegment}>
7078
<span><Fa icon={faForward} /></span><span>Skip current segment</span>
7179
</button>
7280

7381
{#if timerData.stop_at}
74-
<button class="btn variant-filled-tertiary p-4" on:click={() => handleButton('resume')}>
82+
<button class="btn variant-filled-tertiary p-4" on:click={resumeTimer}>
7583
<span><Fa icon={faPlay} /></span><span>Resume</span>
7684
</button>
7785
{:else}
78-
<button class="btn variant-filled-primary p-4" on:click={() => handleButton('stop')}>
86+
<button class="btn variant-filled-primary p-4" on:click={stopTimer}>
7987
<span><Fa icon={faPause} /></span><span>Pause</span>
8088
</button>
8189
{/if}

web/src/routes/manage/[id]/edit/TimerForm.svelte

Lines changed: 22 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import HelpPopup from 'components/HelpPopup.svelte';
1919
import SegmentInfoBox from './SegmentInfoBox.svelte';
2020
import { slide } from 'svelte/transition';
21-
import { calculateNewStartAt, type TimerAction } from '../helpers';
2221
2322
interface TimerFormData {
2423
start_at_date: string;
@@ -37,15 +36,8 @@
3736
let formData: TimerFormData;
3837
let editingSegment: number | undefined = undefined;
3938
40-
const handleSubmit = (e: Event) => {
41-
e.preventDefault();
42-
};
43-
44-
const handleButtonSubmit = (action: TimerAction) => {
45-
console.log('button submit', action);
46-
return () => {
47-
onSubmit(formDataToTimerData(formData, action));
48-
};
39+
const handleSubmit = () => {
40+
onSubmit(formDataToTimerData(formData));
4941
};
5042
5143
const timerDataToFormData = (timerData: Timer): TimerFormData => {
@@ -66,42 +58,9 @@
6658
};
6759
};
6860
69-
/**
70-
* This function calculates the new start_at
71-
* It behaves differently depending on the action:
72-
* - save: if the segments haven't changed, the start_at time is not changed
73-
* if the segments have changed, the start_at time is adjusted to make sure the timer is in the same state as before
74-
* - restart: the start_at time is set to the current time
75-
* - stop: the start_at time is not changed
76-
* - resume: the start_at time is adjusted to make sure the timer is in the same state as before
77-
*/
78-
const calculateStartAt = (
79-
formData: TimerFormData,
80-
formSegments: Segment[],
81-
action: TimerAction
82-
): number => {
83-
if (action === 'restart') {
84-
return new Date().getTime();
85-
}
86-
87-
const formDataStartedAt = new Date(
88-
`${formData.start_at_date} ${formData.start_at_time}`
89-
).getTime();
90-
if (formDataStartedAt > new Date().getTime()) {
91-
return formDataStartedAt;
92-
}
93-
94-
return calculateNewStartAt(formSegments, timerData, action);
95-
};
96-
97-
const formDataToTimerData = (formData: TimerFormData, action: TimerAction): Timer => {
98-
const start_at = calculateStartAt(formData, formData.segments, action);
99-
const stop_at = action === 'stop' ? new Date().getTime() : undefined;
100-
61+
const formDataToTimerData = (formData: TimerFormData): Timer => {
10162
return {
102-
id: timerData.id,
103-
start_at: start_at,
104-
stop_at: stop_at,
63+
...timerData,
10564
repeat: formData.repeat,
10665
segments: formData.segments,
10766
display_options: {
@@ -127,7 +86,7 @@
12786
<a href="/manage/{timerData.id}" class="btn variant-glass-primary mb-3"
12887
><Fa icon={faArrowLeft} />&nbsp; back to overview</a
12988
>
130-
<form class="w-full grid gap-3" on:submit={handleSubmit}>
89+
<form class="w-full grid gap-3" on:submit|preventDefault>
13190
{#if timerData.stop_at}
13291
<aside class="alert variant-ghost-warning">
13392
<Fa icon={faPauseCircle} class="text-2xl" />
@@ -252,7 +211,17 @@
252211
</div>
253212
</SlideToggle>
254213

255-
<strong>When to start the timer:</strong>
214+
<div class="flex items-center gap-2">
215+
<strong>When to start the timer:</strong>
216+
<HelpPopup>
217+
The time when the
218+
{#if formData.repeat}
219+
first iteration of the timer will begin
220+
{:else}
221+
the timer will be started
222+
{/if}. The start time will be modified if you restart, pause, resume or skip a segment.
223+
</HelpPopup>
224+
</div>
256225

257226
<div class="grid grid-cols-2 gap-3">
258227
<input
@@ -270,16 +239,14 @@
270239
bind:value={formData.start_at_time}
271240
required
272241
/>
273-
<div class="col-span-2 flex items-center gap-2">
274-
<p>This field will only be used if the selected time is in the future.</p>
275-
<HelpPopup>
276-
... otherwise, the field will be adjusted to preserve the current state of the timer or
277-
restart it.
278-
</HelpPopup>
279-
</div>
280242
</div>
281243

282-
<button class="btn variant-filled-secondary" on:click={handleButtonSubmit('save')}>
244+
<p>
245+
<b class="text-[#F59D30]">Warning:</b> if you have modified any times in the sequence, the
246+
current time on the timer <b class="text-[#E01B24]">WILL CHANGE</b> as soon as you save!
247+
</p>
248+
249+
<button class="btn variant-filled-secondary" on:click={handleSubmit}>
283250
<span><Fa icon={faSave} /></span><span>Save</span>
284251
</button>
285252
</form>

web/src/routes/manage/[id]/helpers.ts

Lines changed: 20 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4,80 +4,35 @@ import { get } from 'svelte/store';
44
import type { Fetch } from 'types/fetch';
55
import type { Segment } from 'types/segment';
66
import type { Timer, TimerUpdateRequest } from 'types/timer';
7-
import { calculateTimeInCurrentRound, calculateTimeInCurrentSegment } from 'utils/timer';
7+
import {
8+
calculateTimeInCurrentRound,
9+
calculateTimeInCurrentSegment,
10+
getTimerText
11+
} from 'utils/timer';
812

9-
export type TimerAction = 'save' | 'restart' | 'stop' | 'resume' | 'skip';
10-
11-
/**
12-
* This function calculates the new start_at
13-
* It behaves differently depending on the action:
14-
* - save: if the segments haven't changed, the start_at time is not changed
15-
* if the segments have changed, the start_at time is adjusted to make sure the timer is in the same state as before
16-
* - restart: the start_at time is set to the current time
17-
* - stop: the start_at time is not changed
18-
* - resume: the start_at time is adjusted to make sure the timer is in the same state as before
19-
*/
20-
export const calculateNewStartAt = (
21-
newSegments: Segment[],
22-
oldTimerData: Timer,
23-
action: TimerAction
24-
): number => {
25-
if (action === 'restart') {
26-
return new Date().getTime();
13+
export const calculateStartTimeAfterResume = (timerData: Timer) => {
14+
if (!timerData.stop_at) {
15+
return timerData.start_at;
2716
}
2817

29-
const timeInAnySegmentChanged =
30-
newSegments.length == oldTimerData.segments.length &&
31-
newSegments.some((segment, index) => {
32-
return segment.time !== oldTimerData.segments[index].time;
33-
});
34-
35-
if (action === 'save' && !timeInAnySegmentChanged) {
36-
return oldTimerData.start_at;
37-
}
18+
const timeElapsedBeforeStop = timerData.stop_at - timerData.start_at;
19+
const currentTime = new Date().getTime();
20+
return currentTime - timeElapsedBeforeStop;
21+
};
3822

39-
let currentTime = new Date().getTime();
40-
if (action === 'resume') {
41-
currentTime = oldTimerData.stop_at!;
23+
export const calculateStartTimeAfterSkip = (timerData: Timer) => {
24+
const currentTime = new Date().getTime();
25+
const { timeInCurrentRound, state } = calculateTimeInCurrentRound(timerData, currentTime);
26+
if (state != 'running') {
27+
return timerData.start_at;
4228
}
4329

44-
const { timeInCurrentRound } = calculateTimeInCurrentRound(oldTimerData, currentTime);
45-
const { timeInCurrentSegment, currentSegment } = calculateTimeInCurrentSegment(
30+
const { timeInCurrentSegment } = calculateTimeInCurrentSegment(
4631
timeInCurrentRound,
47-
oldTimerData.segments
48-
);
49-
const currentSegmentIndex = oldTimerData.segments.indexOf(currentSegment);
50-
51-
// find new segment with the same label
52-
let newSegment = newSegments.find(
53-
(segment) =>
54-
segment.label === currentSegment.label &&
55-
(timeInAnySegmentChanged || segment.time === currentSegment.time)
32+
timerData.segments
5633
);
57-
if (!newSegment && newSegments.length > currentSegmentIndex) {
58-
newSegment = newSegments[currentSegmentIndex];
59-
} else if (!newSegment) {
60-
return new Date().getTime();
61-
}
62-
63-
// calculate time before new segment
64-
const newSegmentIndex = newSegments.indexOf(newSegment);
65-
let timeBeforeNewSegment = 0;
66-
for (let i = 0; i < newSegmentIndex; i++) {
67-
timeBeforeNewSegment += newSegments[i].time;
68-
}
69-
70-
if (action === 'skip') {
71-
console.log({ timeBeforeNewSegment, newSegmentIndex, time: newSegments[newSegmentIndex] });
72-
return new Date().getTime() - timeBeforeNewSegment - newSegments[newSegmentIndex].time;
73-
}
74-
75-
// calculate time in new segment
76-
const timeInNewSegment =
77-
timeInCurrentSegment > newSegment.time ? 0 : newSegment.time - timeInCurrentSegment;
7834

79-
// calculate new start_at
80-
return new Date().getTime() - timeBeforeNewSegment - timeInNewSegment;
35+
return timerData.start_at - timeInCurrentSegment;
8136
};
8237

8338
export const getTimer = async (id: string, fetch: Fetch) => {

0 commit comments

Comments
 (0)