mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-02 20:30:10 +00:00
98c89db0a7
Introduce an autoRequest boolean on Goodreads and Hardcover shelves (default true) so users can pause/resume automatic request creation. Schema, API handlers, hooks and types were updated to accept and persist autoRequest when creating or updating shelves; add endpoints only trigger an immediate resync when the feed/token changes. The shelf sync core and service code now respect autoRequest (skipping request creation and annotating logs when disabled). UI updates include an AddShelf toggle, manage/update payload changes, shelf list props, and visual indicators + toggle actions in the shelf cards.
76 lines
2.3 KiB
TypeScript
76 lines
2.3 KiB
TypeScript
/**
|
|
* Component: Combined Shelves API Routes
|
|
* Documentation: documentation/backend/services/goodreads-sync.md
|
|
*/
|
|
|
|
import { NextRequest, NextResponse } from 'next/server';
|
|
import { requireAuth, AuthenticatedRequest } from '@/lib/middleware/auth';
|
|
import { prisma } from '@/lib/db';
|
|
import { RMABLogger } from '@/lib/utils/logger';
|
|
import { processBooks } from '@/lib/utils/shelf-helpers';
|
|
|
|
const logger = RMABLogger.create('API.Shelves');
|
|
|
|
/**
|
|
* GET /api/user/shelves
|
|
* List the current user's shelves (Goodreads, Hardcover) with book counts and covers
|
|
*/
|
|
export async function GET(request: NextRequest) {
|
|
return requireAuth(request, async (req: AuthenticatedRequest) => {
|
|
try {
|
|
if (!req.user) {
|
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
}
|
|
|
|
const [goodreads, hardcover] = await Promise.all([
|
|
prisma.goodreadsShelf.findMany({
|
|
where: { userId: req.user.id },
|
|
orderBy: { createdAt: 'desc' },
|
|
}),
|
|
prisma.hardcoverShelf.findMany({
|
|
where: { userId: req.user.id },
|
|
orderBy: { createdAt: 'desc' },
|
|
}),
|
|
]);
|
|
|
|
const combined = [
|
|
...goodreads.map((s) => ({
|
|
id: s.id,
|
|
type: 'goodreads',
|
|
name: s.name,
|
|
sourceId: s.rssUrl,
|
|
lastSyncAt: s.lastSyncAt,
|
|
createdAt: s.createdAt,
|
|
bookCount: s.bookCount ?? null,
|
|
autoRequest: s.autoRequest,
|
|
books: processBooks(s.coverUrls),
|
|
})),
|
|
...hardcover.map((s) => ({
|
|
id: s.id,
|
|
type: 'hardcover',
|
|
name: s.name,
|
|
sourceId: s.listId,
|
|
lastSyncAt: s.lastSyncAt,
|
|
createdAt: s.createdAt,
|
|
bookCount: s.bookCount ?? null,
|
|
autoRequest: s.autoRequest,
|
|
books: processBooks(s.coverUrls),
|
|
})),
|
|
].sort(
|
|
(a, b) =>
|
|
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
|
|
);
|
|
|
|
return NextResponse.json({ success: true, shelves: combined });
|
|
} catch (error) {
|
|
logger.error('Failed to list shelves', {
|
|
error: error instanceof Error ? error.message : String(error),
|
|
});
|
|
return NextResponse.json(
|
|
{ error: 'Failed to list shelves' },
|
|
{ status: 500 },
|
|
);
|
|
}
|
|
});
|
|
}
|