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

Fixed writer section and admin management

File:
1 edited

Legend:

Unmodified
Added
Removed
  • chapterx-frontend/src/components/writer/StoryAnalytics.tsx

    r0b502c2 r99c1e45  
    11import React from 'react'
    22import {
    3   LineChart,
    4   Line,
    53  BarChart,
    64  Bar,
     
    119  ResponsiveContainer,
    1210} from 'recharts'
    13 import { Eye, Heart, MessageCircle, TrendingUp, Clock, BarChart2 } from 'lucide-react'
    14 import { mockAnalytics } from '../../data/mockData'
     11import { Heart, MessageCircle, BookOpen } from 'lucide-react'
     12import { Story } from '../../types'
     13
     14interface Props {
     15  stories: Story[]
     16}
    1517
    1618const StatCard: React.FC<{ icon: React.ReactNode; label: string; value: string | number; color: string }> = ({
    1719  icon, label, value, color,
    1820}) => (
    19   <div className={`p-4 bg-slate-800 rounded-xl border border-slate-700`}>
     21  <div className="p-4 bg-slate-800 rounded-xl border border-slate-700">
    2022    <div className={`w-10 h-10 rounded-xl ${color} flex items-center justify-center mb-3`}>
    2123      {icon}
    2224    </div>
    23     <p className="text-2xl font-bold text-white">{value.toLocaleString()}</p>
     25    <p className="text-2xl font-bold text-white">{typeof value === 'number' ? value.toLocaleString() : value}</p>
    2426    <p className="text-slate-400 text-sm mt-0.5">{label}</p>
    2527  </div>
     
    4244}
    4345
    44 export const StoryAnalytics: React.FC = () => {
    45   const analytics = mockAnalytics
    46   const viewsData = analytics.views_over_time.filter((_, i) => i % 5 === 0)
    47   const likesData = analytics.likes_over_time.filter((_, i) => i % 5 === 0)
     46export const StoryAnalytics: React.FC<Props> = ({ stories }) => {
     47  const published = stories.filter(s => s.status === 'published')
     48
     49  const totalLikes = stories.reduce((a, s) => a + s.total_likes, 0)
     50  const totalComments = stories.reduce((a, s) => a + s.total_comments, 0)
     51  const totalChapters = stories.reduce((a, s) => a + s.total_chapters, 0)
     52
     53  // Likes per story (sorted by created_at)
     54  const likesData = [...published]
     55    .sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime())
     56    .map(s => ({
     57      date: new Date(s.created_at).toLocaleDateString('en-US', { month: 'short', year: '2-digit' }),
     58      likes: s.total_likes,
     59      story: s.title,
     60    }))
     61
     62  if (published.length === 0) {
     63    return (
     64      <div className="text-center py-12 text-slate-500">
     65        <p>No published stories yet — analytics will appear here once you publish.</p>
     66      </div>
     67    )
     68  }
    4869
    4970  return (
    5071    <div className="space-y-6">
    5172      {/* Stat cards */}
    52       <div className="grid grid-cols-2 lg:grid-cols-5 gap-4">
    53         <StatCard icon={<Eye size={18} className="text-blue-300" />} label="Total Views" value={analytics.total_views} color="bg-blue-500/20" />
    54         <StatCard icon={<Heart size={18} className="text-rose-300" />} label="Total Likes" value={analytics.total_likes} color="bg-rose-500/20" />
    55         <StatCard icon={<MessageCircle size={18} className="text-violet-300" />} label="Comments" value={analytics.total_comments} color="bg-violet-500/20" />
    56         <StatCard icon={<Clock size={18} className="text-amber-300" />} label="Avg Read (min)" value={analytics.avg_read_time} color="bg-amber-500/20" />
    57         <StatCard icon={<BarChart2 size={18} className="text-emerald-300" />} label="Completion %" value={`${analytics.completion_rate}%`} color="bg-emerald-500/20" />
    58       </div>
    59 
    60       {/* Views chart */}
    61       <div className="bg-slate-800 border border-slate-700 rounded-2xl p-6">
    62         <div className="flex items-center gap-2 mb-4">
    63           <TrendingUp size={16} className="text-blue-400" />
    64           <h3 className="text-white font-semibold">Views Over Time</h3>
    65         </div>
    66         <ResponsiveContainer width="100%" height={200}>
    67           <LineChart data={viewsData}>
    68             <CartesianGrid strokeDasharray="3 3" stroke="#334155" />
    69             <XAxis dataKey="date" tick={{ fill: '#64748b', fontSize: 11 }} tickLine={false} axisLine={false} />
    70             <YAxis tick={{ fill: '#64748b', fontSize: 11 }} tickLine={false} axisLine={false} />
    71             <Tooltip content={<CustomTooltip />} />
    72             <Line type="monotone" dataKey="views" stroke="#6366f1" strokeWidth={2} dot={false} name="Views" />
    73           </LineChart>
    74         </ResponsiveContainer>
     73      <div className="grid grid-cols-2 lg:grid-cols-3 gap-4">
     74        <StatCard icon={<Heart size={18} className="text-rose-300" />} label="Total Likes" value={totalLikes} color="bg-rose-500/20" />
     75        <StatCard icon={<MessageCircle size={18} className="text-violet-300" />} label="Total Comments" value={totalComments} color="bg-violet-500/20" />
     76        <StatCard icon={<BookOpen size={18} className="text-emerald-300" />} label="Total Chapters" value={totalChapters} color="bg-emerald-500/20" />
    7577      </div>
    7678
     
    7981        <div className="flex items-center gap-2 mb-4">
    8082          <Heart size={16} className="text-rose-400" />
    81           <h3 className="text-white font-semibold">Likes Over Time</h3>
     83          <h3 className="text-white font-semibold">Likes per Story</h3>
    8284        </div>
    83         <ResponsiveContainer width="100%" height={200}>
    84           <BarChart data={likesData}>
    85             <CartesianGrid strokeDasharray="3 3" stroke="#334155" />
    86             <XAxis dataKey="date" tick={{ fill: '#64748b', fontSize: 11 }} tickLine={false} axisLine={false} />
    87             <YAxis tick={{ fill: '#64748b', fontSize: 11 }} tickLine={false} axisLine={false} />
    88             <Tooltip content={<CustomTooltip />} />
    89             <Bar dataKey="likes" fill="#f43f5e" radius={[4, 4, 0, 0]} name="Likes" />
    90           </BarChart>
    91         </ResponsiveContainer>
     85        {likesData.length > 0 ? (
     86          <ResponsiveContainer width="100%" height={200}>
     87            <BarChart data={likesData}>
     88              <CartesianGrid strokeDasharray="3 3" stroke="#334155" />
     89              <XAxis dataKey="date" tick={{ fill: '#64748b', fontSize: 11 }} tickLine={false} axisLine={false} />
     90              <YAxis tick={{ fill: '#64748b', fontSize: 11 }} tickLine={false} axisLine={false} />
     91              <Tooltip content={<CustomTooltip />} />
     92              <Bar dataKey="likes" fill="#f43f5e" radius={[4, 4, 0, 0]} name="Likes" />
     93            </BarChart>
     94          </ResponsiveContainer>
     95        ) : (
     96          <p className="text-slate-500 text-sm text-center py-8">No likes data yet</p>
     97        )}
    9298      </div>
     99
     100      {/* Per-story breakdown */}
     101      {published.length > 1 && (
     102        <div className="bg-slate-800 border border-slate-700 rounded-2xl p-6">
     103          <h3 className="text-white font-semibold mb-4">Story Breakdown</h3>
     104          <div className="space-y-3">
     105            {[...published]
     106              .sort((a, b) => b.total_likes - a.total_likes)
     107              .map(s => (
     108                <div key={s.story_id} className="flex items-center justify-between text-sm">
     109                  <span className="text-slate-300 truncate max-w-xs">{s.title}</span>
     110                  <div className="flex items-center gap-4 text-slate-400 flex-shrink-0">
     111                    <span className="flex items-center gap-1"><Heart size={12} /> {s.total_likes}</span>
     112                    <span className="flex items-center gap-1"><MessageCircle size={12} /> {s.total_comments}</span>
     113                  </div>
     114                </div>
     115              ))}
     116          </div>
     117        </div>
     118      )}
    93119    </div>
    94120  )
Note: See TracChangeset for help on using the changeset viewer.