group date pills when days are consecutive
This commit is contained in:
@ -8,9 +8,14 @@ import {
|
|||||||
EventFragment,
|
EventFragment,
|
||||||
getFutureOccurrences,
|
getFutureOccurrences,
|
||||||
} from "@/lib/event";
|
} from "@/lib/event";
|
||||||
import { formatDate, formatExtendedDateTime } from "@/lib/date";
|
import {
|
||||||
|
formatDate,
|
||||||
|
formatDateRange,
|
||||||
|
formatExtendedDateTime,
|
||||||
|
groupConsecutiveDates,
|
||||||
|
} from "@/lib/date";
|
||||||
|
|
||||||
const DATES_TO_SHOW = 2;
|
const DATE_PILLS_TO_SHOW = 2;
|
||||||
|
|
||||||
export const EventItem = ({
|
export const EventItem = ({
|
||||||
event,
|
event,
|
||||||
@ -22,8 +27,11 @@ export const EventItem = ({
|
|||||||
size?: "small" | "medium" | "large";
|
size?: "small" | "medium" | "large";
|
||||||
}) => {
|
}) => {
|
||||||
const futureOccurrences = getFutureOccurrences(event);
|
const futureOccurrences = getFutureOccurrences(event);
|
||||||
|
const groupedOccurrences = groupConsecutiveDates(
|
||||||
|
futureOccurrences.map((occurrence) => occurrence.start)
|
||||||
|
);
|
||||||
const numOccurrences = event?.occurrences?.length ?? 0;
|
const numOccurrences = event?.occurrences?.length ?? 0;
|
||||||
const nextOccurrence = numOccurrences ? futureOccurrences[0] : null;
|
const nextOccurrence = numOccurrences ? groupedOccurrences[0] : null;
|
||||||
const featuredImage: any = event.featuredImage;
|
const featuredImage: any = event.featuredImage;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -46,15 +54,15 @@ export const EventItem = ({
|
|||||||
<div className={styles.time}>
|
<div className={styles.time}>
|
||||||
{mode === "list" && nextOccurrence && (
|
{mode === "list" && nextOccurrence && (
|
||||||
<div className={styles.dates}>
|
<div className={styles.dates}>
|
||||||
{futureOccurrences.slice(0, DATES_TO_SHOW).map((occurrence) => (
|
{groupedOccurrences.slice(0, DATE_PILLS_TO_SHOW).map((group) => (
|
||||||
<span key={occurrence.id} className={styles.datePill}>
|
<span key={group[0]} className={styles.datePill}>
|
||||||
{formatDate(occurrence.start, "d. MMMM")}
|
{formatDateRange(group)}
|
||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
{futureOccurrences.length > DATES_TO_SHOW && (
|
{groupedOccurrences.length > DATE_PILLS_TO_SHOW && (
|
||||||
<span className={styles.moreDates}>{`+${
|
<span className={styles.moreDates}>{`+${groupedOccurrences
|
||||||
futureOccurrences.length - DATES_TO_SHOW
|
.slice(DATE_PILLS_TO_SHOW)
|
||||||
}`}</span>
|
.reduce((sum, group) => sum + group.length, 0)}`}</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
import { isToday, isAfter, parse, compareAsc } from "date-fns";
|
import {
|
||||||
|
isToday,
|
||||||
|
isAfter,
|
||||||
|
parse,
|
||||||
|
compareAsc,
|
||||||
|
addDays,
|
||||||
|
isSameDay,
|
||||||
|
} from "date-fns";
|
||||||
import { nb } from "date-fns/locale";
|
import { nb } from "date-fns/locale";
|
||||||
import { toZonedTime, format } from "date-fns-tz";
|
import { toZonedTime, format } from "date-fns-tz";
|
||||||
|
|
||||||
@ -51,3 +58,53 @@ export function isTodayOrFuture(
|
|||||||
export function compareDates(a: Date | string, b: Date | string) {
|
export function compareDates(a: Date | string, b: Date | string) {
|
||||||
return compareAsc(new Date(a), new Date(b));
|
return compareAsc(new Date(a), new Date(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isConsectutiveDays(a: Date, b: Date): boolean {
|
||||||
|
const nextDay = addDays(a, 1);
|
||||||
|
return isSameDay(nextDay, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function groupConsecutiveDates(dates: string[]): string[][] {
|
||||||
|
const groupedDates: string[][] = [];
|
||||||
|
let group: string[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < dates.length; i++) {
|
||||||
|
if (
|
||||||
|
i === 0 ||
|
||||||
|
isConsectutiveDays(toLocalTime(dates[i - 1]), toLocalTime(dates[i]))
|
||||||
|
) {
|
||||||
|
group.push(dates[i]);
|
||||||
|
} else {
|
||||||
|
groupedDates.push(group);
|
||||||
|
group = [dates[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group.length > 0) {
|
||||||
|
groupedDates.push(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
return groupedDates;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatDateRange(dates: string[]): string {
|
||||||
|
if (dates.length === 1) {
|
||||||
|
return formatDate(dates[0], "d. MMMM");
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstDate = toLocalTime(dates[0]);
|
||||||
|
const lastDate = toLocalTime(dates[dates.length - 1]);
|
||||||
|
|
||||||
|
if (firstDate.getMonth() === lastDate.getMonth()) {
|
||||||
|
// same month
|
||||||
|
return `${firstDate.getDay()}.-${lastDate.getDay()}. ${formatDate(
|
||||||
|
firstDate,
|
||||||
|
"MMMM"
|
||||||
|
)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// continues into next month
|
||||||
|
const formattedFirstDate = formatDate(firstDate, "d. MMMM");
|
||||||
|
const formattedLastDate = formatDate(lastDate, "d. MMMM");
|
||||||
|
return `${formattedFirstDate} - ${formattedLastDate}`;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user