- To get started, edit the page.tsx file.
+ <>
+
+
+ {/* Hero Section */}
+
+ {/* Background decoration */}
+
+
+
+
+
+
+
+
+
+ Kind Box Management System v2.0
+
+
+
+ Connecting{' '}
+
+ Kindness
+ {' '}
+ with Those in Need
-
- Looking for a starting point or more instructions? Head over to{" "}
-
+ Niki is a comprehensive kind box management platform that connects benefactors,
+ agents, and administrators to streamline donations, deliveries, and tracking
+ across cities.
+
+
+
+
- Templates
- {" "}
- or the{" "}
-
+
+
+ Get Started
+
+
- Learning
- {" "}
- center.
+
+ Browse Shop
+
+
+
+
+
+ {/* Stats Section */}
+
+
+ {stats.map((stat) => (
+
+
+
+ {stat.value}
+
+ {stat.label}
+
+ ))}
+
+
+
+ {/* How It Works Section */}
+
+
+
+ How It Works
+
+
+ From registration to delivery โ Niki makes the entire process seamless and transparent.
-
-
-
- Deploy Now
-
-
- Documentation
-
+
+
+ {howItWorks.map((item, index) => (
+
+ {/* Connector line */}
+ {index < howItWorks.length - 1 && (
+
+ )}
+
+
+ {item.icon}
+
+
+ Step {item.step}
+
+
+ {item.title}
+
+
+ {item.description}
+
+
+
+ ))}
-
-
+
+
+ {/* System Portals */}
+
+
+
+ System Portals
+
+
+ Role-based dashboards designed for each user type.
+
+
+
+
+ {portals.map((portal) => (
+
+
+ {portal.icon}
+
+
+ {portal.title}
+
+
+ {portal.description}
+
+
+ Access portal โ
+
+
+ {portal.roles}
+
+
+ ))}
+
+
+
+ {/* Testimonials Section */}
+
+
+
+ What Our Users Say
+
+
+ Hear from the people who use Niki every day.
+
+
+
+
+ {testimonials.map((t) => (
+
+ {/* Quote icon */}
+
+
+ “{t.quote}”
+
+
+
+ {t.avatar}
+
+
+ {t.name}
+ {t.role}
+
+
+
+ ))}
+
+
+
+ {/* CTA Section */}
+
+
+ {/* Decorative elements */}
+
+
+
+
+
+
+ Ready to Get Started?
+
+
+ Join thousands of benefactors, agents, and administrators making a difference
+ through the Niki kind box management system.
+
+
+
+ Create Free Account
+
+
+
+ Browse Products
+
+
+
+
+
+
+
+ >
);
}
diff --git a/src/app/patients/page.tsx b/src/app/patients/page.tsx
new file mode 100644
index 0000000..fd1221d
--- /dev/null
+++ b/src/app/patients/page.tsx
@@ -0,0 +1,57 @@
+'use client';
+
+import { useState } from 'react';
+import PageHeader from '@/components/PageHeader';
+import EmptyState from '@/components/EmptyState';
+
+const mockPatients = [
+ { id: 1, firstName: 'Zahra', lastName: 'Moradi', phone: '09171234567', sex: 'female' as const, caseStatus: 'open' as const, referralSource: 'hospital' as const, dateOfBirth: '1980-03-12' },
+ { id: 2, firstName: 'Hassan', lastName: 'Jafari', phone: '09181234567', sex: 'male' as const, caseStatus: 'inProgress' as const, referralSource: 'community' as const, dateOfBirth: '1995-07-25' },
+];
+
+export default function PatientsPage() {
+ const [search, setSearch] = useState('');
+ const filtered = mockPatients.filter((p) => `${p.firstName} ${p.lastName} ${p.phone}`.toLowerCase().includes(search.toLowerCase()));
+
+ return (
+
+
+
+
+ setSearch(e.target.value)} className="form-input pl-10" />
+
+ {filtered.length > 0 ? (
+
+
+
+
+ ID
+ Name
+ Phone
+ Sex
+ Case Status
+ Referral
+ Actions
+
+
+
+ {filtered.map((p) => (
+
+ #{p.id}
+ {p.firstName} {p.lastName}
+ {p.phone}
+ {p.sex}
+ {p.caseStatus}
+ {p.referralSource}
+
+
+ ))}
+
+
+
+ ) : (
+
+ )}
+
+ );
+}
diff --git a/src/app/products/page.tsx b/src/app/products/page.tsx
new file mode 100644
index 0000000..51c7572
--- /dev/null
+++ b/src/app/products/page.tsx
@@ -0,0 +1,142 @@
+'use client';
+
+import { useState } from 'react';
+import PageHeader from '@/components/PageHeader';
+import EmptyState from '@/components/EmptyState';
+import { formatCurrency } from '@/lib/utils';
+
+const categories = ['All', 'Care Packages', 'Health', 'Education', 'Food', 'Clothing', 'Hygiene'] as const;
+
+const mockProducts = [
+ // Care Packages
+ { id: 1, name: 'Basic Care Package', slug: 'basic-care', description: 'Essential items for daily needs including rice, oil, and canned goods', price: 250000, stock: 50, isActive: true, category: 'Care Packages', image: '๐ฆ' },
+ { id: 2, name: 'Family Support Pack', slug: 'family-support', description: 'Monthly family essentials bundle for a family of four', price: 580000, stock: 25, isActive: true, category: 'Care Packages', image: '๐ ' },
+ { id: 3, name: 'Emergency Relief Kit', slug: 'emergency-relief', description: 'Quick response kit with food, water, and first aid supplies', price: 420000, stock: 15, isActive: true, category: 'Care Packages', image: '๐จ' },
+ // Health
+ { id: 4, name: 'Health Kit', slug: 'health-kit', description: 'Medical and hygiene supplies including bandages and sanitizers', price: 500000, stock: 30, isActive: true, category: 'Health', image: '๐' },
+ { id: 5, name: 'First Aid Bundle', slug: 'first-aid', description: 'Complete first aid kit for home and community use', price: 350000, stock: 40, isActive: true, category: 'Health', image: '๐ฉน' },
+ { id: 6, name: 'Wellness Package', slug: 'wellness', description: 'Vitamins, supplements, and wellness products for all ages', price: 620000, stock: 20, isActive: true, category: 'Health', image: '๐ฟ' },
+ // Education
+ { id: 7, name: 'Education Pack', slug: 'education-pack', description: 'School supplies, notebooks, and books for students', price: 350000, stock: 20, isActive: true, category: 'Education', image: '๐' },
+ { id: 8, name: 'Student Starter Kit', slug: 'student-starter', description: 'Backpack filled with essential school supplies', price: 450000, stock: 35, isActive: true, category: 'Education', image: '๐' },
+ { id: 9, name: 'Library Bundle', slug: 'library-bundle', description: 'Collection of educational books and learning materials', price: 750000, stock: 10, isActive: true, category: 'Education', image: '๐' },
+ // Food
+ { id: 10, name: 'Monthly Food Basket', slug: 'food-basket', description: 'Rice, beans, cooking oil, pasta, and canned vegetables', price: 380000, stock: 60, isActive: true, category: 'Food', image: '๐' },
+ { id: 11, name: 'Nutrition Pack for Children', slug: 'kids-nutrition', description: 'Healthy snacks, milk powder, and cereals for children', price: 290000, stock: 45, isActive: true, category: 'Food', image: '๐ฅ' },
+ { id: 12, name: 'Ramadan Essentials', slug: 'ramadan-essentials', description: 'Dates, nuts, cooking ingredients for the holy month', price: 520000, stock: 30, isActive: true, category: 'Food', image: '๐' },
+ // Clothing
+ { id: 13, name: 'Winter Clothing Set', slug: 'winter-clothing', description: 'Warm jackets, scarves, and gloves for cold weather', price: 680000, stock: 18, isActive: true, category: 'Clothing', image: '๐งฅ' },
+ { id: 14, name: 'Children Clothing Pack', slug: 'kids-clothing', description: 'Set of seasonal clothes for children ages 2-12', price: 420000, stock: 25, isActive: true, category: 'Clothing', image: '๐' },
+ // Hygiene
+ { id: 15, name: 'Hygiene Package', slug: 'hygiene-kit', description: 'Soap, shampoo, toothpaste, and sanitary products', price: 180000, stock: 80, isActive: true, category: 'Hygiene', image: '๐งผ' },
+ { id: 16, name: 'Baby Care Kit', slug: 'baby-care', description: 'Diapers, baby wipes, lotion, and baby food', price: 320000, stock: 22, isActive: true, category: 'Hygiene', image: '๐ถ' },
+];
+
+export default function ProductsPage() {
+ const [search, setSearch] = useState('');
+ const [activeCategory, setActiveCategory] = useState('All');
+ const [cartCount, setCartCount] = useState(0);
+
+ const filtered = mockProducts.filter((p) => {
+ const matchesSearch = p.name.toLowerCase().includes(search.toLowerCase()) ||
+ p.description.toLowerCase().includes(search.toLowerCase());
+ const matchesCategory = activeCategory === 'All' || p.category === activeCategory;
+ return matchesSearch && matchesCategory;
+ });
+
+ const handleAddToCart = () => {
+ setCartCount((c) => c + 1);
+ };
+
+ return (
+
+ 0 ? {
+ label: `Cart (${cartCount})`,
+ href: '/cart',
+ } : undefined}
+ />
+
+ {/* Search and Filters */}
+
+
+
+ setSearch(e.target.value)}
+ className="form-input pl-10"
+ />
+
+
+
+ {/* Category Pills */}
+
+ {categories.map((cat) => (
+
+ ))}
+
+
+ {/* Product Grid */}
+ {filtered.length > 0 ? (
+
+ {filtered.map((p) => (
+
+ {/* Product Image Placeholder */}
+
+ {p.image}
+
+
+ {p.category}
+
+
+
+
+
+ {p.name}
+ {p.description}
+
+
+
+ {formatCurrency(p.price)}
+
+
+ {p.stock <= 15 ? `Only ${p.stock} left` : `Stock: ${p.stock}`}
+
+
+
+
+
+
+ ))}
+
+ ) : (
+
+ )}
+
+ );
+}
diff --git a/src/app/sales-reports/page.tsx b/src/app/sales-reports/page.tsx
new file mode 100644
index 0000000..dcef16e
--- /dev/null
+++ b/src/app/sales-reports/page.tsx
@@ -0,0 +1,51 @@
+'use client';
+
+import { useState } from 'react';
+import PageHeader from '@/components/PageHeader';
+import { formatCurrency } from '@/lib/utils';
+
+const mockStats = { totalRevenue: 15000000, totalOrders: 45, totalBenefactors: 120, totalCampaigns: 8 };
+const mockRecent = [
+ { id: 1, date: '2025-06-10', amount: 750000, orders: 3 },
+ { id: 2, date: '2025-06-09', amount: 500000, orders: 2 },
+ { id: 3, date: '2025-06-08', amount: 1250000, orders: 5 },
+];
+
+export default function SalesReportsPage() {
+ return (
+
+
+
+
+ Total Revenue
{formatCurrency(mockStats.totalRevenue)}
+ Total Orders
{mockStats.totalOrders}
+ Benefactors
{mockStats.totalBenefactors}
+ Campaigns
{mockStats.totalCampaigns}
+
+
+
+ Recent Sales
+
+
+
+
+ Date
+ Orders
+ Revenue
+
+
+
+ {mockRecent.map((r) => (
+
+ {r.date}
+ {r.orders}
+ {formatCurrency(r.amount)}
+
+ ))}
+
+
+
+
+
+ );
+}
diff --git a/src/app/staff/page.tsx b/src/app/staff/page.tsx
new file mode 100644
index 0000000..e732a6c
--- /dev/null
+++ b/src/app/staff/page.tsx
@@ -0,0 +1,59 @@
+'use client';
+
+import { useState } from 'react';
+import PageHeader from '@/components/PageHeader';
+import StatusBadge from '@/components/StatusBadge';
+import EmptyState from '@/components/EmptyState';
+import { formatDateTime } from '@/lib/utils';
+
+const mockStaff = [
+ { id: 1, firstName: 'Dr. Amir', lastName: 'Hosseini', phoneNumber: '09111234567', email: 'amir@niki.com', role: 'doctor', isActive: true, createdAt: '2025-01-15T08:00:00' },
+ { id: 2, firstName: 'Nurse Maryam', lastName: 'Akbari', phoneNumber: '09121234567', email: 'maryam@niki.com', role: 'nurse', isActive: true, createdAt: '2025-02-01T08:00:00' },
+];
+
+export default function StaffPage() {
+ const [search, setSearch] = useState('');
+ const filtered = mockStaff.filter((s) => `${s.firstName} ${s.lastName}`.toLowerCase().includes(search.toLowerCase()));
+
+ return (
+
+
+
+
+ setSearch(e.target.value)} className="form-input pl-10" />
+
+ {filtered.length > 0 ? (
+
+
+
+
+ ID
+ Name
+ Phone
+ Email
+ Role
+ Status
+ Joined
+
+
+
+ {filtered.map((s) => (
+
+ #{s.id}
+ {s.firstName} {s.lastName}
+ {s.phoneNumber}
+ {s.email}
+ {s.role}
+
+ {formatDateTime(s.createdAt)}
+
+ ))}
+
+
+
+ ) : (
+
+ )}
+
+ );
+}
diff --git a/src/app/wallet/page.tsx b/src/app/wallet/page.tsx
new file mode 100644
index 0000000..cb0468d
--- /dev/null
+++ b/src/app/wallet/page.tsx
@@ -0,0 +1,71 @@
+'use client';
+
+import { useState } from 'react';
+import PageHeader from '@/components/PageHeader';
+import StatusBadge from '@/components/StatusBadge';
+import { formatCurrency, formatDateTime } from '@/lib/utils';
+
+const mockWallet = { id: 1, balance: '2500000', currency: 'IRR' as const, status: 'active' as const, createdAt: '2025-01-01' };
+
+const mockTransactions = [
+ { id: 1, amount: '500000', currency: 'IRR', actionType: 'deposit' as const, timestamp: '2025-06-10T09:00:00', description: 'Deposit' },
+ { id: 2, amount: '250000', currency: 'IRR', actionType: 'withdraw' as const, timestamp: '2025-06-08T14:30:00', description: 'Order #123 payment' },
+ { id: 3, amount: '100000', currency: 'IRR', actionType: 'donate' as const, timestamp: '2025-06-05T11:00:00', description: 'Donation to Winter Campaign' },
+];
+
+export default function WalletPage() {
+ const [activeTab, setActiveTab] = useState<'wallet' | 'transactions'>('wallet');
+
+ return (
+
+
+
+
+
+ Current Balance
+ {formatCurrency(Number(mockWallet.balance))}
+
+ Status:
+ Currency: {mockWallet.currency}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {activeTab === 'transactions' && (
+
+
+
+
+ ID
+ Type
+ Amount
+ Description
+ Date
+
+
+
+ {mockTransactions.map((t) => (
+
+ #{t.id}
+ {t.actionType}
+ {t.actionType === 'deposit' ? '+' : '-'}{formatCurrency(Number(t.amount))}
+ {t.description}
+ {formatDateTime(t.timestamp)}
+
+ ))}
+
+
+
+ )}
+
+ );
+}
diff --git a/src/components/AuthGuard.tsx b/src/components/AuthGuard.tsx
new file mode 100644
index 0000000..249ae52
--- /dev/null
+++ b/src/components/AuthGuard.tsx
@@ -0,0 +1,67 @@
+'use client';
+
+import { useEffect, ReactNode } from 'react';
+import { useRouter } from 'next/navigation';
+import { useAuth } from '@/lib/AuthContext';
+
+interface AuthGuardProps {
+ children: ReactNode;
+ requiredRoles?: string[];
+}
+
+export default function AuthGuard({ children, requiredRoles }: AuthGuardProps) {
+ const router = useRouter();
+ const { isAuthenticated, isLoading, role } = useAuth();
+
+ useEffect(() => {
+ if (!isLoading && !isAuthenticated) {
+ router.replace('/login');
+ }
+ }, [isLoading, isAuthenticated, router]);
+
+ // Check role requirements
+ useEffect(() => {
+ if (!isLoading && isAuthenticated && requiredRoles && role) {
+ if (!requiredRoles.includes(role)) {
+ router.replace('/');
+ }
+ }
+ }, [isLoading, isAuthenticated, role, requiredRoles, router]);
+
+ if (isLoading) {
+ return (
+
+
+
+ Loading...
+
+
+ );
+ }
+
+ if (!isAuthenticated) {
+ return (
+
+
+
+ Redirecting to login...
+
+
+ );
+ }
+
+ // Check role
+ if (requiredRoles && role && !requiredRoles.includes(role)) {
+ return (
+
+
+ ๐
+ Access Denied
+ You do not have permission to access this page.
+
+
+ );
+ }
+
+ return <>{children}>;
+}
diff --git a/src/components/EmptyState.tsx b/src/components/EmptyState.tsx
new file mode 100644
index 0000000..2a69058
--- /dev/null
+++ b/src/components/EmptyState.tsx
@@ -0,0 +1,28 @@
+'use client';
+
+import Link from 'next/link';
+
+interface EmptyStateProps {
+ icon?: string;
+ title: string;
+ description?: string;
+ action?: {
+ label: string;
+ href: string;
+ };
+}
+
+export default function EmptyState({ icon = '๐ญ', title, description, action }: EmptyStateProps) {
+ return (
+
+ {icon}
+ {title}
+ {description && {description}
}
+ {action && (
+
+ {action.label}
+
+ )}
+
+ );
+}
diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx
new file mode 100644
index 0000000..e8896d1
--- /dev/null
+++ b/src/components/Footer.tsx
@@ -0,0 +1,105 @@
+import Link from 'next/link';
+
+const roleGroups = [
+ {
+ role: 'Super Admin / Admin',
+ dashboards: [
+ { label: 'Admin Dashboard', href: '/admin/dashboard' },
+ { label: 'Benefactors', href: '/admin/benefactors' },
+ { label: 'Agents', href: '/admin/agents' },
+ { label: 'Kind Boxes', href: '/admin/kind-boxes' },
+ { label: 'Kind Box Requests', href: '/admin/kind-box-requests' },
+ { label: 'Refer Times', href: '/admin/refer-times' },
+ { label: 'Patients', href: '/patients' },
+ { label: 'Drivers', href: '/drivers' },
+ { label: 'Staff', href: '/staff' },
+ { label: 'Sales Reports', href: '/sales-reports' },
+ { label: 'Gamification', href: '/gamification' },
+ ],
+ },
+ {
+ role: 'Benefactor',
+ dashboards: [
+ { label: 'My Kind Boxes', href: '/benefactor/kind-boxes' },
+ { label: 'My Requests', href: '/benefactor/kind-box-requests' },
+ { label: 'My Addresses', href: '/benefactor/addresses' },
+ { label: 'Refer Times', href: '/benefactor/refer-times' },
+ ],
+ },
+ {
+ role: 'Agent',
+ dashboards: [
+ { label: 'Agent Dashboard', href: '/agent/dashboard' },
+ { label: 'Return Awaiting', href: '/agent/kind-boxes' },
+ { label: 'Delivery Awaiting', href: '/agent/kind-box-requests' },
+ ],
+ },
+ {
+ role: 'General',
+ dashboards: [
+ { label: 'Products', href: '/products' },
+ { label: 'Cart', href: '/cart' },
+ { label: 'Orders', href: '/orders' },
+ { label: 'Campaigns', href: '/campaigns' },
+ { label: 'Wallet', href: '/wallet' },
+ ],
+ },
+];
+
+export default function Footer() {
+ return (
+
+ );
+}
diff --git a/src/components/LandingFooter.tsx b/src/components/LandingFooter.tsx
new file mode 100644
index 0000000..a1358a7
--- /dev/null
+++ b/src/components/LandingFooter.tsx
@@ -0,0 +1,95 @@
+import Link from 'next/link';
+
+const footerLinks = {
+ platform: {
+ title: 'Platform',
+ links: [
+ { label: 'Admin Dashboard', href: '/admin/dashboard' },
+ { label: 'Benefactor Portal', href: '/benefactor/kind-boxes' },
+ { label: 'Agent Panel', href: '/agent/dashboard' },
+ { label: 'Marketplace', href: '/products' },
+ ],
+ },
+ resources: {
+ title: 'Resources',
+ links: [
+ { label: 'Cart', href: '/cart' },
+ { label: 'Orders', href: '/orders' },
+ { label: 'Campaigns', href: '/campaigns' },
+ { label: 'Wallet', href: '/wallet' },
+ ],
+ },
+ company: {
+ title: 'Company',
+ links: [
+ { label: 'About Us', href: '/' },
+ { label: 'Contact', href: '/' },
+ { label: 'Privacy Policy', href: '/' },
+ { label: 'Terms of Service', href: '/' },
+ ],
+ },
+};
+
+export default function LandingFooter() {
+ return (
+
+ );
+}
diff --git a/src/components/LandingNavbar.tsx b/src/components/LandingNavbar.tsx
new file mode 100644
index 0000000..a8172ab
--- /dev/null
+++ b/src/components/LandingNavbar.tsx
@@ -0,0 +1,98 @@
+'use client';
+
+import Link from 'next/link';
+import { useAuth } from '@/lib/AuthContext';
+
+export default function LandingNavbar() {
+ const { isAuthenticated, user, logout } = useAuth();
+
+ return (
+
+ );
+}
diff --git a/src/components/MainContent.tsx b/src/components/MainContent.tsx
new file mode 100644
index 0000000..aa7a2e9
--- /dev/null
+++ b/src/components/MainContent.tsx
@@ -0,0 +1,22 @@
+'use client';
+
+import { ReactNode } from 'react';
+import { usePathname } from 'next/navigation';
+import { useSidebar } from '@/lib/SidebarContext';
+import Footer from './Footer';
+
+export default function MainContent({ children }: { children: ReactNode }) {
+ const pathname = usePathname();
+ const { collapsed } = useSidebar();
+ const isPublicPage = pathname === '/login' || pathname === '/';
+
+ return (
+
+ {children}
+ {!isPublicPage && }
+
+ );
+}
diff --git a/src/components/PageHeader.tsx b/src/components/PageHeader.tsx
new file mode 100644
index 0000000..51bb92d
--- /dev/null
+++ b/src/components/PageHeader.tsx
@@ -0,0 +1,33 @@
+'use client';
+
+import Link from 'next/link';
+
+interface PageHeaderProps {
+ title: string;
+ description?: string;
+ action?: {
+ label: string;
+ href: string;
+ };
+}
+
+export default function PageHeader({ title, description, action }: PageHeaderProps) {
+ return (
+
+
+ {title}
+ {description && (
+ {description}
+ )}
+
+ {action && (
+
+
+ {action.label}
+
+ )}
+
+ );
+}
diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx
index 77e5f74..a0326cf 100644
--- a/src/components/Sidebar.tsx
+++ b/src/components/Sidebar.tsx
@@ -5,6 +5,8 @@ import { usePathname } from 'next/navigation';
import { cn } from '@/lib/utils';
import { getUserRole } from '@/lib/api';
import { useState, useEffect } from 'react';
+import { useSidebar } from '@/lib/SidebarContext';
+import ThemeToggle from './ThemeToggle';
interface NavItem {
label: string;
@@ -17,7 +19,7 @@ interface NavItem {
const navItems: NavItem[] = [
{
label: 'Dashboard',
- href: '/',
+ href: '/admin/dashboard',
icon: '๐',
},
{
@@ -160,19 +162,23 @@ const navItems: NavItem[] = [
export default function Sidebar() {
const pathname = usePathname();
const [role, setRole] = useState(null);
- const [collapsed, setCollapsed] = useState(false);
+ const { collapsed, toggle } = useSidebar();
useEffect(() => {
setRole(getUserRole());
}, []);
+ // Don't render sidebar on login or landing page
+ if (pathname === '/login' || pathname === '/') {
+ return null;
+ }
+
const filteredItems = navItems.filter((item) => {
if (!item.roles || item.roles.length === 0) return true;
return role && item.roles.includes(role);
});
const isActive = (href: string) => {
- if (href === '/') return pathname === '/';
return pathname.startsWith(href);
};
@@ -189,9 +195,17 @@ export default function Sidebar() {
N
+ Connecting{' '} + + Kindness + {' '} + with Those in Need
-- Looking for a starting point or more instructions? Head over to{" "} - + Niki is a comprehensive kind box management platform that connects benefactors, + agents, and administrators to streamline donations, deliveries, and tracking + across cities. +
+ ++ How It Works +
++ From registration to delivery โ Niki makes the entire process seamless and transparent.
+ {item.title} +
++ {item.description} +
++ System Portals +
++ Role-based dashboards designed for each user type. +
++ {portal.title} +
++ {portal.description} +
++ What Our Users Say +
++ Hear from the people who use Niki every day. +
++ “{t.quote}” +
++ Ready to Get Started? +
++ Join thousands of benefactors, agents, and administrators making a difference + through the Niki kind box management system. +
+| ID | +Name | +Phone | +Sex | +Case Status | +Referral | +Actions | +
|---|---|---|---|---|---|---|
| #{p.id} | +{p.firstName} {p.lastName} | +{p.phone} | +{p.sex} | +{p.caseStatus} | +{p.referralSource} | ++ |
{p.name}
+{p.description}
+ +Total Revenue
{formatCurrency(mockStats.totalRevenue)}
Total Orders
{mockStats.totalOrders}
Benefactors
{mockStats.totalBenefactors}
Campaigns
{mockStats.totalCampaigns}
Recent Sales
| Date | +Orders | +Revenue | +
|---|---|---|
| {r.date} | +{r.orders} | +{formatCurrency(r.amount)} | +
| ID | +Name | +Phone | +Role | +Status | +Joined | +|
|---|---|---|---|---|---|---|
| #{s.id} | +{s.firstName} {s.lastName} | +{s.phoneNumber} | +{s.email} | +{s.role} | +{formatDateTime(s.createdAt)} | +
Current Balance
+{formatCurrency(Number(mockWallet.balance))}
+| ID | +Type | +Amount | +Description | +Date | +
|---|---|---|---|---|
| #{t.id} | +{t.actionType} | +{t.actionType === 'deposit' ? '+' : '-'}{formatCurrency(Number(t.amount))} | +{t.description} | +{formatDateTime(t.timestamp)} | +
Loading...
+Redirecting to login...
+Access Denied
+You do not have permission to access this page.
+{title}
+ {description &&{description}
} + {action && ( + + {action.label} + + )} +{title}
+ {description && ( +{description}
+ )} +