Skip to content

Commit

Permalink
add front
Browse files Browse the repository at this point in the history
  • Loading branch information
Facundo De Lorenzo committed May 17, 2024
1 parent d2e4f12 commit 3929638
Show file tree
Hide file tree
Showing 18 changed files with 1,105 additions and 53 deletions.
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,17 @@ To debug locally front & api altogether you will need to install concurrently
npm install -g concurrently
```

to invoke use the *pnpm script* or the debug & run vscode function: *Debug challenge!*
and build the api (it uses bash comamnds such as rm -rf and cp)
```
pnpm build:api
```

then, to invoke use the *pnpm script* or the debug & run vscode function: *Debug challenge!*
```
pnpm dev:frontapi
```
```

So as to be able to run the API you must first get the AWS SAM CLI because it's a Serverless API achieved through AWS API Gateway.

Get the lates version of AWS SAM CLI from here
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html
45 changes: 36 additions & 9 deletions packages/api/src/products.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,46 @@ exports.get = async (
callback: Callback,
) => {
try {
const products: Product[] = [
{ name: 'Kuva Roast Rib Eye', price: 418 },
{ name: 'Guadalupe Half Rack', price: 298 },
{ name: 'Tohono Chicken', price: 308 },
console.log('queryStringParameters!: ', event.queryStringParameters);
const req = event.queryStringParameters;
if (!req?.restaurantId)
return {
isBase64Encoded: false,
statusCode: 400,
headers: responseHeaders,
body: 'RestaurantId must be provided',
};
const limit = req.limit ? Number(req.limit) : 5;
const offset = req.offset ? Number(req.offset) : 0;

const productsDB: Product[] = [
{ id: 1, name: 'Kuva Roast Rib Eye', price: 418 },
{ id: 2, name: 'Guadalupe Half Rack', price: 298 },
{ id: 3, name: 'Tohono Chicken', price: 308 },
{ id: 4, name: 'Milanesa napolitana', price: 500 },
{ id: 5, name: 'Asado', price: 800 },
{ id: 6, name: 'Choripan', price: 230 },
{ id: 7, name: 'Asado x4', price: 2700 },
{ id: 8, name: 'Kuva Roast Rib Eye', price: 418 },
{ id: 9, name: 'Guadalupe Half Rack', price: 298 },
{ id: 10, name: 'Tohono Chicken', price: 308 },
{ id: 11, name: 'Milanesa napolitana', price: 500 },
{ id: 12, name: 'Asado', price: 800 },
{ id: 13, name: 'Choripan', price: 230 },
{ id: 14, name: 'Asado x45', price: 2700 },
{ id: 15, name: 'Asado', price: 800 },
{ id: 16, name: 'Choripan', price: 230 },
{ id: 17, name: 'Asado x45', price: 2700 },
];

const products = productsDB.slice(offset, offset + limit);
const hasMore = productsDB.length > offset + limit;

return {
isBase64Encoded: false,
statusCode: 200,
headers: responseHeaders,
body: JSON.stringify(products),
body: JSON.stringify({ products, hasMore }),
};
} catch (error) {
return {
Expand All @@ -48,8 +77,8 @@ exports.createOrder = async (
isBase64Encoded: false,
statusCode: 400,
headers: responseHeaders,
body: "Products must be provided",
}
body: 'Products must be provided',
};
const order: Order = {
products: req.products,
totalPrice: req.products.reduce((acc, val) => acc + val.price, 0),
Expand All @@ -70,5 +99,3 @@ exports.createOrder = async (
};
}
};


45 changes: 45 additions & 0 deletions packages/api/src/restaurants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { APIGatewayEvent, Callback, Context } from 'aws-lambda';
import { Restaurant } from './types';

const responseHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Methods': 'OPTIONS,GET, POST',
};

exports.get = async (
event: APIGatewayEvent,
context: Context,
callback: Callback,
) => {
try {
const restaurants: Restaurant[] = [
{ id: 1, name: 'Big restaurant' },
{ id: 2, name: 'China here' },
{ id: 3, name: 'La parri argenta' },
{ id: 4, name: 'Small restaurant' },
{ id: 5, name: 'China there' },
{ id: 6, name: 'La re parri argenta' },
{ id: 7, name: 'Big restaurant' },
{ id: 8, name: 'China here' },
{ id: 9, name: 'La parri argenta' },
{ id: 10, name: 'Small restaurant' },
{ id: 11, name: 'China there' },
{ id: 12, name: 'La re parri argenta' },
];

return {
isBase64Encoded: false,
statusCode: 200,
headers: responseHeaders,
body: JSON.stringify(restaurants),
};
} catch (error) {
return {
isBase64Encoded: false,
statusCode: 500,
headers: responseHeaders,
body: error.message,
};
}
};
34 changes: 22 additions & 12 deletions packages/api/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
export interface CreateOrderRequest {
products: Product[];
}

export interface Product {
name: string;
price: number;
}

export interface Order {
products: Product[];
totalPrice: number;
}
products: Product[];
}
export interface OrderProduct {
product: Product;
amount: number;
}

export interface Product {
id: number;
name: string;
price: number;
}

export interface Order {
products: Product[];
totalPrice: number;
}

export interface Restaurant {
id: number;
name: string;
}
15 changes: 15 additions & 0 deletions packages/api/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,18 @@ Resources:
Properties:
Method: POST
Path: /createOrder

GetProductsFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: ./dist
Handler: restaurants.get
Runtime: nodejs20.x
MemorySize: 128
Timeout: 10
Events:
Event:
Type: Api
Properties:
Method: GET
Path: /restaurants
7 changes: 6 additions & 1 deletion packages/front/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@mui/material": "^5.15.18",
"@mui/styled-engine-sc": "6.0.0-alpha.18",
"axios": "^1.6.8",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.23.1",
"react-scripts": "5.0.1",
"styled-components": "^6.1.11"
"react-waypoint": "^10.3.0"
},
"devDependencies": {
"@types/node": "^20.12.11",
Expand Down
2 changes: 1 addition & 1 deletion packages/front/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>Challenge time!</title>
</head>
<body>
<body style="margin:0;padding:0">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
Expand Down
37 changes: 17 additions & 20 deletions packages/front/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
import styled from "styled-components";
import useGetProducts from "./components/app/hooks/useGetProducts";
import {
createBrowserRouter,
RouterProvider,
Route,
createRoutesFromElements,
} from "react-router-dom";
import Products from "./pages/Products";
import { CurrentOrderProvider } from "./components/app/contexts/useCurrentOrderProvider";
import Restaurants from "./pages/Restaurant";

const App = () => {
const products = useGetProducts();
const routes = [
<Route path="/" element={<Restaurants />} />,
<Route path="/:restaurant/products/" element={<Products />} />,
];
const router2 = createBrowserRouter(createRoutesFromElements(routes));

return (
<div
style={{
display: "flex",
flexDirection: "column",
width: "100%",
alignItems: "center",
}}
>
<Title>This is a title</Title>
<div>{products.length > 0 && "hay productos"}</div>
<div>{products.length === 0 && "No hay productos :("}</div>
<img height={600} />
</div>
<CurrentOrderProvider>
<RouterProvider router={router2} />
</CurrentOrderProvider>
);
};

export default App;

const Title = styled.a`
font-size: 2rem;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { createContext, useContext } from "react";
import { OrderProduct } from "../hooks/useCreateOrder";

interface CurrentOrderContextType {
orderProducts: OrderProduct[];
setOrderProducts: React.Dispatch<React.SetStateAction<OrderProduct[]>>;
}
export const CurrentOrderContext = createContext<CurrentOrderContextType>({
orderProducts: [],
setOrderProducts: () => {},
} as CurrentOrderContextType);

export const useCurrentOrderContext = () => {
return useContext(CurrentOrderContext);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ReactNode, useState } from "react";
import { CurrentOrderContext } from "./useCurrentOrderContext";
import { OrderProduct } from "../hooks/useCreateOrder";

export interface ICurrentOrderProvider {
children: ReactNode;
}

export const CurrentOrderProvider = ({ children }: ICurrentOrderProvider) => {
const [orderProducts, setOrderProducts] = useState<OrderProduct[]>([]);

return (
<CurrentOrderContext.Provider value={{ orderProducts, setOrderProducts }}>
{children}
</CurrentOrderContext.Provider>
);
};
41 changes: 41 additions & 0 deletions packages/front/src/components/app/hooks/useCreateOrder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Product } from "./useGetProducts";
import { useCurrentOrderContext } from "../contexts/useCurrentOrderContext";

export interface Order {
products: OrderProduct[];
totalPrice: number;
}
export interface OrderProduct {
product: Product;
amount: number;
}
export interface CreateOrderRequest {
products: OrderProduct[];
}

const useCreateOrder = () => {
const { orderProducts, setOrderProducts } = useCurrentOrderContext();

const alterProduct = ({ product, amount }: OrderProduct) => {
let productToAdd: OrderProduct | undefined = undefined;
if (amount !== 0) productToAdd = { product, amount };
setOrderProducts((value) => [
...value
.filter((x) => x.product.id !== product.id)
.concat(productToAdd ? [productToAdd] : []),
]);
};
const createOrder = () => {
if (orderProducts.length > 0) {
console.log("order products: ", orderProducts);
//Execute create order
}
};
const resetFlow = () => {
setOrderProducts([]);
};

return { alterProduct, createOrder, orderProducts, resetFlow };
};

export default useCreateOrder;
Loading

0 comments on commit 3929638

Please sign in to comment.