diff options
author | HombreLaser <sebastian-440@live.com> | 2023-05-25 19:11:31 -0600 |
---|---|---|
committer | HombreLaser <sebastian-440@live.com> | 2023-05-25 19:11:31 -0600 |
commit | e8fa9bd7bba125a339f11876eb5ea99d0cd301b6 (patch) | |
tree | 5d8211221680a3c214b3a16b5d179722a8add085 /src | |
parent | da2631822f902094e691143302d6fc6b68e1cf56 (diff) |
Añade historial de órdenes
Diffstat (limited to 'src')
-rw-r--r-- | src/clients/actions.ts | 13 | ||||
-rw-r--r-- | src/clients/loaders.ts | 40 | ||||
-rw-r--r-- | src/components/forms/login_form.tsx | 3 | ||||
-rw-r--r-- | src/components/order_table.tsx | 56 | ||||
-rw-r--r-- | src/components/product_cart.tsx | 2 | ||||
-rw-r--r-- | src/components/user_account_dropdown_menu.tsx | 2 | ||||
-rw-r--r-- | src/main.tsx | 11 | ||||
-rw-r--r-- | src/models/card.ts | 8 | ||||
-rw-r--r-- | src/models/order.ts | 6 | ||||
-rw-r--r-- | src/routes/account/cart.tsx | 72 | ||||
-rw-r--r-- | src/routes/account/orders.tsx | 14 |
11 files changed, 205 insertions, 22 deletions
diff --git a/src/clients/actions.ts b/src/clients/actions.ts index bd99519..447d054 100644 --- a/src/clients/actions.ts +++ b/src/clients/actions.ts @@ -111,4 +111,17 @@ export async function deleteFromCart({ request }) { } return req.status; +} + +export async function placeOrder({ request }) { + const client = new ApiClient(); + const form = await request.formData(); + + try { + const response = await client.post('/orders', form, client.authorizationHeaders()); + + return redirect('/products'); + } catch(error) { + return redirect('/account/cart') + } }
\ No newline at end of file diff --git a/src/clients/loaders.ts b/src/clients/loaders.ts index 9f5a131..a114e8d 100644 --- a/src/clients/loaders.ts +++ b/src/clients/loaders.ts @@ -1,7 +1,9 @@ import { redirect } from "react-router-dom"; import { ApiClient } from "./api_client"; import { Product, mapProduct } from "../models/product"; +import { Card } from "../models/card"; import Token from "../lib/token"; +import Order from "../models/order"; export async function loader({ request }) { const client = new ApiClient(); @@ -12,22 +14,29 @@ export async function loader({ request }) { } export async function cartLoader() { - const data = new Array<Product>(); + const product_data = new Array<Product>(); + const cards_data = new Array<Card>(); const token = new Token(); const client = new ApiClient(); - const request = await client.authenticatedGet("/account/cart"); + const product_request = await client.authenticatedGet("/account/cart"); + const cards_request = await client.authenticatedGet("/account/cards"); - if(request.response) { + if(product_request.response || cards_request.response) { token.logout(); return redirect("/products") } - request.data.data.attributes.products.data.map(response_data => { - data.push(mapProduct(response_data)); + product_request.data.data.attributes.products.data.map(response_data => { + product_data.push(mapProduct(response_data)); }); - return data; + cards_request.data.data.map(data => { + cards_data.push(data.attributes); + }); + + + return [product_data, cards_data]; } export async function addressLoader({ params }) { @@ -71,4 +80,23 @@ export async function productLoader({ params }) { const response = await client.getProduct(params.productId); return [response[0], response[1]]; +} + +export async function ordersLoader() { + const client = new ApiClient(); + const response = await client.authenticatedGet('/orders'); + const orders = new Array<Order> + + try { + response.data.data.map(order => { + delete order.attributes.products; + order.attributes['id'] = order.id; + orders.push(order.attributes) + }); + + return orders; + } catch(error) { + + return redirect('/products'); + } }
\ No newline at end of file diff --git a/src/components/forms/login_form.tsx b/src/components/forms/login_form.tsx index 44c3da5..b1a2296 100644 --- a/src/components/forms/login_form.tsx +++ b/src/components/forms/login_form.tsx @@ -7,9 +7,8 @@ import "../stylesheets/shared.css" export function LoginForm() { const [error_message, setErrorMessage] = useState(''); - // const [modal, setModal] = useState(new Modal()); - // Error rendering useEffecT + // Error rendering useEffect useEffect(() => { document.getElementById("errorMessage").innerHTML = error_message; }, [error_message]); diff --git a/src/components/order_table.tsx b/src/components/order_table.tsx new file mode 100644 index 0000000..207b3e4 --- /dev/null +++ b/src/components/order_table.tsx @@ -0,0 +1,56 @@ +import Order from "../models/order"; +import "./stylesheets/shared.css"; + +function getRows(orders: Array<Order>) { + const rows = orders.map(order => ( + <tr className="bg-white border-b dark:bg-gray-800 dark:border-gray-700"> + <td scope="row" className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white"> + {order.id} + </td> + <td className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white"> + {order.public_id} + </td> + <td className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white"> + {order.created_at.toLocaleString().split('T')[0]} + </td> + <td className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white"> + {order.total} + </td> + </tr> + )); + + return rows; +} + +export default function OrderTable({ orders }) { + const rows = getRows(orders); + + return( + <div className="my-4 w-4/5 relative overflow-x-auto"> + <h1 className="text-2xl my-2"> + Historial de órdenes + </h1> + <table className="w-full text-sm text-left text-gray-500 dark:text-gray-400"> + <thead className="bg-blue-arma text-xs text-white uppercase dark:bg-gray-700 dark:text-gray-400"> + <tr> + <th scope="col" className="px-6 py-3"> + Número de orden + </th> + <th scope="col" className="px-6 py-3"> + Identificador + </th> + <th scope="col" className="px-6 py-3"> + Fecha + </th> + <th scope="col" className="px-6 py-3"> + Total + </th> + </tr> + </thead> + <tbody> + {rows} + </tbody> + </table> + </div> + ); +}
\ No newline at end of file diff --git a/src/components/product_cart.tsx b/src/components/product_cart.tsx index 4e78d1a..14710d1 100644 --- a/src/components/product_cart.tsx +++ b/src/components/product_cart.tsx @@ -3,7 +3,7 @@ import "./stylesheets/product_listing.css"; export default function ProductCart({ product }) { return ( - <div className="my-2 w-3/6 grid grid-cols-2 gap-2 border-2 border-gray-300"> + <div className="my-2 grid grid-cols-2 gap-2 border-2 border-gray-300"> <div> <img className="listing-image" src={product.picture} /> </div> diff --git a/src/components/user_account_dropdown_menu.tsx b/src/components/user_account_dropdown_menu.tsx index b70aa4e..495f3c8 100644 --- a/src/components/user_account_dropdown_menu.tsx +++ b/src/components/user_account_dropdown_menu.tsx @@ -10,7 +10,7 @@ export default function UserAccountDropdownMenu() { </li> <li className="flex"> <i className="px-1 my-2"><CardList size={16} color="#394490"/></i> - <a href="#" className="block px-2 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">Historial de pedidos</a> + <a href="/account/orders" className="block px-2 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">Historial de órdenes</a> </li> </ul> <div className="flex py-2"> diff --git a/src/main.tsx b/src/main.tsx index 147d913..8f9c586 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -6,11 +6,12 @@ import Product from "./routes/products/product"; import Companies from "./routes/companies/companies"; import Account from "./routes/account/account"; import Cart from "./routes/account/cart"; +import Orders from "./routes/account/orders"; import { EditAccount } from './routes/account/edit'; import { Edit as EditAddress } from "./routes/account/addresses/edit"; -import { create, editAccount, authenticatedEdit, addToCart, deleteFromCart } from './clients/actions'; +import { create, editAccount, authenticatedEdit, addToCart, deleteFromCart, placeOrder } from './clients/actions'; import Layout from "./components/layout"; -import { accountLoader, loader, productLoader, addressLoader, cardLoader, cartLoader } from "./clients/loaders"; +import { accountLoader, loader, productLoader, addressLoader, cardLoader, cartLoader, ordersLoader } from "./clients/loaders"; import './index.css'; import { Create as CreateAddress } from './routes/account/addresses/create'; import { Edit as EditCard } from './routes/account/cards/edit'; @@ -73,6 +74,12 @@ const routes = [ action: deleteFromCart }, { + path: "/account/orders", + element: <Orders/>, + loader: ordersLoader, + action: placeOrder + }, + { path: '/', element: <Navigate to='/products'/> } diff --git a/src/models/card.ts b/src/models/card.ts new file mode 100644 index 0000000..b143580 --- /dev/null +++ b/src/models/card.ts @@ -0,0 +1,8 @@ +export interface Card { + id: number; + number: number; + expiration_year: string; + expiration_month: number; + expiration_day: number; + security_code: number; +}
\ No newline at end of file diff --git a/src/models/order.ts b/src/models/order.ts new file mode 100644 index 0000000..c2a4190 --- /dev/null +++ b/src/models/order.ts @@ -0,0 +1,6 @@ +export default interface Order { + id: number; + created_at: Date; + public_id: string; + total: number; +}
\ No newline at end of file diff --git a/src/routes/account/cart.tsx b/src/routes/account/cart.tsx index a98cf20..cc81756 100644 --- a/src/routes/account/cart.tsx +++ b/src/routes/account/cart.tsx @@ -1,25 +1,60 @@ -import { useLoaderData } from "react-router-dom"; -import { cartLoader } from "../../clients/loaders"; +import { Form, useLoaderData } from "react-router-dom"; import ProductCart from "../../components/product_cart"; import { Product } from "../../models/product"; import MainContentLayout from "../../components/main_content_layout"; import { CartXFill } from "react-bootstrap-icons"; +import { Card } from "../../models/card"; +import "../../components/stylesheets/shared.css" -export default function Cart() { - let products; - const data = useLoaderData() as Array<Product>; +function getOrderForm(cards: Array<Card>) { + if(cards.length > 0) { + const options = cards.map(card => + <option value={card.id}>{card.number}</option> + ); - if(data.length > 0) { - products = data.map(product => + return( + <div className="mx-4 my-1"> + <div className="border-b-2 w-2/6 border-slate-500 my-4"> + <h1 className="text-3xl "> + Completar pago + </h1> + </div> + <Form method="post" action="/account/orders"> + <div className="my-2 mb-6"> + <select name="card_id" id="card-select"> + {options} + </select> + </div> + <div className="my-2 mb-6"> + <button type="submit" className="text-white button focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 mr-2 mb-2 focus:outline-none dark:focus:ring-blue-800"> + Enviar + </button> + </div> + </Form> + </div> + ); + } + else { + <div className="mx-4 my-1"> + <span className="text-red-600 italic text-lg"> + No tiene ningún método de pago configurado. + </span> + </div> + } +} + +function getProducts(product_data: Array<Product>) { + if(product_data.length > 0) { + return (product_data.map(product => <ul> <li key={product.id}> <ProductCart product={product}/> </li> </ul> - ); + )); } else { - products = ( + return ( <div> <div className="flex justify-center my-4 w-4/6"> <CartXFill color="rgb(55 65 81)" size={256}/> @@ -30,11 +65,28 @@ export default function Cart() { </div> ); } +} + +export default function Cart() { + const product_data = useLoaderData()[0] as Array<Product>; + const cards_data = useLoaderData()[1] as Array<Card>; + let order_form; + const products = getProducts(product_data); + + if(product_data.length > 0) + order_form = getOrderForm(cards_data); + else + order_form = null; return( <> <MainContentLayout> - {products} + <div className="grid grid-cols-2"> + <div> + {products} + </div> + {order_form} + </div> </MainContentLayout> </> ); diff --git a/src/routes/account/orders.tsx b/src/routes/account/orders.tsx new file mode 100644 index 0000000..1e655d1 --- /dev/null +++ b/src/routes/account/orders.tsx @@ -0,0 +1,14 @@ +import { useLoaderData } from "react-router-dom"; +import MainContentLayout from "../../components/main_content_layout"; +import OrderTable from "../../components/order_table"; + + +export default function Orders() { + const orders = useLoaderData(); + + return( + <MainContentLayout> + <OrderTable orders={orders}/> + </MainContentLayout> + ); +}
\ No newline at end of file |