From 04b3c4e07b5244fecbaa8a258ff40715a3c57894 Mon Sep 17 00:00:00 2001 From: Suraj Birewar Date: Thu, 1 Aug 2024 15:21:35 +0530 Subject: [PATCH] added product categories pages to the application --- .env | 14 ++- src/App.jsx | 12 ++ src/api/axiosConfig.jsx | 11 +- src/api/employeeServices.js | 2 +- src/components/categories/CategoryList.jsx | 45 ++++---- .../categories/JacketsProductList.jsx | 66 +++++++++++ src/components/categories/ProductRow.jsx | 39 ++++--- .../categories/ShirtsProductList.jsx | 66 +++++++++++ .../categories/SuitsProductList.jsx | 66 +++++++++++ .../categories/TuxedosProductList.jsx | 66 +++++++++++ src/components/customize/Customize.jsx | 106 +++++++++++++++++ src/services_1/usersService.js | 2 +- src/styles/Customize.css | 82 ++++++++++++++ src/styles/ProductList.css | 107 ++++++++++++++++++ 14 files changed, 643 insertions(+), 41 deletions(-) create mode 100644 src/components/categories/JacketsProductList.jsx create mode 100644 src/components/categories/ShirtsProductList.jsx create mode 100644 src/components/categories/SuitsProductList.jsx create mode 100644 src/components/categories/TuxedosProductList.jsx create mode 100644 src/components/customize/Customize.jsx create mode 100644 src/styles/Customize.css create mode 100644 src/styles/ProductList.css diff --git a/.env b/.env index 6862980..5370f7d 100644 --- a/.env +++ b/.env @@ -1,2 +1,12 @@ -VITE_ENVIRONMENT=dev -VITE_API_URL=https://api.yourproductionurl.com + +const environment = import.meta.env.VITE_ENVIRONMENT; +const apiUrl = import.meta.env.VITE_API_URL; + +console.log('Environment:', environment); +console.log('API URL:', apiUrl); + +// Example of using the API URL +fetch(`${apiUrl}/endpoint`) + .then(response => response.json()) + .then(data => console.log(data)) + .catch(error => console.error('Error:', error)); diff --git a/src/App.jsx b/src/App.jsx index 33d7e8f..d735aa8 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -14,6 +14,13 @@ import EmployeeList from "./components/admin/EmployeeList"; import AddEmployee from "./components/admin/AddEmployee"; import EmployeeProfile from "./components/admin/EmployeeProfile"; import CategoryList from "./components/categories/CategoryList"; +import ShirtsProductList from "./components/categories/ShirtsProductList"; +import SuitsProductList from "./components/categories/SuitsProductList"; +import TuxedosProductList from "./components/categories/TuxedosProductList"; +import JacketsProductList from "./components/categories/JacketsProductList"; +import Customize from "./components/customize/Customize"; + + import { Refine } from "@refinedev/core"; import { RefineKbarProvider } from "@refinedev/kbar"; import { ToastContainer, toast } from "react-toastify"; @@ -46,6 +53,11 @@ const App = () => { } /> } /> } /> + } /> + } /> + } /> + } /> + } /> diff --git a/src/api/axiosConfig.jsx b/src/api/axiosConfig.jsx index 150d2e5..8d63b85 100644 --- a/src/api/axiosConfig.jsx +++ b/src/api/axiosConfig.jsx @@ -2,10 +2,12 @@ import axios from 'axios'; // Determine environment and set baseURL accordingly const environment = import.meta.env.VITE_ENVIRONMENT; -const baseURL = environment === 'dev' +const baseURL = environment === 'production' ? import.meta.env.VITE_API_URL : 'http://localhost:5000'; // Default for development +console.log(`Axios baseURL set to: ${baseURL}`); // Log the base URL for debugging + const axiosInstance = axios.create({ baseURL, headers: { @@ -13,18 +15,23 @@ const axiosInstance = axios.create({ }, }); +// Request interceptor to add JWT token axiosInstance.interceptors.request.use((config) => { const token = localStorage.getItem('token'); if (token) { config.headers['Authorization'] = `Bearer ${token}`; } return config; +}, error => { + // Handle request error + console.error('Request error:', error); + return Promise.reject(error); }); +// Response interceptor to handle responses globally axiosInstance.interceptors.response.use( response => response, error => { - // Handle errors globally if (error.response) { // Server responded with a status other than 2xx console.error('Error response:', error.response.data); diff --git a/src/api/employeeServices.js b/src/api/employeeServices.js index d317c86..0f7f45b 100644 --- a/src/api/employeeServices.js +++ b/src/api/employeeServices.js @@ -1,4 +1,4 @@ -import axiosInstance from './axiosConfig'; +import axiosInstance from '../axiosConfig'; export const getEmployees = async () => { diff --git a/src/components/categories/CategoryList.jsx b/src/components/categories/CategoryList.jsx index 690db73..8dc0b43 100644 --- a/src/components/categories/CategoryList.jsx +++ b/src/components/categories/CategoryList.jsx @@ -1,15 +1,17 @@ import React from 'react'; import { useNavigate } from 'react-router-dom'; -import Sidebar from '../sidebar/Sidebar'; // Ensure the correct path to Sidebar +import Sidebar from '../sidebar/Sidebar'; +import '../../styles/ProductList.css'; const CategoryList = () => { const navigate = useNavigate(); + // Updated categories array with names and specifications const categories = [ - { name: 'shirts', image: 'https://www2.hm.com/en_in/productpage.1032522123.html' }, - { name: 'suits', image: 'https://www2.hm.com/en_in/productpage.1032522123.html' }, - { name: 'tuxedos', image: 'https://www2.hm.com/en_in/productpage.1032522123.html' }, - { name: 'jackets', image: 'https://image.coolblue.nl/422x390/products/1101120' }, + { name: 'Shirts', image: 'https://www2.hm.com/en_in/productpage.1032522123.html', description: 'shirts' }, + { name: 'Suits', image: 'https://www2.hm.com/en_in/productpage.1032522123.html', description: 'suits' }, + { name: 'Tuxedos', image: 'https://www2.hm.com/en_in/productpage.1032522123.html', description: 'tuxedos' }, + { name: 'Jackets', image: 'https://image.coolblue.nl/422x390/products/1101120', description: 'jackets' }, ]; const handleClick = (category) => { @@ -22,20 +24,25 @@ const CategoryList = () => { {/* Main content */} -
-

categories

-
- {categories.map((category, index) => ( -
handleClick(category.name)} - > - {category.name} -

{category.name}

-

click to view products

-
- ))} +
+
+

Categories

+
+
+
+ {categories.map((category, index) => ( +
handleClick(category.name.toLowerCase())} // Updated to handle lowercase category names + > + {category.name} +

{category.name}

+

{category.description}

+

Click to view products

+
+ ))} +
diff --git a/src/components/categories/JacketsProductList.jsx b/src/components/categories/JacketsProductList.jsx new file mode 100644 index 0000000..222cbed --- /dev/null +++ b/src/components/categories/JacketsProductList.jsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import Sidebar from '../sidebar/Sidebar'; +import ProductRow from './ProductRow'; +import '../../styles/ProductList.css'; + +const products = [ + { id: 1, name: 'red bomber jacket', price: 129, image: 'path/to/red-bomber-jacket-image.png' }, + { id: 2, name: 'green utility jacket', price: 149, image: 'path/to/green-utility-jacket-image.png' }, + { id: 3, name: 'black leather jacket', price: 199, image: 'path/to/black-leather-jacket-image.png' }, + { id: 4, name: 'blue aces', price: 99, image: 'path/to/blue-aces-image.png' }, + { id: 5, name: 'blue birdseye', price: 99, image: 'path/to/blue-birdseye-image.png' }, + { id: 6, name: 'blue hydrangea', price: 99, image: 'path/to/blue-hydrangea-image.png' }, +]; + +const JacketsProductList = () => { + const navigate = useNavigate(); + + const handleCustomize = (id) => { + navigate(`/customize/${id}`); + }; + + return ( +
+ {/* Sidebar */} + + + {/* Main content */} +
+

Products (Jackets)

+
+

Total jackets: ({products.length})

+
+ + + + filter +
+
+
+ {products.map((product) => ( + handleCustomize(product.id)} + /> + ))} +
+
+
+ ); +}; + +export default JacketsProductList; diff --git a/src/components/categories/ProductRow.jsx b/src/components/categories/ProductRow.jsx index 1874d3b..8dcdbe1 100644 --- a/src/components/categories/ProductRow.jsx +++ b/src/components/categories/ProductRow.jsx @@ -1,7 +1,8 @@ -import { useMemo } from "react"; -import PropTypes from "prop-types"; +import React, { useMemo } from 'react'; +import PropTypes from 'prop-types'; +import '../../styles/ProductList.css'; -const ProductRow = ({ className = "", image17, shirts, propLeft, propTop }) => { +const ProductRow = ({ className = "", image17, shirts, onClick, propLeft, propTop }) => { const productRowStyle = useMemo(() => { return { left: propLeft, @@ -11,37 +12,43 @@ const ProductRow = ({ className = "", image17, shirts, propLeft, propTop }) => { return (
-
-
+
+
{shirts}
-
-
- Click to view products +
+
+ Click to view product details
+ {/* Customize Button */} +
); }; ProductRow.propTypes = { className: PropTypes.string, - image17: PropTypes.string, - shirts: PropTypes.string, - - /** Style props */ + image17: PropTypes.string.isRequired, + shirts: PropTypes.string.isRequired, + onClick: PropTypes.func.isRequired, propLeft: PropTypes.any, propTop: PropTypes.any, }; -export default ProductRow; \ No newline at end of file +export default ProductRow; diff --git a/src/components/categories/ShirtsProductList.jsx b/src/components/categories/ShirtsProductList.jsx new file mode 100644 index 0000000..3037969 --- /dev/null +++ b/src/components/categories/ShirtsProductList.jsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import Sidebar from '../sidebar/Sidebar'; +import ProductRow from './ProductRow'; +import '../../styles/ProductList.css'; + +const products = [ + { id: 1, name: 'blue aces', price: 99, image: 'path/to/blue-aces-image.png' }, + { id: 2, name: 'blue birdseye', price: 99, image: 'path/to/blue-birdseye-image.png' }, + { id: 3, name: 'blue hydrangea', price: 99, image: 'path/to/blue-hydrangea-image.png' }, + { id: 4, name: 'blue aces', price: 99, image: 'path/to/blue-aces-image.png' }, + { id: 5, name: 'blue birdseye', price: 99, image: 'path/to/blue-birdseye-image.png' }, + { id: 6, name: 'blue hydrangea', price: 99, image: 'path/to/blue-hydrangea-image.png' }, +]; + +const ShirtsProductList = () => { + const navigate = useNavigate(); + + const handleCustomize = (id) => { + navigate(`/customize/${id}`); + }; + + return ( +
+ {/* Sidebar */} + + + {/* Main content */} +
+

Products (Shirts)

+
+

Total shirts: ({products.length})

+
+ + + + filter +
+
+
+ {products.map((product) => ( + handleCustomize(product.id)} + /> + ))} +
+
+
+ ); +}; + +export default ShirtsProductList; diff --git a/src/components/categories/SuitsProductList.jsx b/src/components/categories/SuitsProductList.jsx new file mode 100644 index 0000000..1ba321c --- /dev/null +++ b/src/components/categories/SuitsProductList.jsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import Sidebar from '../sidebar/Sidebar'; +import ProductRow from './ProductRow'; +import '../../styles/ProductList.css'; + +const products = [ + { id: 1, name: 'blue aces', price: 99, image: 'path/to/blue-aces-image.png' }, + { id: 2, name: 'blue birdseye', price: 99, image: 'path/to/blue-birdseye-image.png' }, + { id: 3, name: 'blue hydrangea', price: 99, image: 'path/to/blue-hydrangea-image.png' }, + { id: 4, name: 'blue aces', price: 99, image: 'path/to/blue-aces-image.png' }, + { id: 5, name: 'blue birdseye', price: 99, image: 'path/to/blue-birdseye-image.png' }, + { id: 6, name: 'blue hydrangea', price: 99, image: 'path/to/blue-hydrangea-image.png' }, +]; + +const SuitsProductList = () => { + const navigate = useNavigate(); + + const handleCustomize = (id) => { + navigate(`/customize/${id}`); + }; + + return ( +
+ {/* Sidebar */} + + + {/* Main content */} +
+

Products (Suits)

+
+

Total suits: ({products.length})

+
+ + + + filter +
+
+
+ {products.map((product) => ( + handleCustomize(product.id)} + /> + ))} +
+
+
+ ); +}; + +export default SuitsProductList; diff --git a/src/components/categories/TuxedosProductList.jsx b/src/components/categories/TuxedosProductList.jsx new file mode 100644 index 0000000..676f64d --- /dev/null +++ b/src/components/categories/TuxedosProductList.jsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import Sidebar from '../sidebar/Sidebar'; +import ProductRow from './ProductRow'; +import '../../styles/ProductList.css'; + +const products = [ + { id: 1, name: 'black tuxedo', price: 199, image: 'path/to/black-tuxedo-image.png' }, + { id: 2, name: 'navy tuxedo', price: 199, image: 'path/to/navy-tuxedo-image.png' }, + { id: 3, name: 'grey tuxedo', price: 199, image: 'path/to/grey-tuxedo-image.png' }, + { id: 4, name: 'blue aces', price: 99, image: 'path/to/blue-aces-image.png' }, + { id: 5, name: 'blue birdseye', price: 99, image: 'path/to/blue-birdseye-image.png' }, + { id: 6, name: 'blue hydrangea', price: 99, image: 'path/to/blue-hydrangea-image.png' }, +]; + +const TuxedosProductList = () => { + const navigate = useNavigate(); + + const handleCustomize = (id) => { + navigate(`/customize/${id}`); + }; + + return ( +
+ {/* Sidebar */} + + + {/* Main content */} +
+

Products (Tuxedos)

+
+

Total tuxedos: ({products.length})

+
+ + + + filter +
+
+
+ {products.map((product) => ( + handleCustomize(product.id)} + /> + ))} +
+
+
+ ); +}; + +export default TuxedosProductList; diff --git a/src/components/customize/Customize.jsx b/src/components/customize/Customize.jsx new file mode 100644 index 0000000..225c680 --- /dev/null +++ b/src/components/customize/Customize.jsx @@ -0,0 +1,106 @@ +import React, { useState } from 'react'; +import { useParams, useNavigate, Link } from 'react-router-dom'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faChevronLeft } from '@fortawesome/free-solid-svg-icons'; +import Sidebar from '../sidebar/Sidebar'; +import '../../styles/Customize.css'; + + + +const Customize = () => { + const { id } = useParams(); + const navigate = useNavigate(); + const [style, setStyle] = useState(''); + const [material, setMaterial] = useState(''); + + const handleStyleChange = (event) => { + setStyle(event.target.value); + }; + + const handleMaterialChange = (event) => { + setMaterial(event.target.value); + }; + + const handleSave = () => { + const customization = { + productId: id, + style, + material, + }; + + fetch('/api/saveCustomization', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(customization), + }) + .then(response => response.json()) + .then(data => { + console.log('Success:', data); + navigate('/'); + }) + .catch((error) => { + console.error('Error:', error); + }); + }; + + return ( +
+ {/* Sidebar */} + + + {/* Main content */} +
+
+ + + +

Customize Product

+
+
+
+
+ +
+
+ +
+ +
+
+
+
+ ); +}; + +export default Customize; diff --git a/src/services_1/usersService.js b/src/services_1/usersService.js index b66823e..21c418f 100644 --- a/src/services_1/usersService.js +++ b/src/services_1/usersService.js @@ -1,4 +1,4 @@ -import axiosInstance from "../api/axiosConfig"; // Import the global axios instance +import axiosInstance from "../api/axiosConfig"; // Get all users with their metadata export const getAllUsers = async () => { diff --git a/src/styles/Customize.css b/src/styles/Customize.css new file mode 100644 index 0000000..8ef11f1 --- /dev/null +++ b/src/styles/Customize.css @@ -0,0 +1,82 @@ + +.container { + display: flex; + flex-direction: row; + height: 100vh; +} + + + +.main-content { + flex-grow: 1; + display: flex; + flex-direction: column; +} + +.header { + background-color: #ffffff; + padding: 1rem; + display: flex; + align-items: center; + border-bottom: 1px solid #ffffff; +} + +.header-title { + display: flex; + align-items: center; + font-size: 1.5rem; /* text-2xl */ + font-weight: 600; /* font-semibold */ + color: #0e355b; /* Dark blue */ + margin-left: 1rem; +} + +.back-button { + color: #0e355b; + font-size: 1.25rem; +} + +.inner-content { + flex-grow: 1; + padding: 1.5rem; + background-color: #f9fafb; + color: #4a5568; +} + + + + + +.form-input, +.form-select { + width: 100%; + padding: 0.75rem; /* p-3 */ + border: 1px solid #cbd5e0; /* border-gray-400 */ + border-radius: 0.375rem; /* rounded-md */ +} + +.form-input:focus, +.form-select:focus { + border-color: #2d3748; /* Darker gray border on focus */ + outline: none; +} + +.submit-button { + background-color: #0e355b; /* Dark blue */ + color: white; + padding: 0.75rem 1.5rem; /* p-3 */ + border-radius: 0.375rem; /* rounded-md */ + font-weight: 600; /* font-semibold */ + cursor: pointer; + border: none; + transition: background-color 0.3s ease; +} + +.submit-button:hover { + background-color: #1e3a8a; /* Darker blue on hover */ +} + + + + + + \ No newline at end of file diff --git a/src/styles/ProductList.css b/src/styles/ProductList.css new file mode 100644 index 0000000..4ec7cfd --- /dev/null +++ b/src/styles/ProductList.css @@ -0,0 +1,107 @@ +.product-list { + padding: 20px; + background-color: #ffffff; + border-radius: 8px; + max-width: 1200px; + margin: 0 auto; + } + + .product-list h1 { + color: #0e355b; + text-align: left; + margin-bottom: 20px; + } + + .product-actions { + display: flex; + justify-content: space-between; + margin-bottom: 20px; + } + + .filter-button { + padding: 10px 20px; + background-color: #0e355b; + color: #ffffff; + border: none; + cursor: pointer; + border-radius: 5px; + transition: background-color 0.3s; + } + + .filter-button:hover { + background-color: #154676; + } + + .product-grid { + display: grid; + grid-template-columns: repeat(1, 1fr); + gap: 20px; + } + + @media (min-width: 640px) { + .product-grid { + grid-template-columns: repeat(2, 1fr); + } + } + + @media (min-width: 768px) { + .product-grid { + grid-template-columns: repeat(3, 1fr); + } + } + + .product-row { + display: flex; + flex-direction: column; + border: 1px solid #e8e8e8; + border-radius: 8px; + overflow: hidden; + transition: box-shadow 0.3s; + } + + .product-row:hover { + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + } + + .product-row img { + width: 100%; + height: auto; + } + + .product-row .product-name { + font-size: 1.5rem; + font-weight: 600; + color: #0e355b; + padding: 10px 20px; + text-align: center; + } + + .product-row .view-products { + font-size: 1rem; + color: #ffffff; + background-color: #0e355b; + padding: 10px 20px; + text-align: center; + cursor: pointer; + transition: background-color 0.3s; + } + + .product-row .view-products:hover { + background-color: #154676; + } + + .customize-button { + background-color: #0e355b; + color: #d1d5db; + border: none; + border-radius: 4px; + padding: 8px 16px; + cursor: pointer; + text-align: center; + } + + .customize-button:hover { + background-color: #154676; + } + + \ No newline at end of file