'use client'; import { useState } from 'react'; import Link from 'next/link'; import Image from 'next/image'; import { Story } from '../../types/api'; import { storyApi, getImageUrl } from '../../lib/api'; import Button from '../ui/Button'; import TagDisplay from '../tags/TagDisplay'; interface StoryCardProps { story: Story; viewMode: 'grid' | 'list'; onUpdate?: () => void; showSelection?: boolean; isSelected?: boolean; onSelect?: () => void; } export default function StoryCard({ story, viewMode, onUpdate, showSelection = false, isSelected = false, onSelect }: StoryCardProps) { const [rating, setRating] = useState(story.rating || 0); const [updating, setUpdating] = useState(false); // Helper function to get tags from either tags array or tagNames array const getTags = () => { if (Array.isArray(story.tags) && story.tags.length > 0) { return story.tags; } if (Array.isArray(story.tagNames) && story.tagNames.length > 0) { // Convert tagNames to Tag objects for display compatibility return story.tagNames.map((name, index) => ({ id: `tag-${index}`, // Temporary ID for display name: name })); } return []; }; const displayTags = getTags(); const handleRatingClick = async (e: React.MouseEvent, newRating: number) => { // Prevent default and stop propagation to avoid triggering navigation e.preventDefault(); e.stopPropagation(); if (updating) return; try { setUpdating(true); await storyApi.updateRating(story.id, newRating); setRating(newRating); onUpdate?.(); } catch (error) { console.error('Failed to update rating:', error); } finally { setUpdating(false); } }; const formatWordCount = (wordCount: number) => { return wordCount.toLocaleString() + ' words'; }; const formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString(); }; const calculateReadingPercentage = (story: Story): number => { if (!story.readingPosition) return 0; const totalLength = story.contentPlain?.length || story.contentHtml?.length || 0; if (totalLength === 0) return 0; return Math.round((story.readingPosition / totalLength) * 100); }; const readingPercentage = calculateReadingPercentage(story); if (viewMode === 'list') { return (
{/* Cover Image */}
{story.coverPath ? ( {story.title} ) : (
📖
)}
{/* Content */}

{story.title}

{story.authorName}

{formatWordCount(story.wordCount)} {formatDate(story.createdAt)} {readingPercentage > 0 && ( {readingPercentage}% read )} {story.seriesName && ( {story.seriesName} #{story.volume} )}
{/* Tags */} {displayTags.length > 0 && (
{displayTags.slice(0, 3).map((tag) => ( ))} {displayTags.length > 3 && ( +{displayTags.length - 3} more )}
)}
{/* Actions */}
{/* Rating */}
{[1, 2, 3, 4, 5].map((star) => ( ))}
{/* Action Buttons */}
); } // Grid view return (
{/* Cover Image */}
{story.coverPath ? ( {story.title} ) : (
📖
)}
{/* Title and Author */}

{story.title}

{story.authorName}

{/* Rating */}
{[1, 2, 3, 4, 5].map((star) => ( ))}
{/* Metadata */}
{formatWordCount(story.wordCount)}
{formatDate(story.createdAt)}
{readingPercentage > 0 && (
{readingPercentage}% read
)} {story.seriesName && (
{story.seriesName} #{story.volume}
)}
{/* Tags */} {displayTags.length > 0 && (
{displayTags.slice(0, 2).map((tag) => ( ))} {displayTags.length > 2 && ( +{displayTags.length - 2} )}
)} {/* Actions */}
); }