Skip to content

Commit

Permalink
refactor: use widgets own timer hook
Browse files Browse the repository at this point in the history
  • Loading branch information
DNR500 committed Jul 10, 2024
1 parent f8075fd commit 20525d9
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 13 deletions.
1 change: 0 additions & 1 deletion packages/widget/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@
"react-i18next": "^14.1.2",
"react-intersection-observer": "^9.10.3",
"react-router-dom": "^6.24.0",
"react-timer-hook": "^3.0.7",
"uuid": "^10.0.0",
"viem": "^2.16.2",
"wagmi": "^2.10.7",
Expand Down
3 changes: 1 addition & 2 deletions packages/widget/src/components/Step/StepTimer.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { LiFiStepExtended } from '@lifi/sdk';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import * as reactTimerHook from 'react-timer-hook';
const { useTimer } = reactTimerHook;
import { useTimer } from '../../hooks/timer/useTimer.js';

const getExpiryTimestamp = (step: LiFiStepExtended) =>
new Date(
Expand Down
21 changes: 21 additions & 0 deletions packages/widget/src/hooks/timer/useInterval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useEffect, useRef } from 'react';

export function useInterval(callback: Function, delay: number) {
const callbacRef = useRef<Function>();

// update callback function with current render callback that has access to latest props and state
useEffect(() => {
callbacRef.current = callback;
});

useEffect(() => {
if (!delay) {
return () => {};
}

const interval = setInterval(() => {
callbacRef.current && callbacRef.current();
}, delay);
return () => clearInterval(interval);
}, [delay]);
}
91 changes: 91 additions & 0 deletions packages/widget/src/hooks/timer/useTimer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { useCallback, useState } from 'react';
import { useInterval } from './useInterval.js';
import {
getDelayFromExpiryTimestamp,
getSecondsFromExpiry,
getTimeFromSeconds,
validateOnExpire,
} from './utils.js';

const DEFAULT_DELAY = 1000;

interface UseTimerProps {
expiryTimestamp: Date;
onExpire: Function;
autoStart?: boolean;
}

// This implementation was taken from the common js project - https://www.npmjs.com/package/react-timer-hook
// modified to work in the Widget codebase with Typescript
export function useTimer({
expiryTimestamp: expiry,
onExpire,
autoStart = true,
}: UseTimerProps) {
const [expiryTimestamp, setExpiryTimestamp] = useState(expiry);
const [seconds, setSeconds] = useState(getSecondsFromExpiry(expiryTimestamp));
const [isRunning, setIsRunning] = useState(autoStart);
const [didStart, setDidStart] = useState(autoStart);
const [delay, setDelay] = useState(
getDelayFromExpiryTimestamp(expiryTimestamp, DEFAULT_DELAY),
);

const handleExpire = useCallback(() => {
validateOnExpire(onExpire) && onExpire();
setIsRunning(false);
setDelay(0);
}, [onExpire]);

const pause = useCallback(() => {
setIsRunning(false);
}, []);

const restart = useCallback(
(newExpiryTimestamp: Date, newAutoStart = true) => {
setDelay(getDelayFromExpiryTimestamp(newExpiryTimestamp, DEFAULT_DELAY));
setDidStart(newAutoStart);
setIsRunning(newAutoStart);
setExpiryTimestamp(newExpiryTimestamp);
setSeconds(getSecondsFromExpiry(newExpiryTimestamp));
},
[],
);

const resume = useCallback(() => {
const time = new Date();
time.setMilliseconds(time.getMilliseconds() + seconds * 1000);
restart(time);
}, [seconds, restart]);

const start = useCallback(() => {
if (didStart) {
setSeconds(getSecondsFromExpiry(expiryTimestamp));
setIsRunning(true);
} else {
resume();
}
}, [expiryTimestamp, didStart, resume]);

useInterval(
() => {
if (delay !== DEFAULT_DELAY) {
setDelay(DEFAULT_DELAY);
}
const secondsValue = getSecondsFromExpiry(expiryTimestamp);
setSeconds(secondsValue);
if (secondsValue <= 0) {
handleExpire();
}
},
isRunning ? delay : 0,
);

return {
...getTimeFromSeconds(seconds),
start,
pause,
resume,
restart,
isRunning,
};
}
54 changes: 54 additions & 0 deletions packages/widget/src/hooks/timer/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
export function getTimeFromSeconds(secs: number) {
const totalSeconds = Math.ceil(secs);
const days = Math.floor(totalSeconds / (60 * 60 * 24));
const hours = Math.floor((totalSeconds % (60 * 60 * 24)) / (60 * 60));
const minutes = Math.floor((totalSeconds % (60 * 60)) / 60);
const seconds = Math.floor(totalSeconds % 60);

return {
totalSeconds,
seconds,
minutes,
hours,
days,
};
}

export function getSecondsFromExpiry(expiry: Date, shouldRound?: boolean) {
const now = new Date().getTime();
const milliSecondsDistance = expiry.getTime() - now;
if (milliSecondsDistance > 0) {
const val = milliSecondsDistance / 1000;
return shouldRound ? Math.round(val) : val;
}
return 0;
}

export function validateExpiryTimestamp(expiryTimestamp: Date) {
const isValid = new Date(expiryTimestamp).getTime() > 0;
if (!isValid) {
console.warn('useTimer Invalid expiryTimestamp settings', expiryTimestamp); // eslint-disable-line
}
return isValid;
}

export function validateOnExpire(onExpire: Function) {
const isValid = onExpire && typeof onExpire === 'function';
if (onExpire && !isValid) {
console.warn('useTimer Invalid onExpire settings function', onExpire);
}
return isValid;
}

export function getDelayFromExpiryTimestamp(
expiryTimestamp: Date,
defaultDelay: number,
) {
if (!validateExpiryTimestamp(expiryTimestamp)) {
return 0;
}

const seconds = getSecondsFromExpiry(expiryTimestamp);
const extraMilliSeconds = Math.floor((seconds - Math.floor(seconds)) * 1000);
return extraMilliSeconds > 0 ? extraMilliSeconds : defaultDelay;
}
10 changes: 0 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2668,7 +2668,6 @@ __metadata:
react-i18next: "npm:^14.1.2"
react-intersection-observer: "npm:^9.10.3"
react-router-dom: "npm:^6.24.0"
react-timer-hook: "npm:^3.0.7"
typescript: "npm:^5.5.2"
uuid: "npm:^10.0.0"
viem: "npm:^2.16.2"
Expand Down Expand Up @@ -15368,15 +15367,6 @@ __metadata:
languageName: node
linkType: hard

"react-timer-hook@npm:^3.0.7":
version: 3.0.7
resolution: "react-timer-hook@npm:3.0.7"
peerDependencies:
react: ">=16.8.0"
checksum: 10/36807a32245ca7d840805bc5e727951584cb40304331374b27e7b49ba77e820262ecaac90f6d0f1931991f7c9d3b6050cb89384a446812a4463ce890b1547332
languageName: node
linkType: hard

"react-transition-group@npm:^4.4.5":
version: 4.4.5
resolution: "react-transition-group@npm:4.4.5"
Expand Down

0 comments on commit 20525d9

Please sign in to comment.