summaryrefslogtreecommitdiffhomepage
path: root/gui/src/shared
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2023-06-13 18:37:53 +0200
committerOskar Nyberg <oskar@mullvad.net>2023-06-28 09:13:18 +0200
commitee8c6577f91ddf60ffe944624091ceaa6a81ca34 (patch)
tree524c2c4b1af129851d832f1c992f076e0ab1aa2d /gui/src/shared
parent0f2e3c95e88f5eab0fe30ca842b2bc4b12a179bb (diff)
downloadmullvadvpn-ee8c6577f91ddf60ffe944624091ceaa6a81ca34.tar.xz
mullvadvpn-ee8c6577f91ddf60ffe944624091ceaa6a81ca34.zip
Refactor time left calculations
Diffstat (limited to 'gui/src/shared')
-rw-r--r--gui/src/shared/account-expiry.ts17
-rw-r--r--gui/src/shared/date-helper.ts86
-rw-r--r--gui/src/shared/notifications/close-to-account-expiry.ts10
3 files changed, 49 insertions, 64 deletions
diff --git a/gui/src/shared/account-expiry.ts b/gui/src/shared/account-expiry.ts
index 85d0d78315..1b40848220 100644
--- a/gui/src/shared/account-expiry.ts
+++ b/gui/src/shared/account-expiry.ts
@@ -1,5 +1,10 @@
-import { dateByAddingComponent, DateComponent, DateType, formatTimeLeft } from './date-helper';
-import { capitalize } from './string-helpers';
+import {
+ dateByAddingComponent,
+ DateComponent,
+ DateType,
+ FormatDateOptions,
+ formatRelativeDate,
+} from './date-helper';
export function hasExpired(expiry: DateType): boolean {
return new Date(expiry).getTime() < Date.now();
@@ -18,10 +23,6 @@ export function formatDate(date: DateType, locale: string): string {
);
}
-export function formatRemainingTime(
- expiry: DateType,
- shouldCapitalizeFirstLetter?: boolean,
-): string {
- const remaining = formatTimeLeft(new Date(), expiry);
- return shouldCapitalizeFirstLetter ? capitalize(remaining) : remaining;
+export function formatRemainingTime(expiry: DateType, options?: FormatDateOptions): string {
+ return formatRelativeDate(new Date(), expiry, options);
}
diff --git a/gui/src/shared/date-helper.ts b/gui/src/shared/date-helper.ts
index 017b2048f5..be83473cfa 100644
--- a/gui/src/shared/date-helper.ts
+++ b/gui/src/shared/date-helper.ts
@@ -1,6 +1,7 @@
import { sprintf } from 'sprintf-js';
import { messages } from './gettext';
+import { capitalize } from './string-helpers';
export type DateType = Date | string | number;
@@ -72,74 +73,53 @@ export class DateDiff {
}
}
+export interface FormatDateOptions {
+ suffix?: boolean;
+ displayMonths?: boolean;
+ capitalize?: boolean;
+}
+
+// If withSuffix is true then "left" will be added at the end of the remaining time.
+// If noMonths is true then the following applies:
+// If a user has more than 2 years (730 days) left of time it should be displayed in whole years
+// rounded down If a user has less than 2 years left (e.g. 729 days) then this should be displayed
+// in days.
export function formatRelativeDate(
fromDate: DateType,
toDate: DateType,
- withSuffix = false,
+ options?: FormatDateOptions,
): string {
const diff = new DateDiff(fromDate, toDate);
const years = Math.abs(diff.years);
const months = Math.abs(diff.months);
const days = Math.abs(diff.days);
- const hours = Math.abs(diff.hours);
- const minutes = Math.abs(diff.minutes);
- if (!withSuffix) {
- if (years > 0) {
- return sprintf(messages.ngettext('1 year', '%d years', years), years);
- } else if (months >= 3) {
- return sprintf(messages.ngettext('1 month', '%d months', months), months);
+ if (isNaN(years) || isNaN(months) || isNaN(days)) {
+ return '';
+ }
+
+ let result = '';
+ if (!options?.suffix) {
+ if (options?.displayMonths ? years > 0 : days >= 730) {
+ result = sprintf(messages.ngettext('1 year', '%d years', years), years);
+ } else if (options?.displayMonths && months >= 3) {
+ result = sprintf(messages.ngettext('1 month', '%d months', months), months);
} else if (days > 0) {
- return sprintf(messages.ngettext('1 day', '%d days', days), days);
+ result = sprintf(messages.ngettext('1 day', '%d days', days), days);
} else {
- return messages.gettext('less than a day');
+ result = messages.gettext('less than a day');
}
} else if (diff.milliseconds > 0) {
- if (years > 0) {
- return sprintf(messages.ngettext('1 year left', '%d years left', years), years);
- } else if (months >= 3) {
- return sprintf(messages.ngettext('1 month left', '%d months left', months), months);
+ if (options?.displayMonths ? years > 0 : days >= 730) {
+ result = sprintf(messages.ngettext('1 year left', '%d years left', years), years);
+ } else if (options?.displayMonths && months >= 3) {
+ result = sprintf(messages.ngettext('1 month left', '%d months left', months), months);
} else if (days > 0) {
- return sprintf(messages.ngettext('1 day left', '%d days left', days), days);
+ result = sprintf(messages.ngettext('1 day left', '%d days left', days), days);
} else {
- return messages.gettext('less than a day left');
- }
- } else {
- if (years > 0) {
- return sprintf(messages.ngettext('a year ago', '%d years ago', years), years);
- } else if (months > 0) {
- return sprintf(messages.ngettext('a month ago', '%d months ago', months), months);
- } else if (days > 0) {
- return sprintf(messages.ngettext('a day ago', '%d days ago', days), days);
- } else if (hours > 0) {
- return sprintf(messages.ngettext('an hour ago', '%d hours ago', hours), hours);
- } else if (minutes > 0) {
- return sprintf(messages.ngettext('a minute ago', '%d minutes ago', minutes), minutes);
- } else {
- return messages.gettext('less than a minute ago');
+ result = messages.gettext('less than a day left');
}
}
-}
-/**
- * If a user has more than 2 years (730 days) left of time it should be displayed in whole years rounded down
- * If a user has less than 2 years left (e.g. 729 days) then this should be displayed in days.
- *
- * @param fromDate
- * @param toDate
- */
-export const formatTimeLeft = (fromDate: DateType, toDate: DateType): string => {
- const diff = new DateDiff(fromDate, toDate);
- const years = Math.abs(diff.years);
- const days = Math.abs(diff.days);
-
- if (days < 1) {
- return messages.gettext('less than a day left');
- }
-
- if (days < 730) {
- return sprintf(messages.ngettext('1 day left', '%d days left', days), days);
- }
-
- return sprintf(messages.ngettext('1 year left', '%d years left', years), years);
-};
+ return options?.capitalize ? capitalize(result) : result;
+}
diff --git a/gui/src/shared/notifications/close-to-account-expiry.ts b/gui/src/shared/notifications/close-to-account-expiry.ts
index a3f5e749ad..60feb7ec4d 100644
--- a/gui/src/shared/notifications/close-to-account-expiry.ts
+++ b/gui/src/shared/notifications/close-to-account-expiry.ts
@@ -3,7 +3,6 @@ import { sprintf } from 'sprintf-js';
import { links } from '../../config.json';
import { messages } from '../../shared/gettext';
import { closeToExpiry, formatRemainingTime } from '../account-expiry';
-import { formatRelativeDate } from '../date-helper';
import {
InAppNotification,
InAppNotificationProvider,
@@ -34,7 +33,7 @@ export class CloseToAccountExpiryNotificationProvider
'Account credit expires in %(duration)s. Buy more credit.',
),
{
- duration: formatRelativeDate(new Date(), this.context.accountExpiry),
+ duration: formatRemainingTime(this.context.accountExpiry),
},
);
@@ -54,7 +53,12 @@ export class CloseToAccountExpiryNotificationProvider
public getInAppNotification(): InAppNotification {
const subtitle = sprintf(
messages.pgettext('in-app-notifications', '%(duration)s. Buy more credit.'),
- { duration: formatRemainingTime(this.context.accountExpiry, true) },
+ {
+ duration: formatRemainingTime(this.context.accountExpiry, {
+ capitalize: true,
+ suffix: true,
+ }),
+ },
);
return {