products UI

parent 14504ec9
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
"@types/react": "^18.2.55", "@types/react": "^18.2.55",
"@types/react-dom": "^18.2.19", "@types/react-dom": "^18.2.19",
"axios": "^1.6.7", "axios": "^1.6.7",
"bootstrap": "^5.2.3",
"cors": "^2.8.5", "cors": "^2.8.5",
"express": "^4.18.2", "express": "^4.18.2",
"mongodb": "^6.3.0", "mongodb": "^6.3.0",
...@@ -3353,6 +3354,16 @@ ...@@ -3353,6 +3354,16 @@
} }
} }
}, },
"node_modules/@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@reduxjs/toolkit": { "node_modules/@reduxjs/toolkit": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.0.tgz", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.0.tgz",
...@@ -5690,6 +5701,24 @@ ...@@ -5690,6 +5701,24 @@
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
}, },
"node_modules/bootstrap": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.3.tgz",
"integrity": "sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/twbs"
},
{
"type": "opencollective",
"url": "https://opencollective.com/bootstrap"
}
],
"peerDependencies": {
"@popperjs/core": "^2.11.6"
}
},
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
"@types/react": "^18.2.55", "@types/react": "^18.2.55",
"@types/react-dom": "^18.2.19", "@types/react-dom": "^18.2.19",
"axios": "^1.6.7", "axios": "^1.6.7",
"bootstrap": "^5.2.3",
"cors": "^2.8.5", "cors": "^2.8.5",
"express": "^4.18.2", "express": "^4.18.2",
"mongodb": "^6.3.0", "mongodb": "^6.3.0",
......
...@@ -72,7 +72,8 @@ app.post('/registeruser', checkUserIdExists, (req, res) => { ...@@ -72,7 +72,8 @@ app.post('/registeruser', checkUserIdExists, (req, res) => {
// Get Users endpoint // Get Users endpoint
app.get('/users', (req, res) => { app.get('/users', (req, res) => {
db.collection('users').find({}, { projection: { _id: false, userId: true, password: true } }).toArray() // db.collection('users').find({}, { projection: { _id: false, userId: true, password: true } }).toArray()
db.collection('users').find({}, { projection: { _id: false} }).toArray()
.then(result => { .then(result => {
res.send(result); res.send(result);
}) })
......
...@@ -5,6 +5,8 @@ import Login from './components/Login/Login'; ...@@ -5,6 +5,8 @@ import Login from './components/Login/Login';
import Register from './components/Register/Register'; import Register from './components/Register/Register';
import Cart from './components/Cart/Cart'; import Cart from './components/Cart/Cart';
import Profile from './components/Profile/Profile'; import Profile from './components/Profile/Profile';
import Products from './components/catelog/Products';
import Product from './components/catelog/Product';
import ForgetPasswordForm from './components/ForgetPasswordForm/ForgetPasswordForm'; import ForgetPasswordForm from './components/ForgetPasswordForm/ForgetPasswordForm';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import store from './reduxstore/store'; import store from './reduxstore/store';
...@@ -20,8 +22,9 @@ function App() { ...@@ -20,8 +22,9 @@ function App() {
<Route path="/register" Component={Register} /> <Route path="/register" Component={Register} />
<Route path="/cart" Component={Cart}/> <Route path="/cart" Component={Cart}/>
<Route path="/profile" Component={Profile}/> <Route path="/profile" Component={Profile}/>
<Route path="/products" Component={Products}/>
<Route path="/forgot-password" Component={ForgetPasswordForm}/> <Route path="/forgot-password" Component={ForgetPasswordForm}/>
</Routes> </Routes>
</BrowserRouter> </BrowserRouter>
</Provider> </Provider>
......
.loginsignup{ .loginsignup{
width:100%; width:100%;
height: 80vh; height: 100vh;
background:#fce3fe ; background:#fce3fe ;
padding-top: 100px; padding-top: 100px;
display: flex;
justify-content: center;
align-items: center;
} }
.loginsignup-container{ .loginsignup-container{
width:580px; width:580px;
height:600px; height:max-content;
background: white; background: white;
margin: auto; margin: auto;
padding:40px 60px; padding:40px 60px;
...@@ -31,7 +34,7 @@ ...@@ -31,7 +34,7 @@
font-size: 18px; font-size: 18px;
} }
.loginsignup-container button{ .loginsignup-container button{
width: 580px; width: 100%;
height: 72px; height: 72px;
color: white; color: white;
background:#ff4141; background:#ff4141;
......
...@@ -5,6 +5,7 @@ import { useNavigate } from 'react-router-dom'; ...@@ -5,6 +5,7 @@ import { useNavigate } from 'react-router-dom';
import {useSelector, useDispatch} from 'react-redux' import {useSelector, useDispatch} from 'react-redux'
import { fetchUsers } from '../../reduxstore/usersSlice'; import { fetchUsers } from '../../reduxstore/usersSlice';
import { RootState } from '../../reduxstore/store'; import { RootState } from '../../reduxstore/store';
import { loginUser } from '../../reduxstore/userDetailsslice';
const Login: React.FC = memo(() => { const Login: React.FC = memo(() => {
...@@ -18,12 +19,6 @@ const Login: React.FC = memo(() => { ...@@ -18,12 +19,6 @@ const Login: React.FC = memo(() => {
userId: "", userId: "",
password: "" password: ""
}) })
// const validateUserID=useCallback(()=>{
// },[values])
// useEffect(()=>{validateUserID()},[values])
useEffect(() => { useEffect(() => {
dispatch(fetchUsers()); dispatch(fetchUsers());
...@@ -35,8 +30,10 @@ const Login: React.FC = memo(() => { ...@@ -35,8 +30,10 @@ const Login: React.FC = memo(() => {
users.map((user)=>{ users.map((user)=>{
if(user.userId==values.userId.trim()){ if(user.userId==values.userId.trim()){
if(user.password==values.password.trim()){ if(user.password==values.password.trim()){
console.log(user.userId) // console.log(user)
navigate("/") dispatch(loginUser(user))
navigate("/products")
} }
else{ else{
setError(("UserId/Password is incorrect")) setError(("UserId/Password is incorrect"))
...@@ -56,7 +53,7 @@ const Login: React.FC = memo(() => { ...@@ -56,7 +53,7 @@ const Login: React.FC = memo(() => {
}; };
return ( return (
<div className='loginsignup'> <div className='loginsignup py-5'>
<div className='loginsignup-container'> <div className='loginsignup-container'>
<h1>Log In</h1> <h1>Log In</h1>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
...@@ -81,7 +78,7 @@ const Login: React.FC = memo(() => { ...@@ -81,7 +78,7 @@ const Login: React.FC = memo(() => {
<button type="submit" >Login</button> <button type="submit" >Login</button>
</form> </form>
<p className='loginsignup-login'> <p className='loginsignup-login'>
<span> <Link to="/forgot-password">Forgot Password</Link></span> <span>If new user please <Link to="/register">Register</Link></span>
</p> </p>
</div> </div>
......
...@@ -3,12 +3,12 @@ p, div { ...@@ -3,12 +3,12 @@ p, div {
} }
.wrapper { .wrapper {
height: 97vh; height: 100vh;
width: 100%; width: 100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
background-color: rgb(6, 150, 30); background-color:#fce3fe ;
} }
.form-wrapper { .form-wrapper {
......
import React, { memo, useState, useEffect, useCallback } from 'react'; import React, { memo, useState, useEffect, useCallback } from 'react';
import axios from 'axios'; import axios from 'axios';
import { useNavigate } from 'react-router-dom'; import { Link, useNavigate } from 'react-router-dom';
import './Register.css'; import './Register.css';
import { useSelector, useDispatch } from 'react-redux' import { useSelector, useDispatch } from 'react-redux'
import { fetchUsers } from '../../reduxstore/usersSlice'; import { fetchUsers } from '../../reduxstore/usersSlice';
...@@ -10,7 +10,7 @@ const Register = () => { ...@@ -10,7 +10,7 @@ const Register = () => {
const navigate = useNavigate() const navigate = useNavigate()
const dispatch = useDispatch() const dispatch = useDispatch()
const users = useSelector((state: RootState) => state.users.users) const users = useSelector((state: RootState) => state.users.users)
const [userErr, setUserErr] = useState<any|null>(null); const [userErr, setUserErr] = useState<any | null>(null);
const [enablesubmit, setEnablesubmit] = useState<boolean>(true); const [enablesubmit, setEnablesubmit] = useState<boolean>(true);
const [values, setValues] = useState<any>({ const [values, setValues] = useState<any>({
...@@ -27,7 +27,7 @@ const Register = () => { ...@@ -27,7 +27,7 @@ const Register = () => {
setValues({ ...values, [name]: value }) setValues({ ...values, [name]: value })
}; };
const validateUserID =useCallback( () => { const validateUserID = useCallback(() => {
let errors = { let errors = {
userIdErr: "", userIdErr: "",
fnameErr: "", fnameErr: "",
...@@ -38,49 +38,49 @@ const Register = () => { ...@@ -38,49 +38,49 @@ const Register = () => {
}; };
if (values.userId !== "" && values.userId.length < 5) { if (values.userId !== "" && values.userId.length < 5) {
errors.userIdErr= "UserId should have atleast 5 to 10 characters" errors.userIdErr = "UserId should have atleast 5 to 10 characters"
} }
if (values.userId !== "" && values.userId.length >= 5) { if (values.userId !== "" && values.userId.length >= 5) {
users.map((user) => { users.map((user) => {
if (user.userId == values.userId.trim()) { if (user.userId == values.userId.trim()) {
errors.userIdErr= "User ID is already taken" errors.userIdErr = "User ID is already taken"
} else { } else {
errors.userIdErr= "" errors.userIdErr = ""
} }
}) })
} }
if (values.fname != "" && values.fname.length <= 4) { if (values.fname != "" && values.fname.length <= 4) {
errors.fnameErr= "Name should be more than 4 characters" errors.fnameErr = "Name should be more than 4 characters"
}else { } else {
errors.fnameErr= "" errors.fnameErr = ""
} }
if (values.lname != "" && values.lname.length <= 4) { if (values.lname != "" && values.lname.length <= 4) {
errors.lnameErr= "Last Name should be more than 4 characters" errors.lnameErr = "Last Name should be more than 4 characters"
}else { } else {
errors.lnameErr= "" errors.lnameErr = ""
} }
if (values.email !== "") { if (values.email !== "") {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(values.email)) { if (!emailRegex.test(values.email)) {
errors.emailErr="Enter valid email address" errors.emailErr = "Enter valid email address"
} else { } else {
errors.emailErr="" errors.emailErr = ""
} }
} }
if (values.mobile !== "") { if (values.mobile !== "") {
const mobileRegex = /^\d{10}$/; const mobileRegex = /^\d{10}$/;
if (!mobileRegex.test(values.mobile)) { if (!mobileRegex.test(values.mobile)) {
errors.mobileErr= "Enter valid mobile number" errors.mobileErr = "Enter valid mobile number"
} else { } else {
errors.mobileErr= "" errors.mobileErr = ""
} }
} }
if (values.password !== "") { if (values.password !== "") {
const passwordRegex = /^(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{6,}$/; const passwordRegex = /^(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{6,}$/;
if (!passwordRegex.test(values.password)) { if (!passwordRegex.test(values.password)) {
errors.passwordErr= "Password >5 characters and one special character" errors.passwordErr = "Password >5 characters and one special character"
} else { } else {
errors.passwordErr= "" errors.passwordErr = ""
} }
} }
...@@ -97,17 +97,17 @@ const Register = () => { ...@@ -97,17 +97,17 @@ const Register = () => {
Object.values(errors).every(error => error === "") Object.values(errors).every(error => error === "")
) { ) {
setEnablesubmit(false); setEnablesubmit(false);
}else { } else {
setEnablesubmit(true); setEnablesubmit(true);
} }
setUserErr(errors); setUserErr(errors);
},[values]) }, [values])
useEffect(() => { useEffect(() => {
validateUserID(); validateUserID();
}, [values,validateUserID]); }, [values, validateUserID]);
const handleSubmit = async (e: any) => { const handleSubmit = async (e: any) => {
e.preventDefault() e.preventDefault()
...@@ -128,7 +128,6 @@ const Register = () => { ...@@ -128,7 +128,6 @@ const Register = () => {
<div className='form-wrapper'> <div className='form-wrapper'>
<h2>Registration Form</h2> <h2>Registration Form</h2>
<form onSubmit={handleSubmit} noValidate={true}> <form onSubmit={handleSubmit} noValidate={true}>
<table> <table>
<tbody> <tbody>
<tr> <tr>
...@@ -154,7 +153,7 @@ const Register = () => { ...@@ -154,7 +153,7 @@ const Register = () => {
<td><input value={values.lname} name='lname' onChange={handleChange} type='text' /></td> <td><input value={values.lname} name='lname' onChange={handleChange} type='text' /></td>
</tr> </tr>
{ {
userErr&& <tr> userErr && <tr>
<td colSpan={2} style={{ textAlign: "center", color: "red" }}><span>{userErr.lnameErr}</span></td> <td colSpan={2} style={{ textAlign: "center", color: "red" }}><span>{userErr.lnameErr}</span></td>
</tr> </tr>
} }
...@@ -186,12 +185,17 @@ const Register = () => { ...@@ -186,12 +185,17 @@ const Register = () => {
</tr> </tr>
} }
<tr> <tr>
<td colSpan={2} style={{textAlign:"center"}}><button type='submit' disabled={enablesubmit} style={enablesubmit ? { width: "100px",height:"30px", color: "black", fontWeight: "bolder", backgroundColor: "grey",borderRadius:"50%",boxShadow:"0px 0px 10px",marginTop:"10px"} : {color: "white", backgroundColor: "green",width: "100px",height:"30px",borderRadius:"50%",boxShadow:"0px 0px 20px black",marginTop:"10px" }}>Submit</button></td> <td colSpan={2} style={{ textAlign: "center" }}><button type='submit' disabled={enablesubmit} style={enablesubmit ? { width: "100px", height: "30px", color: "black", fontWeight: "bolder", backgroundColor: "grey", borderRadius: "10%", boxShadow: "0px 0px 10px", marginTop: "10px" } : { color: "white", backgroundColor: "green", width: "100px", height: "30px", borderRadius: "10%", boxShadow: "0px 0px 20px black", marginTop: "10px" }}>Submit</button></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</form> </form>
<div className='d-flex justify-content-end mt-3'>
<span>Already registered <Link to={"/login"}><button className='btn btn-warning'>Sign In</button></Link></span>
</div>
</div> </div>
</div> </div>
); );
}; };
......
import React, { memo } from 'react';
type ProductType = {
_id:string
id?: string
title: string
price: number
inStock: boolean
description: string
category:string
image:string
rating:{rate:number,count:number}
qty:number
}
type ProductPropsType = {
product: ProductType | null
}
const Product = memo((props: ProductPropsType) => {
console.log(props.product)
const {id,title,description,category,image,rating:{rate,count},qty,price}:ProductType= props.product!;
return (<div className='col-lg-4 col-md-2 col-sm-1 my-2' style={{width: "300px"}}>
<div className="card" >
<img src={image} className="img-fluid" style={{width:"100%",height:"200px"}} alt="..."/>
<div className="card-body" style={{width:"100%",height:"130px",overflowY: "scroll"}}>
<p className="card-title fw-bolder">Title: {title}</p>
<p className="card-text" style={{fontSize:"10px"}}><span className='fw-bold'>Description:</span><br/>{description}</p>
</div>
<ul className="list-group list-group-flush">
<li className="list-group-item"><span className='fw-bold'>Category : </span> {category}</li>
<li className="list-group-item">Rating :{rate}/5({count})</li>
<li className="list-group-item">Price :{price}</li>
</ul>
<div className="card-body">
<button className='btn btn-danger w-100'>Add To Cart</button>
</div>
</div>
</div>
);
});
export default Product;
\ No newline at end of file
import React, { memo, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux'
import { useNavigate } from 'react-router-dom';
import { RootState } from '../../reduxstore/store';
import { fetchProducts } from '../../reduxstore/productsSlice';
import Product from './Product';
const Products = memo(() => {
const navigate = useNavigate()
const dispatch=useDispatch()
const products = useSelector((state: RootState) => state.products);
const user = useSelector((state: RootState) => state.userDetails.userDetails)
console.log(products)
useEffect(() => {
if (user !== null) {
const isEmpty = Object.keys(user).length === 0 && user.constructor === Object;
if (isEmpty) {
navigate('/login');
} else {
dispatch(fetchProducts());
}
} else {
navigate('/login');
}
}, [user])
if (products.loading) { return <div className="text-center mt-5">Loading...</div> }
else if(products.error!=="") { return <h1>{products.error}</h1>}
else {
return (
<div className='row d-flex justify-content-evenly bg-dark'>
{
products.products && products.products.map((product) => <Product key={product.id} product={product} />)
}
</div>
);
}
});
export default Products;
\ No newline at end of file
...@@ -3,6 +3,8 @@ import ReactDOM from 'react-dom/client'; ...@@ -3,6 +3,8 @@ import ReactDOM from 'react-dom/client';
import './index.css'; import './index.css';
import App from './App'; import App from './App';
import reportWebVitals from './reportWebVitals'; import reportWebVitals from './reportWebVitals';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css'
import '../node_modules/bootstrap/dist/js/bootstrap.bundle'
const root = ReactDOM.createRoot( const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement document.getElementById('root') as HTMLElement
......
...@@ -2,17 +2,20 @@ import { configureStore } from '@reduxjs/toolkit' ...@@ -2,17 +2,20 @@ import { configureStore } from '@reduxjs/toolkit'
import cartReducer,{CartStateType} from './cartSlice' import cartReducer,{CartStateType} from './cartSlice'
import productsReducer,{ProductsStateType} from './productsSlice' import productsReducer,{ProductsStateType} from './productsSlice'
import usersReducer,{UsersStateType} from './usersSlice' import usersReducer,{UsersStateType} from './usersSlice'
import userDetailsslice,{UserDetailsType} from './userDetailsslice'
export type RootState= { export type RootState= {
products:ProductsStateType; products:ProductsStateType;
cart: CartStateType; cart: CartStateType;
users: UsersStateType; users: UsersStateType;
userDetails:UserDetailsType
} }
const store=configureStore({ const store=configureStore({
reducer:{ reducer:{
products:productsReducer, products:productsReducer,
cart: cartReducer, cart: cartReducer,
users: usersReducer users: usersReducer,
userDetails:userDetailsslice
}, },
}) })
......
import { createSlice } from "@reduxjs/toolkit" import { createSlice } from "@reduxjs/toolkit"
type UserDetailsType={ export type UserDetailsType={
userDetails:any[]|null userDetails:{}|null
} }
const initialState:UserDetailsType={ const initialState:UserDetailsType={
userDetails:[], userDetails:{},
} }
const userDetailsSlice=createSlice({ const userDetailsSlice=createSlice({
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment