diff --git a/frontend/app/components/Domain/Announcement/AnnouncementDialog.vue b/frontend/app/components/Domain/Announcement/AnnouncementDialog.vue new file mode 100644 index 000000000..3f38c91c2 --- /dev/null +++ b/frontend/app/components/Domain/Announcement/AnnouncementDialog.vue @@ -0,0 +1,139 @@ + + + diff --git a/frontend/app/components/Domain/Announcement/Announcements/2026-03-27_1_welcome.vue b/frontend/app/components/Domain/Announcement/Announcements/2026-03-27_1_welcome.vue new file mode 100644 index 000000000..3134e1856 --- /dev/null +++ b/frontend/app/components/Domain/Announcement/Announcements/2026-03-27_1_welcome.vue @@ -0,0 +1,62 @@ + + + + + + + diff --git a/frontend/app/components/Domain/Announcement/Announcements/announcements.test.ts b/frontend/app/components/Domain/Announcement/Announcements/announcements.test.ts new file mode 100644 index 000000000..e1aa007dd --- /dev/null +++ b/frontend/app/components/Domain/Announcement/Announcements/announcements.test.ts @@ -0,0 +1,37 @@ +import { describe, test, expect } from "vitest"; + +const announcementFiles = import.meta.glob<{ default: unknown }>( + "~/components/Domain/Announcement/Announcements/*.vue", +); + +// Expected format: YYYY-MM-DD_N_slug e.g. 2026-03-27_1_welcome +const FILE_FORMAT = /^\d{4}-\d{2}-\d{2}_\d+_.+$/; + +describe("Announcement files", () => { + const filenames = Object.keys(announcementFiles).map(path => + path.split("/").at(-1)!.replace(".vue", ""), + ); + + test("directory is not empty", () => { + expect(filenames.length).toBeGreaterThan(0); + }); + + test("all filenames match YYYY-MM-DD_N_slug format", () => { + for (const name of filenames) { + expect(name, `"${name}" does not match the expected format`).toMatch(FILE_FORMAT); + } + }); + + test("all date prefixes are valid dates", () => { + for (const name of filenames) { + const datePart = name.split("_", 1)[0]!; + const date = new Date(datePart); + expect(isNaN(date.getTime()), `"${name}" has an invalid date prefix "${datePart}"`).toBe(false); + } + }); + + test("all filenames are unique", () => { + const unique = new Set(filenames); + expect(unique.size).toBe(filenames.length); + }); +}); diff --git a/frontend/app/components/Domain/Group/GroupPreferencesEditor.vue b/frontend/app/components/Domain/Group/GroupPreferencesEditor.vue index 1bfd0c935..e00c163a3 100644 --- a/frontend/app/components/Domain/Group/GroupPreferencesEditor.vue +++ b/frontend/app/components/Domain/Group/GroupPreferencesEditor.vue @@ -1,11 +1,38 @@ @@ -14,5 +41,3 @@ import type { ReadGroupPreferences } from "~/lib/api/types/user"; const preferences = defineModel({ required: true }); - - diff --git a/frontend/app/components/Domain/Household/HouseholdPreferencesEditor.vue b/frontend/app/components/Domain/Household/HouseholdPreferencesEditor.vue index bcbed74a8..6c24e033a 100644 --- a/frontend/app/components/Domain/Household/HouseholdPreferencesEditor.vue +++ b/frontend/app/components/Domain/Household/HouseholdPreferencesEditor.vue @@ -18,6 +18,20 @@

+
+ +
+

+ {{ $t("announcements.show-announcements-setting-description") }} +

+
+
+