Batch #4 UAT items. 1. Documents — clicking any file dumped raw presigned-URL JSON. Was systemic: 6 surfaces linked a browser directly at the JSON-returning /files/[id]/{download,preview} routes. Those routes now 302-redirect when called with ?redirect=1 (default stays JSON for the dialog + interest-eoi-tab programmatic consumers); the six <Link> sites use it. The documents-hub file row now opens the inline FilePreviewDialog + has a per-row Download button, and the preview dialog header gained a persistent Download button for all file types. 2. Clients-by-country — the widget's "+N more" dead text is now a "Show all" link to a new /clients/by-country page rendering the full ranked country breakdown (each row drills into the filtered list). 3. Residential clients list — moved off its bespoke table onto the shared DataTable + ColumnPicker (same UX as clients/interests). Adds a "Date added" column, default-hides the empty "Residence" column, preserves the mobile card view, persists per-user column choices. tsc clean, eslint clean, 1584/1584 vitest. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
23 lines
845 B
TypeScript
23 lines
845 B
TypeScript
import { NextResponse } from 'next/server';
|
|
|
|
import { withAuth, withPermission } from '@/lib/api/helpers';
|
|
import { errorResponse } from '@/lib/errors';
|
|
import { getPreviewUrl } from '@/lib/services/files';
|
|
|
|
export const GET = withAuth(
|
|
withPermission('files', 'view', async (req, ctx, params) => {
|
|
try {
|
|
const result = await getPreviewUrl(params.id!, ctx.portId);
|
|
// `?redirect=1` → 302 to the presigned (inline) URL so a plain
|
|
// <a href>/<Link> opens the file in the browser. Default returns the
|
|
// JSON envelope for programmatic consumers (e.g. FilePreviewDialog).
|
|
if (new URL(req.url).searchParams.has('redirect')) {
|
|
return NextResponse.redirect(result.url, 302);
|
|
}
|
|
return NextResponse.json({ data: result });
|
|
} catch (error) {
|
|
return errorResponse(error);
|
|
}
|
|
}),
|
|
);
|