Changeset a8f4a2d for chapterx-frontend/src/pages
- Timestamp:
- 06/24/26 16:51:52 (12 days ago)
- Branches:
- main
- Children:
- 3ae4bab
- Parents:
- 99c1e45
- Location:
- chapterx-frontend/src/pages
- Files:
-
- 4 edited
-
profile/ProfilePage.tsx (modified) (3 diffs)
-
story/ChapterReadPage.tsx (modified) (5 diffs)
-
story/StoryDetailPage.tsx (modified) (1 diff)
-
writer/WriterDashboard.tsx (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
chapterx-frontend/src/pages/profile/ProfilePage.tsx
r99c1e45 ra8f4a2d 1 1 import React, { useState, useEffect } from 'react' 2 2 import { useParams, useNavigate } from 'react-router-dom' 3 import { BookOpen, Heart, Calendar, MessageCircle } from 'lucide-react'3 import { BookOpen, Heart, Calendar, MessageCircle, Eye } from 'lucide-react' 4 4 import { useAuthStore } from '../../store/authStore' 5 5 import { useStoryStore } from '../../store/storyStore' … … 76 76 const totalLikes = userStories.reduce((acc, s) => acc + s.total_likes, 0) 77 77 const totalComments = userStories.reduce((acc, s) => acc + s.total_comments, 0) 78 const totalViews = userStories.reduce((acc, s) => acc + s.total_views, 0) 78 79 const allGenres = [...new Set(userStories.flatMap(s => s.genres))] 79 80 … … 120 121 121 122 {/* Stats */} 122 <div className="grid grid-cols- 3gap-4 mb-8">123 <div className="grid grid-cols-2 sm:grid-cols-4 gap-4 mb-8"> 123 124 {[ 124 125 { icon: <BookOpen size={16} className="text-indigo-400" />, value: userStories.length, label: 'Stories' }, 125 126 { icon: <Heart size={16} className="text-rose-400" />, value: totalLikes.toLocaleString(), label: 'Likes' }, 126 127 { icon: <MessageCircle size={16} className="text-amber-400" />, value: totalComments, label: 'Comments' }, 128 { icon: <Eye size={16} className="text-cyan-400" />, value: totalViews.toLocaleString(), label: 'Views' }, 127 129 ].map(s => ( 128 130 <div key={s.label} className="bg-slate-800 border border-slate-700 rounded-xl p-4 text-center"> -
chapterx-frontend/src/pages/story/ChapterReadPage.tsx
r99c1e45 ra8f4a2d 1 1 import React, { useEffect, useState } from 'react' 2 2 import { useParams, useNavigate } from 'react-router-dom' 3 import { ArrowLeft, ArrowRight, BookOpen, Eye, ChevronLeft, ChevronRight } from 'lucide-react' 3 import { ArrowLeft, ChevronLeft, ChevronRight } from 'lucide-react' 4 import axios from 'axios' 4 5 import { useStoryStore } from '../../store/storyStore' 6 import { Chapter } from '../../types' 5 7 import { Button } from '../../components/ui/Button' 8 9 const API = 'https://localhost:7125/api' 10 11 function mapChapter(c: any): Chapter { 12 return { 13 chapter_id: c.id ?? c.chapter_id, 14 story_id: c.storyId ?? c.story_id, 15 title: c.title ?? c.name ?? '', 16 content: c.content ?? '', 17 chapter_number: c.number ?? c.chapter_number ?? 0, 18 word_count: c.wordCount ?? c.word_count ?? 0, 19 view_count: c.viewCount ?? c.view_count ?? 0, 20 is_published: true, 21 created_at: c.createdAt ?? c.created_at ?? '', 22 updated_at: c.updatedAt ?? c.updated_at ?? '', 23 } 24 } 6 25 7 26 export const ChapterReadPage: React.FC = () => { … … 11 30 const [scrollProgress, setScrollProgress] = useState(0) 12 31 const [viewed, setViewed] = useState(false) 32 const [chapter, setChapter] = useState<Chapter | null>(null) 33 const [loading, setLoading] = useState(true) 34 35 useEffect(() => { 36 setLoading(true) 37 setViewed(false) 38 setScrollProgress(0) 39 axios.get(`${API}/chapters/${chapterId}`) 40 .then(res => { 41 const data = res.data?.chapter ?? res.data 42 setChapter(mapChapter(data)) 43 }) 44 .catch(() => { 45 const fallback = chapters.find(c => c.chapter_id === Number(chapterId)) 46 if (fallback) setChapter(fallback) 47 }) 48 .finally(() => setLoading(false)) 49 }, [chapterId]) 13 50 14 51 const story = stories.find(s => s.story_id === Number(storyId)) 15 const chapter = chapters.find(c => c.chapter_id === Number(chapterId))16 52 const storyChapters = chapters 17 53 .filter(c => c.story_id === Number(storyId) && c.is_published) … … 37 73 return () => window.removeEventListener('scroll', handler) 38 74 }, [chapter, viewed, incrementViewCount]) 75 76 if (loading) { 77 return ( 78 <div className="max-w-4xl mx-auto px-4 py-20 text-center"> 79 <p className="text-slate-400">Loading chapter...</p> 80 </div> 81 ) 82 } 39 83 40 84 if (!story || !chapter) { … … 73 117 </div> 74 118 75 <div className="flex items-center gap-1 text-slate-400 text-xs"> 76 <Eye size={12} /> 77 {scrollProgress.toFixed(0)}% 78 </div> 119 <div /> 79 120 </div> 80 121 </div> … … 90 131 {chapter.title} 91 132 </h1> 92 <div className="flex items-center justify-center gap-4 text-slate-500 text-sm">93 <span className="flex items-center gap-1">94 <BookOpen size={13} />95 {chapter.word_count.toLocaleString()} words96 </span>97 <span className="flex items-center gap-1">98 <Eye size={13} />99 {chapter.view_count.toLocaleString()} reads100 </span>101 </div>102 133 <div className="mt-4 w-16 h-px bg-gradient-to-r from-transparent via-indigo-500 to-transparent mx-auto" /> 103 134 </div> -
chapterx-frontend/src/pages/story/StoryDetailPage.tsx
r99c1e45 ra8f4a2d 217 217 <span className="text-slate-400">Comments</span> 218 218 <span className="text-white">{liveComments ?? story.total_comments}</span> 219 </div> 220 <div className="flex justify-between"> 221 <span className="text-slate-400">Views</span> 222 <span className="text-white">{story.total_views.toLocaleString()}</span> 219 223 </div> 220 224 <div className="flex justify-between"> -
chapterx-frontend/src/pages/writer/WriterDashboard.tsx
r99c1e45 ra8f4a2d 1 1 import React, { useEffect } from 'react' 2 2 import { useNavigate } from 'react-router-dom' 3 import { Plus, BookOpen, Heart, MessageCircle, TrendingUp, Bell } from 'lucide-react'3 import { Plus, BookOpen, Heart, MessageCircle, TrendingUp, Bell, Eye } from 'lucide-react' 4 4 import { useAuthStore } from '../../store/authStore' 5 5 import { useStoryStore } from '../../store/storyStore' … … 37 37 const drafts = myStories.filter(s => s.status === 'draft') 38 38 const totalLikes = myStories.reduce((acc, s) => acc + s.total_likes, 0) 39 const totalViews = myStories.reduce((acc, s) => acc + s.total_views, 0) 39 40 40 41 const recentNotifs = notifications.slice(0, 5) … … 57 58 58 59 {/* Stats */} 59 <div className="grid grid-cols-2 lg:grid-cols- 3gap-4 mb-8">60 <div className="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-8"> 60 61 {[ 61 62 { icon: <BookOpen size={20} className="text-indigo-300" />, label: 'Total Stories', value: myStories.length, sub: `${published.length} published`, color: 'bg-indigo-500/20' }, 62 63 { icon: <Heart size={20} className="text-rose-300" />, label: 'Total Likes', value: totalLikes.toLocaleString(), sub: 'Across all stories', color: 'bg-rose-500/20' }, 64 { icon: <Eye size={20} className="text-cyan-300" />, label: 'Total Views', value: totalViews.toLocaleString(), sub: 'Chapter reads', color: 'bg-cyan-500/20' }, 63 65 { icon: <TrendingUp size={20} className="text-emerald-300" />, label: 'Drafts', value: drafts.length, sub: 'In progress', color: 'bg-emerald-500/20' }, 64 66 ].map(s => ( … … 110 112 <span className="flex items-center gap-1"><Heart size={11} /> {story.total_likes}</span> 111 113 <span className="flex items-center gap-1"><MessageCircle size={11} /> {story.total_comments}</span> 114 <span className="flex items-center gap-1"><Eye size={11} /> {story.total_views.toLocaleString()}</span> 112 115 <span>{story.total_chapters} chapters</span> 113 116 </div>
Note:
See TracChangeset
for help on using the changeset viewer.
