This commit is contained in:
g
2025-02-07 14:09:21 +00:00
parent 717451ac9f
commit 6158f232db
6 changed files with 111 additions and 47 deletions

View File

@@ -25,6 +25,7 @@ import {
} from "@/components/ui/card"; } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Clipboard, Truck, Package } from "lucide-react"; import { Clipboard, Truck, Package } from "lucide-react";
import { useRouter } from "next/navigation";
interface Order { interface Order {
orderId: string; orderId: string;
@@ -49,6 +50,8 @@ export default function OrderDetailsPage() {
const [productNames, setProductNames] = useState<Record<string, string>>({}); const [productNames, setProductNames] = useState<Record<string, string>>({});
const [isPaid, setIsPaid] = useState(false); const [isPaid, setIsPaid] = useState(false);
const router = useRouter();
const params = useParams(); const params = useParams();
const orderId = params?.id; const orderId = params?.id;
@@ -110,6 +113,7 @@ export default function OrderDetailsPage() {
setIsPaid(true); setIsPaid(true);
} }
} catch (err: any) { } catch (err: any) {
router.push("/dashboard/orders");
setError(err.message); setError(err.message);
} finally { } finally {
setLoading(false); setLoading(false);

View File

@@ -1,8 +1,25 @@
"use client";
import { useEffect } from "react";
import { useRouter } from "next/navigation";
import Dashboard from "@/components/kokonutui/dashboard"; import Dashboard from "@/components/kokonutui/dashboard";
import { Package } from "lucide-react"; import { Package } from "lucide-react";
import OrderTable from "@/components/order-table" import OrderTable from "@/components/order-table";
export default function OrdersPage() { export default function OrdersPage() {
const router = useRouter();
useEffect(() => {
const authToken = document.cookie
.split("; ")
.find((row) => row.startsWith("Authorization="))
?.split("=")[1];
if (!authToken) {
router.push("/login");
}
}, [router]);
return ( return (
<Dashboard> <Dashboard>
<div className="space-y-6"> <div className="space-y-6">
@@ -13,7 +30,6 @@ export default function OrdersPage() {
</h1> </h1>
</div> </div>
{/* ✅ Order Table Component */}
<OrderTable /> <OrderTable />
</div> </div>
</Dashboard> </Dashboard>

View File

@@ -33,10 +33,18 @@ export default function ProductsPage() {
// Fetch products and categories // Fetch products and categories
useEffect(() => { useEffect(() => {
const authToken = document.cookie
.split("; ")
.find((row) => row.startsWith("Authorization="))
?.split("=")[1];
if (!authToken) {
router.push("/login");
return;
}
const fetchDataAsync = async () => { const fetchDataAsync = async () => {
try { try {
const authToken = document.cookie.split("Authorization=")[1];
const [fetchedProducts, fetchedCategories] = await Promise.all([ const [fetchedProducts, fetchedCategories] = await Promise.all([
fetchProductData( fetchProductData(
`${process.env.NEXT_PUBLIC_API_URL}/products`, `${process.env.NEXT_PUBLIC_API_URL}/products`,

View File

@@ -1,18 +1,11 @@
"use client"; "use client";
import { useState, useEffect, ChangeEvent } from "react"; import { useState, useEffect, ChangeEvent } from "react";
import { useRouter } from "next/navigation";
import Layout from "@/components/kokonutui/layout"; import Layout from "@/components/kokonutui/layout";
import { Edit, Plus, Trash } from "lucide-react"; import { Edit, Plus, Trash } from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { ShippingModal } from "@/components/shipping-modal"; import { ShippingModal } from "@/components/shipping-modal";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Skeleton } from "@/components/ui/skeleton"; import { Skeleton } from "@/components/ui/skeleton";
import { import {
fetchShippingMethods, fetchShippingMethods,
@@ -23,7 +16,7 @@ import {
import { ShippingMethod, ShippingData } from "@/lib/types"; import { ShippingMethod, ShippingData } from "@/lib/types";
import { ShippingTable } from "@/components/shipping-table" import { ShippingTable } from "@/components/shipping-table";
export default function ShippingPage() { export default function ShippingPage() {
const [shippingMethods, setShippingMethods] = useState<ShippingMethod[]>([]); const [shippingMethods, setShippingMethods] = useState<ShippingMethod[]>([]);
@@ -35,17 +28,31 @@ export default function ShippingPage() {
const [modalOpen, setModalOpen] = useState<boolean>(false); const [modalOpen, setModalOpen] = useState<boolean>(false);
const [editing, setEditing] = useState<boolean>(false); const [editing, setEditing] = useState<boolean>(false);
const router = useRouter();
useEffect(() => { useEffect(() => {
const fetchShippingMethodsData = async () => { const fetchShippingMethodsData = async () => {
try { try {
const authToken = document.cookie.split("Authorization=")[1]; const authToken = document.cookie
const fetchedMethods: ShippingMethod[] = await fetchShippingMethods(authToken); .split("; ")
.find((row) => row.startsWith("Authorization="))
?.split("=")[1];
// Ensure `_id` is always a string if (!authToken) {
const sanitizedMethods: ShippingMethod[] = fetchedMethods.map((method) => ({ router.push("/login");
return;
}
const fetchedMethods: ShippingMethod[] = await fetchShippingMethods(
authToken
);
const sanitizedMethods: ShippingMethod[] = fetchedMethods.map(
(method) => ({
...method, ...method,
_id: method._id ?? "", // Default to empty string if undefined _id: method._id ?? "",
})); })
);
setShippingMethods(sanitizedMethods); setShippingMethods(sanitizedMethods);
} catch (error) { } catch (error) {
@@ -63,7 +70,10 @@ export default function ShippingPage() {
try { try {
const authToken = document.cookie.split("Authorization=")[1]; const authToken = document.cookie.split("Authorization=")[1];
const updatedMethods: ShippingMethod[] = await addShippingMethod(authToken, newShipping); const updatedMethods: ShippingMethod[] = await addShippingMethod(
authToken,
newShipping
);
setShippingMethods(updatedMethods); setShippingMethods(updatedMethods);
setNewShipping({ name: "", price: 0 }); // No `_id` needed for new entry setNewShipping({ name: "", price: 0 }); // No `_id` needed for new entry
@@ -78,10 +88,16 @@ export default function ShippingPage() {
try { try {
const authToken = document.cookie.split("Authorization=")[1]; const authToken = document.cookie.split("Authorization=")[1];
const updatedShipping: ShippingMethod = await updateShippingMethod(authToken, newShipping._id, newShipping); const updatedShipping: ShippingMethod = await updateShippingMethod(
authToken,
newShipping._id,
newShipping
);
setShippingMethods((prevMethods) => setShippingMethods((prevMethods) =>
prevMethods.map((method) => (method._id === updatedShipping._id ? updatedShipping : method)) prevMethods.map((method) =>
method._id === updatedShipping._id ? updatedShipping : method
)
); );
setNewShipping({ name: "", price: 0 }); setNewShipping({ name: "", price: 0 });
setEditing(false); setEditing(false);

View File

@@ -32,6 +32,16 @@ export default function StorefrontPage() {
// ✅ Fetch Storefront Data // ✅ Fetch Storefront Data
useEffect(() => { useEffect(() => {
const authToken = document.cookie
.split("; ")
.find((row) => row.startsWith("Authorization="))
?.split("=")[1];
if (!authToken) {
router.push("/login");
return;
}
const fetchStorefront = async () => { const fetchStorefront = async () => {
try { try {
setLoading(true); setLoading(true);
@@ -48,7 +58,9 @@ export default function StorefrontPage() {
}, []); }, []);
// ✅ Handle Form Input Changes // ✅ Handle Form Input Changes
const handleInputChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => { const handleInputChange = (
e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
setStorefront({ ...storefront, [e.target.name]: e.target.value }); setStorefront({ ...storefront, [e.target.name]: e.target.value });
}; };
@@ -134,12 +146,20 @@ export default function StorefrontPage() {
{/* Buttons */} {/* Buttons */}
<div className="sticky bottom-6 mt-8 flex justify-between"> <div className="sticky bottom-6 mt-8 flex justify-between">
<Button onClick={() => setBroadcastOpen(true)} className="gap-2 bg-emerald-600 hover:bg-emerald-700 text-white"> <Button
onClick={() => setBroadcastOpen(true)}
className="gap-2 bg-emerald-600 hover:bg-emerald-700 text-white"
>
<Send className="h-5 w-5" /> Broadcast Message <Send className="h-5 w-5" /> Broadcast Message
</Button> </Button>
<Button onClick={saveStorefront} disabled={saving} className="gap-2 bg-gradient-to-r from-purple-600 to-indigo-600 hover:from-purple-700 hover:to-indigo-700 text-white"> <Button
<Save className="h-5 w-5" /> {saving ? "Saving..." : "Save Configuration"} onClick={saveStorefront}
disabled={saving}
className="gap-2 bg-gradient-to-r from-purple-600 to-indigo-600 hover:from-purple-700 hover:to-indigo-700 text-white"
>
<Save className="h-5 w-5" />{" "}
{saving ? "Saving..." : "Save Configuration"}
</Button> </Button>
</div> </div>
</div> </div>

View File

@@ -3,7 +3,7 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Package, Eye } from "lucide-react"; import { Eye } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { fetchWithAuthClient } from "@/lib/client-utils"; // ✅ Import client-safe API helper import { fetchWithAuthClient } from "@/lib/client-utils"; // ✅ Import client-safe API helper
import { toast } from "sonner"; import { toast } from "sonner";
@@ -17,10 +17,9 @@ interface Order {
} }
export default function OrderTable() { export default function OrderTable() {
const [orders, setOrders] = useState<Order[]>([]); const [orders, setOrders] = useState<Order[] | null>(null);
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
// ✅ Fetch Orders on Load
useEffect(() => { useEffect(() => {
const fetchOrders = async () => { const fetchOrders = async () => {
try { try {
@@ -28,6 +27,7 @@ export default function OrderTable() {
setOrders(data); setOrders(data);
} catch (error) { } catch (error) {
toast.error("Failed to fetch orders."); toast.error("Failed to fetch orders.");
console.error("Error fetching orders:", error);
} finally { } finally {
setLoading(false); setLoading(false);
} }
@@ -59,7 +59,7 @@ export default function OrderTable() {
<TableCell className="text-right">Loading...</TableCell> <TableCell className="text-right">Loading...</TableCell>
</TableRow> </TableRow>
)) ))
) : orders.length > 0 ? ( ) : orders && orders.length > 0 ? (
orders.map((order) => ( orders.map((order) => (
<TableRow key={order._id} className="transition-colors hover:bg-gray-50 dark:hover:bg-zinc-800/70"> <TableRow key={order._id} className="transition-colors hover:bg-gray-50 dark:hover:bg-zinc-800/70">
<TableCell className="font-medium">{order._id.slice(-6)}</TableCell> <TableCell className="font-medium">{order._id.slice(-6)}</TableCell>
@@ -77,7 +77,7 @@ export default function OrderTable() {
)) ))
) : ( ) : (
<TableRow> <TableRow>
<TableCell colSpan={6} className="h-24 text-center"> <TableCell colSpan={5} className="h-24 text-center">
No orders found. No orders found.
</TableCell> </TableCell>
</TableRow> </TableRow>