refactor: uptime expire time formatting

This commit is contained in:
Zack Spear
2023-08-03 16:17:33 -07:00
parent 4ec1d58fa8
commit 31c8bc68ae
11 changed files with 268 additions and 159 deletions

View File

@@ -85,3 +85,58 @@ withDefaults(defineProps<Props>(), {
/>
</svg>
</template>
<style lang="postcss">
@tailwind base;
@tailwind components;
.unraid_mark_2,
.unraid_mark_4 {
animation: mark_2 1.5s ease infinite;
}
.unraid_mark_3 {
animation: mark_3 1.5s ease infinite;
}
.unraid_mark_6,
.unraid_mark_8 {
animation: mark_6 1.5s ease infinite;
}
.unraid_mark_7 {
animation: mark_7 1.5s ease infinite;
}
@keyframes mark_2 {
50% {
transform: translateY(-40px);
}
100% {
transform: translateY(0);
}
}
@keyframes mark_3 {
50% {
transform: translateY(-62px);
}
100% {
transform: translateY(0);
}
}
@keyframes mark_6 {
50% {
transform: translateY(40px);
}
100% {
transform: translateY(0);
}
}
@keyframes mark_7 {
50% {
transform: translateY(62px);
}
100% {
transform: translateY(0);
}
}
@tailwind utilities;
</style>

View File

@@ -79,7 +79,7 @@ onBeforeMount(() => {
<div v-if="bannerGradient" class="absolute z-0 w-[125%] top-0 bottom-0 right-0" :style="bannerGradient" />
<div class="text-gamma text-10px xs:text-12px text-right font-semibold leading-normal relative z-10 flex flex-col items-end justify-end gap-x-4px xs:flex-row xs:items-baseline xs:gap-x-12px">
<UpcUptimeExpire />
<UpcUptimeExpire :t="t" />
<span class="hidden xs:block">&bull;</span>
<UpcServerState :t="t" />
</div>

View File

@@ -193,7 +193,12 @@ const accountActionStatusCopy = computed((): { text: string; } => {
:error="keyInstallStatus === 'failed'"
:text="keyInstallStatusCopy.text"
>
<UpcUptimeExpire v-if="keyType === 'Trial'" :for-expire="true" class="opacity-75 italic mt-4px" />
<UpcUptimeExpire
v-if="keyType === 'Trial'"
:for-expire="true"
class="opacity-75 italic mt-4px"
:t="t"
/>
<template v-if="keyInstallStatus === 'failed'">
<div v-if="isSupported" class="flex justify-center">
@@ -281,5 +286,54 @@ const accountActionStatusCopy = computed((): { text: string; } => {
<style lang="postcss">
@tailwind base;
@tailwind components;
.unraid_mark_2,
.unraid_mark_4 {
animation: mark_2 1.5s ease infinite;
}
.unraid_mark_3 {
animation: mark_3 1.5s ease infinite;
}
.unraid_mark_6,
.unraid_mark_8 {
animation: mark_6 1.5s ease infinite;
}
.unraid_mark_7 {
animation: mark_7 1.5s ease infinite;
}
@keyframes mark_2 {
50% {
transform: translateY(-40px);
}
100% {
transform: translateY(0);
}
}
@keyframes mark_3 {
50% {
transform: translateY(-62px);
}
100% {
transform: translateY(0);
}
}
@keyframes mark_6 {
50% {
transform: translateY(40px);
}
100% {
transform: translateY(0);
}
}
@keyframes mark_7 {
50% {
transform: translateY(62px);
}
100% {
transform: translateY(0);
}
}
@tailwind utilities;
</style>

View File

@@ -30,7 +30,11 @@ const showExpireTime = computed(() => {
<header :class="{ 'text-center': showConnectCopy }">
<h2 class="text-24px text-center font-semibold" v-html="heading" />
<div class="flex flex-col gap-y-8px" v-html="subheading" />
<UpcUptimeExpire v-if="showExpireTime" class="text-center opacity-75 mt-12px" />
<UpcUptimeExpire
v-if="showExpireTime"
class="text-center opacity-75 mt-12px"
:t="t"
/>
</header>
<ul v-if="stateData.actions" class="list-reset flex flex-col gap-y-8px px-16px">
<li v-for="action in stateData.actions" :key="action.name">

View File

@@ -1,18 +1,20 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import dateDiff from '~/helpers/time/dateDiff';
import dateFormat from '~/helpers/time/dateFormat';
import buildStringFromValues from '~/helpers/time/buildTimeString';
import useTimeHelper from '~/composables/time';
import { useServerStore } from '~/store/server';
export interface Props {
forExpire?: boolean;
t: any;
}
const props = withDefaults(defineProps<Props>(), {
forExpire: false,
});
const { buildStringFromValues, dateDiff, formatDate } = useTimeHelper(props.t);
const serverStore = useServerStore();
const { uptime, expireTime, state } = storeToRefs(serverStore);
@@ -26,9 +28,7 @@ const time = computed(() => {
});
const parsedTime = ref<string>('');
const formattedTime = computed<string>(() => {
return dateFormat(time.value);
});
const formattedTime = computed<string>(() => formatDate(time.value));
const countUp = computed<boolean>(() => {
if (props.forExpire && expireTime.value) {
@@ -41,16 +41,16 @@ const output = computed(() => {
if (!countUp.value || state.value === 'EEXPIRED') {
return {
title: state.value === 'EEXPIRED'
? `Trial Key Expired at ${formattedTime.value}`
: `Trial Key Expires at ${formattedTime.value}`,
? props.t('Trial Key Expired at {0}', [formattedTime.value])
: props.t('Trial Key Expires at {0}', [formattedTime.value]),
text: state.value === 'EEXPIRED'
? `Trial Key Expired ${parsedTime.value}`
: `Trial Key Expires in ${parsedTime.value}`,
? props.t('Trial Key Expired {0}', [parsedTime.value])
: props.t('Trial Key Expires in {0}', [parsedTime.value]),
};
}
return {
title: `Server Up Since ${formattedTime.value}`,
text: `Uptime ${parsedTime.value}`,
title: props.t('Server Up Since {0}', [formattedTime.value]),
text: props.t('Uptime {0}', [parsedTime.value]),
};
});

140
composables/time.ts Normal file
View File

@@ -0,0 +1,140 @@
import dayjs, { extend } from 'dayjs';
import localizedFormat from 'dayjs/plugin/localizedFormat';
/** @see https://day.js.org/docs/en/display/format#localized-formats */
extend(localizedFormat);
export interface TimeStringsObject {
years: number;
months: number;
days: number;
hours: number;
minutes: number;
seconds: number;
firstDateWasLater: boolean;
displaySeconds?: boolean;
}
const useTimeHelper = (t: any) => {
const buildStringFromValues = (payload: TimeStringsObject) => {
const {
years,
months,
days,
hours,
minutes,
seconds,
firstDateWasLater,
displaySeconds,
} = payload;
const result = [];
if (years) { result.push(t('year', years)); }
if (months) { result.push(t('month', months)); }
if (days) { result.push(t('day', days)); }
if (hours) { result.push(t('hour', hours)); }
if (minutes) { result.push(t('minute', minutes)); }
if (seconds && ((!years && !months && !days && !hours && !minutes) || displaySeconds)) { result.push(t('second', seconds)); }
if (firstDateWasLater) { result.push(t('ago')); }
return result.join(' ');
};
const formatDate = (date: number): string => dayjs(date).format('llll');
/**
* Original meat and potatos from:
* @version: 1.0.1
* @author: huangjinlin
* @repo: https://github.com/huangjinlin/dayjs-precise-range
*/
const buildValueObject = (
yDiff: number,
mDiff: number,
dDiff: number,
hourDiff: number,
minDiff: number,
secDiff: number,
firstDateWasLater: boolean
): TimeStringsObject => ({
years: yDiff,
months: mDiff,
days: dDiff,
hours: hourDiff,
minutes: minDiff,
seconds: secDiff,
firstDateWasLater,
});
const preciseDateDiff = (d1: dayjs.Dayjs, d2: dayjs.Dayjs): TimeStringsObject => {
let m1 = dayjs(d1);
let m2 = dayjs(d2);
let firstDateWasLater;
if (m1.isSame(m2)) {
return buildValueObject(0, 0, 0, 0, 0, 0, false);
}
if (m1.isAfter(m2)) {
const tmp = m1;
m1 = m2;
m2 = tmp;
firstDateWasLater = true;
} else {
firstDateWasLater = false;
}
let yDiff = m2.year() - m1.year();
let mDiff = m2.month() - m1.month();
let dDiff = m2.date() - m1.date();
let hourDiff = m2.hour() - m1.hour();
let minDiff = m2.minute() - m1.minute();
let secDiff = m2.second() - m1.second();
if (secDiff < 0) {
secDiff = 60 + secDiff;
minDiff -= 1;
}
if (minDiff < 0) {
minDiff = 60 + minDiff;
hourDiff -= 1;
}
if (hourDiff < 0) {
hourDiff = 24 + hourDiff;
dDiff -= 1;
}
if (dDiff < 0) {
const daysInLastFullMonth = dayjs(`${m2.year()}-${m2.month() + 1}`).subtract(1, 'M').daysInMonth();
if (daysInLastFullMonth < m1.date()) { // 31/01 -> 2/03
dDiff = daysInLastFullMonth + dDiff + (m1.date() - daysInLastFullMonth);
} else {
dDiff = daysInLastFullMonth + dDiff;
}
mDiff -= 1;
}
if (mDiff < 0) {
mDiff = 12 + mDiff;
yDiff -= 1;
}
return buildValueObject(yDiff, mDiff, dDiff, hourDiff, minDiff, secDiff, firstDateWasLater);
};
const readableDifference = (a = '', b = '') => {
try {
const x = a ? dayjs(parseInt(a, 10)) : dayjs();
const y = b ? dayjs(parseInt(b, 10)) : dayjs();
return preciseDateDiff(x, y);
} catch (error) {
throw new Error('Couldn\'t calculate date difference');
}
};
const dateDiff = (time: string, countUp: boolean) => countUp ? readableDifference(time, '') : readableDifference('', time);
return {
buildStringFromValues,
dateDiff,
formatDate,
};
};
export default useTimeHelper;

View File

@@ -1,42 +0,0 @@
import { TimeStringsObject } from '~/types/time';
const buildStringFromValues = ({
years, months, days, hours, minutes, seconds, firstDateWasLater, displaySeconds,
}: TimeStringsObject) => {
const result = [];
type DateStrings = {
[key: string]: string;
};
const dateStrings: DateStrings = {
year: 'year',
years: 'years',
month: 'month',
months: 'months',
day: 'day',
days: 'days',
hour: 'hour',
hours: 'hours',
minute: 'minute',
minutes: 'minutes',
second: 'second',
seconds: 'seconds',
firstDateWasLater: 'ago',
delimiter: ' ',
};
const pluralize = (num: number, word: string) => {
const index = word + (num === 1 ? '' : 's');
return `${num} ${dateStrings[index]}`;
};
if (years) { result.push(pluralize(years, 'year')); }
if (months) { result.push(pluralize(months, 'month')); }
if (days) { result.push(pluralize(days, 'day')); }
if (hours) { result.push(pluralize(hours, 'hour')); }
if (minutes) { result.push(pluralize(minutes, 'minute')); }
if (seconds && ((!years && !months && !days && !hours && !minutes) || displaySeconds)) { result.push(pluralize(seconds, 'second')); }
if (firstDateWasLater) { result.push(dateStrings.firstDateWasLater); }
return result.join(dateStrings.delimiter);
};
export default buildStringFromValues;

View File

@@ -1,11 +0,0 @@
import dayjs from 'dayjs';
import preciseDateDiff from './preciseDateDiff';
const readbleDifference = (a = '', b = '') => {
const x = a ? dayjs(parseInt(a, 10)) : dayjs();
const y = b ? dayjs(parseInt(b, 10)) : dayjs();
return preciseDateDiff(x, y);
};
const dateDiff = (time: string, countUp: boolean) => countUp ? readbleDifference(time, '') : readbleDifference('', time);
export default dateDiff;

View File

@@ -1,9 +0,0 @@
import dayjs, { extend } from 'dayjs';
import localizedFormat from 'dayjs/plugin/localizedFormat';
/** @see https://day.js.org/docs/en/display/format#localized-formats */
extend(localizedFormat);
const formatDate = (date: number): string => dayjs(date).format('llll');
export default formatDate;

View File

@@ -1,72 +0,0 @@
import dayjs from 'dayjs';
import { TimeStringsObject } from '~/types/time';
/**
* Original meat and potatos from:
* @version: 1.0.1
* @author: huangjinlin
* @repo: https://github.com/huangjinlin/dayjs-precise-range
*/
const buildValueObject = (yDiff: number, mDiff: number, dDiff: number, hourDiff: number, minDiff: number, secDiff: number, firstDateWasLater: boolean): TimeStringsObject => ({
years: yDiff,
months: mDiff,
days: dDiff,
hours: hourDiff,
minutes: minDiff,
seconds: secDiff,
firstDateWasLater,
});
const preciseDateDiff = (d1: dayjs.Dayjs, d2: dayjs.Dayjs): TimeStringsObject => {
let m1 = dayjs(d1);
let m2 = dayjs(d2);
let firstDateWasLater;
if (m1.isSame(m2)) {
return buildValueObject(0, 0, 0, 0, 0, 0, false);
}
if (m1.isAfter(m2)) {
const tmp = m1;
m1 = m2;
m2 = tmp;
firstDateWasLater = true;
} else {
firstDateWasLater = false;
}
let yDiff = m2.year() - m1.year();
let mDiff = m2.month() - m1.month();
let dDiff = m2.date() - m1.date();
let hourDiff = m2.hour() - m1.hour();
let minDiff = m2.minute() - m1.minute();
let secDiff = m2.second() - m1.second();
if (secDiff < 0) {
secDiff = 60 + secDiff;
minDiff -= 1;
}
if (minDiff < 0) {
minDiff = 60 + minDiff;
hourDiff -= 1;
}
if (hourDiff < 0) {
hourDiff = 24 + hourDiff;
dDiff -= 1;
}
if (dDiff < 0) {
const daysInLastFullMonth = dayjs(`${m2.year()}-${m2.month() + 1}`).subtract(1, 'M').daysInMonth();
if (daysInLastFullMonth < m1.date()) { // 31/01 -> 2/03
dDiff = daysInLastFullMonth + dDiff + (m1.date() - daysInLastFullMonth);
} else {
dDiff = daysInLastFullMonth + dDiff;
}
mDiff -= 1;
}
if (mDiff < 0) {
mDiff = 12 + mDiff;
yDiff -= 1;
}
return buildValueObject(yDiff, mDiff, dDiff, hourDiff, minDiff, secDiff, firstDateWasLater);
};
export default preciseDateDiff;

View File

@@ -1,10 +0,0 @@
export interface TimeStringsObject {
years: number;
months: number;
days: number;
hours: number;
minutes: number;
seconds: number;
firstDateWasLater: boolean;
displaySeconds?: boolean;
}