Ignore:
Timestamp:
06/24/26 16:28:50 (12 days ago)
Author:
kikisrbinoska <srbinoskakristina07@…>
Branches:
main
Children:
a8f4a2d
Parents:
0b502c2
Message:

Fixed writer section and admin management

Location:
chapterx-frontend/src/pages
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • chapterx-frontend/src/pages/profile/ProfilePage.tsx

    r0b502c2 r99c1e45  
    11import React, { useState, useEffect } from 'react'
    22import { useParams, useNavigate } from 'react-router-dom'
    3 import { BookOpen, Heart, Users, Calendar, MessageCircle, Eye } from 'lucide-react'
     3import { BookOpen, Heart, Calendar, MessageCircle } from 'lucide-react'
    44import { useAuthStore } from '../../store/authStore'
    55import { useStoryStore } from '../../store/storyStore'
     
    1818  const navigate = useNavigate()
    1919  const { allUsers, currentUser, fetchAllUsers, updateUser } = useAuthStore()
    20   const { stories, comments } = useStoryStore()
     20  const { stories, fetchStories } = useStoryStore()
    2121  const { addToast } = useUIStore()
    2222  const [tab, setTab] = useState<Tab>('stories')
     
    2727
    2828  useEffect(() => {
     29    fetchStories()
    2930    if (allUsers.length === 0) {
    3031      setLoading(true)
     
    7475  const userStories = stories.filter(s => s.user_id === user.user_id && s.status === 'published')
    7576  const totalLikes = userStories.reduce((acc, s) => acc + s.total_likes, 0)
    76   const totalViews = userStories.reduce((acc, s) => acc + s.total_views, 0)
    77   const userComments = comments.filter(c => c.user_id === user.user_id)
     77  const totalComments = userStories.reduce((acc, s) => acc + s.total_comments, 0)
    7878  const allGenres = [...new Set(userStories.flatMap(s => s.genres))]
    7979
     
    116116            Joined {new Date(user.created_at).toLocaleDateString('en-US', { month: 'long', year: 'numeric' })}
    117117          </span>
    118           <span className="flex items-center gap-1 text-slate-400 text-sm">
    119             <Users size={14} />
    120             {user.follower_count} followers · {user.following_count} following
    121           </span>
    122118        </div>
    123119      </div>
    124120
    125121      {/* Stats */}
    126       <div className="grid grid-cols-2 sm:grid-cols-4 gap-4 mb-8">
     122      <div className="grid grid-cols-3 gap-4 mb-8">
    127123        {[
    128124          { icon: <BookOpen size={16} className="text-indigo-400" />, value: userStories.length, label: 'Stories' },
    129125          { icon: <Heart size={16} className="text-rose-400" />, value: totalLikes.toLocaleString(), label: 'Likes' },
    130           { icon: <Eye size={16} className="text-blue-400" />, value: totalViews.toLocaleString(), label: 'Views' },
    131           { icon: <MessageCircle size={16} className="text-amber-400" />, value: userComments.length, label: 'Comments' },
     126          { icon: <MessageCircle size={16} className="text-amber-400" />, value: totalComments, label: 'Comments' },
    132127        ].map(s => (
    133128          <div key={s.label} className="bg-slate-800 border border-slate-700 rounded-xl p-4 text-center">
     
    172167      ) : (
    173168        <div className="space-y-6">
    174           <div className="bg-slate-800 border border-slate-700 rounded-2xl p-6">
    175             <h3 className="text-white font-semibold mb-3">About</h3>
    176             <p className="text-slate-300">{user.bio || 'No bio provided.'}</p>
    177           </div>
    178169          {allGenres.length > 0 && (
    179170            <div className="bg-slate-800 border border-slate-700 rounded-2xl p-6">
  • chapterx-frontend/src/pages/story/StoryDetailPage.tsx

    r0b502c2 r99c1e45  
    11import React, { useState } from 'react'
    22import { useParams, useNavigate } from 'react-router-dom'
    3 import { ArrowLeft, BookOpen, Eye, Users, Calendar, Plus, BookmarkPlus } from 'lucide-react'
     3import { ArrowLeft, BookOpen, Users, Calendar, Plus, BookmarkPlus } from 'lucide-react'
    44import { useStoryStore } from '../../store/storyStore'
    55import { useAuthStore } from '../../store/authStore'
     
    117117      {/* Hero */}
    118118      <div className={`relative rounded-2xl overflow-hidden mb-8 bg-gradient-to-br ${gradient}`}>
     119        {story.cover_image && (
     120          <img src={story.cover_image} alt={story.title} className="absolute inset-0 w-full h-full object-cover opacity-30" />
     121        )}
    119122        <div className="absolute inset-0 bg-gradient-to-t from-slate-950/90 via-slate-950/30 to-transparent" />
    120123        <div className="relative p-8 sm:p-12">
     
    134137              <Avatar name={story.author_username} size="sm" />
    135138              <span className="text-white text-sm font-medium">{story.author_username}</span>
    136             </div>
    137             <div className="flex items-center gap-1 text-slate-400 text-sm">
    138               <Eye size={14} />
    139               {story.total_views.toLocaleString()} views
    140139            </div>
    141140            <div className="flex items-center gap-1 text-slate-400 text-sm">
     
    170169          </div>
    171170
     171          {/* Story content */}
     172          {story.content && (
     173            <div className="bg-slate-800/50 border border-slate-700 rounded-2xl p-6">
     174              <p className="text-slate-200 leading-relaxed font-serif whitespace-pre-wrap">{story.content}</p>
     175            </div>
     176          )}
     177
    172178          {/* Chapters */}
    173179          <div>
     
    207213                <span className="text-slate-400">Likes</span>
    208214                <span className="text-white">{(liveLikes ?? story.total_likes).toLocaleString()}</span>
    209               </div>
    210               <div className="flex justify-between">
    211                 <span className="text-slate-400">Views</span>
    212                 <span className="text-white">{story.total_views.toLocaleString()}</span>
    213215              </div>
    214216              <div className="flex justify-between">
  • chapterx-frontend/src/pages/writer/CreateStoryPage.tsx

    r0b502c2 r99c1e45  
    2121    short_description: '',
    2222    content: '',
     23    cover_image: '',
    2324    genres: [] as string[],
    2425    mature_content: false,
     
    4546      story_id: Date.now(),
    4647      ...form,
     48      cover_image: form.cover_image || undefined,
    4749      user_id: currentUser.user_id,
    4850      author_username: currentUser.username,
     
    124126              <span className="text-slate-600 text-xs">{form.short_description.length}/280</span>
    125127            </div>
     128          </div>
     129
     130          {/* Cover image */}
     131          <div>
     132            <label className="block text-sm font-medium text-slate-300 mb-1.5">Cover Image URL <span className="text-slate-500 font-normal">(optional)</span></label>
     133            <input
     134              value={form.cover_image}
     135              onChange={e => {
     136                const val = e.target.value
     137                if (!val || val.startsWith('http')) setField('cover_image', val)
     138              }}
     139              placeholder="https://example.com/image.jpg"
     140              className="w-full px-4 py-3 bg-slate-800 border border-slate-700 rounded-xl text-white placeholder-slate-500 focus:outline-none focus:border-indigo-500"
     141            />
     142            {form.cover_image?.startsWith('http') && (
     143              <img src={form.cover_image} alt="Cover preview" className="mt-2 h-32 w-full object-cover rounded-xl opacity-80" onError={e => (e.currentTarget.style.display = 'none')} />
     144            )}
    126145          </div>
    127146
  • chapterx-frontend/src/pages/writer/WriterDashboard.tsx

    r0b502c2 r99c1e45  
    1 import React from 'react'
     1import React, { useEffect } from 'react'
    22import { useNavigate } from 'react-router-dom'
    3 import { Plus, BookOpen, Eye, Heart, MessageCircle, TrendingUp, Bell } from 'lucide-react'
     3import { Plus, BookOpen, Heart, MessageCircle, TrendingUp, Bell } from 'lucide-react'
    44import { useAuthStore } from '../../store/authStore'
    55import { useStoryStore } from '../../store/storyStore'
     
    2222  const navigate = useNavigate()
    2323  const { currentUser } = useAuthStore()
    24   const { stories, collaborations } = useStoryStore()
     24  const { stories, collaborations, fetchStories } = useStoryStore()
    2525  const { notifications } = useNotificationStore()
     26
     27  useEffect(() => { fetchStories() }, [])
    2628
    2729  if (!currentUser) return null
     
    3436  const published = myStories.filter(s => s.status === 'published')
    3537  const drafts = myStories.filter(s => s.status === 'draft')
    36   const totalViews = myStories.reduce((acc, s) => acc + s.total_views, 0)
    3738  const totalLikes = myStories.reduce((acc, s) => acc + s.total_likes, 0)
    3839
     
    5657
    5758      {/* Stats */}
    58       <div className="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
     59      <div className="grid grid-cols-2 lg:grid-cols-3 gap-4 mb-8">
    5960        {[
    6061          { icon: <BookOpen size={20} className="text-indigo-300" />, label: 'Total Stories', value: myStories.length, sub: `${published.length} published`, color: 'bg-indigo-500/20' },
    61           { icon: <Eye size={20} className="text-blue-300" />, label: 'Total Views', value: totalViews.toLocaleString(), sub: 'All time', color: 'bg-blue-500/20' },
    6262          { icon: <Heart size={20} className="text-rose-300" />, label: 'Total Likes', value: totalLikes.toLocaleString(), sub: 'Across all stories', color: 'bg-rose-500/20' },
    6363          { icon: <TrendingUp size={20} className="text-emerald-300" />, label: 'Drafts', value: drafts.length, sub: 'In progress', color: 'bg-emerald-500/20' },
     
    108108                      <div className="flex items-center gap-3 text-slate-500 text-xs">
    109109                        {isCollab && <span className="text-slate-500">by {story.author_username}</span>}
    110                         <span className="flex items-center gap-1"><Eye size={11} /> {story.total_views.toLocaleString()}</span>
    111110                        <span className="flex items-center gap-1"><Heart size={11} /> {story.total_likes}</span>
    112111                        <span className="flex items-center gap-1"><MessageCircle size={11} /> {story.total_comments}</span>
     
    155154            <TrendingUp size={18} className="text-indigo-400" />
    156155            <h2 className="font-serif text-xl font-bold text-white">Analytics</h2>
    157             <span className="text-slate-500 text-sm">(Story: The Chronicles of Eldoria)</span>
    158156          </div>
    159           <StoryAnalytics />
     157          <StoryAnalytics stories={myStories} />
    160158        </div>
    161159      )}
Note: See TracChangeset for help on using the changeset viewer.