feat(notes): aggregate-on-read for yachts, companies, residential clients
Extends the listForClientAggregated pattern to three new symmetric
helpers in notes.service so the Notes tab on yacht / company /
residential-client detail pages surfaces the full timeline (own notes
+ related-entity notes) instead of just rows on the entity itself.
- listForYachtAggregated: yacht own + owner client (when ownership
is polymorphic 'client') + linked interest notes.
- listForCompanyAggregated: company own + company-owned yacht notes
+ interests linked to those yachts.
- listForResidentialClientAggregated: own + residential interests.
Generalises NotesList so aggregate=true works for all four entity
types via SELF_SOURCE / AGGREGATABLE / SOURCE_BADGE_CLASS / SOURCE_LABEL
maps; cross-source notes render with a coloured chip and are read-only
(rep edits on the source entity's page so the right timeline records
the change).
Wires ?aggregate=true into the yacht / company / residential-client
notes routes; the yacht / company / residential-client tabs now pass
aggregate. Drops the legacy single-textarea spots on the companies
overview tab and the residential-interest "Initial brief" row in
favour of the threaded feed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,11 +8,14 @@ import { createNoteSchema } from '@/lib/validators/notes';
|
||||
import * as notesService from '@/lib/services/notes.service';
|
||||
|
||||
export const GET = withAuth(
|
||||
withPermission('companies', 'view', async (_req, ctx, params) => {
|
||||
withPermission('companies', 'view', async (req, ctx, params) => {
|
||||
try {
|
||||
const companyId = params.id;
|
||||
if (!companyId) throw new NotFoundError('Company');
|
||||
const notes = await notesService.listForEntity(ctx.portId, 'companies', companyId);
|
||||
const aggregate = new URL(req.url).searchParams.get('aggregate') === 'true';
|
||||
const notes = aggregate
|
||||
? await notesService.listForCompanyAggregated(ctx.portId, companyId)
|
||||
: await notesService.listForEntity(ctx.portId, 'companies', companyId);
|
||||
return NextResponse.json({ data: notes });
|
||||
} catch (error) {
|
||||
return errorResponse(error);
|
||||
|
||||
@@ -7,11 +7,14 @@ import * as notesService from '@/lib/services/notes.service';
|
||||
import { errorResponse, NotFoundError } from '@/lib/errors';
|
||||
|
||||
export const GET = withAuth(
|
||||
withPermission('residential_clients', 'view', async (_req, ctx, params) => {
|
||||
withPermission('residential_clients', 'view', async (req, ctx, params) => {
|
||||
try {
|
||||
const id = params.id;
|
||||
if (!id) throw new NotFoundError('Residential client');
|
||||
const notes = await notesService.listForEntity(ctx.portId, 'residential_clients', id);
|
||||
const aggregate = new URL(req.url).searchParams.get('aggregate') === 'true';
|
||||
const notes = aggregate
|
||||
? await notesService.listForResidentialClientAggregated(ctx.portId, id)
|
||||
: await notesService.listForEntity(ctx.portId, 'residential_clients', id);
|
||||
return NextResponse.json({ data: notes });
|
||||
} catch (error) {
|
||||
return errorResponse(error);
|
||||
|
||||
@@ -8,11 +8,14 @@ import { createNoteSchema } from '@/lib/validators/notes';
|
||||
import * as notesService from '@/lib/services/notes.service';
|
||||
|
||||
export const GET = withAuth(
|
||||
withPermission('yachts', 'view', async (_req, ctx, params) => {
|
||||
withPermission('yachts', 'view', async (req, ctx, params) => {
|
||||
try {
|
||||
const yachtId = params.id;
|
||||
if (!yachtId) throw new NotFoundError('Yacht');
|
||||
const notes = await notesService.listForEntity(ctx.portId, 'yachts', yachtId);
|
||||
const aggregate = new URL(req.url).searchParams.get('aggregate') === 'true';
|
||||
const notes = aggregate
|
||||
? await notesService.listForYachtAggregated(ctx.portId, yachtId)
|
||||
: await notesService.listForEntity(ctx.portId, 'yachts', yachtId);
|
||||
return NextResponse.json({ data: notes });
|
||||
} catch (error) {
|
||||
return errorResponse(error);
|
||||
|
||||
Reference in New Issue
Block a user