cleanup
This commit is contained in:
@@ -8,11 +8,11 @@ import { Input } from "@/components/ui/input";
|
||||
import { Product } from "@/models/products";
|
||||
import { Plus, Upload, Search, RefreshCw } from "lucide-react";
|
||||
import {
|
||||
fetchProductData,
|
||||
saveProductData,
|
||||
saveProductImage,
|
||||
deleteProductData,
|
||||
} from "@/lib/productData";
|
||||
import { clientFetch } from "@/lib/client-utils";
|
||||
import { ProductModal } from "@/components/modals/product-modal";
|
||||
import ProductTable from "@/components/tables/product-table";
|
||||
import { Category } from "@/models/categories";
|
||||
@@ -55,12 +55,9 @@ export default function ProductsPage() {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const productsUrl = `${process.env.NEXT_PUBLIC_API_URL}/products`;
|
||||
const categoriesUrl = `${process.env.NEXT_PUBLIC_API_URL}/categories`;
|
||||
|
||||
const [fetchedProducts, fetchedCategories] = await Promise.all([
|
||||
fetchProductData(productsUrl, authToken),
|
||||
fetchProductData(categoriesUrl, authToken),
|
||||
clientFetch('/products'),
|
||||
clientFetch('/categories'),
|
||||
]);
|
||||
|
||||
console.log("Fetched Products:", fetchedProducts);
|
||||
@@ -76,6 +73,7 @@ export default function ProductsPage() {
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
toast.error("Failed to load products");
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
@@ -115,67 +113,41 @@ export default function ProductsPage() {
|
||||
|
||||
|
||||
const handleSaveProduct = async (data: Product, file?: File | null) => {
|
||||
const authToken = document.cookie
|
||||
.split("; ")
|
||||
.find((row) => row.startsWith("Authorization="))
|
||||
?.split("=")[1];
|
||||
|
||||
if (!authToken) {
|
||||
router.push("/login");
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const url = editing
|
||||
? `${process.env.NEXT_PUBLIC_API_URL}/products/${data._id}`
|
||||
: `${process.env.NEXT_PUBLIC_API_URL}/products`;
|
||||
setLoading(true);
|
||||
|
||||
// Save product data
|
||||
const savedProduct = await saveProductData(
|
||||
url,
|
||||
{
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
unitType: data.unitType,
|
||||
category: data.category,
|
||||
pricing: data.pricing,
|
||||
stockTracking: data.stockTracking,
|
||||
currentStock: data.currentStock,
|
||||
lowStockThreshold: data.lowStockThreshold
|
||||
},
|
||||
authToken,
|
||||
editing ? "PUT" : "POST"
|
||||
);
|
||||
|
||||
if (file) {
|
||||
const imageUrl = `${process.env.NEXT_PUBLIC_API_URL}/products/${savedProduct._id}/image`;
|
||||
await saveProductImage(
|
||||
imageUrl,
|
||||
file,
|
||||
authToken
|
||||
);
|
||||
if (editing && !data._id) {
|
||||
throw new Error("Cannot update product without an ID");
|
||||
}
|
||||
|
||||
// If editing and stock values were updated, update stock in the dedicated endpoint
|
||||
if (editing && data.stockTracking !== undefined) {
|
||||
const stockUrl = `${process.env.NEXT_PUBLIC_API_URL}/stock/${data._id}`;
|
||||
await saveProductData(
|
||||
stockUrl,
|
||||
{
|
||||
stockTracking: data.stockTracking,
|
||||
currentStock: data.currentStock || 0,
|
||||
lowStockThreshold: data.lowStockThreshold || 10
|
||||
},
|
||||
authToken,
|
||||
"PUT"
|
||||
);
|
||||
// Save the product data
|
||||
const endpoint = editing ? `/products/${data._id}` : "/products";
|
||||
const method = editing ? "PUT" : "POST";
|
||||
|
||||
const productResponse = await clientFetch(endpoint, {
|
||||
method,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
// If there's a new image to upload
|
||||
if (file) {
|
||||
const imageEndpoint = `/products/${productResponse._id || data._id}/image`;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
|
||||
await clientFetch(imageEndpoint, {
|
||||
method: "PUT",
|
||||
body: formData,
|
||||
headers: {}, // Let the browser set the content-type for FormData
|
||||
});
|
||||
}
|
||||
|
||||
// Refresh products list
|
||||
const productsUrl = `${process.env.NEXT_PUBLIC_API_URL}/products`;
|
||||
const fetchedProducts = await fetchProductData(productsUrl, authToken);
|
||||
const fetchedProducts = await clientFetch('/products');
|
||||
setProducts(fetchedProducts);
|
||||
|
||||
setModalOpen(false);
|
||||
@@ -195,25 +167,23 @@ export default function ProductsPage() {
|
||||
const handleDeleteProduct = async (productId: string) => {
|
||||
if (!confirm("Are you sure you want to delete this product?")) return;
|
||||
|
||||
const authToken = document.cookie
|
||||
.split("; ")
|
||||
.find((row) => row.startsWith("Authorization="))
|
||||
?.split("=")[1];
|
||||
|
||||
if (!authToken) {
|
||||
router.push("/login");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const url = `${process.env.NEXT_PUBLIC_API_URL}/products/${productId}`;
|
||||
await deleteProductData(url, authToken);
|
||||
setLoading(true);
|
||||
|
||||
await clientFetch(`/products/${productId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
// Refresh products list
|
||||
const fetchedProducts = await clientFetch('/products');
|
||||
setProducts(fetchedProducts);
|
||||
|
||||
setProducts(products.filter((p) => p._id !== productId));
|
||||
toast.success("Product deleted successfully");
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
console.error("Error deleting product:", error);
|
||||
console.error(error);
|
||||
toast.error("Failed to delete product");
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ const KeepOnline = () => {
|
||||
if(window.location.pathname.includes("/dashboard")){
|
||||
const updateOnlineStatus = () => {
|
||||
console.log("Updating online status...");
|
||||
clientFetch("/auth/me");
|
||||
clientFetch('/auth/me');
|
||||
}
|
||||
|
||||
updateOnlineStatus();
|
||||
|
||||
@@ -14,7 +14,16 @@ export async function clientFetch(url: string, options: RequestInit = {}): Promi
|
||||
...options.headers,
|
||||
};
|
||||
|
||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}${url}`, {
|
||||
// Ensure the url doesn't start with a slash if it's going to be appended to a URL that ends with one
|
||||
const cleanUrl = url.startsWith('/') ? url.substring(1) : url;
|
||||
const baseUrl = process.env.NEXT_PUBLIC_API_URL || '/api';
|
||||
|
||||
// Ensure there's only one slash between the base URL and endpoint
|
||||
const fullUrl = baseUrl.endsWith('/')
|
||||
? `${baseUrl}${cleanUrl}`
|
||||
: `${baseUrl}/${cleanUrl}`;
|
||||
|
||||
const res = await fetch(fullUrl, {
|
||||
...options,
|
||||
headers,
|
||||
});
|
||||
|
||||
@@ -13,9 +13,21 @@ export async function fetchServer<T = unknown>(
|
||||
|
||||
if (!authToken) redirect('/login');
|
||||
|
||||
// Ensure the endpoint doesn't start with a slash if it's going to be appended to a URL that ends with one
|
||||
const cleanEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
|
||||
|
||||
try {
|
||||
console.log(`${endpoint}`)
|
||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}${endpoint}`, {
|
||||
// Make sure we're using a complete URL (protocol + hostname + path)
|
||||
const apiUrl = process.env.SERVER_API_URL || 'https://internal-api.inboxi.ng/api';
|
||||
|
||||
// Ensure there's only one slash between the base URL and endpoint
|
||||
const url = apiUrl.endsWith('/')
|
||||
? `${apiUrl}${cleanEndpoint}`
|
||||
: `${apiUrl}/${cleanEndpoint}`;
|
||||
|
||||
console.log(`Making server request to: ${url}`);
|
||||
|
||||
const res = await fetch(url, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -10,8 +10,11 @@ export async function middleware(req: NextRequest) {
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/auth/me`, {
|
||||
method: "GET",
|
||||
// Need to use a full URL for server-side fetch
|
||||
const baseUrl = req.nextUrl.origin + '/api';
|
||||
|
||||
const res = await fetch(`${baseUrl}/auth/me`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
|
||||
Reference in New Issue
Block a user