-
+
|
|
@@ -192,7 +192,7 @@ export default function AdminUsersPage() {
{/* Delete Button */}
|
|
{/* User ID */}
diff --git a/frontend/src/pages/DocumentPage.tsx b/frontend/src/pages/DocumentPage.tsx
index cd999fa..00c4dde 100644
--- a/frontend/src/pages/DocumentPage.tsx
+++ b/frontend/src/pages/DocumentPage.tsx
@@ -1,6 +1,9 @@
import { useParams } from 'react-router-dom';
-import { useGetDocument, useGetProgress } from '../generated/anthoLumeAPIV1';
-import { formatDuration, formatNumber } from '../utils/formatters';
+import { useGetDocument, useGetProgress, useEditDocument } from '../generated/anthoLumeAPIV1';
+import { formatDuration } from '../utils/formatters';
+import { DeleteIcon, ActivityIcon, SearchIcon, DownloadIcon, EditIcon, InfoIcon } from '../icons';
+import { X, Check } from 'lucide-react';
+import { useState } from 'react';
interface Document {
id: string;
@@ -34,18 +37,34 @@ interface Progress {
export default function DocumentPage() {
const { id } = useParams<{ id: string }>();
const { data: docData, isLoading: docLoading } = useGetDocument(id || '');
-
const { data: progressData, isLoading: progressLoading } = useGetProgress(id || '');
+ const editMutation = useEditDocument();
+
+ const [showEditCover, setShowEditCover] = useState(false);
+ const [showDelete, setShowDelete] = useState(false);
+ const [showIdentify, setShowIdentify] = useState(false);
+ const [isEditingTitle, setIsEditingTitle] = useState(false);
+ const [isEditingAuthor, setIsEditingAuthor] = useState(false);
+ const [isEditingDescription, setIsEditingDescription] = useState(false);
+ const [showTimeReadInfo, setShowTimeReadInfo] = useState(false);
+
+ // Edit values - initialized after document is loaded
+ const [editTitle, setEditTitle] = useState('');
+ const [editAuthor, setEditAuthor] = useState('');
+ const [editDescription, setEditDescription] = useState('');
if (docLoading || progressLoading) {
return
Loading...
;
}
- const document = docData?.data?.document as Document;
- const progressDataArray = progressData?.data?.progress;
- const progress = Array.isArray(progressDataArray)
- ? (progressDataArray[0] as Progress)
- : undefined;
+ // Check for successful response (status 200)
+ if (!docData || docData.status !== 200) {
+ return
Document not found
;
+ }
+
+ const document = docData.data.document as Document;
+ const progress =
+ progressData?.status === 200 ? (progressData.data.progress as Progress | undefined) : undefined;
if (!document) {
return
Document not found
;
@@ -56,21 +75,66 @@ export default function DocumentPage() {
const secondsPerPercent = document.seconds_per_percent || 0;
const totalTimeLeftSeconds = Math.round((100 - percentage) * secondsPerPercent);
+ // Helper to start editing
+ const startEditing = (field: 'title' | 'author' | 'description') => {
+ if (field === 'title') setEditTitle(document.title);
+ if (field === 'author') setEditAuthor(document.author);
+ if (field === 'description') setEditDescription(document.description || '');
+ };
+
+ // Save edit handlers
+ const saveTitle = () => {
+ editMutation.mutate(
+ {
+ id: document.id,
+ data: { title: editTitle },
+ },
+ {
+ onSuccess: () => setIsEditingTitle(false),
+ onError: () => setIsEditingTitle(false),
+ }
+ );
+ };
+
+ const saveAuthor = () => {
+ editMutation.mutate(
+ {
+ id: document.id,
+ data: { author: editAuthor },
+ },
+ {
+ onSuccess: () => setIsEditingAuthor(false),
+ onError: () => setIsEditingAuthor(false),
+ }
+ );
+ };
+
+ const saveDescription = () => {
+ editMutation.mutate(
+ {
+ id: document.id,
+ data: { description: editDescription },
+ },
+ {
+ onSuccess: () => setIsEditingDescription(false),
+ onError: () => setIsEditingDescription(false),
+ }
+ );
+ };
+
return (
-
-
+
+
{/* Document Info - Left Column */}
- {/* Cover Image */}
- {document.filepath && (
-
-

-
- )}
+ {/* Cover Image with Edit Label */}
+
{/* Read Button - Only if file exists */}
{document.filepath && (
@@ -82,8 +146,9 @@ export default function DocumentPage() {
)}
- {/* Action Buttons */}
-
+ {/* Action Buttons Container */}
+
+ {/* ISBN Info */}
ISBN-10:
@@ -95,112 +160,375 @@ export default function DocumentPage() {
- {/* Download Button - Only if file exists */}
- {document.filepath && (
+ {/* Icons Container */}
+
+ {/* Edit Cover Dropdown */}
+
+
setShowEditCover(e.target.checked)}
+ />
+
+
+
+
+
+
+ {/* Delete Button */}
+
+
+
+
+
+
+
+ {/* Activity Button */}
-
+
- )}
+
+ {/* Identify/Search Button */}
+
+
+
+
+
+
+
+ {/* Download Button */}
+ {document.filepath ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
{/* Document Details Grid */}
{/* Title - Editable */}
-
+
Title
+ {isEditingTitle ? (
+
+
+
+
+ ) : (
+
+ )}
-
+ {isEditingTitle ? (
+
+ setEditTitle(e.target.value)}
+ className="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white rounded font-medium text-lg flex-grow"
+ />
+
+ ) : (
+
{document.title}
+ )}
{/* Author - Editable */}
-
+
Author
+ {isEditingAuthor ? (
+
+
+
+
+ ) : (
+
+ )}
-
+ {isEditingAuthor ? (
+
+ setEditAuthor(e.target.value)}
+ className="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white rounded font-medium text-lg flex-grow"
+ />
+
+ ) : (
+
{document.author}
+ )}
- {/* Time Read */}
+ {/* Time Read with Info Dropdown */}
Time Read
+
+
+
+
Seconds / Percent
+
+ {secondsPerPercent !== 0 ? secondsPerPercent : 'N/A'}
+
+
+
+
Words / Minute
+
+ {document.wpm && document.wpm > 0 ? document.wpm : 'N/A'}
+
+
+
+
Est. Time Left
+
+ {totalTimeLeftSeconds > 0 ? formatDuration(totalTimeLeftSeconds) : 'N/A'}
+
+
+
-
-
- {document.total_time_seconds ? formatDuration(document.total_time_seconds) : 'N/A'}
-
-
+
+ {document.total_time_seconds && document.total_time_seconds > 0
+ ? formatDuration(document.total_time_seconds)
+ : 'N/A'}
+
{/* Progress */}
Progress
-
+
{percentage ? `${Math.round(percentage)}%` : '0%'}
{/* Description - Editable */}
-
+
Description
+ {isEditingDescription ? (
+
+
+
+
+ ) : (
+
+ )}
-
-
{document.description || 'N/A'}
-
+ {isEditingDescription ? (
+
+
+ ) : (
+
+
{document.description || 'N/A'}
+
+ )}
- {/* Reading Statistics */}
-
-
-
Words
-
- {document.words != null ? formatNumber(document.words) : 'N/A'}
-
-
-
-
Created
-
{new Date(document.created_at).toLocaleDateString()}
-
-
-
Updated
-
{new Date(document.updated_at).toLocaleDateString()}
-
-
-
- {/* Additional Reading Stats - Matching Legacy Template */}
- {progress && (
-
-
-
Words / Minute:
-
{document.wpm || 'N/A'}
-
-
-
Est. Time Left:
-
- {formatDuration(totalTimeLeftSeconds)}
-
-
-
- )}
+ {/* Metadata Section */}
+ {/* TODO: Add metadata component when available */}
);
diff --git a/frontend/src/pages/DocumentsPage.tsx b/frontend/src/pages/DocumentsPage.tsx
index 083a027..fe4f4c4 100644
--- a/frontend/src/pages/DocumentsPage.tsx
+++ b/frontend/src/pages/DocumentsPage.tsx
@@ -1,7 +1,7 @@
import { useState, FormEvent, useRef } from 'react';
import { Link } from 'react-router-dom';
import { useGetDocuments, useCreateDocument } from '../generated/anthoLumeAPIV1';
-import { Activity, Download, Search, Upload } from 'lucide-react';
+import { ActivityIcon, DownloadIcon, SearchIcon, UploadIcon } from '../icons';
import { Button } from '../components/Button';
import { useToasts } from '../components/ToastContext';
import { formatDuration } from '../utils/formatters';
@@ -64,14 +64,14 @@ function DocumentCard({ doc }: DocumentCardProps) {
-
+
{doc.filepath ? (
-
+
) : (
-
+
)}
@@ -140,7 +140,7 @@ export default function DocumentsPage() {
diff --git a/frontend/src/pages/HomePage.tsx b/frontend/src/pages/HomePage.tsx
index 50a1857..d25c032 100644
--- a/frontend/src/pages/HomePage.tsx
+++ b/frontend/src/pages/HomePage.tsx
@@ -1,6 +1,6 @@
import { useState } from 'react';
import { Link } from 'react-router-dom';
-import { useGetHome, useGetDocuments } from '../generated/anthoLumeAPIV1';
+import { useGetHome } from '../generated/anthoLumeAPIV1';
import type { LeaderboardData } from '../generated/model';
import ReadingHistoryGraph from '../components/ReadingHistoryGraph';
import { formatNumber, formatDuration } from '../utils/formatters';
@@ -191,15 +191,13 @@ function LeaderboardCard({ name, data }: LeaderboardCardProps) {
export default function HomePage() {
const { data: homeData, isLoading: homeLoading } = useGetHome();
- const { data: docsData, isLoading: docsLoading } = useGetDocuments({ page: 1, limit: 9 });
- const docs = docsData?.data?.documents;
const dbInfo = homeData?.data?.database_info;
const streaks = homeData?.data?.streaks?.streaks;
const graphData = homeData?.data?.graph_data?.graph_data;
const userStats = homeData?.data?.user_statistics;
- if (homeLoading || docsLoading) {
+ if (homeLoading) {
return
Loading...
;
}
@@ -254,25 +252,6 @@ export default function HomePage() {
data={userStats?.words || { all: [], year: [], month: [], week: [] }}
/>
-
- {/* Recent Documents */}
-
- {docs?.slice(0, 6).map((doc: any) => (
-
-
{doc.title}
-
{doc.author}
-
- View Document
-
-
- ))}
-
);
}
diff --git a/frontend/src/pages/SearchPage.tsx b/frontend/src/pages/SearchPage.tsx
index 08ef3a5..c9e00fb 100644
--- a/frontend/src/pages/SearchPage.tsx
+++ b/frontend/src/pages/SearchPage.tsx
@@ -1,7 +1,8 @@
import { useState, FormEvent } from 'react';
import { useGetSearch } from '../generated/anthoLumeAPIV1';
import { GetSearchSource } from '../generated/model/getSearchSource';
-import { Search, Book, Download } from 'lucide-react';
+import { SearchIcon, DownloadIcon } from '../icons';
+import { Book } from 'lucide-react';
import { Button } from '../components/Button';
export default function SearchPage() {
@@ -25,7 +26,7 @@ export default function SearchPage() {
-
+
|
|
diff --git a/frontend/src/pages/SettingsPage.tsx b/frontend/src/pages/SettingsPage.tsx
index 716b92e..91e923c 100644
--- a/frontend/src/pages/SettingsPage.tsx
+++ b/frontend/src/pages/SettingsPage.tsx
@@ -1,6 +1,6 @@
import { useState, useEffect, FormEvent } from 'react';
import { useGetSettings, useUpdateSettings } from '../generated/anthoLumeAPIV1';
-import { User, Lock, Clock } from 'lucide-react';
+import { UserIcon, PasswordIcon, ClockIcon } from '../icons';
import { Button } from '../components/Button';
import { useToasts } from '../components/ToastContext';
@@ -108,7 +108,7 @@ export default function SettingsPage() {
{/* User Profile Card */}
-
+
{settingsData?.data.user.username || 'N/A'}
@@ -121,7 +121,7 @@ export default function SettingsPage() {
|