summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHombreLaser <sebastian-440@live.com>2023-05-25 19:11:31 -0600
committerHombreLaser <sebastian-440@live.com>2023-05-25 19:11:31 -0600
commite8fa9bd7bba125a339f11876eb5ea99d0cd301b6 (patch)
tree5d8211221680a3c214b3a16b5d179722a8add085
parentda2631822f902094e691143302d6fc6b68e1cf56 (diff)
Añade historial de órdenes
-rw-r--r--src/clients/actions.ts13
-rw-r--r--src/clients/loaders.ts40
-rw-r--r--src/components/forms/login_form.tsx3
-rw-r--r--src/components/order_table.tsx56
-rw-r--r--src/components/product_cart.tsx2
-rw-r--r--src/components/user_account_dropdown_menu.tsx2
-rw-r--r--src/main.tsx11
-rw-r--r--src/models/card.ts8
-rw-r--r--src/models/order.ts6
-rw-r--r--src/routes/account/cart.tsx72
-rw-r--r--src/routes/account/orders.tsx14
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