feat: implement shopping cart
This commit is contained in:
parent
cb6cc845e5
commit
0e10083372
|
@ -19,6 +19,7 @@
|
|||
"@testing-library/user-event": "14.4.3",
|
||||
"@types/node": "18.15.5",
|
||||
"@types/react": "18.0.30",
|
||||
"axios": "^1.6.7",
|
||||
"babel-plugin-styled-components": "2.0.7",
|
||||
"electron-context-menu": "3.3.0",
|
||||
"electron-is-dev": "2.0.0",
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import axios, { AxiosError } from 'axios';
|
||||
|
||||
export const API_BASE = 'https://api.chec.io/v1';
|
||||
|
||||
const api = axios.create({
|
||||
baseURL: API_BASE,
|
||||
});
|
||||
|
||||
api.interceptors.request.use(
|
||||
async (config) => {
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
api.interceptors.response.use(
|
||||
(response) => {
|
||||
return response;
|
||||
},
|
||||
async (error) => {
|
||||
if (error.response?.status === 401) {
|
||||
try {
|
||||
console.log('error.response', error.response);
|
||||
} catch (e) {
|
||||
console.log('error', e);
|
||||
}
|
||||
}
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
export { api };
|
|
@ -0,0 +1,110 @@
|
|||
const token = 'sk_test_56290c1603cc68a61b59eb003647fdb91940a2cdc5b31';
|
||||
|
||||
export async function createCart() {
|
||||
try {
|
||||
const url = new URL(`https://api.chec.io/v1/carts`);
|
||||
|
||||
const headers = {
|
||||
'X-Authorization': token,
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: headers,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCart(cartId) {
|
||||
try {
|
||||
const url = new URL(`https://api.chec.io/v1/carts/${cartId}`);
|
||||
|
||||
const headers = {
|
||||
'X-Authorization': token,
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: headers,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function addItemToCart(cartId, body) {
|
||||
try {
|
||||
const url = new URL(`https://api.chec.io/v1/carts/${cartId}`);
|
||||
|
||||
const headers = {
|
||||
'X-Authorization': token,
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: headers,
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeItemFromCart(cartId, line_item_id) {
|
||||
try {
|
||||
const url = new URL(`https://api.chec.io/v1/carts/${cartId}/items/${line_item_id}`);
|
||||
|
||||
const headers = {
|
||||
'X-Authorization': token,
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'DELETE',
|
||||
headers: headers,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,8 @@ import { TEMP_PRODUCTS_DATA } from './Shop';
|
|||
import Categories from '../Shop/Categories';
|
||||
import FooterSection from '../FooterSection';
|
||||
import SidebarMenu from '../SidebarMenu';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { createCart, addItemToCart } from '../../common/shop/cart';
|
||||
|
||||
const Image = styled.img`
|
||||
max-width: unset !important;
|
||||
|
@ -14,8 +16,31 @@ const Image = styled.img`
|
|||
`;
|
||||
|
||||
const ProductItem = () => {
|
||||
const { id } = useParams();
|
||||
const { name, price, src, description } = TEMP_PRODUCTS_DATA.find((product) => String(product.id) === String(id));
|
||||
const { id: productId } = useParams();
|
||||
const { name, price, src, description } = TEMP_PRODUCTS_DATA.find((product) => String(product.id) === String(productId));
|
||||
const [cartId, setCartId] = useState('');
|
||||
const [quantity, setQuantity] = useState(1);
|
||||
|
||||
useEffect(() => {
|
||||
const getCartId = async () => {
|
||||
const cart = await createCart();
|
||||
setCartId(cart?.id);
|
||||
};
|
||||
getCartId();
|
||||
}, []);
|
||||
|
||||
const handlePurchase = async () => {
|
||||
await addItemToCart(cartId, {
|
||||
id: 'prod_8XO3wp77QNlYAz',
|
||||
quantity: quantity,
|
||||
});
|
||||
|
||||
alert('Item added to cart');
|
||||
};
|
||||
|
||||
const handleQuantityChange = (e) => {
|
||||
setQuantity(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -37,7 +62,7 @@ const ProductItem = () => {
|
|||
<br />
|
||||
<Categories />
|
||||
<BoardsBox>
|
||||
<div className='board' key={id}>
|
||||
<div className='board' key={productId}>
|
||||
<div className='boxbar'>
|
||||
<h2>{name}</h2>
|
||||
</div>
|
||||
|
@ -49,12 +74,12 @@ const ProductItem = () => {
|
|||
<br />
|
||||
<div>
|
||||
<p>Quantity:</p>
|
||||
<input type='number' placeholder='Quantity' defaultValue={1} style={{ width: '50px' }} />
|
||||
<input type='number' placeholder='Quantity' defaultValue={1} style={{ width: '50px' }} onChange={handleQuantityChange} />
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
<div>
|
||||
<button>Buy</button>
|
||||
<button onClick={handlePurchase}>Buy</button>
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { Header, Logo, AboutContent } from '../styled/views/Home.styled';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
@ -7,9 +7,14 @@ import { useNavigate } from 'react-router-dom';
|
|||
const SignInAuth = () => {
|
||||
const { id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const loaded = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!id) return;
|
||||
|
||||
if (!loaded.current) {
|
||||
loaded.current = true;
|
||||
|
||||
const getUser = async () => {
|
||||
try {
|
||||
const url = new URL('https://api.chec.io/v1/customers/exchange-token');
|
||||
|
@ -28,8 +33,7 @@ const SignInAuth = () => {
|
|||
|
||||
const { customer_id, jwt } = response;
|
||||
|
||||
console.log('customer_id', customer_id);
|
||||
console.log('jwt', jwt);
|
||||
localStorage.setItem('login_token', id);
|
||||
localStorage.setItem('customer_id', customer_id);
|
||||
localStorage.setItem('jwt', jwt);
|
||||
|
||||
|
@ -39,7 +43,8 @@ const SignInAuth = () => {
|
|||
}
|
||||
};
|
||||
getUser();
|
||||
}, [id]);
|
||||
}
|
||||
}, [id, loaded]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
16
yarn.lock
16
yarn.lock
|
@ -4616,6 +4616,15 @@ axios@^0.27.2:
|
|||
follow-redirects "^1.14.9"
|
||||
form-data "^4.0.0"
|
||||
|
||||
axios@^1.6.7:
|
||||
version "1.6.7"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.7.tgz#7b48c2e27c96f9c68a2f8f31e2ab19f59b06b0a7"
|
||||
integrity sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==
|
||||
dependencies:
|
||||
follow-redirects "^1.15.4"
|
||||
form-data "^4.0.0"
|
||||
proxy-from-env "^1.1.0"
|
||||
|
||||
axobject-query@^3.1.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.2.1.tgz#39c378a6e3b06ca679f29138151e45b2b32da62a"
|
||||
|
@ -8053,7 +8062,7 @@ follow-redirects@^1.0.0, follow-redirects@^1.14.9:
|
|||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
|
||||
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
|
||||
|
||||
follow-redirects@^1.14.0:
|
||||
follow-redirects@^1.14.0, follow-redirects@^1.15.4:
|
||||
version "1.15.5"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020"
|
||||
integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==
|
||||
|
@ -13213,6 +13222,11 @@ proxy-addr@~2.0.7:
|
|||
forwarded "0.2.0"
|
||||
ipaddr.js "1.9.1"
|
||||
|
||||
proxy-from-env@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||
|
||||
psl@^1.1.33:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
|
||||
|
|
Loading…
Reference in New Issue