incorporating basic logic for viewing distinct products

This commit is contained in:
2022-06-01 16:13:05 -05:00
parent 8cc4365ffe
commit f753e9e2dc
10 changed files with 130 additions and 45 deletions

View File

@@ -1,11 +1,17 @@
export default function ProductCard() {
export default function ProductCard({ productData }: any) {
const { name, category, description, price, id } = productData;
return (
<div className="card product-card">
<div className="photo"></div>
<h1>Product name</h1>
<p>$4.99</p>
<p>This is a mini description of the product</p>
<button>Add to Cart</button>
<div className="card product-card" key={`product-id-${id}`}>
<div className="product-photo"></div>
<h1>{name}</h1>
<p>Category: {category}</p>
<p>{description}</p>
<p>Price: {`$${price}` || "Free, apparently!"}</p>
<div className="product-options">
<button>More info</button>
<button>Add to Cart</button>
</div>
</div>
)
}

View File

@@ -1,14 +1,47 @@
import Page from "../../util/Page";
import ProductCard from "./ProductCard";
import { getAllProducts } from '../../util/apiUtils';
import { useState, useEffect } from "react";
type ProductResponse = {
category: string,
category_id?: number,
description: string,
id: number,
inventory: number,
minidescription?: string,
name: string,
price: string
}
function Products() {
const [productData, setProductData] = useState([]);
const [productFeed, setProductFeed] = useState<Array<JSX.Element>>([]);
useEffect(() => {
getAllProducts().then(res => setProductData(res));
}, [])
useEffect(() => {
if (!productData) return;
console.log(productData);
let results = productData.map((each: ProductResponse) => {
return <ProductCard key={each.id} productData={each} />
});
setProductFeed(results);
}, [productData]);
return (
<Page>
<h1>Found 2 products</h1>
<h1>Found {productFeed.length} products</h1>
<div className="filter-results">
</div>
<div className="products-results">
<ProductCard/>
<ProductCard/>
{ productFeed || <p>Loading...</p> }
</div>
</Page>
)

View File

@@ -16,7 +16,6 @@ function LoginForm() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [showPass, setShowPass] = useState(PassVisible.hide);
const [toDispatch, setToDispatch] = useState<userInfo>();
const displaySession = async () => {
if (username === '' || password === '') return;
@@ -27,21 +26,18 @@ function LoginForm() {
if (json) {
const { session, userProfile } = json;
let thisUser: userInfo = {
firstName: userProfile.first_name,
lastName: userProfile.last_name,
id: userProfile.id,
email: userProfile.email,
password: userProfile.password,
headers: session
}
setToDispatch(thisUser);
dispatch({ type: ActionType.USERLOGIN, payload: thisUser });
}
}
useEffect(() => {
if (!toDispatch) return;
dispatch({ type: ActionType.USERLOGIN, payload: toDispatch });
}, [toDispatch]);
return (
<Page classes="login light-page">
<h1>Welcome back to my store!</h1>

View File

@@ -1,7 +1,8 @@
import { useEffect, useState } from "react";
import { emptySessionHeader } from "../../store/store_types";
import { useEffect, useReducer, useState } from "react";
import { initialState, reducer } from "../../store/store";
import { ActionType, emptySessionHeader } from "../../store/store_types";
import { userInfo } from '../../types/main';
import { registerNewUser } from "../../util/apiUtils";
import { handleLogin, registerNewUser, unwrapLogin } from "../../util/apiUtils";
import Page from "../../util/Page";
function Register() {
@@ -15,6 +16,7 @@ function Register() {
headers: emptySessionHeader
}
const [state, dispatch] = useReducer(reducer, initialState);
const [userInput, setUserInput] = useState(formInitialState);
const [warningText, setWarningText] = useState('initial');
@@ -50,9 +52,15 @@ function Register() {
// allows registration submission if warning text has correct value and userData is defined with all required values
const handleRegistration = async () => {
if (userInput === formInitialState) return;
warningText === "Conditions met!" && await registerNewUser(userInput);
if (warningText !== "Conditions met!") return;
let register = await registerNewUser(userInput);
setUserInput(formInitialState);
if (register.ok) {
setUserInput(formInitialState);
} else {
console.log('Something went wrong');
}
}
return (
@@ -73,7 +81,7 @@ function Register() {
<div className="form-row">
<label htmlFor="email-register">Email address:</label>
<input type="email" id="email-register" value={userInput.email} onChange={(e) => setUserInput({...userInput, email: e.target.value})}/>
<input required type="email" id="email-register" value={userInput.email} onChange={(e) => setUserInput({...userInput, email: e.target.value})}/>
</div>
<p style={(warningText === 'initial') ? {display: 'none'} : {display: 'block'}}>{warningText}</p>
@@ -82,13 +90,13 @@ function Register() {
<label htmlFor="password-register" style={(warningText && warningText !== 'Conditions met!') ? {color: 'red'} : {color: 'green'}}>
Password:
</label>
<input type="password" id="password-register" value={userInput.password} onChange={(e) => setUserInput({...userInput, password: e.target.value})}/>
<input required type="password" id="password-register" value={userInput.password} onChange={(e) => setUserInput({...userInput, password: e.target.value})}/>
</div>
<div className="form-row">
<label htmlFor="password-verify" style={(warningText && warningText !== 'Conditions met!') ? {color: 'red'} : {color: 'green'}}>
Re-enter password:
</label>
<input type="password" id="password-verify" value={userInput.verifyPassword} onChange={(e) => setUserInput({...userInput, verifyPassword: e.target.value})}/>
<input required type="password" id="password-verify" value={userInput.verifyPassword} onChange={(e) => setUserInput({...userInput, verifyPassword: e.target.value})}/>
</div>
</form>

View File

@@ -1,5 +1,4 @@
import { useContext, useEffect } from "react"
import { useNavigate } from "react-router-dom";
import { useContext } from "react"
import { AppContext } from "../../store/store"
import Page from "../../util/Page";
@@ -7,18 +6,10 @@ import Page from "../../util/Page";
export default function UserProfile(profile: any): JSX.Element {
const [state, dispatch] = useContext(AppContext);
const navigate = useNavigate();
// useEffect(() => {
// if (!state.user.headers.authenticated) {
// console.log('bad');
// }
// }, []);
return (
<Page>
if (state.user) return (
<Page classes="light-page">
<h1>User Profile</h1>
<h2>Thanks for supporting us{`, ${state.user.name}!` || '!'}</h2>
<h2>Thanks for supporting us{`, ${state.user.firstName}!` || '!'}</h2>
<h2>{state.user.id || 'Profile not found'}</h2>
<h3>{state.user.email}</h3>
@@ -29,5 +20,7 @@ export default function UserProfile(profile: any): JSX.Element {
<button>Profile Settings</button>
</div>
</Page>
)
);
return (<></>)
}

View File

@@ -19,15 +19,11 @@ export const reducer = (state: appState, action: userAction) => {
case ActionType.UPDATEONE:
return state;
case ActionType.SEARCH:
console.log(payload);
return {
...state,
searchTerm: payload
}
case ActionType.USERLOGIN:
console.log(payload);
return {
...state,
user: payload

View File

@@ -3,6 +3,7 @@ import { userInfo, Cart } from '../types/main';
// type definitions for reducer
export enum ActionType {
GETALL,
GETPROFILE,
GETCATEGORY,
REGISTERNEW,
UPDATEONE,

View File

@@ -24,6 +24,7 @@ export const registerNewUser = async (user: userInfo) => {
});
if (serverCall.ok) console.log('User added successfully.');
return serverCall;
}
export const handleLogin = async (email: string, password: string) => {
@@ -37,3 +38,21 @@ export const handleLogin = async (email: string, password: string) => {
return serverCall;
}
export const unwrapLogin = async (email: string, password: string) => {
const response = await handleLogin(email, password);
const { session, userProfile } = await response.json();
return { session, userProfile };
}
export const getAllProducts = async () => {
let serverCall = await fetch('http://localhost:8088/products', {
method: "GET",
headers: {
"Content-Type": "application/json"
}
}).then(res => res.json());
return serverCall;
}

31
package-lock.json generated
View File

@@ -19,7 +19,11 @@
"oauth2-server": "^3.1.1",
"passport": "^0.6.0",
"passport-local": "^1.0.0",
"pg": "^8.7.3"
"pg": "^8.7.3",
"uuid": "^8.3.2"
},
"devDependencies": {
"@types/uuid": "^8.3.4"
}
},
"node_modules/@mapbox/node-pre-gyp": {
@@ -41,6 +45,12 @@
"node-pre-gyp": "bin/node-pre-gyp"
}
},
"node_modules/@types/uuid": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
"dev": true
},
"node_modules/abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@@ -1581,6 +1591,14 @@
"node": ">= 0.4.0"
}
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -1647,6 +1665,12 @@
"tar": "^6.1.11"
}
},
"@types/uuid": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
"dev": true
},
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@@ -2804,6 +2828,11 @@
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",

View File

@@ -20,6 +20,10 @@
"oauth2-server": "^3.1.1",
"passport": "^0.6.0",
"passport-local": "^1.0.0",
"pg": "^8.7.3"
"pg": "^8.7.3",
"uuid": "^8.3.2"
},
"devDependencies": {
"@types/uuid": "^8.3.4"
}
}