bookwiz.io / lib / hooks / useBooks.ts
useBooks.ts
Raw
'use client'

import { useState, useEffect, useRef, useCallback } from 'react'
import { useAuth } from '@/components/AuthProvider'

export interface Book {
  id: string
  title: string
  description: string | null
  author?: string | null
  lastModified: string
  word_count: number
  status: string
  genre?: string | null
  target_word_count?: number | null
  cover_image_url?: string | null
  created_at?: string
  updated_at?: string
}

export function useBooks() {
  const { user } = useAuth()
  const [books, setBooks] = useState<Book[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const hasFetched = useRef(false)

  useEffect(() => {
    if (!user?.id) {
      setBooks([])
      setLoading(false)
      hasFetched.current = false
      return
    }

    // Only fetch if we haven't fetched for this user yet
    if (!hasFetched.current) {
      fetchBooks()
    }
  }, [user?.id])

  const fetchBooks = async () => {
    if (!user?.id) return

    try {
      setLoading(true)
      setError(null)
      
      const response = await fetch(`/api/books?userId=${user.id}`)
      if (!response.ok) {
        throw new Error('Failed to fetch books')
      }
      
      const data = await response.json()
      const fetchedBooks = data.books || []
      
      setBooks(fetchedBooks)
      hasFetched.current = true
    } catch (error) {
      console.error('Error fetching books:', error)
      setError('Failed to load books')
    } finally {
      setLoading(false)
    }
  }

  // Get a specific book by ID
  const getBook = useCallback((bookId: string): Book | undefined => {
    return books.find(book => book.id === bookId)
  }, [books])

  // Get recent books (for dashboard)
  const getRecentBooks = useCallback((limit: number = 5): Book[] => {
    return books
      .sort((a, b) => new Date(b.lastModified).getTime() - new Date(a.lastModified).getTime())
      .slice(0, limit)
  }, [books])

  // Add a new book to the state
  const addBook = useCallback((newBook: Book) => {
    const updatedBooks = [newBook, ...books]
    setBooks(updatedBooks)
  }, [books])

  // Update an existing book in the state
  const updateBook = useCallback((bookId: string, updates: Partial<Book>) => {
    const updatedBooks = books.map(book => 
      book.id === bookId ? { ...book, ...updates } : book
    )
    setBooks(updatedBooks)
  }, [books])

  // Remove a book from the state
  const deleteBook = useCallback((bookId: string) => {
    const updatedBooks = books.filter(book => book.id !== bookId)
    setBooks(updatedBooks)
  }, [books])

  // Force refresh by fetching fresh data
  const refetch = useCallback(() => {
    hasFetched.current = false
    fetchBooks()
  }, [])

  return {
    books,
    loading,
    error,
    getBook,
    getRecentBooks,
    addBook,
    updateBook,
    deleteBook,
    refetch
  }
}