diff --git a/greenGrocers-component-hierarchy.png b/greenGrocers-component-hierarchy.png new file mode 100644 index 0000000..6c53fb4 Binary files /dev/null and b/greenGrocers-component-hierarchy.png differ diff --git a/package-lock.json b/package-lock.json index ea547b5..0460136 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3654,9 +3654,9 @@ } }, "node_modules/vite": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", - "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", + "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", "dev": true, "dependencies": { "esbuild": "^0.18.10", diff --git a/src/App.jsx b/src/App.jsx index 03e658b..c62b2ce 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,31 +1,95 @@ -import './styles/reset.css' -import './styles/index.css' - -import initialStoreItems from './store-items' +import React, { useState } from "react"; +import "./styles/reset.css"; +import "./styles/index.css"; +import initialStoreItems from "./store-items"; +import Header from "./Header.jsx"; +import CartContainer from "./CartContainer.jsx"; +import Cart from "./Cart.jsx"; +import Filter from "./Filter.jsx"; +import Sort from "./Sort.jsx"; +import Detail from "./Detail.jsx"; +import ItemList from "./ItemList.jsx"; export default function App() { + const [storeItems, setStoreItems] = useState(initialStoreItems); + const [cartItems, setCartItems] = useState([]); + const [totalPrice, setTotalPrice] = useState(0); + const [filter, setFilter] = useState(""); + const [sort, setSort] = useState(""); + const [selectedItem, setSelectedItem] = useState(null); + + const addToCart = (item) => { + const existingItem = cartItems.find((cartItem) => cartItem.id === item.id); + if (existingItem) { + setCartItems( + cartItems.map((cartItem) => + cartItem.id === item.id + ? { ...cartItem, quantity: cartItem.quantity + 1 } + : cartItem + ) + ); + } else { + setCartItems([...cartItems, { ...item, quantity: 1 }]); + } + setTotalPrice(totalPrice + item.price); + }; + + const removeFromCart = (item) => { + const existingItem = cartItems.find((cartItem) => cartItem.id === item.id); + if (existingItem.quantity === 1) { + setCartItems(cartItems.filter((cartItem) => cartItem.id !== item.id)); + } else { + setCartItems( + cartItems.map((cartItem) => + cartItem.id === item.id + ? { ...cartItem, quantity: cartItem.quantity - 1 } + : cartItem + ) + ); + } + setTotalPrice(totalPrice - item.price); + }; + + const filterItems = (items) => { + if (filter === "") return items; + return items.filter((item) => item.type === filter); + }; + + const sortItems = (items) => { + if (sort === "price") { + return items.sort((a, b) => a.price - b.price); + } + if (sort === "alphabetical") { + return items.sort((a, b) => a.name.localeCompare(b.name)); + } + return items; + }; + + const handleItemClick = (item) => { + setSelectedItem(item.id === selectedItem?.id ? null : item); + }; + + const filteredAndSortedItems = sortItems(filterItems([...storeItems])); + return ( <> -
-

Greengrocers

- -
-
-

Your Cart

-
- -
-
-
-

Total

-
-
- £0.00 -
-
-
+
+ + + + {selectedItem && } + + +
Icons made by
- ) + ); } diff --git a/src/Cart.jsx b/src/Cart.jsx new file mode 100644 index 0000000..655068f --- /dev/null +++ b/src/Cart.jsx @@ -0,0 +1,19 @@ +import React from "react"; +import CartItemList from "./CartItemList"; +import Total from "./Total"; + +export default function Cart({ items, removeFromCart, addToCart, totalPrice }) { + return ( +
+

Your Cart

+
+ +
+ +
+ ); +} diff --git a/src/CartContainer.jsx b/src/CartContainer.jsx new file mode 100644 index 0000000..a10ae4d --- /dev/null +++ b/src/CartContainer.jsx @@ -0,0 +1,5 @@ +import React from "react"; + +export default function CartContainer({ children }) { + return
{children}
; +} diff --git a/src/CartItem.jsx b/src/CartItem.jsx new file mode 100644 index 0000000..3e95b41 --- /dev/null +++ b/src/CartItem.jsx @@ -0,0 +1,27 @@ +import React from "react"; + +export default function CartItem(props) { + return ( +
  • + {props.item.name} +

    {props.item.name}

    + + {props.item.quantity} + +
  • + ); +} diff --git a/src/CartItemList.jsx b/src/CartItemList.jsx new file mode 100644 index 0000000..a6dd026 --- /dev/null +++ b/src/CartItemList.jsx @@ -0,0 +1,17 @@ +import React from "react"; +import CartItem from "./CartItem"; + +export default function CartItemList({ items, removeFromCart, addToCart }) { + return ( +
      + {items.map((item) => ( + + ))} +
    + ); +} diff --git a/src/Detail.jsx b/src/Detail.jsx new file mode 100644 index 0000000..5c19b3c --- /dev/null +++ b/src/Detail.jsx @@ -0,0 +1,13 @@ +import React from "react"; + +export default function Detail(props) { + return ( +
    +

    {props.item.name}

    + {props.item.name} +

    Type: {props.item.type}

    +

    Price: £{props.item.price.toFixed(2)}

    +

    Description: {props.item.description}

    +
    + ); +} diff --git a/src/Filter.jsx b/src/Filter.jsx new file mode 100644 index 0000000..0751b17 --- /dev/null +++ b/src/Filter.jsx @@ -0,0 +1,11 @@ +import React from "react"; + +export default function Filter(props) { + return ( +
    + + + +
    + ); +} diff --git a/src/Header.jsx b/src/Header.jsx new file mode 100644 index 0000000..894a3b0 --- /dev/null +++ b/src/Header.jsx @@ -0,0 +1,10 @@ +import React from "react"; + +export default function Header() { + return ( +
    +

    Greengrocers

    +
      +
      + ); +} diff --git a/src/Item.jsx b/src/Item.jsx new file mode 100644 index 0000000..ebd300e --- /dev/null +++ b/src/Item.jsx @@ -0,0 +1,19 @@ +import React from "react"; + +export default function Item(props) { + return ( +
    • props.onItemClick(props.item)}> +
      + {props.item.name} +
      + +
    • + ); +} diff --git a/src/ItemList.jsx b/src/ItemList.jsx new file mode 100644 index 0000000..6a6fdaf --- /dev/null +++ b/src/ItemList.jsx @@ -0,0 +1,17 @@ +import React from "react"; +import Item from "./Item"; + +export default function ItemList(props) { + return ( +
        + {props.items.map((item) => ( + + ))} +
      + ); +} diff --git a/src/Sort.jsx b/src/Sort.jsx new file mode 100644 index 0000000..7a47f89 --- /dev/null +++ b/src/Sort.jsx @@ -0,0 +1,12 @@ +import React from "react"; + +export default function Sort(props) { + return ( +
      + + +
      + ); +} diff --git a/src/Total.jsx b/src/Total.jsx new file mode 100644 index 0000000..d401ebe --- /dev/null +++ b/src/Total.jsx @@ -0,0 +1,14 @@ +import React from "react"; + +export default function Total({ totalPrice }) { + return ( +
      +
      +

      Total

      +
      +
      + £{totalPrice.toFixed(2)} +
      +
      + ); +} diff --git a/src/store-items.js b/src/store-items.js index 96dd2ea..c606881 100644 --- a/src/store-items.js +++ b/src/store-items.js @@ -1,75 +1,84 @@ - -const storeItems = [ +const initialStoreItems = [ { - id: "001-beetroot", - name: "beetroot", - price: 0.35, - description: "The beetroot is the taproot portion of a beet plant, usually known in North America as beets while the vegetable is referred to as beetroot in British English, and also known as the table beet, garden beet, red beet, dinner beet or golden beet.", - type: "vegetable" + id: 1, + name: "Beetroot", + type: "vegetable", + price: 0.5, + image: "/assets/icons/001-beetroot.svg", + description: "Fresh beetroot, perfect for salads and juices.", }, { - id: "002-carrot", - name: "carrot", - price: 0.35, - description: "The carrot is a root vegetable, typically orange in color, though heirloom variants including purple, black, red, white, and yellow cultivars exist, all of which are domesticated forms of the wild carrot, Daucus carota, native to Europe and Southwestern Asia.", - type: "vegetable" + id: 2, + name: "Carrot", + type: "vegetable", + price: 0.3, + image: "/assets/icons/002-carrot.svg", + description: "Crunchy and sweet carrots, great for snacking.", }, { - id: "003-apple", - name: "apple", - price: 0.35, - description: "An apple is a round, edible fruit produced by an apple tree (Malus spp., among them the domestic or orchard apple; Malus domestica).", - type: "fruit" + id: 3, + name: "Apple", + type: "fruit", + price: 0.6, + image: "/assets/icons/003-apple.svg", + description: "Juicy and crisp apples, ideal for a healthy snack.", }, { - id: "004-apricot", - name: "apricot", - price: 0.35, - description: "An apricot is a fruit, or the tree that bears the fruit, of several species in the genus Prunus.", - type: "fruit" + id: 4, + name: "Apricot", + type: "fruit", + price: 0.7, + image: "/assets/icons/004-apricot.svg", + description: "Sweet and tangy apricots, great for desserts.", }, { - id: "005-avocado", - name: "avocado", - price: 0.35, - description: "The avocado, alligator pear or avocado pear (Persea americana) is a medium-sized, evergreen tree in the laurel family (Lauraceae).", - type: "fruit" + id: 5, + name: "Avocado", + type: "fruit", + price: 1.5, + image: "/assets/icons/005-avocado.svg", + description: "Creamy avocados, perfect for guacamole.", }, { - id: "006-bananas", - name: "bananas", - price: 0.35, - description: "A banana is an elongated, edible fruit – botanically a berry – produced by several kinds of large herbaceous flowering plants in the genus Musa.", - type: "fruit" + id: 6, + name: "Bananas", + type: "fruit", + price: 0.4, + image: "/assets/icons/006-bananas.svg", + description: "Ripe and sweet bananas, ideal for a quick snack.", }, { - id: "007-bell-pepper", - name: "bell pepper", - price: 0.35, - description: "The bell pepper (also known as sweet pepper, pepper, capsicum /ˈkæpsɪkəm/ or in some places, mangoes) is the fruit of plants in the Grossum Group of the species Capsicum annuum.", - type: "fruit" + id: 7, + name: "Bell Pepper", + type: "vegetable", + price: 0.8, + image: "/assets/icons/007-bell-pepper.svg", + description: "Colorful bell peppers, great for salads and stir-fries.", }, { - id: "008-berry", - name: "berry", - price: 0.35, - description: "A berry is a small, pulpy, and often edible fruit. Typically, berries are juicy, rounded, brightly colored, sweet, sour or tart, and do not have a stone or pit, although many pips or seeds may be present.", - type: "fruit" + id: 8, + name: "Berry", + type: "fruit", + price: 2.0, + image: "/assets/icons/008-berry.svg", + description: "Mixed berries, perfect for smoothies and desserts.", }, { - id: "009-blueberry", - name: "blueberry", - price: 0.35, - description: "Blueberry is a widely distributed and widespread group of perennial flowering plant with blue or purple berries.", - type: "fruit" + id: 9, + name: "Blueberry", + type: "fruit", + price: 1.8, + image: "/assets/icons/009-blueberry.svg", + description: "Sweet and tangy blueberries, ideal for snacking.", }, { - id: "010-eggplant", - name: "eggplant", - price: 0.35, - description: "Eggplant, aubergine, brinjal, or baigan is a plant species in the nightshade family Solanaceae. Solanum melongena is grown worldwide for its edible fruit.", - type: "vegetable" - } -] + id: 10, + name: "Eggplant", + type: "vegetable", + price: 1.0, + image: "/assets/icons/010-eggplant.svg", + description: "Versatile eggplants, perfect for grilling and baking.", + }, +]; -export default storeItems +export default initialStoreItems; diff --git a/src/styles/detailComponent.css b/src/styles/detailComponent.css new file mode 100644 index 0000000..8a94945 --- /dev/null +++ b/src/styles/detailComponent.css @@ -0,0 +1,15 @@ +.item-detail { + border: 1px solid #ddd; + padding: 20px; + margin: 20px 0; + background-color: #f9f9f9; +} + +.item-detail img { + max-width: 100%; + height: auto; +} + +.item-detail h2 { + margin-top: 0; +} diff --git a/src/styles/index.css b/src/styles/index.css index 0a04c2b..324406a 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -1,4 +1,5 @@ @import "./reset.css"; +@import "detailComponent.css"; /* Typography */