From 3bec70b932bf8e11c5505fa542d0b5c1ac669e3b Mon Sep 17 00:00:00 2001 From: aleepe-1 Date: Tue, 23 Jan 2024 10:09:55 +0100 Subject: [PATCH 01/18] product page display information --- package-lock.json | 18 ++ src/models/Product.js | 25 +- src/pages/api/v1/product/[productID].js | 10 +- src/pages/product/[productId].js | 353 +++++++++++++++++++++--- 4 files changed, 356 insertions(+), 50 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1062f4be..e8edd716 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2334,6 +2334,19 @@ "is-callable": "^1.1.3" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -4501,6 +4514,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/src/models/Product.js b/src/models/Product.js index 791f35b8..da4ddecf 100644 --- a/src/models/Product.js +++ b/src/models/Product.js @@ -7,6 +7,24 @@ const eventSchema = new Schema( id: Number, dpp_class: String, creation_time: Date, // Assuming this should be a Date type + action: String, + }, + { _id: false } +) + +const has_event_trail = new Schema( + { + privacy: String, + event: [eventSchema], + }, + { _id: false } +) + +const componentSchema = new Schema( + { + id: Number, + dpp_class: String, + has_event_trail: [has_event_trail], }, { _id: false } ) @@ -30,15 +48,20 @@ const productSchema = new Schema( id: Number, dpp_class: String, privacy: String, + effect: String, }, main_component: { + privacy: String, + component: [componentSchema], + }, + has_crm: { id: Number, dpp_class: String, privacy: String, }, has_event_trail: { privacy: String, - events: [eventSchema], // Define a separate schema for events + event: [eventSchema], // Define a separate schema for events }, }, { strict: false } diff --git a/src/pages/api/v1/product/[productID].js b/src/pages/api/v1/product/[productID].js index 5f8f1a31..d153fc7c 100644 --- a/src/pages/api/v1/product/[productID].js +++ b/src/pages/api/v1/product/[productID].js @@ -2,16 +2,16 @@ import { defaultHandler } from '@/utils/server/api-helpers' import { ObjectId } from 'mongodb' import Product from '@/models/Product' -const getProductByID = async (req, res) => { +const getProductById = async (req, res) => { try { - const { productID } = req.query + const { productId } = req.query - if (!ObjectId.isValid(productID)) { + if (!ObjectId.isValid(productId)) { return res.status(400).json({ message: 'Invalid ID' }) } // Use 'new' to create a new instance of ObjectId - const productData = await Product.findOne({ _id: new ObjectId(productID) }) + const productData = await Product.findOne({ _id: new ObjectId(productId) }) if (!productData) { return res.status(404).json({ message: 'Product not found' }) @@ -31,7 +31,7 @@ const handler = async (req, res) => req, res, { - GET: getProductByID, + GET: getProductById, }, { requiresAuth: false, diff --git a/src/pages/product/[productId].js b/src/pages/product/[productId].js index 0f841ff1..f0c54bf9 100644 --- a/src/pages/product/[productId].js +++ b/src/pages/product/[productId].js @@ -4,12 +4,12 @@ import { Container } from '@/components/utils/Container' import { useEffect, useState } from 'react' export async function getServerSideProps(context) { - const { productID } = context.params + const { productId } = context.params - const baseUrl = process.env.NEXT_PUBLIC_API_BASE_URL //REDO THIS LATER WE CANT HAVE BASE URL SHOULD WORK TO JUST DO /api/v1/product/${productID} + //const baseUrl = process.env.NEXT_PUBLIC_API_BASE_URL //REDO THIS LATER WE CANT HAVE BASE URL SHOULD WORK TO JUST DO /api/v1/product/${productID} try { - const res = await fetch(`${baseUrl}/api/v1/product/${productID}`) // Use backticks for template literal + const res = await fetch(`http://localhost:3000/api/v1/product/${productId}`) // Use backticks for template literal if (!res.ok) { throw new Error(`Failed to fetch product, status: ${res.status}`) // Template literal @@ -27,7 +27,7 @@ export async function getServerSideProps(context) { } } } - +/* export default function ProductPage({ product }) { // Function to recursively render product properties, including nested objects/arrays const renderProductData = data => { @@ -60,59 +60,137 @@ export default function ProductPage({ product }) { {renderProductData(product)} ) +}*/ + +/* +function ProductDetails({ product }) { + return ( + + +
+
+
+

+ {product.name} +

+

+ ProductID: {product.id} +

+
+
+
+
+
+ ProductID: +
+
+ 198454 +
+
+
+
+ Main Component: +
+
+ Lithium +
+
+
+
+ MaterialID: +
+
+ 223411 +
+
+
+
+ Owner +
+
+ Scania +
+
+
+
+ Creation time +
+
+ aug 2023 +
+
+
+
+ + Events + +
+

{[product.has_carbon_footprint.id]}

+
+
+
+
+
+
+
+
+
+
+
+
Weight
+
+
+
+
+
+
+ ) } -/* function ProductDetails() { - const router = useRouter() - const ProductId = router.query.productId - const [productData, setProductData] = useState({ - _id, - id, - name, - dpp_class, - creation_time, - privacy, - }) - - const fetchproduct = async () => { - try { - // Make a GET request to the API route - const response = await fetch('/api/v1/product/export-product') - - // Check if the response is successful (status code 200) - if (response.ok) { - // Parse the response body as JSON - const result = await response.json() - - // Update the component state with the fetched data - setData(result) - } else { - // Handle non-successful responses (e.g., log an error) - console.error( - 'Error fetching data:', - response.status, - response.statusText - ) +export default ProductDetails +*/ + +/* +const CarComponent = ({ product }) => { + const extractComponents = data => { + const components = [] + + for (const key in data) { + if (typeof data[key] === 'object') { + if (data[key].id && data[key].dpp_class) { + components.push({ + id: data[key].id, + dpp_class: data[key].dpp_class, + action: data[key].action, + }) + + if (Object.keys(data[key]).length > 2) { + const subcomponents = extractComponents(data[key]) + components[components.length - 1].subcomponents = subcomponents + } + } else { + const subcomponents = extractComponents(data[key]) + components.push(...subcomponents) + } } - } catch (error) { - // Handle network errors or other exceptions - console.error('Error fetching data:', error.message) } + + return components } - fetchproduct() + const components = extractComponents(product) return ( -
+

- Battery + {product.name}

- Text. + ProductID: {product.id}

@@ -157,6 +235,45 @@ export default function ProductPage({ product }) { aug 2023
+
+
+ + Events + +
+ {components.map((component, index) => ( +
+

ID: {component.id}

+

DPP CLASS {component.dpp_class}

+

Action: {component.action}

+ {component.subcomponents && ( +
+ {component.subcomponents.map( + (subcomponent, subIndex) => ( +
+

ID: {subcomponent.id}

+

DPP Class: {subcomponent.dpp_class}

+ {subcomponent.has_event_trail && ( +
+

+ Has Event Trail Privacy:{' '} + {subcomponent.has_event_trail.privacy} +

+
+ )} +
+ ) + )} +
+ )} +
+ ))} +
+
+
@@ -175,5 +292,153 @@ export default function ProductPage({ product }) { ) } -export default ProductDetails - */ +export default CarComponent +*/ + +/* +const extractComponents = data => { + const components = [] + + const processObject = obj => { + for (const key in obj) { + if (typeof obj[key] === 'object') { + if (obj[key].id && obj[key].dpp_class) { + components.push({ + id: obj[key].id, + dpp_class: obj[key].dpp_class, + action: obj[key].action, // Include action property + }) + + if (Object.keys(obj[key]).length >= 2) { + const subcomponents = extractComponents(obj[key]) + components[components.length - 1].subcomponents = subcomponents + } + } else if (Array.isArray(obj[key]) && obj[key].length > 0) { + // Handle arrays, such as the 'component' array + const arrayComponents = obj[key].map(item => extractComponents(item)) + components.push(...arrayComponents) + } else { + const subcomponents = extractComponents(obj[key]) + components.push(...subcomponents) + } + } + } + } + + processObject(data) + + return components +} + +const DisplayNestedObjects = ({ product }) => { + const components = extractComponents(product) + + return ( +
+
+ + Events and Components + +
+ {components.map((component, index) => ( +
+ {component.id &&

ID: {component.id}

} + {component.dpp_class &&

DPP CLASS {component.dpp_class}

} + {component.action &&

Action: {component.action}

} + {component.subcomponents && ( +
+ {component.subcomponents.map((subcomponent, subIndex) => ( +
+ {subcomponent.id &&

ID: {subcomponent.id}

} + {subcomponent.dpp_class && ( +

DPP Class: {subcomponent.dpp_class}

+ )} + {subcomponent.action && ( +

Action: {subcomponent.action}

+ )} +
+ ))} +
+ )} +
+ ))} +
+
+
+ ) +} + +export default DisplayNestedObjects +*/ +import React from 'react' + +const extractComponents = data => { + const components = [] + + const processObject = obj => { + for (const key in obj) { + if (typeof obj[key] === 'object') { + if (obj[key].id && obj[key].dpp_class) { + components.push({ + id: obj[key].id, + dpp_class: obj[key].dpp_class, + }) + + if (Object.keys(obj[key]).length >= 2) { + const subcomponents = extractComponents(obj[key]) + components[components.length - 1].subcomponents = subcomponents + } + } else { + const subcomponents = extractComponents(obj[key]) + components.push(...subcomponents) + } + } + } + } + + processObject(data) + + return components +} + +const DisplayNestedObjects = ({ product }) => { + const components = extractComponents(product) + + return ( +
+
+ + Components + +
+ {components.map((component, index) => ( +
+

ID: {component.id}

+

DPP Class: {component.dpp_class}

+ {component.subcomponents && ( +
+ {/* Recursive call for subcomponents */} + {component.subcomponents.map((subcomponent, subIndex) => ( +
+

ID: {subcomponent.id}

+

DPP Class: {subcomponent.dpp_class}

+ {/* Add more properties if needed */} +
+ ))} +
+ )} +
+ ))} +
+
+
+ ) +} + +export default DisplayNestedObjects From e6c41631b871a8c247a84e7738017aa948607fca Mon Sep 17 00:00:00 2001 From: aleepe-1 Date: Thu, 25 Jan 2024 20:12:33 +0100 Subject: [PATCH 02/18] productPage UI and mapping data --- src/models/Product.js | 21 +- src/pages/product/[productId].js | 417 ++++++++----------------------- 2 files changed, 116 insertions(+), 322 deletions(-) diff --git a/src/models/Product.js b/src/models/Product.js index da4ddecf..1a8de88a 100644 --- a/src/models/Product.js +++ b/src/models/Product.js @@ -12,19 +12,12 @@ const eventSchema = new Schema( { _id: false } ) -const has_event_trail = new Schema( - { - privacy: String, - event: [eventSchema], - }, - { _id: false } -) - const componentSchema = new Schema( { id: Number, + name: String, dpp_class: String, - has_event_trail: [has_event_trail], + _id: Schema.Types.ObjectId, }, { _id: false } ) @@ -41,25 +34,25 @@ const productSchema = new Schema( privacy: String, }, created_at: { - creation_time: Date, // Assuming this should be a Date type + creation_time: String, // Assuming this should be a Date type privacy: String, }, - has_carbon_footprint: { + carbon_footprint: { id: Number, dpp_class: String, privacy: String, effect: String, }, - main_component: { + key_components: { privacy: String, component: [componentSchema], }, - has_crm: { + crm: { id: Number, dpp_class: String, privacy: String, }, - has_event_trail: { + event_trail: { privacy: String, event: [eventSchema], // Define a separate schema for events }, diff --git a/src/pages/product/[productId].js b/src/pages/product/[productId].js index f0c54bf9..25cb743d 100644 --- a/src/pages/product/[productId].js +++ b/src/pages/product/[productId].js @@ -2,6 +2,7 @@ import { useRouter } from 'next/router' import LayoutGlobal from '@/components/Layout/LayoutGlobal' import { Container } from '@/components/utils/Container' import { useEffect, useState } from 'react' +import React from 'react' export async function getServerSideProps(context) { const { productId } = context.params @@ -60,125 +61,72 @@ export default function ProductPage({ product }) { {renderProductData(product)}
) -}*/ - -/* -function ProductDetails({ product }) { - return ( - - -
-
-
-

- {product.name} -

-

- ProductID: {product.id} -

-
-
-
-
-
- ProductID: -
-
- 198454 -
-
-
-
- Main Component: -
-
- Lithium -
-
-
-
- MaterialID: -
-
- 223411 -
-
-
-
- Owner -
-
- Scania -
-
-
-
- Creation time -
-
- aug 2023 -
-
-
-
- - Events - -
-

{[product.has_carbon_footprint.id]}

-
-
-
-
-
-
-
-
-
-
-
-
Weight
-
-
-
-
-
-
- ) } - -export default ProductDetails */ -/* -const CarComponent = ({ product }) => { - const extractComponents = data => { - const components = [] +//* + +const extractObjects = data => { + const events = [] + const components = [] - for (const key in data) { - if (typeof data[key] === 'object') { - if (data[key].id && data[key].dpp_class) { - components.push({ - id: data[key].id, - dpp_class: data[key].dpp_class, - action: data[key].action, + const processObject = obj => { + for (const key in obj) { + if (typeof obj[key] === 'object') { + if (isEventObject(obj[key])) { + events.push({ + id: obj[key].id, + dpp_class: obj[key].dpp_class, + creation_time: obj[key].creation_time, + action: obj[key].action, }) - if (Object.keys(data[key]).length > 2) { - const subcomponents = extractComponents(data[key]) - components[components.length - 1].subcomponents = subcomponents + const objects = extractObjects(obj[key]) + if (objects.hasEvents.length > 0) { + events[events.length - 1].subcomponents = objects.hasEvents + } + } else if (isComponentObject(obj[key])) { + // Handle component object logic + const componentData = { + id: obj[key].id, + dpp_class: obj[key].dpp_class, + name: obj[key].name, + _id: obj[key]._id, + } + components.push(componentData) + + const subcomponents = extractObjects(obj[key]) + if (subcomponents.hasEvents.length > 0) { + componentData.subcomponents = subcomponents.hasEvents } } else { - const subcomponents = extractComponents(data[key]) - components.push(...subcomponents) + const subcomponents = extractObjects(obj[key]) + events.push(...subcomponents.hasEvents) + components.push(...subcomponents.componentObjects) } } } + } - return components + const isEventObject = obj => { + return obj.hasOwnProperty('action') + // Add any additional conditions for the 'has_event' object if needed } - const components = extractComponents(product) + const isComponentObject = obj => { + // Change the condition to check if the object has a 'name' property + return obj.hasOwnProperty('name') + } + + processObject(data) + + return { + hasEvents: events, + componentObjects: components, + } +} +function ProductDetails({ product }) { + const nestedObjects = extractObjects(product) return ( @@ -197,34 +145,10 @@ const CarComponent = ({ product }) => {
- ProductID: -
-
- 198454 -
-
-
-
- Main Component: -
-
- Lithium -
-
-
-
- MaterialID: -
-
- 223411 -
-
-
-
- Owner + Manufactuter:
- Scania + {product.manufactured_by.owner_name}
@@ -232,47 +156,73 @@ const CarComponent = ({ product }) => { Creation time
- aug 2023 + {product.created_at.creation_time}
+ {product.carbon_footprint.effect != null && ( +
+
+ Carbon footprint +
+
+ {product.carbon_footprint.effect} +
+
+ )} + {product.crm > 0 && ( +
+
+ Crm +
+
+ Scania +
+
+ )}
-
+
Events
- {components.map((component, index) => ( + {nestedObjects.hasEvents.map((component, index) => (

ID: {component.id}

-

DPP CLASS {component.dpp_class}

+

DPP Class: {component.dpp_class}

+

Creation Time: {component.creation_time}

Action: {component.action}

- {component.subcomponents && ( -
- {component.subcomponents.map( - (subcomponent, subIndex) => ( -
-

ID: {subcomponent.id}

-

DPP Class: {subcomponent.dpp_class}

- {subcomponent.has_event_trail && ( -
-

- Has Event Trail Privacy:{' '} - {subcomponent.has_event_trail.privacy} -

-
- )} -
- ) - )} -
- )} +

))}
+ + {nestedObjects.componentObjects.length > 0 && ( +
+ + Key components + +
+ {nestedObjects.componentObjects.map( + (component, index) => ( +
+

ID: {component.id}

+

DPP Class: {component.dpp_class}

+

+ Name: + + {component.name} + +

+

+
+ ) + )} +
+
+ )}
@@ -292,153 +242,4 @@ const CarComponent = ({ product }) => { ) } -export default CarComponent -*/ - -/* -const extractComponents = data => { - const components = [] - - const processObject = obj => { - for (const key in obj) { - if (typeof obj[key] === 'object') { - if (obj[key].id && obj[key].dpp_class) { - components.push({ - id: obj[key].id, - dpp_class: obj[key].dpp_class, - action: obj[key].action, // Include action property - }) - - if (Object.keys(obj[key]).length >= 2) { - const subcomponents = extractComponents(obj[key]) - components[components.length - 1].subcomponents = subcomponents - } - } else if (Array.isArray(obj[key]) && obj[key].length > 0) { - // Handle arrays, such as the 'component' array - const arrayComponents = obj[key].map(item => extractComponents(item)) - components.push(...arrayComponents) - } else { - const subcomponents = extractComponents(obj[key]) - components.push(...subcomponents) - } - } - } - } - - processObject(data) - - return components -} - -const DisplayNestedObjects = ({ product }) => { - const components = extractComponents(product) - - return ( -
-
- - Events and Components - -
- {components.map((component, index) => ( -
- {component.id &&

ID: {component.id}

} - {component.dpp_class &&

DPP CLASS {component.dpp_class}

} - {component.action &&

Action: {component.action}

} - {component.subcomponents && ( -
- {component.subcomponents.map((subcomponent, subIndex) => ( -
- {subcomponent.id &&

ID: {subcomponent.id}

} - {subcomponent.dpp_class && ( -

DPP Class: {subcomponent.dpp_class}

- )} - {subcomponent.action && ( -

Action: {subcomponent.action}

- )} -
- ))} -
- )} -
- ))} -
-
-
- ) -} - -export default DisplayNestedObjects -*/ -import React from 'react' - -const extractComponents = data => { - const components = [] - - const processObject = obj => { - for (const key in obj) { - if (typeof obj[key] === 'object') { - if (obj[key].id && obj[key].dpp_class) { - components.push({ - id: obj[key].id, - dpp_class: obj[key].dpp_class, - }) - - if (Object.keys(obj[key]).length >= 2) { - const subcomponents = extractComponents(obj[key]) - components[components.length - 1].subcomponents = subcomponents - } - } else { - const subcomponents = extractComponents(obj[key]) - components.push(...subcomponents) - } - } - } - } - - processObject(data) - - return components -} - -const DisplayNestedObjects = ({ product }) => { - const components = extractComponents(product) - - return ( -
-
- - Components - -
- {components.map((component, index) => ( -
-

ID: {component.id}

-

DPP Class: {component.dpp_class}

- {component.subcomponents && ( -
- {/* Recursive call for subcomponents */} - {component.subcomponents.map((subcomponent, subIndex) => ( -
-

ID: {subcomponent.id}

-

DPP Class: {subcomponent.dpp_class}

- {/* Add more properties if needed */} -
- ))} -
- )} -
- ))} -
-
-
- ) -} - -export default DisplayNestedObjects +export default ProductDetails From d5ffbab89e961e815f88099e88c24d599fa90899 Mon Sep 17 00:00:00 2001 From: aleepe-1 Date: Fri, 26 Jan 2024 18:32:43 +0100 Subject: [PATCH 03/18] color on link and space for name --- src/pages/product/[productId].js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/product/[productId].js b/src/pages/product/[productId].js index 25cb743d..1db0bacc 100644 --- a/src/pages/product/[productId].js +++ b/src/pages/product/[productId].js @@ -209,8 +209,9 @@ function ProductDetails({ product }) {

ID: {component.id}

DPP Class: {component.dpp_class}

- Name: + Name:  {component.name} From 241914f385aa12cbc4be407c873db80ae1252ef6 Mon Sep 17 00:00:00 2001 From: aleepe-1 Date: Fri, 2 Feb 2024 14:44:08 +0100 Subject: [PATCH 04/18] correct date --- src/pages/product/[productId].js | 102 +++++++++++-------------------- 1 file changed, 36 insertions(+), 66 deletions(-) diff --git a/src/pages/product/[productId].js b/src/pages/product/[productId].js index 1db0bacc..9dda047b 100644 --- a/src/pages/product/[productId].js +++ b/src/pages/product/[productId].js @@ -3,6 +3,7 @@ import LayoutGlobal from '@/components/Layout/LayoutGlobal' import { Container } from '@/components/utils/Container' import { useEffect, useState } from 'react' import React from 'react' +import { formatDate } from '@/utils/server/helpers' export async function getServerSideProps(context) { const { productId } = context.params @@ -28,43 +29,6 @@ export async function getServerSideProps(context) { } } } -/* -export default function ProductPage({ product }) { - // Function to recursively render product properties, including nested objects/arrays - const renderProductData = data => { - if (Array.isArray(data)) { - return ( -

- ) - } else if (typeof data === 'object' && data !== null) { - return ( -
    - {Object.entries(data).map(([key, value]) => ( -
  • - {key}: {renderProductData(value)} -
  • - ))} -
- ) - } else { - return data.toString() - } - } - - return ( -
-

Product Details

- {renderProductData(product)} -
- ) -} -*/ - -//* const extractObjects = data => { const events = [] @@ -156,7 +120,7 @@ function ProductDetails({ product }) { Creation time
- {product.created_at.creation_time} + {formatDate(product.created_at.creation_time)}
{product.carbon_footprint.effect != null && ( @@ -169,7 +133,7 @@ function ProductDetails({ product }) { )} - {product.crm > 0 && ( + {product.crm !== undefined && (
Crm @@ -179,24 +143,27 @@ function ProductDetails({ product }) {
)} -
-
- - Events - -
- {nestedObjects.hasEvents.map((component, index) => ( -
-

ID: {component.id}

-

DPP Class: {component.dpp_class}

-

Creation Time: {component.creation_time}

-

Action: {component.action}

-

-
- ))} -
-
- +
+ {nestedObjects.hasEvents.length > 0 && ( +
+ + Events + +
+ {nestedObjects.hasEvents.map((component, index) => ( +
+

ID: {component.id}

+

+ Creation Time:{' '} + {formatDate(component.creation_time)} +

+

Action: {component.action}

+

+
+ ))} +
+
+ )} {nestedObjects.componentObjects.length > 0 && (
@@ -229,18 +196,21 @@ function ProductDetails({ product }) {
-
-
-
-
-
Weight
-
-
-
-
) } export default ProductDetails + +/* +
+
+
+
+
Weight
+
+
+
+
+*/ From 62de8b0daeb1c9ccc81fea575b2079ddc9cca2bf Mon Sep 17 00:00:00 2001 From: themooses Date: Sat, 3 Feb 2024 14:41:00 +0100 Subject: [PATCH 05/18] test --- .../Components/sections/products/index.jsx | 199 ++++++++++++++++++ src/components/Admin/Layout/AdminLayout.jsx | 10 +- src/components/Global/NavbarGlobal.jsx | 26 ++- src/components/Global/SearchBar.jsx | 10 +- src/components/Layout/LayoutGlobal.jsx | 5 +- src/components/UI/Forms/UserDropdown.jsx | 10 +- src/components/UI/global/SearchResultCard.jsx | 26 +-- src/models/ProductCollection.js | 0 src/pages/api/v1/admin/products/index.js | 62 ++++++ src/pages/index.jsx | 16 +- src/pages/product/[productId].js | 42 +--- src/pages/product/index.jsx | 7 - 12 files changed, 325 insertions(+), 88 deletions(-) create mode 100644 src/models/ProductCollection.js delete mode 100644 src/pages/product/index.jsx diff --git a/src/components/Admin/Components/sections/products/index.jsx b/src/components/Admin/Components/sections/products/index.jsx index e69de29b..d6d1dad2 100644 --- a/src/components/Admin/Components/sections/products/index.jsx +++ b/src/components/Admin/Components/sections/products/index.jsx @@ -0,0 +1,199 @@ +import { Fragment, useState, useEffect } from 'react' +import { Dialog, Transition } from '@headlessui/react' +import { Cog6ToothIcon, XMarkIcon } from '@heroicons/react/24/solid' +import TextField from '@/components/UI/Forms/TextField' + +export default function Products() { + const [formOpen, setFormOpen] = useState(false) + const [products, setProducts] = useState([]) + const [page, setPage] = useState(1) + const [pageSize, setPageSize] = useState(25) + const [productCount, setProductCount] = useState(0) + + const totalPages = productCount > 0 ? Math.ceil(productCount / pageSize) : 1 + + useEffect(() => { + const fetchProducts = async () => { + try { + const response = await fetch( + `/api/v1/admin/products?page=${page}&pageSize=${pageSize}` + ) + if (!response.ok) { + throw new Error('Network response was not ok') + } + const data = await response.json() + setProducts(data.products) + setProductCount(data.totalProducts) + } catch (error) { + console.error('Failed to fetch products:', error) + } + } + + fetchProducts() + }, [page, pageSize]) + + const toggleFormOpen = () => { + setFormOpen(prevState => !prevState) + } + + return ( +
+
+

Products

+

{productCount} products found

+
+
+ +
+ + {formOpen && ( + + )} + +
+ + + + + + + + + + {products.map(product => ( + + + + + + ))} + +
+ ID + + Product Name + + Manufactured By +
{product._id}{product.name} + {product.manufactured_by.owner_name} +
+
+
+ + + Page {page} of {totalPages} + + +
+
+ ) +} + +function ProductForm({ + formOpen, + setFormOpen, + setProducts, + setPage, + setProductCount, +}) { + const [submitted, setSubmitted] = useState(false) + const [formProduct, setFormProduct] = useState({ + name: '', + // Initialize other fields as needed + }) + + const handleFormChange = e => { + const { name, value } = e.target + setFormProduct(prev => ({ + ...prev, + [name]: value, + })) + } + + const SubmitForm = async e => { + e.preventDefault() + setSubmitted(true) + + if (!formProduct.name) { + return + } + try { + const response = await fetch('/api/v1/products', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(formProduct), + }) + + if (!response.ok) { + throw new Error('Network response was not ok') + } + + const data = await response.json() + setFormOpen(false) + // Optionally, refresh the products list or update state to include the new product + } catch (error) { + console.error('Submit failed:', error) + } + } + + return ( + + setFormOpen(false)} + > + {/* Dialog and form content */} +
+ {/* Form fields and submit button */} + + {/* Add more fields as needed */} + + +
+
+ ) +} diff --git a/src/components/Admin/Layout/AdminLayout.jsx b/src/components/Admin/Layout/AdminLayout.jsx index 0d1d1ebc..2830e7c7 100644 --- a/src/components/Admin/Layout/AdminLayout.jsx +++ b/src/components/Admin/Layout/AdminLayout.jsx @@ -16,6 +16,7 @@ import Image from 'next/image' import Dashboard from '../Components/sections/dashboard' import Users from '../Components/sections/users' import Roles from '../Components/sections/roles' +import Products from '../Components/sections/products' const teams = [ { id: 1, name: 'Heroicons', href: '#', initial: 'H', current: false }, @@ -45,8 +46,6 @@ export default function AdminLayout() { return case 'Products': return - case 'Logs': - return // Add cases for other sections as needed default: return

Selected Section: {selectedSection}

@@ -82,13 +81,6 @@ export default function AdminLayout() { current: selectedSection === 'Products', onClick: e => handleNavigationClick('Products', e), }, - { - name: 'Logs', - href: '#', - icon: DocumentTextIcon, - current: selectedSection === 'Logs', - onClick: e => handleNavigationClick('Logs', e), - }, ] return ( diff --git a/src/components/Global/NavbarGlobal.jsx b/src/components/Global/NavbarGlobal.jsx index f1da0a91..44aaa541 100644 --- a/src/components/Global/NavbarGlobal.jsx +++ b/src/components/Global/NavbarGlobal.jsx @@ -5,22 +5,32 @@ import { Container } from '../utils/Container' import { HomeIcon } from '@heroicons/react/24/outline' import Example from '../UI/Forms/UserDropdown' import SearchBar from './SearchBar' +import Link from 'next/link' -export function Header(props) { +export function NavbarGlobal({ searchBar = true, navClassName }) { const router = useRouter() const [isElementVisible, setElementVisibility] = useState(false) return ( -
+