Commit 4c3e5daf authored by Alex Segers's avatar Alex Segers

[AFP-97 & AFP-135] 🐛 🔧 Port config, bug fixes, pagination, & styles (@asegers)

parent b5faa8a4
REACT_APP_BACKEND_URL=http://localhost:8080
PORT=8090
REACT_APP_GOOGLE_CLIENT_ID=925243198137-hhe2e3ejlethf321hh7tbm7ontc19cpj.apps.googleusercontent.com
\ No newline at end of file
REACT_APP_BACKEND_URL=http://localhost:8084
PORT=8090
REACT_APP_GOOGLE_CLIENT_ID=925243198137-hhe2e3ejlethf321hh7tbm7ontc19cpj.apps.googleusercontent.com
\ No newline at end of file
This diff is collapsed.
......@@ -2,7 +2,6 @@
"name": "order-management-client",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:4",
"dependencies": {
"@chakra-ui/icons": "^1.0.13",
"@chakra-ui/react": "^1.6.0",
......@@ -25,6 +24,7 @@
"axios": "^0.21.1",
"bootstrap": "^4.6.0",
"framer-motion": "^4",
"http-proxy-middleware": "^2.0.0",
"moment": "^2.29.1",
"react": "^17.0.2",
"react-bootstrap": "^1.5.2",
......@@ -32,6 +32,7 @@
"react-dom": "^17.0.2",
"react-google-login": "^5.2.2",
"react-hook-form": "^7.4.0",
"react-infinite-scroll-hook": "^4.0.1",
"react-redux": "^7.2.4",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
......
declare module "ManagerRequests" {
export interface OrdersRequestBody {
pagination: OrdersReqBodyPagination
date: BodyDate
search: BodySearch
status: BodyStatus
}
export interface BodyPagination {
page: number
size: number
}
export enum BodyFilter {
ORDER_CREATED_AT = 'orderCreatedAt',
ORDER_UPDATED_AT = 'orderUpdatedAt'
}
export interface BodyDate {
start: number | null
end: number | null
filter?: BodyFilter | null
}
export enum BodySearchFields {
ID = 'id',
CUSTOMER_EMAIL_ADDRESS = 'customerEmailAddress',
ORDER_TRACKING_CODE = 'orderTrackingCode'
}
export interface BodySearch {
by: any // Fix
query?: string
}
export enum OrderStatus {
RECEIVED = 'received',
FULFILLED = 'fulfilled',
CANCELLED = 'cancelled'
}
export interface OrdersReqBodyStatus {
[OrderStatus.RECEIVED]: boolean
[OrderStatus.FULFILLED]: boolean
[OrderStatus.CANCELLED]: boolean
}
}
\ No newline at end of file
import { IconButton, useColorMode } from '@chakra-ui/react'
import { MoonIcon, SunIcon } from '@chakra-ui/icons'
const ColorModeToggle = () => {
const { colorMode, toggleColorMode } = useColorMode();
return <IconButton
icon={colorMode === 'light' ? <SunIcon/> : <MoonIcon/>}
variant="outline"
aria-label="Color mode switcher"
onClick={toggleColorMode}
/>
}
export default ColorModeToggle
import React from 'react'
import { Box, Heading, Flex, Spacer, Button, Image, Avatar, Text, Stack } from "@chakra-ui/react"
const Logo = () => {
return (
<Stack m={2} isInline>
<Text
ml={2}
textTransform="uppercase"
fontSize="lg"
fontWeight="bold"
variant="logo"
>
Order Management Console
</Text>
<Text
ml={2}
textTransform="uppercase"
fontSize="lg"
fontWeight="bold"
variant="logoSuffix"
>
Pro
</Text>
</Stack>
)
}
export default Logo
export { default as ColorModeToggle } from './ColorModeToggle'
export { default as Logo } from './Logo'
\ No newline at end of file
import React from 'react'
import { GoogleLogin } from 'react-google-login';
const Login = () => {
const storage = window.localStorage;
const loginSuccess = (response: any) => {
storage.setItem("tokenId", response.tokenId);
const apiUrl = "https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=" + response.tokenId
fetch(apiUrl).then((response) => response.json()).then((data) => {
console.log(data)
})
console.log("Log in succesful", storage);
}
const loginFailure = (response: any) => {
storage.setItem("loggedIn", "false")
console.log("Log in failed", storage);
}
return (
<GoogleLogin
clientId="925243198137-hhe2e3ejlethf321hh7tbm7ontc19cpj.apps.googleusercontent.com"
buttonText="Login"
onSuccess={loginSuccess}
onFailure={loginFailure}
cookiePolicy={'single_host_origin'}
/>
)
}
export default Login
import React from 'react'
import { useForm } from "react-hook-form";
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from "yup";
const schema = yup.object().shape({
firstName: yup.string().required(),
lastName: yup.string().required(),
email: yup.string().email().required(),
password: yup.string().required(),
});
export default function LoginForm() {
const { register, handleSubmit, watch, formState: { errors } } = useForm({
resolver: yupResolver(schema)
});
const onSubmit = (data: any) => console.log(data);
console.log(watch("example")); // watch input value by passing the name of it
return (
/* "handleSubmit" will validate your inputs before invoking "onSubmit" */
<form onSubmit={handleSubmit(onSubmit)}>
{/* register your input into the hook by invoking the "register" function */}
<input defaultValue="First name" {...register("firstName", { required: true })} />
{/* include validation with required or other standard HTML validation rules */}
<input defaultValue="Last name" {...register("lastName", { required: true })} />
<input defaultValue="Email" {...register("email", { required: true })} />
<input defaultValue="Password" {...register("password", { required: true })} />
{/* errors will return when field validation fails */}
{errors.password&& <span>This field is required</span>}
<input type="submit" />
</form>
);
}
import React from 'react'
import { GoogleLogout } from 'react-google-login';
const Logout = () => {
const storage = window.localStorage;
const logout = () => {
storage.clear();
storage.setItem("loggedIn", "false")
console.log("Log out complete", storage)
}
return (
<GoogleLogout
clientId="925243198137-hhe2e3ejlethf321hh7tbm7ontc19cpj.apps.googleusercontent.com"
buttonText="Logout"
onFailure={logout}
onLogoutSuccess={logout}
/>
)
}
export default Logout
import React, { useMemo} from 'react'
import { Link } from 'react-router-dom'
import { useGoogleAuth} from 'hooks'
import { Box, Heading, Flex, Spacer, Button, Image, Avatar } from "@chakra-ui/react"
// import Logo from '../img/logo.png'
import { Logo, ColorModeToggle } from 'atoms'
const Nav = () => {
const { isSignedIn, signOut, signIn, manager } = useGoogleAuth();
const handleAuth = () => { isSignedIn ? signOut() : signIn();}
const authLinkText = useMemo(() => isSignedIn ? "Logout" : "Login", [isSignedIn]);
const userIcon = isSignedIn && <Avatar
name={`${manager.firstName} ${manager.lastName}`}
boxSize="40px"
borderRadius="full"
src={manager.imageUrl}
alt="Profile icon"
/>
return (
<Flex>
<Logo/>
<ColorModeToggle/>
</Flex>
)
}
export default Nav
export {}
\ No newline at end of file
export {default} from './Navigation.component';
\ No newline at end of file
export {default as AccountForm} from './AccountForm'
export {default as LoginForm} from './LoginForm'
export {default as Nav} from './Nav'
export {default as Navigation} from './Navigation'
export {default as Footer} from './Footer'
export {default as OrderDetails} from './OrderDetails'
export {default as SignUpForm} from './SignUpForm'
export {default as OrderShowDetails} from './OrderShowDetails'
export {default as Login} from './Login'
export {default as Logout} from './Logout'
\ No newline at end of file
export {default as OrderShowDetails} from './OrderShowDetails'
\ No newline at end of file
export {default as useAllOrders} from './useAllOrders'
export * from './useGoogleAuth'
export {default as useOrder} from './useOrder'
\ No newline at end of file
export { default as useOrder } from './useOrder'
export { default as useOrders } from './useOrders'
\ No newline at end of file
......@@ -44,7 +44,6 @@ export const GoogleAuthProvider: FC = ({ children }) => {
setManager(managerData)
setAccessToken(token)
console.log(token)
ManagerService.authenticate(token)
.then(() => {
......
import { useState, useEffect, useMemo } from 'react'
import { OrderService } from 'services'
import { OrdersRequestBody } from 'ManagerRequests'
import { Order } from 'Order'
enum ResStatus {
IDLE = "IDLE",
FETCHING = "FETCHING",
SUCCESS = "SUCCESS",
ERROR = "ERROR"
}
const initialConstraints: OrdersRequestBody = {
pagination: { page: 0, size: 15},
date: { start: null, end: null, filter: null },
search: { by: 'orderTrackingCode', query: "" },
status: { received: false, fulfilled: false, cancelled: false }
}
const useOrders = (args : OrdersRequestBody = initialConstraints) => {
const [status, setStatus] = useState<ResStatus>(ResStatus.IDLE);
const [dataMap, setDataMap] = useState<{string: Order} | {}>({});
const [error, setError] = useState(null);
const [pagFilters, setPagFilters] = useState(args.pagination)
const [dateFilters, setDateFilters] = useState(args.date)
const [searchFilters, setSearchFilters] = useState(args.search)
const [statusFilters, setStatusFilters] = useState(args.status)
const buildDataMap = (ordersArr: Order[]) => {
const newDataMap: any = {}
for (const order of ordersArr)
newDataMap[order.id] = order;
return newDataMap
}
const fetchOrders = async (requestBody: OrdersRequestBody) => {
setStatus(ResStatus.FETCHING);
try {
const ordersData: Order[] = await OrderService.orders(requestBody)
setDataMap(prevData => ({ ...prevData, ...buildDataMap(ordersData) }));
setStatus(ResStatus.SUCCESS)
} catch (err) {
setError(err)
setStatus(ResStatus.ERROR);
}
};
useEffect(() => {
fetchOrders({
pagination: pagFilters,
date: dateFilters,
search: searchFilters,
status: statusFilters
});
}, [ pagFilters, dateFilters, searchFilters, statusFilters ]);
const orders: Order[] = useMemo(() => {
return Object.values(dataMap).sort((o1, o2) => o2.orderUpdatedAt - o1.orderUpdatedAt)
}, [dataMap])
return {
status,
orders,
error,
fetchOrders,
ResStatus,
pagFilters, setPagFilters,
dateFilters, setDateFilters,
searchFilters, setSearchFilters,
statusFilters, setStatusFilters
};
};
export default useOrders;
\ No newline at end of file
......@@ -134,7 +134,7 @@ body {
input[type=text] {
/* input[type=text] {
width: 220px;
border: 2px solid rgb(184, 180, 180);
border-radius: 4px;
......@@ -151,7 +151,7 @@ input[type=text] {
input[type=text]:focus {
width: 100%;
}
} */
.searchbar:focus {
......
......@@ -52,7 +52,6 @@ const OrderIndexPage = () => {
}, [searchInput, allOrders])
const handleChange = (e: any) => {
console.log(e.target.value)
setSearchInput(e.target.value)
}
......
import { useState } from 'react';
import ReactDatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
import './order-date-picker.css';
const OrderDatePicker = ({ dateFilters, setDateFilters }: any) => {
const today = new Date()
const thirtyDaysAgo = new Date().setDate(today.getDate() - 30)
const [startDate, setStartDate] = useState<any>(thirtyDaysAgo)
const [endDate, setEndDate] = useState<any>(today)
// const [inputErr, setInputError] = useState<null | string>(null)
const handleStartChange = (newDate: any) => {
if (newDate < endDate) {
setDateFilters((prev: any) => ({ ...prev, end: endDate.getTime(), start: newDate.getTime() }))
setStartDate(newDate)
}
}
const handleEndChange = (newDate: any) => {
if (newDate > startDate && newDate < (today.getDate() + 1)) {
setDateFilters((prev: any) => ({ ...prev, start: startDate.getTime(), end: newDate.getTime() }))
setEndDate(newDate)
}
}
return (
<>
<ReactDatePicker
selected={startDate}
name="start"
onChange={handleStartChange}
selectsStart
startDate={startDate}
endDate={endDate}
/>
<ReactDatePicker
selected={endDate}
name="start"
onChange={handleEndChange}
selectsEnd
startDate={startDate}
endDate={endDate}
minDate={startDate}
/>
</>
);
}
export default OrderDatePicker
\ No newline at end of file
import React, { useState, useEffect } from 'react'
import {
Input,
InputGroup,
InputLeftElement, InputRightElement,
InputRightAddon,
Select,
Spinner
} from '@chakra-ui/react'
import { CheckIcon } from '@chakra-ui/icons'
// import { debounce } from 'utils'
const OrderSearchBar = ({ searchFilters, setSearchFilters, status, STATUSES } : any) => {
const [searchQuery, setSearchQuery] = useState("")
const [searchBy, setSearchBy] = useState(searchFilters.by)
const handleInputChange = (e: any) => {
const { currentTarget: { value } } = e
const trimmedValue = value.trim().toLowerCase()
if (trimmedValue.length) {
setSearchFilters({by: searchBy, query: trimmedValue });
}
setSearchQuery(value)
}
const handleSelectChange = (e: any) => {
const { currentTarget: { value } } = e
setSearchBy(value)
}
const boolToBin = (value: any) => Boolean(value) ? 1 : 0
return (
<>
<InputGroup>
<InputLeftElement
pointerEvents="none"
children={<Spinner size="xs" color="gray.300" opacity={boolToBin(status == STATUSES.FETCHING)} />}
/>
<Input
placeholder="Search ..."
// variant="filled"
// focusBorderColor="telegram.400"
value={searchQuery}
onChange={handleInputChange}
onKeyDown={handleInputChange}
/>
<InputRightElement children={<CheckIcon color="green.500" />} />
</InputGroup>
<Select maxWidth="10rem" defaultValue="id" onChange={handleSelectChange}>
<option value="id">Order #</option>
<option value="customerEmailAddress">Email</option>
<option value="orderTrackingCode">Tracking #</option>
</Select>
</>
)
}
export default OrderSearchBar
\ No newline at end of file
import { useState } from 'react'
import {
Tag,
Text,
Button,
Menu, MenuButton, MenuList, MenuItem, MenuOptionGroup, MenuItemOption, MenuDivider,
Checkbox,
} from '@chakra-ui/react'
import { ChevronDownIcon } from '@chakra-ui/icons'
import { tagColorMap } from './index'
const OrderStatusMenu = ({ statusFilters, setStatusFilters }: any) => {
const statusesArr = Object.entries(statusFilters);
const [isAllSelected, setAllSelected] = useState(false)
const [values, setValues] = useState<string[]>([])
const filterSetterAll = () => ({received: true, cancelled: true, fulfilled: true})
const filterInArr = (selected: string[]) => {
const pojo = filterSetterAll()
for (const key in pojo) {
if(!selected.includes(key)){
// @ts-ignore
pojo[key] = false;
}
}
return pojo
}
const handleCheckboxGroup = (checkboxes: any) => {
if (checkboxes.includes("all")) {
setAllSelected(true)
setValues(['all', ...Object.keys(statusFilters)])
setStatusFilters(filterSetterAll())
} else {
setAllSelected(false)
setValues(checkboxes)
setStatusFilters(filterInArr(checkboxes))
}
}
return (
<Menu>
<MenuButton
as={Button}
rightIcon={<ChevronDownIcon />}
>
Status
</MenuButton>
<MenuList>
<MenuOptionGroup
title="Status"
type="checkbox"
textTransform="uppercase"
value={values}
onChange={handleCheckboxGroup}
>
<MenuItemOption
textTransform="uppercase"
value="all"
>All</MenuItemOption>
<MenuDivider />
{statusesArr.map(([statusText, isChecked]) => (
<MenuItemOption
isDisabled={isAllSelected}
key={statusText}
value={statusText}
textTransform="uppercase"
>
<Tag colorScheme={tagColorMap.get(statusText.toUpperCase())}>{statusText}</Tag>
</MenuItemOption>
))}
</MenuOptionGroup>
</MenuList>
</Menu>
)
}
export default OrderStatusMenu
\ No newline at end of file
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react'
import {
Table, Thead, Th, Tbody, Tr, Td,
Heading,
Text,
Stack,
Skeleton,
Box,
Tag,
VisuallyHidden
} from '@chakra-ui/react'
// import { ChevronDownIcon } from '@chakra-ui/icons'
import moment from 'moment'
import { Order } from 'Order';
import { useOrders } from 'hooks';
import { OrderDatePicker, OrderSearchBar, OrderStatusMenu, tagColorMap } from './index'
const OrderRow = ({
order: {
id,
orderTrackingCode,
orderStatus,
orderCreatedAt, orderUpdatedAt,
customerEmailAddress,
orderItems
}
}: { order: Order }) => {
// const parseDate = (unixDate: number) => new Date(unixDate).toLocaleDateString()
return (
<Tr>
<Td fontSize="sm" fontWeight="semibold">{id}</Td>
<Td><Tag colorScheme={tagColorMap.get(orderStatus)}>{orderStatus}</Tag></Td>
<Td fontSize="sm" paddingX={10}>{orderItems.length} item{orderItems.length > 1 && "s"}</Td>
<Td fontSize="sm">{customerEmailAddress}</Td>
<Td fontSize="small">{moment(orderUpdatedAt).calendar()}</Td>
<Td fontSize="small">{moment(orderCreatedAt).calendar()}</Td>
<Td fontSize="smaller">{orderTrackingCode}</Td>
</Tr>
)
}
const OrdersPage = () => {
const {
status,
orders,
error,
ResStatus,
pagFilters, setPagFilters,
dateFilters, setDateFilters,
searchFilters, setSearchFilters,
statusFilters, setStatusFilters
} = useOrders()
const tableHeaders = ['Order #', 'Status', 'Item Count', 'Customer email', 'Updated at', 'Created at', 'Tracking #']
const isLoading = useMemo(() => status === ResStatus.FETCHING, [status])
const $loader = useRef<any>();
const handleObserver = (entities: any) => {
const target = entities[0];
if (target.isIntersecting && !isLoading) {
setPagFilters((prev: any) => ({...prev, page: prev.page + 1}))
}
}
useEffect(() => {
var options = {
root: null,
rootMargin: "20px",
threshold: 1.0
};
// initialize IntersectionObserver
// and attaching to Load More div
const observer = new IntersectionObserver(handleObserver, options);
if ($loader.current) {
observer.observe($loader.current)
}
}, []);
return (
<div>
<div>
<Heading>Orders</Heading>
<Stack p={2} isInline>
<OrderSearchBar
searchFilters={searchFilters}
setSearchFilters={setSearchFilters}
status={status}
STATUSES={ResStatus}
/>
<OrderDatePicker
dateFilters={dateFilters}
setDateFilters={setDateFilters}
/>
<OrderStatusMenu
statusFilters={statusFilters}
setStatusFilters={setStatusFilters}
/>
</Stack>
</div>
<div>
<Table variant="striped">
<Thead>
<Tr>
{tableHeaders.map((headerText, idx) => (
<Th key={idx}>
<Text>{headerText}</Text>
</Th>
))}
</Tr>
</Thead>
<Tbody >
{orders.map(order => <OrderRow
key={order.id}
order={order}
/>)}
</Tbody>
<span ref={$loader}></span>
</Table>
</div>
</div>
)
}
export default OrdersPage
\ No newline at end of file
export { default as OrderDatePicker } from './OrderDatePicker.component'
export { default as OrderSearchBar } from './OrderSearchBar.component'
export { default } from './OrdersPage.component'
export { default as OrderStatusMenu } from './OrderStatusMenu.component'
export const tagColorMap = new Map([[`RECEIVED`, 'orange'], [`CANCELLED`, 'red'], [`FULFILLED`, 'green']])
\ No newline at end of file
.react-datepicker {
font-family: unset;
font-size: 0.9rem;
}
.react-datepicker-wrapper,
.react-datepicker__input-container {
display: block;
}
.react-datepicker__input-container {
font-size: 1rem;
padding-left: 1rem;
padding-right: 1rem;
height: 2.5rem;
border-radius: 0.25rem;
border: 1px solid;
border-color: hsl(0,0%,80%);
}
.react-datepicker__input-container:hover {
border-color: hsl(0,0%,70%);
}
.react-datepicker__input-container:focus-within {
z-index: 1;
border-color: #3182ce;
box-shadow: 0 0 0 1px #3182ce;
}
.react-datepicker__input-container > input {
width: 100%;
height: 100%;
outline: 0;
background-color: transparent;
}
.react-datepicker__navigation--next--with-time:not(.react-datepicker__navigation--next--with-today-button) {
right: 90px;
}
.react-datepicker__navigation--previous,
.react-datepicker__navigation--next {
height: 8px;
}
.react-datepicker__navigation--previous {
border-right-color: #cbd5e0;
}
.react-datepicker__navigation--previous:hover {
border-right-color: #a0aec0;
}
.react-datepicker__navigation--next {
border-left-color: #cbd5e0;
}
.react-datepicker__navigation--next:hover {
border-left-color: #a0aec0;
}
.react-datepicker__header {
background: #f7fafc;
}
.react-datepicker__header,
.react-datepicker__time-container {
border-color: #E2E8F0;
}
.react-datepicker__current-month,
.react-datepicker-time__header,
.react-datepicker-year-header {
font-size: inherit;
font-weight: 600;
}
.react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item {
margin: 0 1px 0 0;
height: auto;
padding: 7px 10px;
}
.react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item:hover {
background: #edf2f7;
}
.react-datepicker__day:hover {
background: #edf2f7;
}
.react-datepicker__day--selected,
.react-datepicker__day--in-selecting-range,
.react-datepicker__day--in-range,
.react-datepicker__month-text--selected,
.react-datepicker__month-text--in-selecting-range,
.react-datepicker__month-text--in-range,
.react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item--selected {
background: #3182ce;
font-weight: normal;
}
.react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item--selected:hover {
background: #2a69ac;
}
.react-datepicker__close-icon::after {
background-color: unset;
border-radius: unset;
font-size: 1.5rem;
font-weight: bold;
color: hsl(0,0%,80%);
height: 20px;
width: 20px;
}
.react-datepicker__close-icon::after:hover {
color: hsl(0,0%,70%)
}
\ No newline at end of file
......@@ -3,3 +3,4 @@ export { default as AuthPage } from './AuthPage'
export { default as HomePage } from './HomePage'
export { default as OrderIndexPage } from './OrderIndexPage'
export { default as OrderShowPage } from './OrderShowPage'
export { default as OrdersPage } from './OrdersPage'
import { BrowserRouter, Switch } from "react-router-dom";
import { Nav, Footer } from 'components'
import { AccountPage, HomePage, OrderIndexPage, OrderShowPage } from 'pages';
import { Nav } from 'components'
import { AccountPage, HomePage, OrderShowPage, OrdersPage } from 'pages';
import { GoogleAuthProvider } from 'hooks'
import { PublicRoute, PrivateRoute } from 'router'
import { StyleProvider } from 'styles'
......@@ -18,11 +18,9 @@ const MainRouter: React.FC = () => {
<PrivateRoute path="/account" component={AccountPage} />
<PublicRoute exact path="/" component={HomePage} />
<PrivateRoute path="/orders/:id" component={OrderShowPage} />
<PrivateRoute path="/orders" component={OrderIndexPage} />
{/* <Route component={NotFoundPage} /> */}
<PrivateRoute path="/orders" component={OrdersPage} />
</Switch>
</main>
<Footer />
</body>
</GoogleAuthProvider>
</BrowserRouter>
......
......@@ -2,14 +2,20 @@ import { Manager } from 'Manager'
import { tokenStorage } from 'utils'
import Axios, { AxiosError } from 'axios'
const BASE_PATH = '/api/managers'
const URL = (process.env.REACT_APP_BACKEND_URL as string)
const BASE_PATH = `${URL}/api/managers`
export const authenticate = async (token: string): Promise<Manager> => {
try {
const { data } = await Axios.post(
`${BASE_PATH}/auth`,
{}, // Empty body
{ headers: { Authorization: `Bearer ${token}` } }
{
headers: {
Authorization: `Bearer ${token}`
}
}
)
return data;
} catch (error) {
......
import orderList from './mock-order-data'
import { Order } from 'Order';
import { OrdersRequestBody } from 'ManagerRequests'
import Axios, { AxiosError } from 'axios'
import { sleep } from 'utils'
const BASE_PATH = '/api/orders'
const URL = (process.env.REACT_APP_BACKEND_URL as string)
const BASE_PATH = `${URL}/api/orders`
export const allOrders = () => {
const apiUrl = 'http://localhost:8084/api/orders';
return fetch(apiUrl).then((response) => response.json())
return fetch(`${BASE_PATH}/`).then((response) => response.json())
}
export const orderById = (apiUrl: string) => {
......@@ -16,15 +17,12 @@ export const orderById = (apiUrl: string) => {
export const orders = async (body: OrdersRequestBody): Promise<Order[]> => {
try {
console.log(JSON.stringify(body, null, 3))
debugger
await sleep(1000)
await sleep(1200)
const response = await Axios.post(`${BASE_PATH}/filtered`, body)
console.log(response.data)
return response.data;
} catch (error) {
const { response } = error as AxiosError;
console.error('`OrderService#orders` FAILED TO FETCH ORDERS: ', response)
error as AxiosError;
console.error('`OrderService#orders` FAILED TO FETCH ORDERS: ', error)
return [];
}
}
......
const { createProxyMiddleware } = require('http-proxy-middleware');
const PORT = process.env.PORT
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: `http://localhost:${PORT}`,
changeOrigin: true,
})
);
app.listen(PORT);
};
\ No newline at end of file
import { ChakraProvider } from "@chakra-ui/react"
import theme from './theme';
import { extendTheme } from "@chakra-ui/react"
// 2. Extend the theme to include custom colors, fonts, etc
const colors = {
brand: {
900: "#1a365d",
800: "#153e75",
700: "#2a69ac",
},
}
const theme = extendTheme({ colors })
const THEME = extendTheme(theme)
const StyleProvider: React.FC = ({ children }) => {
return (
<ChakraProvider theme={theme}>
<ChakraProvider resetCSS theme={THEME}>
{ children }
</ChakraProvider>
)
......
export {default as StyleProvider} from './StyleProvider'
\ No newline at end of file
export {default as StyleProvider} from './StyleProvider'
export {default as theme} from './theme'
\ No newline at end of file
const theme = {
colors: {
brand: {
900: "#1a365d",
800: "#153e75",
700: "#2a69ac",
}
},
config: {
// initialColorMode: "dark",
useSystemColorMode: true,
}
}
export default theme;
\ No newline at end of file
export { default as tokenStorage } from "./tokenStorage"
\ No newline at end of file
export { default as tokenStorage } from "./tokenStorage"
export { default as sleep } from "./sleep"
\ No newline at end of file
const sleep = (duration: number, reject = false) =>
new Promise<void>((res, rej) =>{
setTimeout(()=> {
reject ? rej() : res();
}, duration)
})
export default sleep;
\ No newline at end of file
This diff is collapsed.
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