-
-
-
+
+
+
Secure Crypto Payments
- The Future of E-commerce Management
+ The Future of E-commerce Management
- {isDec
- ? 'Spread joy this holiday season with our all-in-one platform. Secure payments, order tracking, and analytics wrapped up in one beautiful package. 🎄'
- : 'Streamline your online business with our all-in-one platform. Secure payments, order tracking, and analytics in one place.'
- }
+ Streamline your online business with our all-in-one platform. Secure payments, order tracking, and analytics in one place.
Get Started
@@ -103,35 +69,21 @@ export default async function Home() {
title: "Lightning Fast",
description: "Optimized for speed with real-time updates and instant notifications."
}
- ].map((feature, i) => {
- const christmasColors = ['from-red-500/5', 'from-green-500/5', 'from-yellow-500/5'];
- const christmasBorders = ['border-red-500/30', 'border-green-500/30', 'border-yellow-500/30'];
- const christmasIcons = ['text-red-400', 'text-green-400', 'text-yellow-400'];
- const christmasBgs = ['bg-red-500/10', 'bg-green-500/10', 'bg-yellow-500/10'];
-
- return (
-
-
-
-
-
-
-
{feature.title}
-
{feature.description}
+ ].map((feature, i) => (
+
+
+
+
+
+
{feature.title}
+
{feature.description}
- );
- })}
+
+ ))}
@@ -145,13 +97,6 @@ export default async function Home() {
{/* Footer */}
- {isDec && (
-
- 🎄
- Happy Holidays from da ember team!
- 🎄
-
- )}
© {new Date().getFullYear()} Ember. All rights reserved.
diff --git a/components/dashboard/ChatTable.tsx b/components/dashboard/ChatTable.tsx
index 7ffa181..80d7c08 100644
--- a/components/dashboard/ChatTable.tsx
+++ b/components/dashboard/ChatTable.tsx
@@ -304,7 +304,7 @@ export default function ChatTable() {
-
+
{loading ? (
@@ -328,10 +328,10 @@ export default function ChatTable() {
chats.map((chat, index) => (
handleChatClick(chat._id)}
style={{ display: 'table-row' }} // Essential for table layout
@@ -469,8 +469,8 @@ export default function ChatTable() {
-
- )}
+
+ )}
);
}
diff --git a/components/dashboard/quick-actions.tsx b/components/dashboard/quick-actions.tsx
index f09dbe4..a4db859 100644
--- a/components/dashboard/quick-actions.tsx
+++ b/components/dashboard/quick-actions.tsx
@@ -1,26 +1,33 @@
"use client"
+import { useState, useEffect, ChangeEvent } from "react"
import Link from "next/link"
import { motion } from "framer-motion"
import {
PlusCircle,
- Package,
- BarChart3,
- Settings,
- MessageSquare,
Truck,
- Tag,
- Users
+ BarChart3,
+ MessageSquare,
} from "lucide-react"
import { Card, CardContent } from "@/components/ui/card"
+import dynamic from "next/dynamic"
+import { Product } from "@/models/products"
+import { Category } from "@/models/categories"
+import { clientFetch } from "@/lib/api"
+import { toast } from "sonner"
+
+const ProductModal = dynamic(() => import("@/components/modals/product-modal").then(mod => ({ default: mod.ProductModal })), {
+ loading: () => null
+});
const actions = [
{
title: "Add Product",
icon: PlusCircle,
- href: "/dashboard/products/new",
+ href: "/dashboard/products/new", // Fallback text
color: "bg-blue-500/10 text-blue-500",
- description: "Create a new listing"
+ description: "Create a new listing",
+ action: "modal"
},
{
title: "Process Orders",
@@ -46,19 +53,118 @@ const actions = [
]
export default function QuickActions() {
+ const [modalOpen, setModalOpen] = useState(false);
+ const [loading, setLoading] = useState(false);
+ const [categories, setCategories] = useState
([]);
+ const [productData, setProductData] = useState({
+ name: "",
+ description: "",
+ unitType: "pcs",
+ category: "",
+ pricing: [{ minQuantity: 1, pricePerUnit: 0 }],
+ image: null,
+ costPerUnit: 0,
+ });
+
+ // Fetch categories on mount
+ useEffect(() => {
+ const fetchCategories = async () => {
+ try {
+ const data = await clientFetch('/categories');
+ setCategories(data);
+ } catch (error) {
+ console.error("Failed to fetch categories:", error);
+ }
+ };
+ fetchCategories();
+ }, []);
+
+ const handleChange = (e: ChangeEvent) => {
+ setProductData({ ...productData, [e.target.name]: e.target.value });
+ };
+
+ const handleTieredPricingChange = (e: ChangeEvent, index: number) => {
+ const updatedPricing = [...productData.pricing];
+ const name = e.target.name as "minQuantity" | "pricePerUnit";
+ updatedPricing[index][name] = e.target.valueAsNumber || 0;
+ setProductData({ ...productData, pricing: updatedPricing });
+ };
+
+ const handleAddTier = () => {
+ setProductData((prev) => ({
+ ...prev,
+ pricing: [...prev.pricing, { minQuantity: 1, pricePerUnit: 0 }],
+ }));
+ };
+
+ const handleRemoveTier = (index: number) => {
+ setProductData((prev) => ({
+ ...prev,
+ pricing: prev.pricing.filter((_, i) => i !== index),
+ }));
+ };
+
+ const handleSaveProduct = async (data: Product, file?: File | null) => {
+ try {
+ setLoading(true);
+
+ // Prepare the product data
+ const payload = {
+ ...data,
+ stockTracking: data.stockTracking ?? true,
+ currentStock: data.currentStock ?? 0,
+ lowStockThreshold: data.lowStockThreshold ?? 10,
+ stockStatus: data.stockStatus ?? 'out_of_stock'
+ };
+
+ const productResponse = await clientFetch("/products", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(payload),
+ });
+
+ if (file) {
+ const formData = new FormData();
+ formData.append("file", file);
+ await fetch(`${process.env.NEXT_PUBLIC_API_URL}/products/${productResponse._id}/image`, {
+ method: "PUT",
+ headers: {
+ Authorization: `Bearer ${document.cookie.split("; ").find((row) => row.startsWith("Authorization="))?.split("=")[1]}`,
+ },
+ body: formData,
+ });
+ }
+
+ setModalOpen(false);
+ setProductData({
+ name: "",
+ description: "",
+ unitType: "pcs",
+ category: "",
+ pricing: [{ minQuantity: 1, pricePerUnit: 0 }],
+ image: null,
+ costPerUnit: 0,
+ });
+ toast.success("Product added successfully");
+
+ // Optional: trigger a refresh of products or stats if needed
+ // currently just closing modal
+ } catch (error) {
+ console.error(error);
+ toast.error("Failed to save product");
+ } finally {
+ setLoading(false);
+ }
+ };
+
return (
-
- {actions.map((action, index) => (
-
-
-
+ <>
+
+ {actions.map((action, index) => {
+ const isModalAction = action.action === "modal";
+
+ const CardContentWrapper = () => (
+
@@ -67,9 +173,44 @@ export default function QuickActions() {
{action.description}
-
-
- ))}
-
+ );
+
+ return (
+
+ {isModalAction ? (
+ setModalOpen(true)}>
+
+
+ ) : (
+
+
+
+ )}
+
+ );
+ })}
+
+
+ setModalOpen(false)}
+ onSave={handleSaveProduct}
+ productData={productData}
+ categories={categories}
+ editing={false}
+ handleChange={handleChange}
+ handleTieredPricingChange={handleTieredPricingChange}
+ handleAddTier={handleAddTier}
+ handleRemoveTier={handleRemoveTier}
+ setProductData={setProductData}
+ />
+ >
)
}
diff --git a/components/home-navbar.tsx b/components/home-navbar.tsx
index 5eeb0d9..1cd145c 100644
--- a/components/home-navbar.tsx
+++ b/components/home-navbar.tsx
@@ -3,7 +3,6 @@
import Link from "next/link";
import { Button } from "@/components/ui/button";
import { LogIn } from "lucide-react";
-import { ThemeSwitcher } from "@/components/theme-switcher";
import { useState } from "react";
export function HomeNavbar() {
@@ -27,16 +26,16 @@ export function HomeNavbar() {
Log In
-
- Get Started
+
+ Get Started
setMenuOpen(!menuOpen)} className="text-white hover:bg-gray-900">
Toggle menu
-
-
+
{/* Mobile menu */}
{menuOpen && (
- setMenuOpen(false)}
>
Features
- setMenuOpen(false)}
>
Benefits
- setMenuOpen(false)}
>
Log In
- setMenuOpen(false)}
>
- Create Account
+ Get Started
)}
);
-}
\ No newline at end of file
+}
\ No newline at end of file