-
-
{children}
-
+
+ {/* Sidebar */}
+
+
+ {/* Main Content */}
+
+ {children}
+
);
};
diff --git a/src/app/author/page.tsx b/src/app/author/page.tsx
index 058e2b2..8eb93ff 100644
--- a/src/app/author/page.tsx
+++ b/src/app/author/page.tsx
@@ -1,13 +1,326 @@
+"use client";
+import { useState } from 'react';
+import Image from 'next/image';
+import Link from 'next/link';
+import { MoveLeft, Bell, BadgeCheck } from 'lucide-react';
+import { FiBook, FiDollarSign, FiUsers, FiEye } from 'react-icons/fi';
+import ProfileCompletionModal from '@/components/common/Modal';
+import SearchBar from '@/components/common/SearchBar';
+function AuthorDashboard() {
+ const [showProfileModal, setShowProfileModal] = useState(true);
+ const [showProfileAlert, setShowProfileAlert] = useState(true);
+
+ // Mock data - would be fetched from API
+ const stats = {
+ booksPublished: 12,
+ totalEarning: 817.00,
+ totalReads: 12,
+ followers: 12
+ };
+
+ const recentBooks = [
+ { id: 1, title: 'Native Invisibility', author: 'Darrin Collins', price: 10, rating: 4.5, imageUrl: '/bookCover.png', verified: true },
+ { id: 2, title: 'Native Invisibility', author: 'Darrin Collins', price: 10, rating: 4.5, imageUrl: '/bookCover.png', verified: true },
+ { id: 3, title: 'Native Invisibility', author: 'Darrin Collins', price: 10, rating: 4.5, imageUrl: '/bookCover.png', verified: false },
+ { id: 4, title: 'Native Invisibility', author: 'Darrin Collins', price: 10, rating: 4.5, imageUrl: '/bookCover.png', verified: true }
+ ];
+
+ const trendingBooks = [
+ { id: 1, title: 'Native Invisibility', author: 'Darrin Collins', price: 10, rating: 4.5, imageUrl: '/bookCover.png', verified: true },
+ { id: 2, title: 'Native Invisibility', author: 'Darrin Collins', price: 10, rating: 4.5, imageUrl: '/bookCover.png', verified: true },
+ { id: 3, title: 'Native Invisibility', author: 'Darrin Collins', price: 10, rating: 4.5, imageUrl: '/bookCover.png', verified: false },
+ { id: 4, title: 'Native Invisibility', author: 'Darrin Collins', price: 10, rating: 4.5, imageUrl: '/bookCover.png', verified: true }
+ ];
+
+ const topAuthors = [
+ { id: 1, name: 'Elizabeth Joe', imageUrl: '/authorImg.png', verified: true },
+ { id: 2, name: 'Alex Paul', imageUrl: '/authorImg2.png', verified: true },
+ { id: 3, name: 'Samson Tersoor', imageUrl: '/authorImg3.png', verified: true },
+ { id: 4, name: 'Vamika Maya', imageUrl: '/authorImg4.png', verified: true }
+ ];
+ return (
+
+
+
+
+
+
-function Page(){
- return(
-
Page
- )
-}
+
+ {/* Notification bell */}
+
+
+
+
+ {/* Profile */}
+
+
+
+
+
+
Joseph Yanum
+
@joeyanum
+
+
+
+
+
+
+
+
+ {/* Header with Title */}
+
+ {/* Background Image */}
+
+
+
+
+
Your Words
+ Deserve the World
+
+
+
+
+
+
+
+
+ {/* Stats Cards */}
+
+
+
+
+
Books Published
+
{stats.booksPublished}
+
+
+
+
+
+
+
+
+
+
+
Total Earning
+
${stats.totalEarning.toFixed(2)}
+
+
+
+
+
+
+
+
+
+
Total Reads
+
{stats.totalReads}
+
+
+
+
+
+
+
+
+
+
+
Followers
+
{stats.followers}
+
+
+
+
+
+
+
+
+ {/* Profile Completion Alert */}
+ {showProfileAlert && (
+
+
+
+ !
+
+
+ Just a few more details and your profile will be complete!
+
+ Let's get this done so you can enjoy all the features.
+
+
+
+
+ )}
+
+ {/* Recent Published Books */}
+
+
+
Recent Published Books
+
+ View All →
+
+
+
+ {recentBooks.map(book => (
+
+
+
+
+
+
{book.title}
+
+
By {book.author}
+ {book.verified && (
+
+
+
+ )}
+
+
+
${book.price}
+
+ ★
+ {book.rating}
+
+
+
+
+ ))}
+
+
+
+ {/* Trending Books */}
+
+
+
Trending Books
+
+ View All →
+
+
+
+ {trendingBooks.map(book => (
+
+
+
+
+
+
{book.title}
+
+
By {book.author}
+ {book.verified && (
+
+
+
+ )}
+
+
+
${book.price}
+
+ ★
+ {book.rating}
+
+
+
+
+ ))}
+
+
+
+ {/* Top Authors of the Week */}
+
+
+
Top Authors for the Week
+
+ View All →
+
+
+
+ {topAuthors.map(author => (
+
+ {/* Full size author image with overlay */}
+
+
+ {/* Dark gradient overlay */}
+
+
+
+ {/* Author name and verified tag positioned at the bottom */}
+
+
+ ))}
+
+
+
+ {/* Profile Completion Modal */}
+
setShowProfileModal(false)}
+ />
+
+ );
+}
-export default Page;
\ No newline at end of file
+export default AuthorDashboard;
\ No newline at end of file
diff --git a/src/app/author/publish/page.tsx b/src/app/author/publish/page.tsx
index 159f2c1..b9d1117 100644
--- a/src/app/author/publish/page.tsx
+++ b/src/app/author/publish/page.tsx
@@ -1,15 +1,247 @@
+"use client"
+import { useState } from "react"
+import { FileUpload } from "@/components/common/Upload"
+import Image from "next/image"
+import { MoveLeft, Bell, BadgeCheck } from "lucide-react"
+export default function page() {
+ const [seriesType, setSeriesType] = useState
("new")
+ return (
+
+
+ {/* Header with profile and notification */}
+
+
+
+
Manage Content
+
+
+ {/* Notification bell */}
+
+
+
+ {/* Profile */}
+
+
+
+
+
+
Joseph Yanum
+
@joeyanum
+
+
+
+
+
+ {/* Step indicators - updated to match the image */}
+
+
+ {/* Connecting lines */}
+
-function Page(){
- return(
-
Page
- )
-}
+ {/* Step 1 */}
+
+
+ {/* Step 2 */}
+
+
+ {/* Step 3 */}
+
+
+
+
+
+
Series
+
+
+
+ {/* Cover Image Upload */}
+
+
+
+
+
+
Series Content
+
+
+
+
+
+
+
+
+
+
+ {seriesType === "existing" && (
+ <>
+
+
+
+ {/* This is a placeholder for the sunset image in the original */}
+
+
+
Best of the Best
+
Current Series 4
+
+
+ >
+ )}
+
+
-export default Page;
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/components/common/Modal.tsx b/src/components/common/Modal.tsx
index 86e0c4c..4ed36e3 100644
--- a/src/components/common/Modal.tsx
+++ b/src/components/common/Modal.tsx
@@ -1,10 +1,91 @@
+"use client";
+import { useState, useEffect } from 'react';
+import { useRouter } from 'next/navigation';
+import { FiUser, FiX } from 'react-icons/fi';
-function Modal(){
- return(
- Modal
- )
+interface ProfileCompletionModalProps {
+ isOpen: boolean;
+ onClose: () => void;
+ redirectTo?: string;
}
+export default function ProfileCompletionModal({
+ isOpen,
+ onClose,
+ redirectTo = '/author-profile/edit',
+}: ProfileCompletionModalProps) {
+ const router = useRouter();
+ const [isVisible, setIsVisible] = useState(isOpen);
-export default Modal;
\ No newline at end of file
+ useEffect(() => {
+ setIsVisible(isOpen);
+ }, [isOpen]);
+
+ const handleClose = () => {
+ onClose();
+ setIsVisible(false);
+ };
+
+ const handleComplete = () => {
+ handleClose();
+ router.push(redirectTo);
+ };
+
+ // When modal is open, prevent body scrolling
+ useEffect(() => {
+ if (isVisible) {
+ document.body.style.overflow = 'hidden';
+ } else {
+ document.body.style.overflow = 'unset';
+ }
+ return () => {
+ document.body.style.overflow = 'unset';
+ };
+ }, [isVisible]);
+
+ if (!isVisible) return null;
+
+ return (
+
+
e.stopPropagation()}
+ >
+
+
+
+
+
+
+
Unlock Your Full Potential
+
+ You're almost there! Complete your profile so we can tailor your
+ experience and connect you with the right opportunities.
+
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/common/SearchBar.tsx b/src/components/common/SearchBar.tsx
index 6b19580..6f2586f 100644
--- a/src/components/common/SearchBar.tsx
+++ b/src/components/common/SearchBar.tsx
@@ -1,11 +1,37 @@
+"use client";
+import { useState } from 'react';
+import { FiSearch } from 'react-icons/fi';
-
-function SearchBar(){
- return(
- Search bar
- )
+interface SearchBarProps {
+ placeholder?: string;
+ onSearch?: (query: string) => void;
}
+function SearchBar({ placeholder = "Search...", onSearch }: SearchBarProps) {
+ const [query, setQuery] = useState('');
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+ if (onSearch) {
+ onSearch(query);
+ }
+ };
+
+ return (
+
+ );
+}
export default SearchBar;
\ No newline at end of file
diff --git a/src/components/common/Upload.tsx b/src/components/common/Upload.tsx
new file mode 100644
index 0000000..5ed877c
--- /dev/null
+++ b/src/components/common/Upload.tsx
@@ -0,0 +1,219 @@
+"use client"
+
+import { useState, useRef, type DragEvent, type ChangeEvent } from "react"
+import Image from "next/image"
+
+interface FileUploadProps {
+ supportedFormats: string
+ icon: "file" | "image"
+ acceptedFileTypes: string[]
+ containerHeight?: string
+}
+
+export function FileUpload({
+ supportedFormats,
+ icon,
+ acceptedFileTypes,
+ containerHeight = "h-44"
+}: FileUploadProps) {
+ const [isDragging, setIsDragging] = useState(false)
+ const [file, setFile] = useState(null)
+ const [preview, setPreview] = useState(null)
+ const fileInputRef = useRef(null)
+
+ const handleDragOver = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ setIsDragging(true)
+ }
+
+ const handleDragLeave = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ setIsDragging(false)
+ }
+
+ const handleDrop = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ setIsDragging(false)
+
+ const droppedFiles = Array.from(e.dataTransfer.files)
+
+ if (droppedFiles.length === 0) return
+
+ const droppedFile = droppedFiles[0]
+
+ // Check if file type is accepted
+ if (!acceptedFileTypes.includes(droppedFile.type)) {
+ alert(
+ `File type not supported. Please upload ${supportedFormats.toLowerCase().replace("supported format: ", "")}`,
+ )
+ return
+ }
+
+ setFile(droppedFile)
+
+ // Create preview for images
+ if (droppedFile.type.startsWith("image/")) {
+ const reader = new FileReader()
+ reader.onload = () => {
+ setPreview(reader.result as string)
+ }
+ reader.readAsDataURL(droppedFile)
+ } else {
+ setPreview(null)
+ }
+ }
+
+ const handleFileChange = (e: ChangeEvent) => {
+ const selectedFiles = e.target.files
+
+ if (!selectedFiles || selectedFiles.length === 0) return
+
+ const selectedFile = selectedFiles[0]
+
+ // Check if file type is accepted
+ if (!acceptedFileTypes.includes(selectedFile.type)) {
+ alert(
+ `File type not supported. Please upload ${supportedFormats.toLowerCase().replace("supported format: ", "")}`,
+ )
+ return
+ }
+
+ setFile(selectedFile)
+
+ // Create preview for images
+ if (selectedFile.type.startsWith("image/")) {
+ const reader = new FileReader()
+ reader.onload = () => {
+ setPreview(reader.result as string)
+ }
+ reader.readAsDataURL(selectedFile)
+ } else {
+ setPreview(null)
+ }
+ }
+
+ const handleClick = () => {
+ fileInputRef.current?.click()
+ }
+
+ const removeFile = () => {
+ setFile(null)
+ setPreview(null)
+ if (fileInputRef.current) {
+ fileInputRef.current.value = ""
+ }
+ }
+
+ return (
+
+ {!file ? (
+
+
+ {icon === "image" ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
+
Drag and drop or Click to choose file from device
+
{supportedFormats}
+
+
+ ) : (
+
+
+ {preview ? (
+
+

+
+ ) : (
+
+ )}
+
+
{file.name}
+
{(file.size / 1024).toFixed(2)} KB
+
+
+
+
+ )}
+
{supportedFormats}
+
+ )
+}
diff --git a/src/components/layout/Sidenavbar.tsx b/src/components/layout/Sidenavbar.tsx
index a6cf30e..f48fdc5 100644
--- a/src/components/layout/Sidenavbar.tsx
+++ b/src/components/layout/Sidenavbar.tsx
@@ -1,15 +1,167 @@
+"use client"
+import type * as React from "react"
+import { useState, useEffect } from "react"
+import Link from "next/link"
+import Image from "next/image"
+import { usePathname } from "next/navigation"
+import { Menu, X } from "lucide-react"
+import { cn } from "../../lib/utils"
-function SideNavBar (){
- return(
- Side bar
- )
+type SidebarItem = {
+ icon: string
+ label: string
+ href: string
+ badge?: number
}
+export function Sidebar() {
+ const pathname = usePathname()
+ // Start with sidebar closed on mobile by default
+ const [isOpen, setIsOpen] = useState(false)
+ const [isMobile, setIsMobile] = useState(true)
+ // Check if we're on mobile screen size
+ useEffect(() => {
+ const checkScreenSize = () => {
+ const mobile = window.innerWidth < 768
+ setIsMobile(mobile)
+ setIsOpen(!mobile) // Open on desktop, closed on mobile
+ }
+
+ // Initial check
+ checkScreenSize()
+
+ // Add event listener
+ window.addEventListener('resize', checkScreenSize)
+
+ // Cleanup
+ return () => window.removeEventListener('resize', checkScreenSize)
+ }, [])
-export default SideNavBar;
+ const sidebarItems: SidebarItem[] = [
+ {
+ icon: "/dashboardIcon.svg",
+ label: "Dashboard",
+ href: "/author",
+ },
+ {
+ icon: "/manageIcon.svg",
+ label: "Manage Content",
+ href: "/author/publish",
+ },
+ {
+ icon: "/earningsIcon.svg",
+ label: "Earnings",
+ href: "/author/earnings",
+ },
+ {
+ icon: "/analyticsIcon.svg",
+ label: "Analytics panel",
+ href: "/author/analytics",
+ },
+ {
+ icon: "/readersIcon.svg",
+ label: "Readers Feedback",
+ href: "/author/feedback",
+ },
+ {
+ icon: "/notificationIcon.svg",
+ label: "Notification",
+ href: "/notifications",
+ badge: 1,
+ },
+ {
+ icon: "/profileIcon.svg",
+ label: "Profile",
+ href: "/profile",
+ },
+ {
+ icon: "/signoutIcon.svg",
+ label: "Sign Out",
+ href: "/signout",
+ },
+ ]
+ return (
+ <>
+ {/* Toggle button for mobile */}
+
+ {/* Sidebar */}
+
+
+ {/* Overlay for mobile when sidebar is open */}
+ {isOpen && isMobile && (
+ setIsOpen(false)}
+ />
+ )}
+ >
+ )
+}
+export default Sidebar;
\ No newline at end of file