This commit is contained in:
parent
e139b35018
commit
925c5a66a6
9 changed files with 27734 additions and 6 deletions
|
|
@ -133,13 +133,14 @@ export const Churches: CollectionConfig = {
|
|||
{ label: '2.', value: 'second' },
|
||||
{ label: '3.', value: 'third' },
|
||||
{ label: '4.', value: 'fourth' },
|
||||
{ label: '5.', value: 'fifth' },
|
||||
{ label: 'Letzter', value: 'last' },
|
||||
],
|
||||
admin: {
|
||||
condition: (_data, siblingData) =>
|
||||
siblingData?.frequency === 'monthlyByWeekday',
|
||||
description:
|
||||
'z. B. „3.“ + „Sonntag“ = jeden 3. Sonntag im Monat',
|
||||
'z. B. „3.“ + „Sonntag“ = jeden 3. Sonntag im Monat.',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -325,6 +325,7 @@ export const Events: CollectionConfig = {
|
|||
{ label: '2.', value: 'second' },
|
||||
{ label: '3.', value: 'third' },
|
||||
{ label: '4.', value: 'fourth' },
|
||||
{ label: '5.', value: 'fifth' },
|
||||
{ label: 'Letzter', value: 'last' },
|
||||
],
|
||||
admin: {
|
||||
|
|
|
|||
|
|
@ -142,6 +142,37 @@ describe('generateOccurrenceDates – monthlyByWeekday', () => {
|
|||
expect(result.map((x) => x.getDate())).toEqual([23])
|
||||
})
|
||||
|
||||
it('yields the 5th thursday only in months that have one', () => {
|
||||
const entry: ScheduleEntry = {
|
||||
frequency: 'monthlyByWeekday',
|
||||
day: 'thursday',
|
||||
weekOfMonth: 'fifth',
|
||||
}
|
||||
// 2026: Jul has 5 Thursdays (2,9,16,23,30), Aug 4 (6,13,20,27), Sep 4, Oct 5 (1,8,15,22,29), Nov 4, Dec 5 (3,10,17,24,31)
|
||||
const result = generateOccurrenceDates(entry, d(2026, 7, 1), d(2026, 12, 31))
|
||||
expect(result.map((x) => `${x.getMonth() + 1}-${x.getDate()}`)).toEqual([
|
||||
'7-30',
|
||||
'10-29',
|
||||
'12-31',
|
||||
])
|
||||
})
|
||||
|
||||
it('"fifth" and "last" differ in months with only 4 occurrences', () => {
|
||||
// Aug 2026 Thursdays: 6, 13, 20, 27 — last = 27, fifth = none
|
||||
const last = generateOccurrenceDates(
|
||||
{ frequency: 'monthlyByWeekday', day: 'thursday', weekOfMonth: 'last' },
|
||||
d(2026, 8, 1),
|
||||
d(2026, 8, 31),
|
||||
)
|
||||
const fifth = generateOccurrenceDates(
|
||||
{ frequency: 'monthlyByWeekday', day: 'thursday', weekOfMonth: 'fifth' },
|
||||
d(2026, 8, 1),
|
||||
d(2026, 8, 31),
|
||||
)
|
||||
expect(last.map((x) => x.getDate())).toEqual([27])
|
||||
expect(fifth).toEqual([])
|
||||
})
|
||||
|
||||
it('works when the start-of-window is after that month\'s occurrence', () => {
|
||||
// 3rd Sunday of April 2026 is 4/19. Start the window on 4/20.
|
||||
// April should be skipped; May should still appear.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export type ScheduleFrequency =
|
|||
| 'monthlyByDate'
|
||||
| 'monthlyByWeekday'
|
||||
|
||||
export type WeekOfMonth = 'first' | 'second' | 'third' | 'fourth' | 'last'
|
||||
export type WeekOfMonth = 'first' | 'second' | 'third' | 'fourth' | 'fifth' | 'last'
|
||||
|
||||
export interface ScheduleEntry {
|
||||
frequency: ScheduleFrequency
|
||||
|
|
@ -40,6 +40,7 @@ const WEEK_OF_MONTH_N: Record<WeekOfMonth, number> = {
|
|||
second: 2,
|
||||
third: 3,
|
||||
fourth: 4,
|
||||
fifth: 5,
|
||||
last: -1,
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +66,7 @@ const firstOccurrenceOnOrAfter = (from: Date, targetDay: number): Date => {
|
|||
|
||||
/**
|
||||
* For a given (year, month), return the date of the Nth occurrence of
|
||||
* `targetDay`. `n` is 1..4 for first..fourth, or -1 for "last".
|
||||
* `targetDay`. `n` is 1..5 for first..fifth, or -1 for "last".
|
||||
* Returns null if the month has no such occurrence (e.g. asking for the
|
||||
* 5th Monday in a month that only has 4).
|
||||
*/
|
||||
|
|
|
|||
27660
src/migrations/20260828_100000_add_fifth_week_of_month.json
Normal file
27660
src/migrations/20260828_100000_add_fifth_week_of_month.json
Normal file
File diff suppressed because it is too large
Load diff
27
src/migrations/20260828_100000_add_fifth_week_of_month.ts
Normal file
27
src/migrations/20260828_100000_add_fifth_week_of_month.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
|
||||
|
||||
export async function up({ db }: MigrateUpArgs): Promise<void> {
|
||||
await db.execute(sql`
|
||||
ALTER TYPE "public"."enum_church_recurring_schedule_week_of_month" ADD VALUE 'fifth' BEFORE 'last';
|
||||
ALTER TYPE "public"."enum_event_recurrence_rules_week_of_month" ADD VALUE 'fifth' BEFORE 'last';
|
||||
ALTER TYPE "public"."enum__event_v_version_recurrence_rules_week_of_month" ADD VALUE 'fifth' BEFORE 'last';`)
|
||||
}
|
||||
|
||||
export async function down({ db }: MigrateDownArgs): Promise<void> {
|
||||
await db.execute(sql`
|
||||
UPDATE "church_recurring_schedule" SET "week_of_month" = 'last' WHERE "week_of_month" = 'fifth';
|
||||
UPDATE "event_recurrence_rules" SET "week_of_month" = 'last' WHERE "week_of_month" = 'fifth';
|
||||
UPDATE "_event_v_version_recurrence_rules" SET "week_of_month" = 'last' WHERE "week_of_month" = 'fifth';
|
||||
ALTER TABLE "church_recurring_schedule" ALTER COLUMN "week_of_month" SET DATA TYPE text;
|
||||
DROP TYPE "public"."enum_church_recurring_schedule_week_of_month";
|
||||
CREATE TYPE "public"."enum_church_recurring_schedule_week_of_month" AS ENUM('first', 'second', 'third', 'fourth', 'last');
|
||||
ALTER TABLE "church_recurring_schedule" ALTER COLUMN "week_of_month" SET DATA TYPE "public"."enum_church_recurring_schedule_week_of_month" USING "week_of_month"::"public"."enum_church_recurring_schedule_week_of_month";
|
||||
ALTER TABLE "event_recurrence_rules" ALTER COLUMN "week_of_month" SET DATA TYPE text;
|
||||
DROP TYPE "public"."enum_event_recurrence_rules_week_of_month";
|
||||
CREATE TYPE "public"."enum_event_recurrence_rules_week_of_month" AS ENUM('first', 'second', 'third', 'fourth', 'last');
|
||||
ALTER TABLE "event_recurrence_rules" ALTER COLUMN "week_of_month" SET DATA TYPE "public"."enum_event_recurrence_rules_week_of_month" USING "week_of_month"::"public"."enum_event_recurrence_rules_week_of_month";
|
||||
ALTER TABLE "_event_v_version_recurrence_rules" ALTER COLUMN "week_of_month" SET DATA TYPE text;
|
||||
DROP TYPE "public"."enum__event_v_version_recurrence_rules_week_of_month";
|
||||
CREATE TYPE "public"."enum__event_v_version_recurrence_rules_week_of_month" AS ENUM('first', 'second', 'third', 'fourth', 'last');
|
||||
ALTER TABLE "_event_v_version_recurrence_rules" ALTER COLUMN "week_of_month" SET DATA TYPE "public"."enum__event_v_version_recurrence_rules_week_of_month" USING "week_of_month"::"public"."enum__event_v_version_recurrence_rules_week_of_month";`)
|
||||
}
|
||||
|
|
@ -54,6 +54,7 @@ import * as migration_20260611_084920_add_image_with_text_block from './20260611
|
|||
import * as migration_20260716_090032_add_user_parish_page_assignments from './20260716_090032_add_user_parish_page_assignments';
|
||||
import * as migration_20260716_113205_add_blog_pinned from './20260716_113205_add_blog_pinned';
|
||||
import * as migration_20260721_090435_add_mass_times_range from './20260721_090435_add_mass_times_range';
|
||||
import * as migration_20260828_100000_add_fifth_week_of_month from './20260828_100000_add_fifth_week_of_month';
|
||||
|
||||
export const migrations = [
|
||||
{
|
||||
|
|
@ -336,4 +337,9 @@ export const migrations = [
|
|||
down: migration_20260721_090435_add_mass_times_range.down,
|
||||
name: '20260721_090435_add_mass_times_range'
|
||||
},
|
||||
{
|
||||
up: migration_20260828_100000_add_fifth_week_of_month.up,
|
||||
down: migration_20260828_100000_add_fifth_week_of_month.down,
|
||||
name: '20260828_100000_add_fifth_week_of_month',
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -368,9 +368,9 @@ export interface Church {
|
|||
day: 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday';
|
||||
time: string;
|
||||
/**
|
||||
* z. B. „3.“ + „Sonntag“ = jeden 3. Sonntag im Monat
|
||||
* z. B. „3.“ + „Sonntag“ = jeden 3. Sonntag im Monat.
|
||||
*/
|
||||
weekOfMonth?: ('first' | 'second' | 'third' | 'fourth' | 'last') | null;
|
||||
weekOfMonth?: ('first' | 'second' | 'third' | 'fourth' | 'fifth' | 'last') | null;
|
||||
/**
|
||||
* Ein Datum, an dem dieser Termin stattfindet. Davon ausgehend wird im 2-Wochen-Rhythmus weitergerechnet.
|
||||
*/
|
||||
|
|
@ -1231,7 +1231,7 @@ export interface Event {
|
|||
| {
|
||||
frequency: 'daily' | 'weekly' | 'monthlyByDate' | 'monthlyByWeekday';
|
||||
weekday?: ('monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday') | null;
|
||||
weekOfMonth?: ('first' | 'second' | 'third' | 'fourth' | 'last') | null;
|
||||
weekOfMonth?: ('first' | 'second' | 'third' | 'fourth' | 'fifth' | 'last') | null;
|
||||
dayOfMonth?: number | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ const WEEK_OF_MONTH_LABEL: Record<string, string> = {
|
|||
second: '2.',
|
||||
third: '3.',
|
||||
fourth: '4.',
|
||||
fifth: '5.',
|
||||
last: 'letzten',
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue