AppEventDate.svelte
1 <script lang="ts"> 2 import { onMount } from 'svelte'; 3 import { fade } from 'svelte/transition'; 4 import type { Optional } from '@jet/environment/types/optional'; 5 import type { AppEvent } from '@jet-app/app-store/api/models'; 6 import { getJet } from '~/jet'; 7 import { 8 chooseAppEventDate, 9 renderDate, 10 computeAppEventFormattedDates, 11 type RequiredAppEventFormattedDate, 12 } from '~/jet/utils/app-event-formatted-date'; 13 14 const jet = getJet(); 15 16 /** 17 * New pattern (*prefered*): accept appEvent object and compute formattedDates on client-side. 18 * This avoids timezone differences in SSR server (UTC) which cause incorrect event date and time. 19 * By computing dates in the browser, we ensure the user sees dates in their local timezone. 20 */ 21 export let appEvent: 22 | Pick<AppEvent, 'appEventBadgeKind' | 'startDate' | 'endDate'> 23 | undefined = undefined; 24 25 // Legacy pattern: accept pre-computed formattedDates from Jet 26 export let formattedDates: RequiredAppEventFormattedDate[] | undefined = 27 undefined; 28 29 let appEventDate: Optional<RequiredAppEventFormattedDate>; 30 31 onMount(() => { 32 const dates = appEvent 33 ? computeAppEventFormattedDates( 34 jet.objectGraph, 35 appEvent.appEventBadgeKind, 36 appEvent.startDate, 37 appEvent.endDate, 38 ) 39 : formattedDates; 40 41 if (dates) { 42 appEventDate = chooseAppEventDate(dates); 43 } 44 }); 45 46 /** 47 * `Date` instances in the view-model will have been serialized to `string` 48 * instances by ServerKit when delivered to the client; we need to normalize 49 * this so that we have a `string` both client- and server-side. 50 */ 51 function normalizeDate(date: Date | string): string { 52 return typeof date === 'string' ? date : date.toISOString(); 53 } 54 </script> 55 56 {#if appEventDate} 57 <time 58 transition:fade={{ duration: 210 }} 59 datetime={appEventDate.displayFromDate && 60 normalizeDate(appEventDate.displayFromDate)} 61 > 62 {renderDate(jet.objectGraph.loc, appEventDate)} 63 </time> 64 {:else} 65 <span aria-hidden="true">…</span> 66 {/if} 67 68 <style> 69 span { 70 color: transparent; 71 } 72 </style>