From dad50d1c979a765d29d8a419e2c9068e5b55d1bb Mon Sep 17 00:00:00 2001 From: Rajpreet0 Date: Tue, 1 Sep 2026 22:03:38 +0200 Subject: [PATCH] fixing bugs --- prisma/schema.prisma | 2 +- .../ui/components/AuthSidebarComponent.tsx | 2 +- src/modules/courses/actions/course-actions.ts | 12 +- .../courses/hooks/useWeekdayTimings.ts | 181 +++++++++++++++++ src/modules/courses/schemas/course-schema.ts | 20 +- src/modules/courses/types/course.types.ts | 6 +- .../courses/ui/views/course-create-view.tsx | 186 +++++++++++------- .../courses/utils/generate-instances.ts | 54 ++++- .../ui/components/DashboardSidebar.tsx | 2 +- .../ui/views/settings-overview-view.tsx | 2 +- src/public/logo-gelb.png | Bin 0 -> 22549 bytes 11 files changed, 372 insertions(+), 95 deletions(-) create mode 100644 src/modules/courses/hooks/useWeekdayTimings.ts create mode 100644 src/public/logo-gelb.png diff --git a/prisma/schema.prisma b/prisma/schema.prisma index fb0d1f7..db9a251 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -139,7 +139,7 @@ model Course { isStandingOrder Boolean @default(false) frequency String? // daily, weekly, biweekly, monthly, custom weekdays String[] // For custom frequency - weekdayTimings Json? // { "monday": { "timeFrom": "08:00", "timeTo": "09:00" }, ... } + weekdayTimings Json? // { "monday": [{ "timeFrom": "08:00", "timeTo": "09:00" }, ...], ... } — mehrere Zeitfenster pro Tag. Legacy: { "monday": { "timeFrom", "timeTo" } } endDate DateTime? // Required when isStandingOrder = true parentCourseId String? // Null on template; set on every child instance parentCourse Course? @relation("StandingOrderInstances", fields: [parentCourseId], references: [id], onDelete: Cascade) diff --git a/src/modules/auth/ui/components/AuthSidebarComponent.tsx b/src/modules/auth/ui/components/AuthSidebarComponent.tsx index e3f92f2..ee6fa66 100644 --- a/src/modules/auth/ui/components/AuthSidebarComponent.tsx +++ b/src/modules/auth/ui/components/AuthSidebarComponent.tsx @@ -1,6 +1,6 @@ import Image from "next/image"; import MultiStepProzess from "./MultiStepProzess"; -import Logo from "@/src/public/logo.png"; +import Logo from "@/src/public/logo-gelb.png"; import { Card, CardHeader, CardTitle, CardContent, CardFooter } from "@/src/components/ui/card"; import Link from "next/link"; diff --git a/src/modules/courses/actions/course-actions.ts b/src/modules/courses/actions/course-actions.ts index c9690b5..f9af49b 100644 --- a/src/modules/courses/actions/course-actions.ts +++ b/src/modules/courses/actions/course-actions.ts @@ -125,11 +125,7 @@ export async function createCourse(data: CourseFormData, status: "draft" | "publ defaultTimeFrom: validatedData.timeFrom || "", defaultTimeTo: validatedData.timeTo || "", weekdays: validatedData.weekdays || [], - weekdayTimings: - (validatedData.weekdayTimings as Record< - string, - { timeFrom: string; timeTo: string } - >) ?? {}, + weekdayTimings: validatedData.weekdayTimings ?? {}, }); if (occurrences.length > 0) { @@ -551,11 +547,7 @@ export async function updateCourse( defaultTimeFrom: validatedData.timeFrom || "", defaultTimeTo: validatedData.timeTo || "", weekdays: validatedData.weekdays || [], - weekdayTimings: - (validatedData.weekdayTimings as Record< - string, - { timeFrom: string; timeTo: string } - >) ?? {}, + weekdayTimings: validatedData.weekdayTimings ?? {}, }); // Das Template selbst wird (wie bei createCourse) nicht als sichtbarer diff --git a/src/modules/courses/hooks/useWeekdayTimings.ts b/src/modules/courses/hooks/useWeekdayTimings.ts new file mode 100644 index 0000000..dc8bed7 --- /dev/null +++ b/src/modules/courses/hooks/useWeekdayTimings.ts @@ -0,0 +1,181 @@ +"use client"; +import { useMemo, useState } from "react"; + +export type WeekdaySlot = { timeFrom: string; timeTo: string }; +export type WeekdayTimings = Record; + +/** Rohform, wie sie aus der DB kommen kann (neues Array- oder altes Einzelobjekt-Format). */ +type RawWeekdayTimings = + | Record + | null + | undefined; + +export const emptySlot = (): WeekdaySlot => ({ timeFrom: "", timeTo: "" }); + +/** + * Bringt gespeicherte weekdayTimings in das Array-Format. Akzeptiert sowohl das + * neue Format ({ monday: [{...}] }) als auch das alte Einzelobjekt-Format + * ({ monday: { timeFrom, timeTo } }) aus bestehenden DB-Datensätzen. + */ +export const normalizeWeekdayTimings = (raw: RawWeekdayTimings): WeekdayTimings => { + if (!raw) return {}; + const result: WeekdayTimings = {}; + for (const [day, value] of Object.entries(raw)) { + if (Array.isArray(value)) { + const slots = value.filter((s): s is WeekdaySlot => !!s && typeof s === "object"); + if (slots.length > 0) result[day] = slots; + } else if (value && typeof value === "object") { + result[day] = [{ timeFrom: value.timeFrom ?? "", timeTo: value.timeTo ?? "" }]; + } + } + return result; +}; + +/** Ermittelt ein Standard-Zeitfenster, falls alle Tage genau ein identisches haben. */ +const deriveDefaultSlot = (timings: WeekdayTimings): WeekdaySlot => { + const daySlots = Object.values(timings); + if (daySlots.length === 0) return emptySlot(); + const first = daySlots[0][0]; + if (!first) return emptySlot(); + const allSame = daySlots.every( + (slots) => + slots.length === 1 && slots[0].timeFrom === first.timeFrom && slots[0].timeTo === first.timeTo + ); + return allSame ? { ...first } : emptySlot(); +}; + +interface UseWeekdayTimingsOptions { + /** Vorbelegung (Edit-Modus) — beliebiges gespeichertes Format. */ + initialWeekdays?: string[]; + initialTimings?: RawWeekdayTimings; +} + +/** + * Kapselt die Wochentag-Auswahl und deren Zeitfenster für die "custom"-Häufigkeit + * eines Dauerauftrags. Jeder Tag kann mehrere Zeitfenster haben; ein + * Standard-Zeitfenster kann auf alle Tage übertragen werden. + */ +export function useWeekdayTimings({ + initialWeekdays = [], + initialTimings, +}: UseWeekdayTimingsOptions = {}) { + const [selectedWeekdays, setSelectedWeekdays] = useState(initialWeekdays); + const [weekdayTimings, setWeekdayTimings] = useState(() => + normalizeWeekdayTimings(initialTimings) + ); + const [defaultSlot, setDefaultSlot] = useState(() => + deriveDefaultSlot(normalizeWeekdayTimings(initialTimings)) + ); + + const isDefaultSlotFilled = !!defaultSlot.timeFrom && !!defaultSlot.timeTo; + + const reset = () => { + setSelectedWeekdays([]); + setWeekdayTimings({}); + setDefaultSlot(emptySlot()); + }; + + // Hält weekdayTimings mit der Tagesauswahl synchron: jeder ausgewählte Tag + // bekommt mindestens einen (ggf. leeren) Slot, abgewählte Tage fallen raus. + const syncWeekdays = (days: string[]) => { + setSelectedWeekdays(days); + setWeekdayTimings((prev) => { + const next: WeekdayTimings = {}; + days.forEach((d) => { + next[d] = prev[d]?.length ? prev[d] : [{ ...defaultSlot }]; + }); + return next; + }); + }; + + // Standard-Zeitfenster auf alle ausgewählten Tage übertragen (ersetzt deren Slots). + const applyDefaultToAll = () => { + if (!isDefaultSlotFilled || selectedWeekdays.length === 0) return; + setWeekdayTimings(() => { + const next: WeekdayTimings = {}; + selectedWeekdays.forEach((d) => { + next[d] = [{ ...defaultSlot }]; + }); + return next; + }); + }; + + const updateDefaultSlot = (patch: Partial) => { + const updated = { ...defaultSlot, ...patch }; + setDefaultSlot(updated); + // Solange noch kein Tag eine eigene Uhrzeit gesetzt hat, die Änderung direkt + // auf alle ausgewählten Tage spiegeln (initiale Bequemlichkeit). + const noDayCustomized = selectedWeekdays.every((d) => + (weekdayTimings[d] ?? []).every((s) => !s.timeFrom && !s.timeTo) + ); + if (noDayCustomized && selectedWeekdays.length > 0) { + setWeekdayTimings(() => { + const next: WeekdayTimings = {}; + selectedWeekdays.forEach((d) => { + next[d] = [{ ...updated }]; + }); + return next; + }); + } + }; + + const updateSlot = (day: string, index: number, patch: Partial) => { + setWeekdayTimings((prev) => { + const slots = (prev[day] ?? [emptySlot()]).map((s, i) => + i === index ? { ...s, ...patch } : s + ); + return { ...prev, [day]: slots }; + }); + }; + + const addSlot = (day: string) => { + setWeekdayTimings((prev) => ({ + ...prev, + [day]: [...(prev[day] ?? []), emptySlot()], + })); + }; + + const removeSlot = (day: string, index: number) => { + setWeekdayTimings((prev) => { + const slots = (prev[day] ?? []).filter((_, i) => i !== index); + return { ...prev, [day]: slots.length ? slots : [emptySlot()] }; + }); + }; + + /** Nur befüllte Slots; Tage ohne gültige Uhrzeit fallen weg. `undefined`, wenn leer. */ + const cleanedTimings = useMemo((): WeekdayTimings | undefined => { + const cleaned: WeekdayTimings = {}; + for (const [day, slots] of Object.entries(weekdayTimings)) { + const filled = slots.filter((s) => s.timeFrom || s.timeTo); + if (filled.length > 0) cleaned[day] = filled; + } + return Object.keys(cleaned).length > 0 ? cleaned : undefined; + }, [weekdayTimings]); + + /** True, wenn ein ausgewählter Tag kein oder ein ungültiges Zeitfenster hat. */ + const hasInvalidTiming = useMemo( + () => + selectedWeekdays.some((day) => { + const slots = weekdayTimings[day] ?? []; + if (slots.length === 0) return true; + return slots.some((s) => !s.timeFrom || !s.timeTo || s.timeFrom >= s.timeTo); + }), + [selectedWeekdays, weekdayTimings] + ); + + return { + selectedWeekdays, + weekdayTimings, + defaultSlot, + isDefaultSlotFilled, + cleanedTimings, + hasInvalidTiming, + reset, + syncWeekdays, + applyDefaultToAll, + updateDefaultSlot, + updateSlot, + addSlot, + removeSlot, + }; +} diff --git a/src/modules/courses/schemas/course-schema.ts b/src/modules/courses/schemas/course-schema.ts index b4d41eb..8505ff1 100644 --- a/src/modules/courses/schemas/course-schema.ts +++ b/src/modules/courses/schemas/course-schema.ts @@ -5,12 +5,26 @@ const frequencyEnum = z.enum(VALID_FREQUENCIES as [string, ...string[]], { message: "Ungültige Häufigkeit", }); +const weekdaySlotSchema = z.object({ timeFrom: z.string(), timeTo: z.string() }); + +// Neues Format: mehrere Zeitfenster pro Tag. Das alte Einzelobjekt-Format +// ({ monday: { timeFrom, timeTo } }) wird für Abwärtskompatibilität weiterhin +// akzeptiert und in ein Array normalisiert. const weekdayTimingsSchema = z - .record(z.string(), z.object({ timeFrom: z.string(), timeTo: z.string() })) + .record(z.string(), z.union([z.array(weekdaySlotSchema), weekdaySlotSchema])) + .transform((timings) => { + const normalized: Record = {}; + for (const [day, value] of Object.entries(timings)) { + const slots = Array.isArray(value) ? value : [value]; + const filled = slots.filter((s) => s.timeFrom || s.timeTo); + if (filled.length > 0) normalized[day] = filled; + } + return normalized; + }) .refine( (timings) => - Object.values(timings).every( - ({ timeFrom, timeTo }) => !timeFrom || !timeTo || timeFrom < timeTo + Object.values(timings).every((slots) => + slots.every(({ timeFrom, timeTo }) => !timeFrom || !timeTo || timeFrom < timeTo) ), { message: "Endzeit muss nach der Anfangszeit liegen (Wochentag-Uhrzeiten)" } ) diff --git a/src/modules/courses/types/course.types.ts b/src/modules/courses/types/course.types.ts index e8eeb34..a1cdffe 100644 --- a/src/modules/courses/types/course.types.ts +++ b/src/modules/courses/types/course.types.ts @@ -14,7 +14,11 @@ export type Course = { isStandingOrder: boolean; frequency: string | null; weekdays: string[]; - weekdayTimings: Record | null; + weekdayTimings: + | Record + // Altes Format, kann noch in bestehenden DB-Datensätzen liegen + | Record + | null; endDate: Date | null; parentCourseId: string | null; status: string; diff --git a/src/modules/courses/ui/views/course-create-view.tsx b/src/modules/courses/ui/views/course-create-view.tsx index 83351f9..46b0ff8 100644 --- a/src/modules/courses/ui/views/course-create-view.tsx +++ b/src/modules/courses/ui/views/course-create-view.tsx @@ -13,7 +13,7 @@ import { getMyRooms } from "@/src/modules/rooms/actions/room-actions"; import { getMyTrainers } from "@/src/modules/employee/actions/employee-actions"; import { toast } from "sonner"; import { Course } from "../../types/course.types"; -import { Trash2, ImagePlus, X, Loader2, AlertTriangle } from "lucide-react"; +import { Trash2, ImagePlus, X, Loader2, AlertTriangle, Plus, CopyCheck } from "lucide-react"; import Image from "next/image"; import DeleteDialog from "@/src/components/layout/DeleteDialog"; import { @@ -28,6 +28,7 @@ import { import { Progress } from "@/src/components/ui/progress"; import { downsizeImage } from "@/src/lib/image/downsize"; import { useDeleteCourse } from "../../hooks/useDeleteCourse"; +import { useWeekdayTimings, type WeekdaySlot } from "../../hooks/useWeekdayTimings"; import { generateOccurrences, TooManyInstancesError, @@ -38,8 +39,6 @@ import { type StandingOrderScope, } from "../components/StandingOrderScopeDialog"; -type WeekdayTiming = { timeFrom: string; timeTo: string }; - const LEVELS = [ { value: "any", label: "Jedes Niveau" }, { value: "beginner", label: "Anfänger" }, @@ -124,15 +123,14 @@ const CourseCreateView = ({ const [selectedFrequency, setSelectedFrequency] = useState( isEdit ? initialData!.frequency || "" : "" ); - const [selectedWeekdays, setSelectedWeekdays] = useState( - isEdit ? initialData!.weekdays || [] : [] - ); - const [weekdayTimings, setWeekdayTimings] = useState>(() => { - if (isEdit && initialData!.weekdayTimings) { - return initialData!.weekdayTimings as Record; - } - return {}; + const weekdays = useWeekdayTimings({ + initialWeekdays: isEdit ? initialData!.weekdays || [] : [], + initialTimings: + isEdit && initialData!.weekdayTimings + ? (initialData!.weekdayTimings as Record) + : undefined, }); + const { selectedWeekdays, weekdayTimings, defaultSlot, isDefaultSlotFilled } = weekdays; const [endDate, setEndDate] = useState(() => { if (isEdit && initialData!.endDate) { const d = new Date(initialData!.endDate); @@ -300,13 +298,13 @@ const CourseCreateView = ({ if (selectedFrequency === "custom" && selectedWeekdays.length === 0) { newErrors.weekdays = "Mindestens ein Tag muss ausgewählt werden"; } - if (selectedFrequency === "custom" && selectedWeekdays.length > 0) { - const hasInvalidTiming = selectedWeekdays.some((day) => { - const t = weekdayTimings[day]; - return !t?.timeFrom || !t?.timeTo || t.timeFrom >= t.timeTo; - }); - if (hasInvalidTiming) - newErrors.weekdayTimings = "Bitte gültige Uhrzeiten für alle Wochentage eingeben"; + if ( + selectedFrequency === "custom" && + selectedWeekdays.length > 0 && + weekdays.hasInvalidTiming + ) { + newErrors.weekdayTimings = + "Bitte gültige Uhrzeiten für alle Zeitfenster eingeben (Ende nach Beginn)"; } if (!newErrors.endDate && selectedFrequency && courseDate && endDate) { try { @@ -355,7 +353,7 @@ const CourseCreateView = ({ isStandingOrder, frequency: selectedFrequency || undefined, weekdays: selectedWeekdays.length > 0 ? selectedWeekdays : undefined, - weekdayTimings: Object.keys(weekdayTimings).length > 0 ? weekdayTimings : undefined, + weekdayTimings: weekdays.cleanedTimings, endDate: endDate || undefined, businessId: selectedBusinessId || undefined, }); @@ -699,9 +697,8 @@ const CourseCreateView = ({ setIsStandingOrder(checked === true); if (!checked) { setSelectedFrequency(""); - setSelectedWeekdays([]); - setWeekdayTimings({}); setEndDate(""); + weekdays.reset(); } }} /> @@ -718,8 +715,7 @@ const CourseCreateView = ({ onSelect={(value) => { setSelectedFrequency(value); if (value !== "custom") { - setSelectedWeekdays([]); - setWeekdayTimings({}); + weekdays.reset(); } }} options={FREQUENCIES} @@ -743,58 +739,108 @@ const CourseCreateView = ({ { - setSelectedWeekdays(days); - // Nicht mehr ausgewählte Tage aus weekdayTimings entfernen - setWeekdayTimings((prev) => { - const next: Record = {}; - days.forEach((d) => { - next[d] = prev[d] ?? { timeFrom: "", timeTo: "" }; - }); - return next; - }); - }} + onSelect={weekdays.syncWeekdays} options={WEEKDAYS} error={errors.weekdays} /> {selectedWeekdays.length > 0 && ( -
-

Uhrzeiten pro Tag

- {selectedWeekdays.map((day) => { - const dayLabel = WEEKDAYS.find((w) => w.value === day)?.label ?? day; - return ( -
- {dayLabel} - - setWeekdayTimings((prev) => ({ - ...prev, - [day]: { ...prev[day], timeFrom: e.target.value }, - })) - } - /> - – - - setWeekdayTimings((prev) => ({ - ...prev, - [day]: { ...prev[day], timeTo: e.target.value }, - })) - } - /> -
- ); - })} - {errors.weekdayTimings && ( -

{errors.weekdayTimings}

- )} +
+ {/* Standard-Zeitfenster mit "für alle übernehmen" */} +
+

Standard-Zeitfenster

+
+ weekdays.updateDefaultSlot({ timeFrom: e.target.value })} + /> + – + weekdays.updateDefaultSlot({ timeTo: e.target.value })} + /> + +
+

+ Wird automatisch für alle Tage gesetzt, solange du keine Uhrzeit einzeln + anpasst. +

+
+ +
+

Uhrzeiten pro Tag

+ {selectedWeekdays.map((day) => { + const dayLabel = WEEKDAYS.find((w) => w.value === day)?.label ?? day; + const slots: WeekdaySlot[] = weekdayTimings[day]?.length + ? weekdayTimings[day] + : [{ timeFrom: "", timeTo: "" }]; + return ( +
+ {dayLabel} +
+ {slots.map((slot, index) => ( +
+ + weekdays.updateSlot(day, index, { + timeFrom: e.target.value, + }) + } + /> + – + + weekdays.updateSlot(day, index, { + timeTo: e.target.value, + }) + } + /> + {slots.length > 1 && ( + + )} +
+ ))} + +
+
+ ); + })} + {errors.weekdayTimings && ( +

{errors.weekdayTimings}

+ )} +
)} diff --git a/src/modules/courses/utils/generate-instances.ts b/src/modules/courses/utils/generate-instances.ts index dcc9f10..8d968a5 100644 --- a/src/modules/courses/utils/generate-instances.ts +++ b/src/modules/courses/utils/generate-instances.ts @@ -1,6 +1,18 @@ export type FrequencyType = "daily" | "weekly" | "biweekly" | "monthly" | "custom"; -export type WeekdayTiming = { timeFrom: string; timeTo: string }; +export type WeekdaySlot = { timeFrom: string; timeTo: string }; + +/** + * Uhrzeiten pro Wochentag. Jeder Tag kann mehrere Zeitfenster haben + * (z.B. Montag 10:00–11:00 UND 18:00–19:00). + */ +export type WeekdayTimings = Record; + +/** + * Altes Format, das noch in der DB liegen kann: genau ein Zeitfenster pro Tag. + * Wird von {@link normalizeWeekdayTimings} in das neue Array-Format überführt. + */ +export type LegacyWeekdayTiming = { timeFrom: string; timeTo: string }; export type CourseOccurrence = { date: Date; timeFrom: string; timeTo: string }; @@ -32,6 +44,27 @@ const WEEKDAY_MAP: Record = { const toWeekdayNumber = (weekday: string): number | undefined => WEEKDAY_MAP[weekday.trim().toLowerCase()]; +/** + * Bringt beliebige gespeicherte weekdayTimings in das Array-Format. + * Akzeptiert das neue Format (`{ monday: [{...}, {...}] }`) und das alte + * Einzelobjekt-Format (`{ monday: { timeFrom, timeTo } }`). + */ +export function normalizeWeekdayTimings( + raw: Record | null | undefined +): WeekdayTimings { + if (!raw) return {}; + const result: WeekdayTimings = {}; + for (const [day, value] of Object.entries(raw)) { + if (Array.isArray(value)) { + const slots = value.filter((s): s is WeekdaySlot => !!s && typeof s === "object"); + if (slots.length > 0) result[day] = slots; + } else if (value && typeof value === "object") { + result[day] = [{ timeFrom: value.timeFrom ?? "", timeTo: value.timeTo ?? "" }]; + } + } + return result; +} + export const MAX_INSTANCES = 365; export class TooManyInstancesError extends Error { @@ -50,7 +83,7 @@ export function generateOccurrences(params: { defaultTimeFrom: string; defaultTimeTo: string; weekdays?: string[]; - weekdayTimings?: Record; + weekdayTimings?: Record; }): CourseOccurrence[] { const { startDate, @@ -102,10 +135,11 @@ export function generateOccurrences(params: { const targetDays = new Set( weekdays.map(toWeekdayNumber).filter((d): d is number => d !== undefined) ); - const timingsByDay = Object.entries(weekdayTimings).reduce>( - (acc, [weekday, timing]) => { + const normalized = normalizeWeekdayTimings(weekdayTimings); + const slotsByDay = Object.entries(normalized).reduce>( + (acc, [weekday, slots]) => { const day = toWeekdayNumber(weekday); - if (day !== undefined) acc[day] = timing; + if (day !== undefined) acc[day] = slots; return acc; }, {} @@ -113,8 +147,14 @@ export function generateOccurrences(params: { const cursor = new Date(startDate); while (cursor <= endDate) { if (targetDays.has(cursor.getDay())) { - const timing = timingsByDay[cursor.getDay()]; - addOccurrence(cursor, timing?.timeFrom ?? defaultTimeFrom, timing?.timeTo ?? defaultTimeTo); + const slots = slotsByDay[cursor.getDay()]; + if (slots && slots.length > 0) { + for (const slot of slots) { + addOccurrence(cursor, slot.timeFrom || defaultTimeFrom, slot.timeTo || defaultTimeTo); + } + } else { + addOccurrence(cursor, defaultTimeFrom, defaultTimeTo); + } } cursor.setDate(cursor.getDate() + 1); } diff --git a/src/modules/dashboard/ui/components/DashboardSidebar.tsx b/src/modules/dashboard/ui/components/DashboardSidebar.tsx index d70feb1..cc38808 100644 --- a/src/modules/dashboard/ui/components/DashboardSidebar.tsx +++ b/src/modules/dashboard/ui/components/DashboardSidebar.tsx @@ -117,7 +117,7 @@ const DashboardSidebar = ({ userData, displayName }: DashboardSidebarProps) => { return ( - + Kumasy Logo diff --git a/src/modules/settings/ui/views/settings-overview-view.tsx b/src/modules/settings/ui/views/settings-overview-view.tsx index a5d7bfb..1300ed6 100644 --- a/src/modules/settings/ui/views/settings-overview-view.tsx +++ b/src/modules/settings/ui/views/settings-overview-view.tsx @@ -29,7 +29,7 @@ const settingsMenuTitles: SettingsMenuItem[] = [ }, { icon: Building2, - name: "Business Einsetllungen", + name: "Business Einstellungen", href: "/settings/business", description: "Verwalte deine Business Daten", }, diff --git a/src/public/logo-gelb.png b/src/public/logo-gelb.png new file mode 100644 index 0000000000000000000000000000000000000000..a65d4569a461b708a6f81b5b99409b3a39b77cb0 GIT binary patch literal 22549 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