Skip to content

Commit f22dd72

Browse files
committed
Merge branch 'development' into aseem-application-jobposting-avghours
2 parents 89b019a + 1830420 commit f22dd72

3 files changed

Lines changed: 85 additions & 23 deletions

File tree

src/components/Timer/Countdown.jsx

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -57,19 +57,51 @@ export default function Countdown({
5757
const hourRef = useRef(null);
5858
const minRef = useRef(null);
5959

60-
const remainingHours = moment.duration(remaining).hours();
61-
const remainingMinutes = moment.duration(remaining).minutes();
62-
const remainingSeconds = moment.duration(remaining).seconds();
60+
const remainingDuration = moment.duration(remaining);
61+
const remainingHours = Math.floor(remainingDuration.asHours());
62+
const remainingMinutes = remainingDuration.minutes();
63+
const remainingSeconds = remainingDuration.seconds();
6364

6465
const remainingHoursDisplay = remainingHours.toString().padStart(2, '0');
6566
const remainingMinutesDisplay = remainingMinutes.toString().padStart(2, '0');
6667
const remainingSecondsDisplay = remainingSeconds.toString().padStart(2, '0');
6768

69+
const goalDuration = moment.duration(goal);
70+
const goalHoursDisplay = Math.floor(goalDuration.asHours()).toString();
71+
const goalMinutesDisplay = goalDuration
72+
.minutes()
73+
.toString()
74+
.padStart(2, '0');
75+
const goalSecondsDisplay = goalDuration
76+
.seconds()
77+
.toString()
78+
.padStart(2, '0');
79+
80+
const elapsedMs = Math.max(goal - remaining, 0);
81+
const elapsedDuration = moment.duration(elapsedMs);
82+
const elapsedHoursDisplay = Math.floor(elapsedDuration.asHours()).toString();
83+
const elapsedMinutesDisplay = elapsedDuration
84+
.minutes()
85+
.toString()
86+
.padStart(2, '0');
87+
const elapsedSecondsDisplay = elapsedDuration
88+
.seconds()
89+
.toString()
90+
.padStart(2, '0');
91+
6892
const shouldDisplay = {
6993
hour: true,
7094
minute: true,
7195
};
7296

97+
const minGoalMs = MIN_MINS * 60 * 1000;
98+
const maxGoalMs = MAX_HOURS * 60 * 60 * 1000;
99+
100+
const canSubtract15 = goal - 15 * 60 * 1000 >= minGoalMs;
101+
const canAdd15 = goal + 15 * 60 * 1000 <= maxGoalMs && checkBtnAvail(15);
102+
const canAdd30 = goal + 30 * 60 * 1000 <= maxGoalMs && checkBtnAvail(30);
103+
const canAdd60 = goal + 60 * 60 * 1000 <= maxGoalMs && checkBtnAvail(60);
104+
73105
const forceMinMax = (event, ref) => {
74106
const { value, min, max } = event.target;
75107
const updatedValue = Math.max(Number(min), Math.min(Number(max), Number(value)));
@@ -120,8 +152,8 @@ export default function Countdown({
120152
}
121153
};
122154

123-
const handleInitialMinuteChange = amout => {
124-
const newMin = initialMinutes + amout;
155+
const handleInitialMinuteChange = amount => {
156+
const newMin = initialMinutes + amount;
125157
switch (true) {
126158
case initialHours === 0 && newMin < MIN_MINS:
127159
toast.error(`Timer cannot be set less than ${MIN_MINS} minutes!`);
@@ -150,15 +182,12 @@ export default function Countdown({
150182
onClick={toggleTimer}
151183
title="close timer dropdown"
152184
/>
185+
153186
<div className={css.infoDisplay}>
154-
<h4>{`Goal: ${moment.utc(goal).format('HH:mm:ss')}`}</h4>
155-
<h6>
156-
{`Elapsed: ${moment
157-
.utc(goal)
158-
.subtract(remaining)
159-
.format('HH:mm:ss')}`}
160-
</h6>
187+
<h4>{`Goal: ${goalHoursDisplay}:${goalMinutesDisplay}:${goalSecondsDisplay}`}</h4>
188+
<h6>{`Elapsed: ${elapsedHoursDisplay}:${elapsedMinutesDisplay}:${elapsedSecondsDisplay}`}</h6>
161189
</div>
190+
162191
<div className={css.countdownCircle}>
163192
<CircularProgressbarWithChildren
164193
value={started ? (moment.duration(remaining).asMilliseconds() / goal) * 100 : 100}
@@ -181,7 +210,9 @@ export default function Countdown({
181210
title="Reset timer"
182211
/>
183212
)}
213+
184214
<span>Time Remaining</span>
215+
185216
<div className={css.remainingTime}>
186217
{shouldDisplay.hour && (
187218
<>
@@ -192,6 +223,7 @@ export default function Countdown({
192223
<div className={css.timeColon}>:</div>
193224
</>
194225
)}
226+
195227
{shouldDisplay.minute && (
196228
<>
197229
<div>
@@ -201,11 +233,13 @@ export default function Countdown({
201233
<div className={css.timeColon}>:</div>
202234
</>
203235
)}
236+
204237
<div>
205238
<div className={css.timeDisplay}>{remainingSecondsDisplay}</div>
206239
<div className={css.label}>seconds</div>
207240
</div>
208241
</div>
242+
209243
<div className={css.operators}>
210244
{running ? (
211245
<button type="button" onClick={sendPause} aria-label="Pause timer">
@@ -228,6 +262,7 @@ export default function Countdown({
228262
/>
229263
</button>
230264
)}
265+
231266
{started && (
232267
<button
233268
type="button"
@@ -245,40 +280,48 @@ export default function Countdown({
245280
</div>
246281
</CircularProgressbarWithChildren>
247282
</div>
283+
248284
<div className={css.bottom}>
249285
{started ? (
250286
<div className={cs(css.addGrid, css.transitionColor)}>
251287
<button
252288
size="sm"
253289
type="button"
254290
aria-label="remove 15 minutes"
255-
onClick={() => handleSubtractButton(15)}
291+
onClick={() => canSubtract15 && handleSubtractButton(15)}
292+
disabled={!canSubtract15}
256293
>
257-
<span className={cs(css.btn, checkBtnAvail(-15) ? '' : css.btnDisabled)}>-15 m</span>
294+
<span className={cs(css.btn, canSubtract15 ? '' : css.btnDisabled)}>-15 m</span>
258295
</button>
296+
259297
<button
260298
size="sm"
261299
type="button"
262300
aria-label="add 15 minutes"
263-
onClick={() => handleAddButton(15)}
301+
onClick={() => canAdd15 && handleAddButton(15)}
302+
disabled={!canAdd15}
264303
>
265-
<span className={cs(css.btn, checkBtnAvail(15) ? '' : css.btnDisabled)}>+15 m</span>
304+
<span className={cs(css.btn, canAdd15 ? '' : css.btnDisabled)}>+15 m</span>
266305
</button>
306+
267307
<button
268308
size="sm"
269309
type="button"
270310
aria-label="add 30 minutes"
271-
onClick={() => handleAddButton(30)}
311+
onClick={() => canAdd30 && handleAddButton(30)}
312+
disabled={!canAdd30}
272313
>
273-
<span className={cs(css.btn, checkBtnAvail(30) ? '' : css.btnDisabled)}>+30 m</span>
314+
<span className={cs(css.btn, canAdd30 ? '' : css.btnDisabled)}>+30 m</span>
274315
</button>
316+
275317
<button
276318
size="sm"
277319
type="button"
278320
aria-label="add 1 hour"
279-
onClick={() => handleAddButton(60)}
321+
onClick={() => canAdd60 && handleAddButton(60)}
322+
disabled={!canAdd60}
280323
>
281-
<span className={cs(css.btn, checkBtnAvail(60) ? '' : css.btnDisabled)}>+1 h</span>
324+
<span className={cs(css.btn, canAdd60 ? '' : css.btnDisabled)}>+1 h</span>
282325
</button>
283326
</div>
284327
) : (
@@ -292,6 +335,7 @@ export default function Countdown({
292335
onClick={() => handleInitialHourChange(1)}
293336
/>
294337
)}
338+
295339
<Input
296340
type="number"
297341
className={editing ? css.editing : ''}
@@ -302,14 +346,17 @@ export default function Countdown({
302346
disabled={!editing}
303347
innerRef={hourRef}
304348
/>
349+
305350
{editing && (
306351
<FaAngleDown
307352
className={cs(css.transitionColor, css.down)}
308353
onClick={() => handleInitialHourChange(-1)}
309354
/>
310355
)}
311356
</div>
357+
312358
<span className={css.timeColon}>:</span>
359+
313360
<div className={css.numberWrapper}>
314361
{editing && (
315362
<FaAngleUp
@@ -319,6 +366,7 @@ export default function Countdown({
319366
}
320367
/>
321368
)}
369+
322370
<Input
323371
type="number"
324372
min={0}
@@ -330,6 +378,7 @@ export default function Countdown({
330378
disabled={!editing}
331379
innerRef={minRef}
332380
/>
381+
333382
{editing && (
334383
<FaAngleDown
335384
className={cs(css.transitionColor, css.down)}
@@ -341,6 +390,7 @@ export default function Countdown({
341390
/>
342391
)}
343392
</div>
393+
344394
{editing ? (
345395
<FaSave
346396
className={cs(css.transitionColor, css.goalBtn)}

src/components/Timer/Timer.jsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,18 @@ function Timer({ authUser, darkMode, isPopout }) {
125125

126126
const sendJsonMessageNoQueue = useCallback(msg => sendJsonMessage(msg, false), [sendMessage]);
127127

128+
const previewDuration = moment.duration(remaining);
129+
const previewHoursDisplay = Math.floor(previewDuration.asHours()).toString();
130+
const previewMinutesDisplay = previewDuration
131+
.minutes()
132+
.toString()
133+
.padStart(2, '0');
134+
const previewSecondsDisplay = previewDuration
135+
.seconds()
136+
.toString()
137+
.padStart(2, '0');
138+
const previewTimeDisplay = `${previewHoursDisplay}:${previewMinutesDisplay}:${previewSecondsDisplay}`;
139+
128140
// Enhanced function to clear submitted time with better logging
129141
const clearSubmittedTime = useCallback(() => {
130142
console.log(' Clearing submitted time - Timer reset or user change detected');
@@ -913,7 +925,7 @@ function Timer({ authUser, darkMode, isPopout }) {
913925
className={css.preview}
914926
onClick={toggleTimer}
915927
>
916-
{moment.utc(remaining).format('HH:mm:ss')}
928+
{previewTimeDisplay}
917929
</button>
918930
) : (
919931
<div className={css.disconnected}>Disconnected</div>

src/components/Timer/__test__/Countdown.test.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ describe('Countdown Component', () => {
3333
it('renders the countdown component with the correct initial values', () => {
3434
// eslint-disable-next-line react/jsx-props-no-spreading
3535
render(<Countdown {...defaultProps} />);
36-
expect(screen.getByText('Goal: 01:00:00')).toBeInTheDocument();
37-
expect(screen.getByText('Elapsed: 00:30:00')).toBeInTheDocument();
36+
expect(screen.getByText('Goal: 1:00:00')).toBeInTheDocument();
37+
expect(screen.getByText('Elapsed: 0:30:00')).toBeInTheDocument();
3838
expect(screen.getByText('Time Remaining')).toBeInTheDocument();
3939
expect(screen.getAllByText('00')).toHaveLength(2);
4040
expect(screen.getByText('30')).toBeInTheDocument();

0 commit comments

Comments
 (0)