diff --git a/app/utils/periodic_inform.ts b/app/utils/periodic_inform.ts new file mode 100644 index 0000000..30126d3 --- /dev/null +++ b/app/utils/periodic_inform.ts @@ -0,0 +1,27 @@ +/** + * Computes the estimated next periodic inform date. + * + * @param lastPeriodicInformAt - Date of the last periodic inform + * @param periodicInformInterval - Interval in seconds (from device parameter) + * @returns The estimated next connection date, or null if cannot be computed + */ +export function computeNextPeriodicInform( + lastPeriodicInformAt: Date | string | null | undefined, + periodicInformInterval: number | string | null | undefined +): Date | null { + if (!lastPeriodicInformAt) return null + + const intervalSeconds = typeof periodicInformInterval === 'string' + ? parseInt(periodicInformInterval, 10) + : periodicInformInterval + + if (!intervalSeconds || intervalSeconds <= 0) return null + + const lastDate = lastPeriodicInformAt instanceof Date + ? lastPeriodicInformAt + : new Date(lastPeriodicInformAt) + + if (isNaN(lastDate.getTime())) return null + + return new Date(lastDate.getTime() + intervalSeconds * 1000) +} diff --git a/inertia/pages/DeviceDetail.vue b/inertia/pages/DeviceDetail.vue index b1206c4..e554cba 100644 --- a/inertia/pages/DeviceDetail.vue +++ b/inertia/pages/DeviceDetail.vue @@ -310,11 +310,11 @@ async function resolveAllProviders() { - +
-
+
@@ -330,7 +330,7 @@ async function resolveAllProviders() {
-
+
@@ -346,7 +346,7 @@ async function resolveAllProviders() {
-
+
@@ -357,7 +357,7 @@ async function resolveAllProviders() {
Prochaine connexion
-
{{ estimatedNextConnection }}
+
{{ estimatedNextConnection || '—' }}
diff --git a/tests/unit/utils/periodic_inform.spec.ts b/tests/unit/utils/periodic_inform.spec.ts new file mode 100644 index 0000000..ff2e978 --- /dev/null +++ b/tests/unit/utils/periodic_inform.spec.ts @@ -0,0 +1,55 @@ +import { describe, it, expect } from 'vitest' +import { computeNextPeriodicInform } from '../../../app/utils/periodic_inform.js' + +describe('computeNextPeriodicInform', () => { + it('computes next date from last periodic + interval', () => { + const last = new Date('2026-06-02T10:00:00Z') + const result = computeNextPeriodicInform(last, 30) + expect(result).toEqual(new Date('2026-06-02T10:00:30Z')) + }) + + it('works with string interval', () => { + const last = new Date('2026-06-02T12:00:00Z') + const result = computeNextPeriodicInform(last, '60') + expect(result).toEqual(new Date('2026-06-02T12:01:00Z')) + }) + + it('works with ISO string date', () => { + const result = computeNextPeriodicInform('2026-06-02T08:00:00Z', 300) + expect(result).toEqual(new Date('2026-06-02T08:05:00Z')) + }) + + it('returns null if lastPeriodicInformAt is null', () => { + expect(computeNextPeriodicInform(null, 30)).toBeNull() + }) + + it('returns null if lastPeriodicInformAt is undefined', () => { + expect(computeNextPeriodicInform(undefined, 30)).toBeNull() + }) + + it('returns null if interval is 0', () => { + expect(computeNextPeriodicInform(new Date(), 0)).toBeNull() + }) + + it('returns null if interval is negative', () => { + expect(computeNextPeriodicInform(new Date(), -10)).toBeNull() + }) + + it('returns null if interval is null', () => { + expect(computeNextPeriodicInform(new Date(), null)).toBeNull() + }) + + it('returns null if interval is empty string', () => { + expect(computeNextPeriodicInform(new Date(), '')).toBeNull() + }) + + it('returns null if date string is invalid', () => { + expect(computeNextPeriodicInform('not-a-date', 30)).toBeNull() + }) + + it('handles large intervals (1 hour)', () => { + const last = new Date('2026-06-02T10:00:00Z') + const result = computeNextPeriodicInform(last, 3600) + expect(result).toEqual(new Date('2026-06-02T11:00:00Z')) + }) +})