Delivered: Super Administrator — env-var provisioned, no StaffProfile at all (structural exclusion from Team/barber-picker/appointments/staff-totals, not a filter). hasPermission short-circuit + new getActingBusinessContext() helper retrofitted across 16 owner pages so it can actually manage the business. Media Manager — one upload/library/external-URL modal + field picker, backing every image field app-wide. Local-disk storage + Docker volume, SVG rejected, size-capped. Welcome backgrounds — desktop/mobile images with CSS breakpoint swap. Business Branding settings — logo/cover/welcome/favicon/icon/colours all editable post-install; cover image finally rendered (was dead config). Service descriptions — now surfaced on Home and in the booking flow. Loyalty card — live preview, ColorPicker/MediaPicker/IconPicker, flip removed for a static premium-styled card, Loyalty added to bottom nav. Fixed a real pre-existing bug where the card's configured colour/image/icon were stored but never actually rendered. Home Screen Redesign — hero gallery + sticky Services/Portfolio/Reviews/Details tabs, backed by a new unified gallery model/service (no hero/portfolio duplication). Details tab surfaces social links and a map that were never shown before. Google Reviews — real sync pipeline (24h cron, CRON_SECRET-gated, mirrors the existing notification cron exactly), DB-only customer reads, owner hide/unhide + policy management page. Architecture cleanup — SettingsPageShell extracted from 6 duplicated page wrappers; fixed a second pre-existing bug where branding image fields could never actually be cleared once set. Verification: 418 tests passing (236 unit + 182 integration, all against a real MySQL database), full typecheck/lint clean across src, and a real Docker build+run cycle — which caught and fixed a genuine bug (scripts/ wasn't copied into the production image, so Super Admin sync would have crashed on every real deployment).
33 lines
1.2 KiB
TypeScript
33 lines
1.2 KiB
TypeScript
import type { Metadata } from "next";
|
|
import { redirect } from "next/navigation";
|
|
import { auth } from "@/auth";
|
|
import { SettingsPageShell } from "@/components/settings/settings-page-shell";
|
|
import { prisma } from "@/lib/db/prisma";
|
|
import { hasPermission } from "@/lib/auth/permissions";
|
|
import { Permission } from "@/generated/prisma/enums";
|
|
import { getActingBusinessContext } from "@/lib/business/get-acting-business-context";
|
|
import { getOpeningHours } from "@/services/business/business.service";
|
|
import { OpeningHoursForm } from "@/features/owner/components/opening-hours-form";
|
|
|
|
export const metadata: Metadata = { title: "Opening Hours" };
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export default async function OwnerOpeningHoursPage() {
|
|
const session = await auth();
|
|
if (!session?.user) redirect("/sign-in");
|
|
|
|
const canManage = await hasPermission(session.user.id, Permission.MANAGE_BUSINESS_PROFILE);
|
|
if (!canManage) redirect("/staff");
|
|
|
|
const context = await getActingBusinessContext();
|
|
if (!context) redirect("/staff");
|
|
|
|
const hours = await getOpeningHours(prisma, context.businessId);
|
|
|
|
return (
|
|
<SettingsPageShell title="Opening Hours" mainClassName="lg:max-w-2xl">
|
|
<OpeningHoursForm initialRows={hours} />
|
|
</SettingsPageShell>
|
|
);
|
|
}
|