← back to Norma

app/api/user-preferences/route.ts

78 lines

/**
 * GET/PUT /api/user-preferences?key=<prefKey>
 * Per-user free-form JSONB preferences (e.g. panel layout, column count).
 * Keyed by the authenticated session username.
 */

import { NextRequest, NextResponse } from 'next/server';
import { requireRole } from '@/lib/require-role';
import { query } from '@/lib/db';

export async function GET(request: NextRequest) {
  const auth = requireRole(request, 'admin', 'staff', 'pulse');
  if (auth instanceof NextResponse) return auth;

  const key = request.nextUrl.searchParams.get('key');
  if (!key) {
    return NextResponse.json({ error: 'key query param required' }, { status: 400 });
  }

  try {
    const { rows } = await query(
      `SELECT pref_value, updated_at
         FROM user_preferences
        WHERE username = $1 AND pref_key = $2`,
      [auth.username, key],
    );
    if (rows.length === 0) {
      return NextResponse.json({ value: null, updatedAt: null });
    }
    return NextResponse.json({
      value: rows[0].pref_value,
      updatedAt: rows[0].updated_at,
    });
  } catch (err) {
    console.error('[user-preferences] GET error:', (err as Error).message);
    return NextResponse.json({ error: 'Failed to load preference' }, { status: 500 });
  }
}

async function writePreference(request: NextRequest) {
  const auth = requireRole(request, 'admin', 'staff', 'pulse');
  if (auth instanceof NextResponse) return auth;

  try {
    const body = await request.json();
    const { key, value } = body as { key?: string; value?: unknown };
    if (!key || typeof key !== 'string') {
      return NextResponse.json({ error: 'key required' }, { status: 400 });
    }
    if (value === undefined) {
      return NextResponse.json({ error: 'value required' }, { status: 400 });
    }

    await query(
      `INSERT INTO user_preferences (username, pref_key, pref_value)
            VALUES ($1, $2, $3::jsonb)
       ON CONFLICT (username, pref_key)
       DO UPDATE SET pref_value = EXCLUDED.pref_value,
                     updated_at = now()`,
      [auth.username, key, JSON.stringify(value)],
    );
    return NextResponse.json({ ok: true });
  } catch (err) {
    console.error('[user-preferences] write error:', (err as Error).message);
    return NextResponse.json({ error: 'Failed to save preference' }, { status: 500 });
  }
}

export async function PUT(request: NextRequest) {
  return writePreference(request);
}

// POST accepted so navigator.sendBeacon (which only POSTs) can flush pending
// saves on page unload, avoiding lost drag-drop changes.
export async function POST(request: NextRequest) {
  return writePreference(request);
}