/ src / components / AppEventDate.svelte
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">&hellip;</span>
66  {/if}
67  
68  <style>
69      span {
70          color: transparent;
71      }
72  </style>