├── public ├── _redirects └── index.html ├── postcss.config.js ├── src ├── utilities │ └── currencyFormatter.js ├── pages │ ├── Home.js │ ├── NotFound.js │ ├── Products.js │ └── Cart.js ├── components │ ├── Footer.js │ ├── Slide.js │ ├── Navbar.js │ ├── Card.js │ └── Slider.js ├── app │ └── store.js ├── index.js ├── features │ └── products │ │ ├── productSlice.js │ │ └── cartSlice.js ├── App.js └── index.css ├── tailwind.config.js ├── .gitignore ├── package.json └── README.md /public/_redirects: -------------------------------------------------------------------------------- 1 | /* /index.html 200 -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/utilities/currencyFormatter.js: -------------------------------------------------------------------------------- 1 | export const currencyFormatter = (price) => { 2 | if (!price) return; 3 | return price.toLocaleString("en-US", { style: "currency", currency: "USD" }); 4 | }; 5 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.{js,jsx,ts,tsx}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /src/pages/Home.js: -------------------------------------------------------------------------------- 1 | import Slider from "../components/Slider"; 2 | import Products from "./Products"; 3 | 4 | const Home = () => { 5 | return ( 6 |
7 | 8 | 9 |
10 | ); 11 | }; 12 | 13 | export default Home; 14 | -------------------------------------------------------------------------------- /src/components/Footer.js: -------------------------------------------------------------------------------- 1 | const Footer = () => { 2 | return ( 3 |
4 |

5 | © {new Date().getFullYear()} Tech Alpha. All rights reserved. 6 |

7 |
8 | ); 9 | }; 10 | 11 | export default Footer; 12 | -------------------------------------------------------------------------------- /src/app/store.js: -------------------------------------------------------------------------------- 1 | import { configureStore } from "@reduxjs/toolkit"; 2 | 3 | import productsReducer, { 4 | productsFetching, 5 | } from "../features/products/productSlice"; 6 | import cartReducer from "../features/products/cartSlice"; 7 | 8 | export const store = configureStore({ 9 | reducer: { 10 | products: productsReducer, 11 | cart: cartReducer, 12 | }, 13 | }); 14 | 15 | store.dispatch(productsFetching()); 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # local env files 12 | .env 13 | 14 | # production 15 | 16 | 17 | # misc 18 | .DS_Store 19 | .env.local 20 | .env.development.local 21 | .env.test.local 22 | .env.production.local 23 | 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | tech-alpha 13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import { BrowserRouter } from "react-router-dom"; 4 | import App from "./App"; 5 | import "./index.css"; 6 | 7 | import { store } from "./app/store"; 8 | import { Provider } from "react-redux"; 9 | 10 | const root = ReactDOM.createRoot(document.getElementById("root")); 11 | root.render( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | -------------------------------------------------------------------------------- /src/pages/NotFound.js: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | const NotFound = () => { 4 | return ( 5 |
6 | 11 |

12 | Page not found 13 |

14 | 15 | 18 | 19 |
20 | ); 21 | }; 22 | 23 | export default NotFound; 24 | -------------------------------------------------------------------------------- /src/pages/Products.js: -------------------------------------------------------------------------------- 1 | import { useSelector } from "react-redux"; 2 | import Card from "../components/Card"; 3 | 4 | const Products = () => { 5 | const { items: data, status } = useSelector((state) => state.products); 6 | 7 | return ( 8 |
9 |

14 | Browse all products 15 |

16 |
17 | {status &&

{status}

} 18 | 19 | {data.map((product) => ( 20 | 21 | ))} 22 |
23 |
24 | ); 25 | }; 26 | 27 | export default Products; 28 | -------------------------------------------------------------------------------- /src/features/products/productSlice.js: -------------------------------------------------------------------------------- 1 | import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"; 2 | import axios from "axios"; 3 | 4 | const initialState = { 5 | items: [], 6 | status: null, 7 | }; 8 | 9 | export const productsFetching = createAsyncThunk( 10 | "products/productsFetching", 11 | async () => { 12 | const res = await axios.get( 13 | `${process.env.REACT_APP_BASE_URL}/api/products` 14 | ); 15 | return res.data; 16 | } 17 | ); 18 | 19 | export const productsSlice = createSlice({ 20 | name: "products", 21 | initialState, 22 | reducers: {}, 23 | extraReducers: (builder) => { 24 | builder.addCase(productsFetching.pending, (state, action) => { 25 | state.status = "Loading..."; 26 | }); 27 | 28 | builder.addCase(productsFetching.fulfilled, (state, action) => { 29 | state.status = ""; 30 | state.items = action.payload; 31 | }); 32 | 33 | builder.addCase(productsFetching.rejected, (state, action) => { 34 | state.status = "Something went wrong!"; 35 | }); 36 | }, 37 | }); 38 | 39 | export default productsSlice.reducer; 40 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import { Route, Routes } from "react-router-dom"; 2 | import { ToastContainer } from "react-toastify"; 3 | 4 | import Footer from "./components/Footer"; 5 | import Navbar from "./components/Navbar"; 6 | import Cart from "./pages/Cart"; 7 | import Home from "./pages/Home"; 8 | import NotFound from "./pages/NotFound"; 9 | import Products from "./pages/Products"; 10 | import "react-toastify/dist/ReactToastify.css"; 11 | import { useEffect } from "react"; 12 | import AOS from "aos"; 13 | import "aos/dist/aos.css"; 14 | 15 | const App = () => { 16 | useEffect(() => { 17 | AOS.init(); 18 | }, []); 19 | return ( 20 | <> 21 |
22 | 23 | 24 | 25 | } /> 26 | } /> 27 | } /> 28 | } /> 29 | } /> 30 | 31 |
32 |