diff --git a/src/app/admin/categories/page.tsx b/src/app/admin/categories/page.tsx new file mode 100644 index 0000000..834eaea --- /dev/null +++ b/src/app/admin/categories/page.tsx @@ -0,0 +1,10 @@ +"use client"; + +export default function AdminCategoriesPage() { + return ( +
+

Categories Management

+

Content for managing categories will go here.

+
+ ); +} diff --git a/src/app/admin/dashboard/page.tsx b/src/app/admin/dashboard/page.tsx new file mode 100644 index 0000000..e2adbb6 --- /dev/null +++ b/src/app/admin/dashboard/page.tsx @@ -0,0 +1,111 @@ +"use client"; + +import { useEffect, useState } from 'react'; +import { useRouter } from 'next/navigation'; +import { ThemeProvider } from '@/providers/themeProvider/ThemeProvider'; +import NavbarStyleFullscreen from '@/components/navbar/NavbarStyleFullscreen/NavbarStyleFullscreen'; + +export default function AdminDashboardPage() { + const router = useRouter(); + const [isAdmin, setIsAdmin] = useState(false); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const token = localStorage.getItem('adminToken'); + const cookieToken = document.cookie.split('; ').find(row => row.startsWith('adminToken='))?.split('=')[1]; + + if (token === 'mock-admin-token' && cookieToken === 'mock-admin-token') { + setIsAdmin(true); + } else { + router.push('/admin/login?message=Unauthorized'); + } + setLoading(false); + }, [router]); + + const handleLogout = () => { + localStorage.removeItem('adminToken'); + document.cookie = 'adminToken=; path=/; max-age=0;'; + router.push('/admin/login'); + }; + + const navItems = [ + { name: "Home", id: "/" }, + { name: "Services", id: "/services" }, + { name: "Pricing", id: "/pricing" }, + { name: "FAQ", id: "/faq" }, + { name: "Contact", id: "/contact" }, + { name: "Admin Login", id: "/admin/login" } + ]; + + if (loading) { + return ( + + +
+

Loading...

+
+
+ ); + } + + if (!isAdmin) { + return null; + } + + return ( + + + +
+
+

Welcome to Admin Dashboard!

+

This is a protected route, accessible only to authenticated administrators.

+ +
+
+
+ ); +} \ No newline at end of file diff --git a/src/app/admin/layout.tsx b/src/app/admin/layout.tsx new file mode 100644 index 0000000..5ae2c39 --- /dev/null +++ b/src/app/admin/layout.tsx @@ -0,0 +1,69 @@ +"use client"; + +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; +import { Home, Package, LayoutGrid, ShoppingCart, Users, ReceiptText, Settings, Menu } from 'lucide-react'; +import React, { useState } from 'react'; + +const adminNavItems = [ + { href: '/admin', label: 'Overview', icon: Home }, + { href: '/admin/services', label: 'Services', icon: Package }, + { href: '/admin/categories', label: 'Categories', icon: LayoutGrid }, + { href: '/admin/orders', label: 'Orders', icon: ShoppingCart }, + { href: '/admin/users', label: 'Users', icon: Users }, + { href: '/admin/transactions', label: 'Transactions', icon: ReceiptText }, + { href: '/admin/settings', label: 'Settings', icon: Settings }, +]; + +export default function AdminLayout({ children }: { children: React.ReactNode }) { + const pathname = usePathname(); + const [isSidebarOpen, setIsSidebarOpen] = useState(false); + + return ( +
+ {/* Mobile Menu Button */} + + + {/* Sidebar */} + + + {/* Main Content */} +
+
+ {children} +
+
+
+ ); +} diff --git a/src/app/admin/login/page.tsx b/src/app/admin/login/page.tsx new file mode 100644 index 0000000..2e6eda5 --- /dev/null +++ b/src/app/admin/login/page.tsx @@ -0,0 +1,101 @@ +"use client"; + +import { useState } from 'react'; +import { useRouter } from 'next/navigation'; +import { ThemeProvider } from '@/providers/themeProvider/ThemeProvider'; +import NavbarStyleFullscreen from '@/components/navbar/NavbarStyleFullscreen/NavbarStyleFullscreen'; + +export default function AdminLoginPage() { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [error, setError] = useState(''); + const router = useRouter(); + + const handleLogin = async (e: React.FormEvent) => { + e.preventDefault(); + setError(''); + + if (email === "admin@demo.com" && password === "Admin@123") { + localStorage.setItem('adminToken', 'mock-admin-token'); + document.cookie = 'adminToken=mock-admin-token; path=/; max-age=3600;'; + router.push('/admin/dashboard'); + } else { + setError('Invalid email or password.'); + } + }; + + const navItems = [ + { name: "Home", id: "/" }, + { name: "Services", id: "/services" }, + { name: "Pricing", id: "/pricing" }, + { name: "FAQ", id: "/faq" }, + { name: "Contact", id: "/contact" }, + { name: "Admin Login", id: "/admin/login" } + ]; + + return ( + + + +
+
+

Admin Login

+
+
+ + setEmail(e.target.value)} + required + /> +
+
+ + setPassword(e.target.value)} + required + /> +
+ {error &&

{error}

} + +
+
+
+
+ ); +} \ No newline at end of file diff --git a/src/app/admin/orders/page.tsx b/src/app/admin/orders/page.tsx new file mode 100644 index 0000000..350c237 --- /dev/null +++ b/src/app/admin/orders/page.tsx @@ -0,0 +1,10 @@ +"use client"; + +export default function AdminOrdersPage() { + return ( +
+

Orders Management

+

Content for managing orders will go here.

+
+ ); +} diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx new file mode 100644 index 0000000..ef2be27 --- /dev/null +++ b/src/app/admin/page.tsx @@ -0,0 +1,100 @@ +"use client"; + +import { BarChart, CreditCard, DollarSign, Package } from 'lucide-react'; +import Link from 'next/link'; + +const revenueData = [ + { date: 'Jan 1', revenue: 1000 }, { date: 'Jan 5', revenue: 1200 }, { date: 'Jan 10', revenue: 1500 }, + { date: 'Jan 15', revenue: 1300 }, { date: 'Jan 20', revenue: 1700 }, { date: 'Jan 25', revenue: 1600 }, + { date: 'Jan 30', revenue: 2000 }, +]; + +const recentOrders = [ + { id: '1001', customer: 'John Doe', amount: '$150.00', status: 'Completed', date: '2024-03-01' }, + { id: '1002', customer: 'Jane Smith', amount: '$230.50', status: 'Pending', date: '2024-03-01' }, + { id: '1003', customer: 'Alice Brown', amount: '$75.25', status: 'Completed', date: '2024-02-29' }, + { id: '1004', customer: 'Bob White', amount: '$400.00', status: 'Processing', date: '2024-02-28' }, + { id: '1005', customer: 'Charlie Green', amount: '$110.00', status: 'Completed', date: '2024-02-28' }, +]; + +export default function AdminOverviewPage() { + return ( +
+

Overview

+ + {/* Revenue Stats Display */} +
+
+
+

Total Revenue

+

$12,450

+
+ +
+
+
+

Total Orders

+

850

+
+ +
+
+
+

Pending Orders

+

32

+
+ +
+
+
+

New Users

+

120

+
+ +
+
+ + {/* Orders Chart (Last 30 Days) */} +
+

Orders Chart (Last 30 Days)

+
+

Placeholder for a chart library (e.g., Recharts, Chart.js)

+
+
+ + {/* Recent Orders Table */} +
+

Recent Orders

+
+ + + + + + + + + + + + {recentOrders.map((order) => ( + + + + + + + + ))} + +
Order IDCustomerAmountStatusDate
{order.id}{order.customer}{order.amount}{order.status}{order.date}
+
+
+ + View All Orders + +
+
+
+ ); +} diff --git a/src/app/admin/services/page.tsx b/src/app/admin/services/page.tsx new file mode 100644 index 0000000..81d18ee --- /dev/null +++ b/src/app/admin/services/page.tsx @@ -0,0 +1,10 @@ +"use client"; + +export default function AdminServicesPage() { + return ( +
+

Services Management

+

Content for managing services will go here.

+
+ ); +} diff --git a/src/app/admin/settings/page.tsx b/src/app/admin/settings/page.tsx new file mode 100644 index 0000000..5bec419 --- /dev/null +++ b/src/app/admin/settings/page.tsx @@ -0,0 +1,10 @@ +"use client"; + +export default function AdminSettingsPage() { + return ( +
+

Settings

+

Content for managing settings will go here.

+
+ ); +} diff --git a/src/app/admin/transactions/page.tsx b/src/app/admin/transactions/page.tsx new file mode 100644 index 0000000..724c09f --- /dev/null +++ b/src/app/admin/transactions/page.tsx @@ -0,0 +1,10 @@ +"use client"; + +export default function AdminTransactionsPage() { + return ( +
+

Transactions Management

+

Content for managing transactions will go here.

+
+ ); +} diff --git a/src/app/admin/users/page.tsx b/src/app/admin/users/page.tsx new file mode 100644 index 0000000..46b3c35 --- /dev/null +++ b/src/app/admin/users/page.tsx @@ -0,0 +1,10 @@ +"use client"; + +export default function AdminUsersPage() { + return ( +
+

Users Management

+

Content for managing users will go here.

+
+ ); +} diff --git a/src/app/api/admin/check-auth/route.ts b/src/app/api/admin/check-auth/route.ts new file mode 100644 index 0000000..b241705 --- /dev/null +++ b/src/app/api/admin/check-auth/route.ts @@ -0,0 +1,14 @@ +import { NextRequest, NextResponse } from 'next/server'; + +export async function GET(req: NextRequest) { + // In a real app, this would verify the JWT token from headers or session cookie. + // For this mock, we assume the middleware handled the primary check, + // or a client component sends a token to be verified. + const token = req.cookies.get('adminToken')?.value || req.headers.get('Authorization')?.split(' ')[1]; + + if (token === 'mock-admin-token') { + return NextResponse.json({ isAuthenticated: true, role: 'admin' }, { status: 200 }); + } else { + return NextResponse.json({ isAuthenticated: false }, { status: 401 }); + } +} \ No newline at end of file diff --git a/src/app/api/admin/login/route.ts b/src/app/api/admin/login/route.ts new file mode 100644 index 0000000..9f493e2 --- /dev/null +++ b/src/app/api/admin/login/route.ts @@ -0,0 +1,13 @@ +import { NextRequest, NextResponse } from 'next/server'; + +export async function POST(req: NextRequest) { + const { email, password } = await req.json(); + + if (email === 'admin@demo.com' && password === 'Admin@123') { + // In a real app, generate a JWT token or create a session. + // For this mock, we'll just indicate success. + return NextResponse.json({ message: 'Login successful', token: 'mock-admin-token' }, { status: 200 }); + } else { + return NextResponse.json({ message: 'Invalid credentials' }, { status: 401 }); + } +} \ No newline at end of file diff --git a/src/app/api/admin/logout/route.ts b/src/app/api/admin/logout/route.ts new file mode 100644 index 0000000..8109f57 --- /dev/null +++ b/src/app/api/admin/logout/route.ts @@ -0,0 +1,7 @@ +import { NextRequest, NextResponse } from 'next/server'; + +export async function POST(req: NextRequest) { + // In a real app, invalidate JWT on server or clear session. + // For this mock, no server-side action is strictly needed as client manages localStorage token and cookie. + return NextResponse.json({ message: 'Logout successful' }, { status: 200 }); +} \ No newline at end of file diff --git a/src/app/orders/page.tsx b/src/app/orders/page.tsx new file mode 100644 index 0000000..6a9b61c --- /dev/null +++ b/src/app/orders/page.tsx @@ -0,0 +1,161 @@ +"use client"; + +import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider"; +import ReactLenis from "lenis/react"; +import NavbarStyleFullscreen from '@/components/navbar/NavbarStyleFullscreen/NavbarStyleFullscreen'; +import FooterBase from '@/components/sections/footer/FooterBase'; +import { CheckCircle, XCircle } from "lucide-react"; + +export default function OrdersManagementPage() { + // Dummy data for orders + const orders = [ + { id: "#1001", user: "John Doe", service: "Instagram Likes", quantity: 1000, status: "Completed", date: "2024-01-15", amount: "$1.00" }, + { id: "#1002", user: "Jane Smith", service: "YouTube Views", quantity: 5000, status: "Pending", date: "2024-01-16", amount: "$5.00" }, + { id: "#1003", user: "Alice Johnson", service: "TikTok Followers", quantity: 200, status: "Processing", date: "2024-01-17", amount: "$0.80" }, + { id: "#1004", user: "Bob Williams", service: "Twitter Retweets", quantity: 100, status: "Cancelled", date: "2024-01-18", amount: "$0.20" }, + { id: "#1005", user: "Charlie Brown", service: "Facebook Shares", quantity: 50, status: "Completed", date: "2024-01-19", amount: "$0.15" }, + ]; + + const statuses = ["All", "Completed", "Pending", "Processing", "Cancelled"]; + + return ( + + + + +
+

Orders Management

+ +
+
+ + +
+ +
+ +
+ + + + + + + + + + + + + + + {orders.map(order => ( + + + + + + + + + + + ))} + +
Order IDUserServiceQuantityAmountDateStatusActions
{order.id}{order.user}{order.service}{order.quantity}{order.amount}{order.date} + + {order.status} + + + + +
+
+
+ + +
+
+ ); +} \ No newline at end of file diff --git a/src/app/page.tsx b/src/app/page.tsx index 86d23f1..320e31b 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -34,7 +34,9 @@ export default function LandingPage() { { name: "Services", id: "/services" }, { name: "Pricing", id: "/pricing" }, { name: "FAQ", id: "/faq" }, - { name: "Contact", id: "/contact" } + { name: "Contact", id: "/contact" }, + { name: "Transactions", id: "/transactions" }, + { name: "Settings", id: "/settings" } ]} logoSrc="http://img.b2bpic.net/free-photo/isolated-white-house-silhouette-minimal-black-landscape_1194-641505.jpg" logoAlt="SocBoost Logo" diff --git a/src/app/users/page.tsx b/src/app/users/page.tsx new file mode 100644 index 0000000..26ed50d --- /dev/null +++ b/src/app/users/page.tsx @@ -0,0 +1,138 @@ +"use client"; + +import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider"; +import ReactLenis from "lenis/react"; +import NavbarStyleFullscreen from '@/components/navbar/NavbarStyleFullscreen/NavbarStyleFullscreen'; +import FooterBase from '@/components/sections/footer/FooterBase'; +import { Plus, Minus } from "lucide-react"; + +export default function UsersManagementPage() { + // Dummy data for users + const users = [ + { id: "u1", username: "johndoe", email: "john@example.com", balance: 150.75, status: "Active" }, + { id: "u2", username: "janesmith", email: "jane@example.com", balance: 23.50, status: "Active" }, + { id: "u3", username: "alicej", email: "alice@example.com", balance: 0.00, status: "Inactive" }, + { id: "u4", username: "bobw", email: "bob@example.com", balance: 500.00, status: "Active" }, + { id: "u5", username: "charlieb", email: "charlie@example.com", balance: 12.30, status: "Active" }, + ]; + + return ( + + + + +
+

Users Management

+ +
+ + + + + + + + + + + + {users.map(user => ( + + + + + + + + ))} + +
UsernameEmailBalanceStatusActions
{user.username}{user.email}${user.balance.toFixed(2)} + + {user.status} + + + + +
+
+
+ + +
+
+ ); +} \ No newline at end of file diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..926c3a5 --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,26 @@ +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; + +export function middleware(request: NextRequest) { + const { pathname } = request.nextUrl; + + // Protect /admin routes + if (pathname.startsWith('/admin') && !pathname.startsWith('/admin/login')) { + const adminToken = request.cookies.get('adminToken'); + + if (adminToken?.value === 'mock-admin-token') { + return NextResponse.next(); + } + + const url = request.nextUrl.clone(); + url.pathname = '/admin/login'; + url.searchParams.set('redirected', 'true'); // Optional: Add a query param to indicate redirection + return NextResponse.redirect(url); + } + + return NextResponse.next(); +} + +export const config = { + matcher: ['/admin/:path*'], // Apply middleware to all routes under /admin +};