Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…t-dpp into profilePagev2
  • Loading branch information
AronGunnar committed Feb 8, 2024
2 parents b9e506c + 0ee9508 commit 2aebbb9
Show file tree
Hide file tree
Showing 15 changed files with 576 additions and 211 deletions.
199 changes: 199 additions & 0 deletions src/components/Admin/Components/sections/products/index.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className='flex flex-col justify-center px-20 py-10'>
<div className='mb-5'>
<h1 className='text-3xl font-bold'>Products</h1>
<p className='text-md text-gray-600'>{productCount} products found</p>
</div>
<div className='mb-5'>
<button
onClick={toggleFormOpen}
className='flex items-center rounded-md bg-gray-50 px-4 py-2 text-sm font-medium text-gray-700 shadow-md transition-all duration-300 ease-in-out hover:bg-indigo-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 sm:rounded-lg'
>
<Cog6ToothIcon className='mr-2 h-4 w-4' />
Add Product
</button>
</div>

{formOpen && (
<ProductForm
formOpen={formOpen}
setFormOpen={setFormOpen}
setProducts={setProducts}
setPage={setPage}
setProductCount={setProductCount}
/>
)}

<div className='relative overflow-x-auto shadow-md sm:rounded-lg'>
<table className='w-full text-left text-sm text-gray-500'>
<thead className='bg-gray-50 text-xs uppercase text-gray-700'>
<tr>
<th scope='col' className='px-6 py-3'>
ID
</th>
<th scope='col' className='px-6 py-3'>
Product Name
</th>
<th scope='col' className='px-6 py-3'>
Manufactured By
</th>
</tr>
</thead>
<tbody className='divide-y divide-gray-200'>
{products.map(product => (
<tr
key={product._id}
className='border-b bg-white hover:bg-gray-50'
>
<td className='px-6 py-4'>{product._id}</td>
<td className='px-6 py-4'>{product.name}</td>
<td className='px-6 py-4'>
{product.manufactured_by.owner_name}
</td>
</tr>
))}
</tbody>
</table>
</div>
<div className='mt-4 flex items-center justify-between'>
<button
onClick={() => setPage(Math.max(page - 1, 1))}
disabled={page === 1}
className={`text-gray-500 hover:text-gray-700 ${
page === 1 && 'cursor-not-allowed'
}`}
>
Previous
</button>
<span>
Page {page} of {totalPages}
</span>
<button
onClick={() => setPage(Math.min(page + 1, totalPages))}
disabled={page === totalPages}
className={`text-gray-500 hover:text-gray-700 ${
page === totalPages && 'cursor-not-allowed'
}`}
>
Next
</button>
</div>
</div>
)
}

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 (
<Transition.Root show={formOpen} as={Fragment}>
<Dialog
as='div'
className='relative z-10'
onClose={() => setFormOpen(false)}
>
{/* Dialog and form content */}
<form onSubmit={SubmitForm} className='...'>
{/* Form fields and submit button */}
<TextField
label='Product Name'
name='name'
value={formProduct.name}
onChange={handleFormChange}
error={submitted && !formProduct.name ? 'Required' : ''}
className='w-full'
type='text'
/>
{/* Add more fields as needed */}
<button type='submit' className='...'>
Add Product
</button>
</form>
</Dialog>
</Transition.Root>
)
}
10 changes: 1 addition & 9 deletions src/components/Admin/Layout/AdminLayout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down Expand Up @@ -45,8 +46,6 @@ export default function AdminLayout() {
return <Roles />
case 'Products':
return <Products />
case 'Logs':
return <Logs />
// Add cases for other sections as needed
default:
return <p>Selected Section: {selectedSection}</p>
Expand Down Expand Up @@ -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 (
Expand Down
26 changes: 18 additions & 8 deletions src/components/Global/NavbarGlobal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<header className={clsx('z-[150]', props.navClassName)}>
<header className={clsx('z-[150]', navClassName)}>
<nav className='border-b p-3 shadow-md'>
<Container className='flex h-[52px] flex-row items-center justify-between'>
<a href='#' className='h-full'>
<HomeIcon className='h-full cursor-pointer rounded-full p-2 text-gray-800 transition duration-200 ease-in-out hover:text-teal-600' />
</a>
<Container className='flex h-[52px] items-center justify-between'>
{/* Left Section for Home Icon */}
<div className='relative flex h-full items-center justify-center'>
<Link href='/' className='flex h-full items-center'>
<HomeIcon className='h-14 cursor-pointer rounded-full p-2 text-gray-800 transition duration-200 ease-in-out hover:text-teal-600' />
</Link>
</div>

<SearchBar />
{/* Conditionally render SearchBar */}
{searchBar && (
<div className='absolute left-0 right-0 mx-auto w-max'>
<SearchBar />
</div>
)}

<div className='nav-links-container flex flex-row items-center space-x-4 text-lg'>
{/* Right Section for Navigation Links */}
<div className='flex items-center'>
<a
href='#'
className='nav-links h-full cursor-pointer rounded-full p-2 font-semibold transition duration-200 ease-in-out hover:text-teal-600'
Expand Down
10 changes: 6 additions & 4 deletions src/components/Global/SearchBar.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { useState, useEffect } from 'react'
import { MagnifyingGlassIcon } from '@heroicons/react/24/solid'
import clsx from 'clsx'
import SearchField from '../UI/Forms/SearchField'
import SearchResultCard from '../UI/global/SearchResultCard'
import Link from 'next/link'

export default function SearchBar() {
export default function SearchBar({ className, ...props }) {
const [searchTerm, setSearchTerm] = useState('')
const [searchResult, setSearchResult] = useState([])
const [loading, setLoading] = useState(false)
Expand Down Expand Up @@ -46,7 +48,7 @@ export default function SearchBar() {
)

return (
<div className='relative w-full md:w-[250px]'>
<div className={clsx('relative', className)}>
<div className='relative w-full'>
<div className='flex w-full items-center'>
<SearchField
Expand All @@ -70,8 +72,8 @@ export default function SearchBar() {
return null
}

const uniqueKey = item.id || item.name + item.dpp_class + index

const uniqueKey = item._id || item.name + item.dpp_class + index
console.log(item)
return (
<li
key={uniqueKey}
Expand Down
5 changes: 3 additions & 2 deletions src/components/Layout/LayoutGlobal.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import Head from 'next/head'
import { Header } from '../Global/NavbarGlobal'
import { NavbarGlobal } from '../Global/NavbarGlobal'

export default function LayoutGlobal({
className,
title,
description = 'Digital Product Passport Project.',
searchBar = true,
...props
}) {
return (
Expand All @@ -18,7 +19,7 @@ export default function LayoutGlobal({
/>
<meta property='og:description' content={description} />
</Head>
<Header />
<NavbarGlobal searchBar={searchBar} />
<main>
<>{props.children}</>
</main>
Expand Down
10 changes: 5 additions & 5 deletions src/components/UI/Forms/UserDropdown.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ export default function DropdownMenu() {
<div className='py-1'>
<Menu.Item>
{({ active }) => (
<a
href='#'
<Link
href='/profile'
className={classNames(
active ? 'bg-gray-100 text-gray-900' : 'text-gray-700',
'block px-4 py-2 text-sm'
Expand All @@ -68,7 +68,7 @@ export default function DropdownMenu() {
<Cog6ToothIcon className='h-5 text-gray-800' />
<p>Account settings</p>
</div>
</a>
</Link>
)}
</Menu.Item>
</div>
Expand All @@ -77,7 +77,7 @@ export default function DropdownMenu() {
<div className='py-1'>
<Menu.Item>
{({ active }) => (
<a
<Link
href='#'
className={classNames(
active ? 'bg-gray-100 text-gray-900' : 'text-gray-700',
Expand All @@ -88,7 +88,7 @@ export default function DropdownMenu() {
<ExclamationCircleIcon className='h-5 text-gray-800' />
<p>Example link</p>
</div>
</a>
</Link>
)}
</Menu.Item>
</div>
Expand Down
26 changes: 13 additions & 13 deletions src/components/UI/global/SearchResultCard.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import Link from 'next/link'
export default function SearchResultCard({ item }) {
console.log(item)
const { name, dpp_class, manufactured_by, created_at } = item

return (
<div className='flex w-full cursor-pointer items-center space-x-3 rounded-md p-3 hover:bg-gray-50'>
<div className='relative'></div>
<div className='flex flex-col'>
<p className='font-semibold'>{name}</p>
<p className='text-xs font-medium text-gray-500'>
{/* {created_at && created_at.creation_time && (
<span> {created_at.creation_time}</span>
)} */}
{manufactured_by && manufactured_by.owner_name && (
<span> {manufactured_by.owner_name}</span>
)}
</p>
<Link className='w-full' href={`/product/${item._id}`} passHref>
<div className='flex w-full cursor-pointer items-center space-x-3 rounded-md p-3 hover:bg-gray-50'>
<div className='relative'></div>
<div className='flex flex-col'>
<p className='font-semibold'>{name}</p>
<p className='text-xs font-medium text-gray-500'>
{manufactured_by && manufactured_by.owner_name && (
<span> {manufactured_by.owner_name}</span>
)}
</p>
</div>
</div>
</div>
</Link>
)
}
Loading

0 comments on commit 2aebbb9

Please sign in to comment.