add some date handling

This commit is contained in:
2024-05-12 01:40:59 +02:00
parent a6fcaa1579
commit e12a9a82fa
6 changed files with 76 additions and 10 deletions

19
web/package-lock.json generated
View File

@ -12,6 +12,8 @@
"@graphql-codegen/client-preset": "^4.2.5", "@graphql-codegen/client-preset": "^4.2.5",
"@parcel/watcher": "^2.4.1", "@parcel/watcher": "^2.4.1",
"@urql/next": "^1.1.1", "@urql/next": "^1.1.1",
"date-fns": "^3.6.0",
"date-fns-tz": "^3.1.3",
"graphql": "^16.8.1", "graphql": "^16.8.1",
"next": "14.2.3", "next": "14.2.3",
"react": "^18", "react": "^18",
@ -3922,6 +3924,23 @@
"resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.2.tgz", "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.2.tgz",
"integrity": "sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==" "integrity": "sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g=="
}, },
"node_modules/date-fns": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz",
"integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
}
},
"node_modules/date-fns-tz": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-3.1.3.tgz",
"integrity": "sha512-ZfbMu+nbzW0mEzC8VZrLiSWvUIaI3aRHeq33mTe7Y38UctKukgqPR4nTDwcwS4d64Gf8GghnVsroBuMY3eiTeA==",
"peerDependencies": {
"date-fns": "^3.0.0"
}
},
"node_modules/debounce": { "node_modules/debounce": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",

View File

@ -14,6 +14,8 @@
"@graphql-codegen/client-preset": "^4.2.5", "@graphql-codegen/client-preset": "^4.2.5",
"@parcel/watcher": "^2.4.1", "@parcel/watcher": "^2.4.1",
"@urql/next": "^1.1.1", "@urql/next": "^1.1.1",
"date-fns": "^3.6.0",
"date-fns-tz": "^3.1.3",
"graphql": "^16.8.1", "graphql": "^16.8.1",
"next": "14.2.3", "next": "14.2.3",
"react": "^18", "react": "^18",

View File

@ -1,16 +1,21 @@
"use client"; "use client";
import styles from "./eventContainer.module.scss"; import { useState } from "react";
import { EventItem } from "./EventItem"; import { EventItem } from "./EventItem";
import { EventFilter } from "./EventFilter"; import { EventFilter } from "./EventFilter";
import { EventFragment } from "@/gql/graphql"; import { EventFragment, getSingularEvents } from "@/lib/event";
import { getSingularEvents } from "@/lib/event"; import {
import { useState } from "react"; toLocalTime,
formatDate,
commonDateFormat,
isTodayOrFuture,
} from "@/lib/date";
import styles from "./eventContainer.module.scss";
type EventContainerMode = "list" | "calendar"; type EventContainerMode = "list" | "calendar";
export const EventContainer = ({ events }: { events: EventFragment[] }) => { export const EventContainer = ({ events }: { events: EventFragment[] }) => {
const [mode, setMode] = useState<EventContainerMode>("list"); const [mode, setMode] = useState<EventContainerMode>("calendar");
return ( return (
<div className={styles.events}> <div className={styles.events}>
@ -38,10 +43,13 @@ const EventList = ({ events }: { events: EventFragment[] }) => {
}; };
const EventCalendar = ({ events }: { events: EventFragment[] }) => { const EventCalendar = ({ events }: { events: EventFragment[] }) => {
const singularEvents = getSingularEvents(events); const singularEvents = getSingularEvents(events).filter((x) =>
x.occurrence?.start && isTodayOrFuture(x.occurrence.start)
);
return ( return (
<ul className={styles.eventList}> <ul className={styles.eventList}>
{events.map((event) => ( {singularEvents.map((event) => (
<EventItem key={event.id} event={event} /> <EventItem key={event.id} event={event} />
))} ))}
</ul> </ul>

View File

@ -1,9 +1,16 @@
import { SingularEvent } from "@/app/arrangementer/page"; "use client";
import styles from "./eventItem.module.scss"; import styles from "./eventItem.module.scss";
import Link from "next/link"; import Link from "next/link";
import Image from "../general/Image"; import Image from "../general/Image";
import { SingularEvent, EventFragment } from "@/lib/event";
import { toLocalTime, formatDate, commonDateFormat } from "@/lib/date";
export const EventItem = ({ event }: { event: SingularEvent }) => { export const EventItem = ({
event,
}: {
event: SingularEvent | EventFragment;
}) => {
return ( return (
<li className={`${styles.eventItem} linkItem`}> <li className={`${styles.eventItem} linkItem`}>
<div className={styles.image}> <div className={styles.image}>
@ -19,7 +26,11 @@ export const EventItem = ({ event }: { event: SingularEvent }) => {
</div> </div>
<div className={styles.text}> <div className={styles.text}>
<h1 className={styles.title}>{event.title}</h1> <h1 className={styles.title}>{event.title}</h1>
{event.occurrence && <p className={styles.details}>{event.occurrence.start}</p>} {event.occurrence?.start && (
<p className={styles.details}>
{formatDate(event.occurrence?.start, commonDateFormat)}
</p>
)}
</div> </div>
<Link href={`/arrangementer/${event.slug}`} className="hiddenLink"> <Link href={`/arrangementer/${event.slug}`} className="hiddenLink">
Mer om arrangementet {event.title} Mer om arrangementet {event.title}

24
web/src/lib/date.ts Normal file
View File

@ -0,0 +1,24 @@
import { isToday, isAfter, parseISO } from "date-fns";
import { toZonedTime, format } from "date-fns-tz";
const timeZone = "Europe/Oslo";
export const commonDateFormat = "dd.MM.yyyy 'kl.' HH:mm";
export function toLocalTime(date: Date | string | number) {
return toZonedTime(date, timeZone);
}
export function formatDate(date: Date | string | number, formatStr: string) {
return format(toLocalTime(date), formatStr, { timeZone });
}
export function isTodayOrFuture(
date: Date | string | number,
timeZone = "UTC"
) {
const now = new Date();
const zonedNow = toZonedTime(now, timeZone);
const zonedDate = toLocalTime(date);
return isToday(zonedDate) || isAfter(zonedDate, zonedNow);
}

View File

@ -1,6 +1,8 @@
import { graphql } from "@/gql"; import { graphql } from "@/gql";
import { EventFragment, EventOccurrence } from "@/gql/graphql"; import { EventFragment, EventOccurrence } from "@/gql/graphql";
export type { EventFragment } from "@/gql/graphql"
const EventFragmentDefinition = graphql(` const EventFragmentDefinition = graphql(`
fragment Event on EventPage { fragment Event on EventPage {
__typename __typename