Files
ReadMeABook/src/app/admin/settings/tabs/EbookTab/useEbookSettings.ts
T
kikootwo 95e63dfc36 Add ROOTLESS_CONTAINER and request UI updates
Introduce ROOTLESS_CONTAINER env to opt out of gosu (replace /proc uid_map detection) and update entrypoint messaging; adjust app-start.sh and redis-start.sh to skip gosu when ROOTLESS_CONTAINER=true and warn on UID/GID mismatch only when applicable. Backend: include audiobook audibleAsin in admin requests response (mapped to asin) and pass baseUrl through test-flaresolverr endpoint to the FlareSolverr tester. Frontend: RecentRequestsTable and RequestActionsDropdown now surface asin, accept/passthrough annasArchiveBaseUrl, and add a "View Details" flow using AudiobookDetailsModal; admin page passes ebook baseUrl from settings. InteractiveTorrentSearchModal refactor: improved UX/UI, keyboard handling, portal/modal mounting, skeleton/loading states, formatting helpers, and richer result display. Tests updated to match changes.
2026-02-06 17:13:39 -05:00

122 lines
3.5 KiB
TypeScript

/**
* Component: E-book Settings Tab - Custom Hook
* Documentation: documentation/settings-pages.md
*/
'use client';
import { useState } from 'react';
import { fetchWithAuth } from '@/lib/utils/api';
import type { EbookSettings, TestResult } from '../../lib/types';
interface UseEbookSettingsProps {
ebook: EbookSettings;
onChange: (ebook: EbookSettings) => void;
onSuccess: (message: string) => void;
onError: (message: string) => void;
markAsSaved: () => void;
}
export function useEbookSettings({ ebook, onChange, onSuccess, onError, markAsSaved }: UseEbookSettingsProps) {
const [saving, setSaving] = useState(false);
const [testingFlaresolverr, setTestingFlaresolverr] = useState(false);
const [flaresolverrTestResult, setFlaresolverrTestResult] = useState<TestResult | null>(null);
/**
* Update a single ebook field
*/
const updateEbook = (field: keyof EbookSettings, value: string | boolean) => {
onChange({ ...ebook, [field]: value });
if (field === 'flaresolverrUrl') {
setFlaresolverrTestResult(null);
}
};
/**
* Test FlareSolverr connection
*/
const testFlaresolverrConnection = async () => {
if (!ebook.flaresolverrUrl) {
setFlaresolverrTestResult({
success: false,
message: 'Please enter a FlareSolverr URL first',
});
return;
}
setTestingFlaresolverr(true);
setFlaresolverrTestResult(null);
try {
const response = await fetchWithAuth('/api/admin/settings/ebook/test-flaresolverr', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
url: ebook.flaresolverrUrl,
baseUrl: ebook.baseUrl || 'https://annas-archive.li',
}),
});
const result = await response.json();
setFlaresolverrTestResult(result);
} catch (error) {
setFlaresolverrTestResult({
success: false,
message: error instanceof Error ? error.message : 'Test failed',
});
} finally {
setTestingFlaresolverr(false);
}
};
/**
* Save e-book settings to API
*/
const saveSettings = async () => {
setSaving(true);
try {
const response = await fetchWithAuth('/api/admin/settings/ebook', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
annasArchiveEnabled: ebook.annasArchiveEnabled || false,
indexerSearchEnabled: ebook.indexerSearchEnabled || false,
format: ebook.preferredFormat || 'epub',
baseUrl: ebook.baseUrl || 'https://annas-archive.li',
flaresolverrUrl: ebook.flaresolverrUrl || '',
autoGrabEnabled: ebook.autoGrabEnabled ?? true,
kindleFixEnabled: ebook.kindleFixEnabled ?? false,
}),
});
if (!response.ok) {
throw new Error('Failed to save e-book settings');
}
onSuccess('E-book sidecar settings saved successfully!');
markAsSaved();
setTimeout(() => onSuccess(''), 3000);
} catch (error) {
onError(error instanceof Error ? error.message : 'Failed to save e-book settings');
} finally {
setSaving(false);
}
};
/**
* Helper to check if any ebook source is enabled
*/
const isAnySourceEnabled = ebook.annasArchiveEnabled || ebook.indexerSearchEnabled;
return {
saving,
testingFlaresolverr,
flaresolverrTestResult,
updateEbook,
testFlaresolverrConnection,
saveSettings,
isAnySourceEnabled,
};
}