@goodandready/dsh-subscriptions 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +23 -4
- package/lib/relative-time.js +47 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -322,6 +322,22 @@ const cssId = 'dsh-subscriptions/settings.module.css'
|
|
|
322
322
|
}
|
|
323
323
|
|
|
324
324
|
// #51: live countdown to the quota window reset (account.quota.resetAt).
|
|
325
|
+
function formatRelativeReset(resetAt, lang, now) {
|
|
326
|
+
if (!resetAt || !Number.isFinite(resetAt) || resetAt <= 0) return ''
|
|
327
|
+
var delta = resetAt - (now || Date.now())
|
|
328
|
+
var isRu = lang !== 'en'
|
|
329
|
+
if (delta <= 0) return isRu ? 'только что' : 'just now'
|
|
330
|
+
var totalMinutes = Math.max(1, Math.round(delta / 60000))
|
|
331
|
+
var days = Math.floor(totalMinutes / 1440)
|
|
332
|
+
var hours = Math.floor((totalMinutes % 1440) / 60)
|
|
333
|
+
var minutes = totalMinutes % 60
|
|
334
|
+
var bits = []
|
|
335
|
+
if (days) bits.push(days + (isRu ? ' дн' : 'd'))
|
|
336
|
+
if (hours) bits.push(hours + (isRu ? ' ч' : 'h'))
|
|
337
|
+
if (minutes || !bits.length) bits.push(minutes + (isRu ? ' мин' : 'm'))
|
|
338
|
+
return (isRu ? 'через ' : 'in ') + bits.join(' ')
|
|
339
|
+
}
|
|
340
|
+
|
|
325
341
|
function ResetCountdown(props) {
|
|
326
342
|
const [now, setNow] = React.useState(Date.now())
|
|
327
343
|
React.useEffect(() => {
|
|
@@ -331,12 +347,15 @@ const cssId = 'dsh-subscriptions/settings.module.css'
|
|
|
331
347
|
const ms = (props.resetAt || 0) - now
|
|
332
348
|
if (ms <= 0) return null
|
|
333
349
|
const total = Math.floor(ms / 1000)
|
|
334
|
-
|
|
335
|
-
|
|
350
|
+
if (total > 3600) {
|
|
351
|
+
return React.createElement('span', { className: 'dsub-sub', style: { fontVariantNumeric: 'tabular-nums' } },
|
|
352
|
+
t('resetLabel') + ' ' + formatRelativeReset(props.resetAt, t('lang'), now))
|
|
353
|
+
}
|
|
354
|
+
const m = Math.floor(total / 60)
|
|
336
355
|
const sec = total % 60
|
|
337
356
|
const pad = (n) => String(n).padStart(2, '0')
|
|
338
357
|
return React.createElement('span', { className: 'dsub-sub', style: { fontVariantNumeric: 'tabular-nums' } },
|
|
339
|
-
t('resetLabel') + ' ' + pad(
|
|
358
|
+
t('resetLabel') + ' ' + pad(m) + ':' + pad(sec))
|
|
340
359
|
}
|
|
341
360
|
|
|
342
361
|
function badgeFor(account, t) {
|
|
@@ -1222,7 +1241,7 @@ const cssId = 'dsh-subscriptions/settings.module.css'
|
|
|
1222
1241
|
React.createElement('div', { className: 'dsub-heroBars' },
|
|
1223
1242
|
React.createElement('div', null,
|
|
1224
1243
|
React.createElement('div', { className: 'dsub-barLabelRow' },
|
|
1225
|
-
React.createElement('span', { style: { fontWeight: 600 } }, (primaryWin && primaryWin.label) ? primaryWin.label + ' window' : t('subs5hWindow')),
|
|
1244
|
+
React.createElement('span', { style: { fontWeight: 600 } }, ((primaryWin && primaryWin.label) ? primaryWin.label + ' window' : t('subs5hWindow')) + (primaryWin && primaryWin.resetAt ? ' (' + formatRelativeReset(primaryWin.resetAt, t('lang'), now) + ')' : '')),
|
|
1226
1245
|
React.createElement('span', { style: { fontVariantNumeric: 'tabular-nums', fontWeight: 600 } }, primPct + '% ' + t('subsUsed') + ' (' + (100 - primPct) + '% ' + t('subsFree') + ')'),
|
|
1227
1246
|
),
|
|
1228
1247
|
React.createElement('div', { className: 'dsub-barTrack' },
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format a future timestamp as a relative remaining duration down to the minute.
|
|
3
|
+
* Supports en and ru.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const RELATIVE_UNITS = {
|
|
7
|
+
en: {
|
|
8
|
+
soon: 'just now',
|
|
9
|
+
prefix: 'in ',
|
|
10
|
+
suffix: '',
|
|
11
|
+
minute: '{n}m',
|
|
12
|
+
hour: '{n}h',
|
|
13
|
+
day: '{n}d',
|
|
14
|
+
},
|
|
15
|
+
ru: {
|
|
16
|
+
soon: 'только что',
|
|
17
|
+
prefix: 'через ',
|
|
18
|
+
suffix: '',
|
|
19
|
+
minute: '{n} мин',
|
|
20
|
+
hour: '{n} ч',
|
|
21
|
+
day: '{n} дн',
|
|
22
|
+
},
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function fill(template, n) {
|
|
26
|
+
return String(template).replace('{n}', String(n))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function formatRelativeReset(resetAt, lang = 'ru', now = Date.now()) {
|
|
30
|
+
if (typeof resetAt !== 'number' || !Number.isFinite(resetAt) || resetAt <= 0) return ''
|
|
31
|
+
const delta = resetAt - now
|
|
32
|
+
const units = RELATIVE_UNITS[lang] || RELATIVE_UNITS.ru
|
|
33
|
+
if (delta <= 0) return units.soon
|
|
34
|
+
|
|
35
|
+
const totalMinutes = Math.max(1, Math.round(delta / 60_000))
|
|
36
|
+
const days = Math.floor(totalMinutes / 1440)
|
|
37
|
+
const hours = Math.floor((totalMinutes % 1440) / 60)
|
|
38
|
+
const minutes = totalMinutes % 60
|
|
39
|
+
|
|
40
|
+
const bits = []
|
|
41
|
+
if (days) bits.push(fill(units.day, days))
|
|
42
|
+
if (hours) bits.push(fill(units.hour, hours))
|
|
43
|
+
if (minutes || bits.length === 0) bits.push(fill(units.minute, minutes))
|
|
44
|
+
|
|
45
|
+
const durationStr = bits.join(' ')
|
|
46
|
+
return `${units.prefix}${durationStr}${units.suffix}`.trim()
|
|
47
|
+
}
|
package/package.json
CHANGED