mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-03 12:50:09 +00:00
Add refresh shelf capability
This commit is contained in:
@@ -41,7 +41,7 @@ export function useUpdateHardcoverShelf() {
|
||||
|
||||
const updateShelf = async (
|
||||
shelfId: string,
|
||||
updates: { listId?: string; apiToken?: string },
|
||||
updates: { listId?: string; apiToken?: string; forceSync?: boolean },
|
||||
) => {
|
||||
return updateGeneric(shelfId, updates);
|
||||
};
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
* Component: Shelves Hook
|
||||
* Documentation: documentation/frontend/components.md
|
||||
*/
|
||||
|
||||
'use client';
|
||||
|
||||
import useSWR from 'swr';
|
||||
import { useState } from 'react';
|
||||
import useSWR, { mutate } from 'swr';
|
||||
import { useAuth } from '@/contexts/AuthContext';
|
||||
import { fetchWithAuth } from '@/lib/utils/api';
|
||||
import { ShelfBook } from './useGoodreadsShelves';
|
||||
@@ -38,3 +36,52 @@ export function useShelves() {
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
export function useSyncShelves() {
|
||||
const { accessToken } = useAuth();
|
||||
const [isSyncing, setIsSyncing] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const syncShelves = async (
|
||||
shelfId?: string,
|
||||
shelfType?: 'goodreads' | 'hardcover',
|
||||
) => {
|
||||
if (!accessToken) throw new Error('Not authenticated');
|
||||
|
||||
setIsSyncing(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await fetchWithAuth('/api/user/shelves/sync', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ shelfId, shelfType }),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.message || data.error || 'Failed to trigger sync');
|
||||
}
|
||||
|
||||
// Invalidate both the provider-specific endpoints and the combined endpoint
|
||||
mutate(
|
||||
(key) =>
|
||||
typeof key === 'string' &&
|
||||
(key.includes('/api/user/shelves') ||
|
||||
key.includes('/api/user/goodreads-shelves') ||
|
||||
key.includes('/api/user/hardcover-shelves')),
|
||||
);
|
||||
|
||||
return true;
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : 'Unknown error';
|
||||
setError(message);
|
||||
throw err;
|
||||
} finally {
|
||||
setIsSyncing(false);
|
||||
}
|
||||
};
|
||||
|
||||
return { syncShelves, isSyncing, error };
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ export interface SyncShelvesPayload {
|
||||
shelfId?: string;
|
||||
/** The type of shelf, if shelfId is specified */
|
||||
shelfType?: 'goodreads' | 'hardcover';
|
||||
/** If set, only process shelves for this user */
|
||||
userId?: string;
|
||||
/** Max Audible lookups per shelf. 0 = unlimited. */
|
||||
maxLookupsPerShelf?: number;
|
||||
}
|
||||
@@ -22,7 +24,7 @@ export interface SyncShelvesPayload {
|
||||
export async function processSyncShelves(
|
||||
payload: SyncShelvesPayload,
|
||||
): Promise<any> {
|
||||
const { jobId, shelfId, shelfType, maxLookupsPerShelf } = payload;
|
||||
const { jobId, shelfId, shelfType, userId, maxLookupsPerShelf } = payload;
|
||||
const logger = RMABLogger.forJob(jobId, 'SyncShelves');
|
||||
|
||||
const stats = {
|
||||
@@ -48,6 +50,7 @@ export async function processSyncShelves(
|
||||
await import('../services/goodreads-sync.service');
|
||||
const grStats = await processGoodreadsShelves(logger, {
|
||||
shelfId: shelfType === 'goodreads' ? shelfId : undefined,
|
||||
userId,
|
||||
maxLookupsPerShelf: maxLookupsPerShelf ?? (shelfId ? 0 : undefined),
|
||||
});
|
||||
|
||||
@@ -70,6 +73,7 @@ export async function processSyncShelves(
|
||||
await import('../services/hardcover-sync.service');
|
||||
const hcStats = await processHardcoverShelves(logger, {
|
||||
shelfId: shelfType === 'hardcover' ? shelfId : undefined,
|
||||
userId,
|
||||
maxLookupsPerShelf: maxLookupsPerShelf ?? (shelfId ? 0 : undefined),
|
||||
});
|
||||
|
||||
|
||||
@@ -118,7 +118,10 @@ export async function processGoodreadsShelves(
|
||||
const stats = createEmptyStats();
|
||||
const maxLookups = resolveMaxLookups(options);
|
||||
|
||||
const whereClause = options.shelfId ? { id: options.shelfId } : {};
|
||||
const whereClause: any = {};
|
||||
if (options.shelfId) whereClause.id = options.shelfId;
|
||||
if (options.userId) whereClause.userId = options.userId;
|
||||
|
||||
const shelves = await prisma.goodreadsShelf.findMany({
|
||||
where: whereClause,
|
||||
include: { user: { select: { id: true, plexUsername: true } } },
|
||||
|
||||
@@ -39,7 +39,10 @@ export async function processHardcoverShelves(
|
||||
const stats = createEmptyStats();
|
||||
const maxLookups = resolveMaxLookups(options);
|
||||
|
||||
const whereClause = options.shelfId ? { id: options.shelfId } : {};
|
||||
const whereClause: any = {};
|
||||
if (options.shelfId) whereClause.id = options.shelfId;
|
||||
if (options.userId) whereClause.userId = options.userId;
|
||||
|
||||
const shelves = await prisma.hardcoverShelf.findMany({
|
||||
where: whereClause,
|
||||
include: { user: { select: { id: true, plexUsername: true } } },
|
||||
|
||||
@@ -112,6 +112,7 @@ export interface SyncShelvesPayload extends JobPayload {
|
||||
scheduledJobId?: string;
|
||||
shelfId?: string;
|
||||
shelfType?: 'goodreads' | 'hardcover';
|
||||
userId?: string;
|
||||
maxLookupsPerShelf?: number;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ export interface ShelfSyncStats {
|
||||
/** Common sync options */
|
||||
export interface ShelfSyncOptions {
|
||||
shelfId?: string;
|
||||
userId?: string;
|
||||
maxLookupsPerShelf?: number;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user