Skip to content

Commit

Permalink
Merge branch 'next-release'
Browse files Browse the repository at this point in the history
  • Loading branch information
mucahit committed Feb 22, 2022
2 parents d911a0a + 123025a commit 5c9fe64
Show file tree
Hide file tree
Showing 9 changed files with 37,121 additions and 87 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ Here is a simple example that shows how to customize `Button` and `Input`

Minimum system versions

- `node >= 12.x`
- `npm >= 6.x`
- `node >= 14.x`
- `npm >= 7.x`

You can start to development with `npm run dev` command. The command watches for changes and builds the toolkit. If you want to generate a production ready build you can use `npm run build`.

Expand Down
37,077 changes: 37,038 additions & 39 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hipo/react-ui-toolkit",
"version": "1.0.0-alpha.5.2.0",
"version": "1.0.0-alpha.5.2.1",
"description": "React based UI toolkit.",
"main": "dist/index.js",
"scripts": {
Expand Down
56 changes: 39 additions & 17 deletions src/core/utils/hooks/useDateTimer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,56 @@ import {useEffect, useRef, useState, useLayoutEffect} from "react";
import {SECOND_IN_MS} from "../time/timeConstants";
import {RemainingTimeBreakdown} from "../time/timeTypes";
import {calculateRemainingTimeBreakdown} from "../time/timeUtils";
import {TimerType} from "../../../date-timer/util/dateTimerTypes";
import {DateTimerProps, TimerType} from "../../../date-timer/util/dateTimerTypes";

/**
* A React Hook that provides a date timer
* @param {Date[]} range - The target date range we're counting down to
* @param {number} cadence - The rate of the timer in milliseconds
* @param {TimerType} timerType - Type of the timer, either "down" or "up"
* @param {Date[]} options.range - The target date range we're counting down to
* @param {number} options.cadence - The rate of the timer in milliseconds
* @param {TimerType} options.timerType - Type of the timer, either "down" or "up"
* @param {onEnd} options.onEnd - If provided, runs this callback when the timer ended
* @returns {object} The RemainingTimeBreakdown object
*/
function useDateTimer(
range: Date[],
function useDateTimer({
range,
cadence = SECOND_IN_MS,
timerType = "down" as TimerType
): RemainingTimeBreakdown {
const cadenceInMs = cadence * SECOND_IN_MS;
const [counter, setCounter] = useState(0);
timerType = "down",
onEnd
}: {
range: DateTimerProps["range"];
cadence?: number;
timerType?: TimerType;
onEnd?: DateTimerProps["onEnd"];
}): RemainingTimeBreakdown {
const counterForIntervalRef = useRef(0);
const interval = useRef<NodeJS.Timeout>();
const [dateTimer, setDateTimer] = useState<RemainingTimeBreakdown>(
calculateRemainingTimeBreakdown(range, counter, timerType)
calculateRemainingTimeBreakdown(range, counterForIntervalRef.current, timerType)
);
const [rangeStart, rangeEnd] = range;

const savedOnEndCallback = useRef<typeof onEnd>();

useLayoutEffect(() => {
savedOnEndCallback.current = onEnd;
}, [onEnd]);

useLayoutEffect(() => {
interval.current = setInterval(() => {
if (range.length > 1) {
setCounter(counter + cadence);
if (rangeEnd) {
counterForIntervalRef.current += cadence;
}

const data = calculateRemainingTimeBreakdown(range, counter, timerType);
const data = calculateRemainingTimeBreakdown(
[rangeStart, rangeEnd],
counterForIntervalRef.current,
timerType
);

if (data.delta >= 0) {
if (data.delta >= SECOND_IN_MS) {
setDateTimer(data);
} else {
clearInterval(interval.current!);
setDateTimer({
delta: 0,
days: 0,
Expand All @@ -43,16 +61,20 @@ function useDateTimer(
seconds: 0
});
}
}, cadenceInMs);
}, cadence);

return () => {
clearInterval(interval.current!);
};
}, [cadence, cadenceInMs, range, counter, timerType]);
}, [cadence, rangeStart, rangeEnd, timerType]);

useEffect(() => {
if (dateTimer.delta <= 0) {
clearInterval(interval.current!);

if (savedOnEndCallback.current) {
savedOnEndCallback.current();
}
}
}, [dateTimer.delta]);

Expand Down
13 changes: 8 additions & 5 deletions src/core/utils/time/timeUtils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {TimerType} from "../../../date-timer/util/dateTimerTypes";
import {DateTimerProps, TimerType} from "../../../date-timer/util/dateTimerTypes";
import {
DAY_IN_HRS,
DAY_IN_S,
Expand All @@ -15,20 +15,23 @@ function sortDateRange(initialRange: Date[]): Date[] {
}

function calculateRemainingTimeBreakdown(
range: Date[],
range: DateTimerProps["range"],
intervalCount = 0,
timerType = "down" as TimerType
): RemainingTimeBreakdown {
let originDate = new Date();
let targetDate = range[0];
let originDate;
let targetDate;

if (range.length > 1 || timerType === "up") {
[originDate, targetDate] = sortDateRange([range[0], range[1] || new Date()]);
} else {
targetDate = range[0];
originDate = new Date();
}

const delta = targetDate.getTime() - originDate.getTime();

const deltaInSeconds = delta / SECOND_IN_MS - intervalCount;
const deltaInSeconds = (delta - intervalCount) / SECOND_IN_MS;

return {
delta,
Expand Down
21 changes: 8 additions & 13 deletions src/date-timer/DateTimer.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import "./_date-timer.scss";

import React, {useEffect, useLayoutEffect, useRef} from "react";
import React, {useEffect} from "react";
import classNames from "classnames";

import useDateTimer from "../core/utils/hooks/useDateTimer";
Expand All @@ -9,6 +9,7 @@ import ListItem from "../list/item/ListItem";
import {generateDateTimerItems} from "./util/dateTimerUtils";
import {DateTimerProps} from "./util/dateTimerTypes";
import {sortDateRange} from "../core/utils/time/timeUtils";
import {SECOND_IN_MS} from "../core/utils/time/timeConstants";

function DateTimer({
testid,
Expand All @@ -20,9 +21,13 @@ function DateTimer({
onEnd,
customClassName
}: DateTimerProps) {
const dateTimerData = useDateTimer(range, timerInterval, timerType);
const dateTimerData = useDateTimer({
range,
cadence: timerInterval * SECOND_IN_MS,
timerType,
onEnd
});
const items = generateDateTimerItems({titleMap, alwaysShowSeconds}, dateTimerData);
const savedOnEndCallback = useRef<DateTimerProps["onEnd"]>();

// Validate the `range` prop according to the `timerType` prop
useEffect(() => {
Expand All @@ -37,16 +42,6 @@ function DateTimer({
}
}, [range, timerType]);

useLayoutEffect(() => {
savedOnEndCallback.current = onEnd;
}, [onEnd]);

useLayoutEffect(() => {
if (dateTimerData.delta <= 0 && savedOnEndCallback.current) {
savedOnEndCallback.current();
}
}, [dateTimerData.delta]);

return (
<List
customClassName={classNames("date-timer", customClassName)}
Expand Down
13 changes: 4 additions & 9 deletions src/date-timer/util/dateTimerTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@ import {RemainingTimeBreakdown} from "../../core/utils/time/timeTypes";

export type TimerType = "down" | "up";

export type DateTimerItemID = keyof Omit<RemainingTimeBreakdown, "delta">;

export interface DateTimerProps {
range: Date[];
range: [Date, Date?];
testid?: string;
titleMap?: {
day?: string;
hour?: string;
minute?: string;
second?: string;
};
titleMap?: Record<DateTimerItemID, undefined | string>;

timerInterval?: number /* in seconds */;
timerType?: TimerType;
Expand All @@ -20,8 +17,6 @@ export interface DateTimerProps {
customClassName?: string;
}

export type DateTimerItemID = keyof Omit<RemainingTimeBreakdown, "delta">;

export interface DateTimerItem {
id: DateTimerItemID;
title: string;
Expand Down
2 changes: 1 addition & 1 deletion src/date-timer/util/dateTimerUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function generateDateTimerItems(
id: key,
// eslint-disable-next-line no-magic-numbers
count: dateTimerData[key].toString().padStart(2, "0"),
title: (titleMap ? titleMap[key.replace("s", "")] : undefined) || key
title: (titleMap ? titleMap[key] : undefined) || key
}));
}

Expand Down
20 changes: 20 additions & 0 deletions stories/15-DateTimer.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ storiesOf("DateTimer", module).add("DateTimer", () => (
onEnd={handleDateTimerEnd}
/>

<DateTimer
range={[calculateFutureDate(1, "day"), calculateFutureDate(3, "day")]}
titleMap={{
days: "d",
hours: "h",
minutes: "m",
seconds: "s"
}}
alwaysShowSeconds={true}
onEnd={handleDateTimerEnd}
/>

<hr />

<span>{"Since `Jan 10 2022` - timerType=`up`"}</span>
Expand Down Expand Up @@ -57,6 +69,14 @@ storiesOf("DateTimer", module).add("DateTimer", () => (
<span>{"10 Seconds Later"}</span>

<DateTimer range={[calculateFutureDate(10, "second")]} onEnd={handleDateTimerEnd} />

<span>{"10 Seconds Later with 5s timer interval"}</span>

<DateTimer
range={[calculateFutureDate(10, "second")]}
onEnd={handleDateTimerEnd}
timerInterval={5}
/>
</StoryFragment>
));

Expand Down

0 comments on commit 5c9fe64

Please sign in to comment.