Be smarter about updating timeago

This commit is contained in:
Nicolas Mowen 2024-02-26 13:58:33 -07:00
parent aa12244425
commit a79a89d855

View File

@ -8,7 +8,7 @@ interface IProp {
/** OPTIONAL: boolean that determines whether to show the time-ago text in dense format */ /** OPTIONAL: boolean that determines whether to show the time-ago text in dense format */
dense?: boolean; dense?: boolean;
/** OPTIONAL: set custom refresh interval in milliseconds, default 1000 (1 sec) */ /** OPTIONAL: set custom refresh interval in milliseconds, default 1000 (1 sec) */
refreshInterval?: number; manualRefreshInterval?: number;
} }
type TimeUnit = { type TimeUnit = {
@ -17,24 +17,28 @@ type TimeUnit = {
value: number; value: number;
}; };
const timeAgo = ({ time, currentTime = new Date(), dense = false }: IProp): string => { const timeAgo = ({
if (typeof time !== 'number' || time < 0) return 'Invalid Time Provided'; time,
currentTime = new Date(),
dense = false,
}: IProp): string => {
if (typeof time !== "number" || time < 0) return "Invalid Time Provided";
const pastTime: Date = new Date(time); const pastTime: Date = new Date(time);
const elapsedTime: number = currentTime.getTime() - pastTime.getTime(); const elapsedTime: number = currentTime.getTime() - pastTime.getTime();
const timeUnits: TimeUnit[] = [ const timeUnits: TimeUnit[] = [
{ unit: 'yr', full: 'year', value: 31536000 }, { unit: "yr", full: "year", value: 31536000 },
{ unit: 'mo', full: 'month', value: 0 }, { unit: "mo", full: "month", value: 0 },
{ unit: 'd', full: 'day', value: 86400 }, { unit: "d", full: "day", value: 86400 },
{ unit: 'h', full: 'hour', value: 3600 }, { unit: "h", full: "hour", value: 3600 },
{ unit: 'm', full: 'minute', value: 60 }, { unit: "m", full: "minute", value: 60 },
{ unit: 's', full: 'second', value: 1 }, { unit: "s", full: "second", value: 1 },
]; ];
const elapsed: number = elapsedTime / 1000; const elapsed: number = elapsedTime / 1000;
if (elapsed < 10) { if (elapsed < 10) {
return 'just now'; return "just now";
} }
for (let i = 0; i < timeUnits.length; i++) { for (let i = 0; i < timeUnits.length; i++) {
@ -48,7 +52,8 @@ const timeAgo = ({ time, currentTime = new Date(), dense = false }: IProp): stri
const currentMonth = currentTime.getUTCMonth(); const currentMonth = currentTime.getUTCMonth();
const currentYear = currentTime.getUTCFullYear(); const currentYear = currentTime.getUTCFullYear();
let monthDiff = (currentYear - pastYear) * 12 + (currentMonth - pastMonth); let monthDiff =
(currentYear - pastYear) * 12 + (currentMonth - pastMonth);
// check if the time provided is the previous month but not exceeded 1 month ago. // check if the time provided is the previous month but not exceeded 1 month ago.
if (currentTime.getUTCDate() < pastTime.getUTCDate()) { if (currentTime.getUTCDate() < pastTime.getUTCDate()) {
@ -57,18 +62,37 @@ const timeAgo = ({ time, currentTime = new Date(), dense = false }: IProp): stri
if (monthDiff > 0) { if (monthDiff > 0) {
const unitAmount = monthDiff; const unitAmount = monthDiff;
return `${unitAmount}${dense ? timeUnits[i].unit : ` ${timeUnits[i].full}`}${dense ? '' : 's'} ago`; return `${unitAmount}${dense ? timeUnits[i].unit : ` ${timeUnits[i].full}`}${dense ? "" : "s"} ago`;
} }
} else if (elapsed >= timeUnits[i].value) { } else if (elapsed >= timeUnits[i].value) {
const unitAmount: number = Math.floor(elapsed / timeUnits[i].value); const unitAmount: number = Math.floor(elapsed / timeUnits[i].value);
return `${unitAmount}${dense ? timeUnits[i].unit : ` ${timeUnits[i].full}`}${dense ? '' : 's'} ago`; return `${unitAmount}${dense ? timeUnits[i].unit : ` ${timeUnits[i].full}`}${dense ? "" : "s"} ago`;
} }
} }
return 'Invalid Time'; return "Invalid Time";
}; };
const TimeAgo: FunctionComponent<IProp> = ({ refreshInterval = 1000, ...rest }): JSX.Element => { const TimeAgo: FunctionComponent<IProp> = ({
time,
manualRefreshInterval,
...rest
}): JSX.Element => {
const [currentTime, setCurrentTime] = useState<Date>(new Date()); const [currentTime, setCurrentTime] = useState<Date>(new Date());
const refreshInterval = useMemo(() => {
if (manualRefreshInterval) {
return manualRefreshInterval;
}
const currentTs = currentTime.getTime() / 1000;
if (currentTs - time < 60) {
return 1000; // refresh every second
} else if (currentTs - time < 3600) {
return 60000; // refresh every minute
} else {
return 3600000; // refresh every hour
}
}, [currentTime, manualRefreshInterval]);
useEffect(() => { useEffect(() => {
const intervalId: NodeJS.Timeout = setInterval(() => { const intervalId: NodeJS.Timeout = setInterval(() => {
setCurrentTime(new Date()); setCurrentTime(new Date());
@ -76,7 +100,10 @@ const TimeAgo: FunctionComponent<IProp> = ({ refreshInterval = 1000, ...rest }):
return () => clearInterval(intervalId); return () => clearInterval(intervalId);
}, [refreshInterval]); }, [refreshInterval]);
const timeAgoValue = useMemo(() => timeAgo({ currentTime, ...rest }), [currentTime, rest]); const timeAgoValue = useMemo(
() => timeAgo({ time, currentTime, ...rest }),
[currentTime, rest]
);
return <span>{timeAgoValue}</span>; return <span>{timeAgoValue}</span>;
}; };