Fixes
CI / ci (push) Canceled after 0s

fixed super admin showing in client list

added a reconnect button to google calendar syncying

fixed ui issue with whatsapp undo link
This commit is contained in:
Stefan Lazic committed 2026-10-17 09:35:52 +01:00
1 parent 2ed9c5ecca
commit 05ea83e059
21 files changed
+1180 -118

No files matched your search

+8 -24
View File
@@ -9,6 +9,7 @@ import { hasPermission } from "@/lib/auth/permissions";
import { prisma } from "@/lib/db/prisma";
import { getActingBusinessContext } from "@/lib/business/get-acting-business-context";
import { getUnreadNotificationCount } from "@/services/notifications/notification.service";
import { clientDirectoryWhere } from "@/services/customer/client-directory";
import { matchesCustomerSearch } from "@/services/customer/customer.service";
import { getLoyaltySummariesForCustomers } from "@/services/loyalty/loyalty.service";
import { InlineNotificationBell } from "@/features/notifications/components/notification-bell";
@@ -34,31 +35,14 @@ export default async function StaffClientsPage({
hasPermission(context.userId, Permission.MANAGE_BUSINESS_PROFILE),
]);
// Scoped via the appointment relation, not "every CustomerProfile row" —
// a real business boundary even though this is a single-business v1 app
// (see docs/phase-5-summary.md). A registered client with NO appointment
// anywhere yet (freshly added via /staff/clients/add, or self-registered
// but never booked) is also included — otherwise a client staff just
// added would be invisible here until their first booking, which reads
// as "did that even work?". A registered client with appointments only
// at some other business (not reachable in this single-business-per-
// deployment app, but kept as a real predicate rather than an assumption)
// is correctly excluded either way. Guests are never included by this
// second branch — a guest profile is only ever created alongside an
// appointment (see resolveGuestCustomer), so one with zero appointments
// shouldn't exist, but isGuest: false is there as a real guard, not a
// guess. `select`-scoped rather than the full row + full appointment
// `include` this used to fetch — the card only ever reads status/startAt
// off each appointment, never the service lines/notes/discount that a
// full include would also pull down for every appointment of every
// client on every page view (see the Phase 7 performance pass).
// Who counts as a client is defined once, in clientDirectoryWhere (shared with
// the detail page so the two can't disagree). `select`-scoped rather than a
// full row + appointment `include`: the card only ever reads status/startAt
// off each appointment, never the service lines/notes/discount a full
// include would pull down for every appointment of every client on every
// page view (see the Phase 7 performance pass).
const customers = await prisma.customerProfile.findMany({
where: {
OR: [
{ appointments: { some: { businessId: context.businessId } } },
{ isGuest: false, appointments: { none: {} } },
],
},
where: clientDirectoryWhere(context.businessId),
select: {
id: true,
firstName: true,