bookwiz.io / lib / types / database.ts
database.ts
Raw
// Database types for Supabase tables

export interface Book {
  id: string;
  title: string;
  description: string | null;
  status: 'Planning' | 'Draft' | 'In Progress' | 'Completed' | 'Published';
  word_count: number;
  created_at: string;
  updated_at: string;
  user_id: string;
  
  // Metadata
  author: string | null;
  cover_image_url: string | null;
  genre: string | null;
  target_word_count: number | null;
  template_id: string | null;
  
  // Settings (stored as JSONB)
  settings: Record<string, any>;
}

export interface GeneratedImage {
  id: string;
  user_id: string;
  book_id: string | null;
  prompt: string;
  revised_prompt: string | null;
  image_url: string;
  model: string;
  size: string;
  quality: string;
  style: string;
  cost_usd: number;
  metadata: Record<string, any>;
  created_at: string;
  updated_at: string;
}

export interface BookTemplate {
  id: string;
  name: string;
  description: string | null;
  is_default: boolean;
  is_system: boolean;
  structure: TemplateStructure;
  created_by: string | null;
  created_at: string;
  updated_at: string;
  metadata: Record<string, any>;
}

export interface TemplateStructure {
  files: TemplateFile[];
  folders: TemplateFolder[];
}

export interface TemplateFile {
  name: string;
  type: 'file';
  content: string;
  file_extension: string;
  mime_type: string;
  sort_order: number;
}

export interface TemplateFolder {
  name: string;
  type: 'folder';
  expanded: boolean;
  sort_order: number;
  children?: (TemplateFile | TemplateFolder)[];
}

export interface FileSystemItem {
  id: string;
  book_id: string;
  parent_id: string | null;
  
  // Basic properties
  name: string;
  type: 'file' | 'folder';
  
  // File-specific properties
  content: string | null;
  file_extension: string | null;
  mime_type: string | null;
  file_size: number | null;
  file_url: string | null;
  
  // Folder-specific properties
  expanded: boolean;
  
  // Ordering and organization
  sort_order: number;
  
  // Timestamps
  created_at: string;
  updated_at: string;
  
  // Metadata (stored as JSONB)
  metadata: Record<string, any>;
}

// Extended interface for UI purposes (matches current FileItem interface)
export interface FileItem {
  // Convert database IDs to numbers for compatibility with existing UI
  id: number;
  parent_id?: number | null;
  
  // Basic properties
  name: string;
  type: 'file' | 'folder';
  
  // File-specific properties
  content?: string;
  file_extension?: string | null;
  mime_type?: string | null;
  file_size?: number | null;
  file_url?: string | null;
  
  // Folder-specific properties
  expanded?: boolean;
  
  // Ordering and organization
  sort_order?: number;
  
  // For nested structure in UI
  children?: FileItem[];
}

// For API requests
export interface CreateBookRequest {
  title: string;
  description?: string;
  author?: string;
  genre?: string;
  genres?: string[];
  target_word_count?: number;
  template_id?: string;
}

export interface UpdateBookRequest {
  title?: string;
  description?: string;
  author?: string;
  status?: Book['status'];
  genre?: string;
  target_word_count?: number;
  cover_image_url?: string;
  settings?: Record<string, any>;
}

export interface CreateFileSystemItemRequest {
  book_id: string;
  parent_id?: string | null;
  name: string;
  type: 'file' | 'folder';
  content?: string;
  file_extension?: string;
  mime_type?: string;
  sort_order?: number;
}

export interface UpdateFileSystemItemRequest {
  name?: string;
  content?: string;
  expanded?: boolean;
  sort_order?: number;
  parent_id?: string | null;
}

// Response types
export interface BookWithStats extends Book {
  file_count?: number;
  folder_count?: number;
  last_modified_file?: string;
}

// For the file tree view
export interface FileTreeItem extends FileSystemItem {
  depth: number;
  path: number[];
  children?: FileTreeItem[];
}

// Utility types for common operations
export type BookStatus = Book['status'];
export type FileType = FileSystemItem['type'];

// Common mime types for validation
export const SUPPORTED_MIME_TYPES = {
  // Text files
  'text/plain': ['.txt'],
  'text/markdown': ['.md', '.markdown'],
  'text/html': ['.html', '.htm'],
  'application/json': ['.json'],
  
  // Documents
  'application/pdf': ['.pdf'],
  'application/msword': ['.doc'],
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['.docx'],
  
  // Images
  'image/jpeg': ['.jpg', '.jpeg'],
  'image/png': ['.png'],
  'image/gif': ['.gif'],
  'image/svg+xml': ['.svg'],
  'image/webp': ['.webp'],
  
  // Audio
  'audio/mpeg': ['.mp3'],
  'audio/wav': ['.wav'],
  'audio/ogg': ['.ogg'],
  
  // Video
  'video/mp4': ['.mp4'],
  'video/webm': ['.webm'],
  'video/ogg': ['.ogv'],
} as const;

// Helper function to get mime type from file extension
export function getMimeTypeFromExtension(extension: string): string | null {
  const ext = extension.toLowerCase().startsWith('.') ? extension : `.${extension}`;
  
  for (const [mimeType, extensions] of Object.entries(SUPPORTED_MIME_TYPES)) {
    if ((extensions as readonly string[]).includes(ext)) {
      return mimeType;
    }
  }
  
  return null;
}

// Helper function to check if a file type is supported
export function isSupportedFileType(extension: string): boolean {
  return getMimeTypeFromExtension(extension) !== null;
}

// Default file extensions for new files
export const DEFAULT_FILE_EXTENSIONS = {
  markdown: 'md',
  text: 'txt',
  html: 'html',
  json: 'json',
} as const;

// Chat-related interfaces
export interface Chat {
  id: string;
  book_id: string;
  user_id: string;
  title: string;
  created_at: string;
  updated_at: string;
  
  // Chat metadata
  model: string;
  total_messages: number;
  last_message_at: string;
}

export interface Message {
  id: string;
  chat_id: string;
  type: 'user' | 'ai';
  content: string;
  created_at: string;
  
  // Message ordering
  sequence_number: number;
  
  // Optional metadata for AI messages
  model?: string | null;
  tool_results?: Record<string, any> | null;
  context_info?: Record<string, any> | null;
}

// UI-compatible message interface (for compatibility with existing code)
export interface MessageUI {
  id: number | string;
  type: 'user' | 'ai';
  content: string;
  timestamp?: Date;
  
  // Optional metadata
  model?: string;
  tool_results?: Record<string, any>;
  context_info?: Record<string, any>;
}