From da2631822f902094e691143302d6fc6b68e1cf56 Mon Sep 17 00:00:00 2001 From: HombreLaser Date: Wed, 24 May 2023 20:18:00 -0600 Subject: Añade lógica de carrito MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/clients/actions.ts | 34 +++++++++++++++++++++++ src/clients/api_client.ts | 8 ++++++ src/components/forms/fields/field.tsx | 4 +-- src/components/info_modal.tsx | 37 +++++++++++++++++++++++++ src/components/product_cart.tsx | 35 +++++++++++++++++------- src/main.tsx | 8 +++--- src/models/product.ts | 4 +-- src/routes/products/product.tsx | 51 ++++++++++++++++++++++++++++++++--- src/routes/products/products.tsx | 2 +- 9 files changed, 162 insertions(+), 21 deletions(-) create mode 100644 src/components/info_modal.tsx diff --git a/src/clients/actions.ts b/src/clients/actions.ts index cee9a85..bd99519 100644 --- a/src/clients/actions.ts +++ b/src/clients/actions.ts @@ -77,4 +77,38 @@ export async function create({ request }) { return requestErrorsToArray(error.response.data.errors); } } +} + +export async function addToCart({ params, request }) { + const client = new ApiClient(); + const product = await client.get(`/products/${ params.productId }`); + const post_request_path = "/account/cart"; + const id = product.data.data.id; + const form = await request.formData(); + + form.append('product_id', id); + + if(form.get('quantity') == '') + form.set('quantity', 1); + + try { + await client.post(post_request_path, form, client.authorizationHeaders()); + } catch(error) { + return error.response.status; + } + + return 200; +} + +export async function deleteFromCart({ request }) { + const client = new ApiClient(); + const form = await request.formData(); + const to_delete = `/account/cart/${ form.get('product_id') }`; + const req = await client.del(to_delete); + + if(req.response) { // 404 + return redirect("/account/cart"); + } + + return req.status; } \ No newline at end of file diff --git a/src/clients/api_client.ts b/src/clients/api_client.ts index 81ae482..e544f16 100644 --- a/src/clients/api_client.ts +++ b/src/clients/api_client.ts @@ -44,6 +44,14 @@ export class ApiClient { return response } + async del(path: string) { + const request_url = `${ this.url }${ path }`; + const options = this.authorizationHeaders(); + + const response = await axios.delete(request_url, options); + return response; + } + async getProduct(id: string) { const request_url = `${ this.url }/products/${ id }`; const [product_response, product_reviews] = await Promise.all([ diff --git a/src/components/forms/fields/field.tsx b/src/components/forms/fields/field.tsx index d7aa342..8faa425 100644 --- a/src/components/forms/fields/field.tsx +++ b/src/components/forms/fields/field.tsx @@ -5,7 +5,7 @@ export default function Field({ properties }) { field_component = (
- +

{properties.error_message }

); @@ -14,7 +14,7 @@ export default function Field({ properties }) { field_component = (
- +
); } diff --git a/src/components/info_modal.tsx b/src/components/info_modal.tsx new file mode 100644 index 0000000..1123901 --- /dev/null +++ b/src/components/info_modal.tsx @@ -0,0 +1,37 @@ +import { Modal } from "flowbite"; +import "./stylesheets/shared.css"; + +function createModal() { + const target = document.getElementById('info-modal'); + const button = document.getElementById('modal-button'); + const options = { + placement: 'center-center', + backdrop: 'dynamic', + backdropClasses: 'bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40', + closable: true + }; + + const new_modal = new Modal(target, options); + button?.addEventListener('click', () => new_modal.hide()); + + return new_modal; +} + +export function InfoModal({ text }) { + + return ( + + ); +} \ No newline at end of file diff --git a/src/components/product_cart.tsx b/src/components/product_cart.tsx index 86d2615..4e78d1a 100644 --- a/src/components/product_cart.tsx +++ b/src/components/product_cart.tsx @@ -1,27 +1,44 @@ +import { Form } from "react-router-dom"; import "./stylesheets/product_listing.css"; export default function ProductCart({ product }) { return ( -
-
+
+
-
+
{product.name}
+
+ Precio unitario +
- - Precio unitario - {product.unitary_price}
+
+ Precio al por mayor +
- - Precio al por mayor - {product.bulk_price}
+
+
+ Cantidad en carrito: +
+
+ {product.quantity} +
+
+
+ + +
+
+
); diff --git a/src/main.tsx b/src/main.tsx index ebe246a..147d913 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -8,7 +8,7 @@ import Account from "./routes/account/account"; import Cart from "./routes/account/cart"; import { EditAccount } from './routes/account/edit'; import { Edit as EditAddress } from "./routes/account/addresses/edit"; -import { create, editAccount, authenticatedEdit } from './clients/actions'; +import { create, editAccount, authenticatedEdit, addToCart, deleteFromCart } from './clients/actions'; import Layout from "./components/layout"; import { accountLoader, loader, productLoader, addressLoader, cardLoader, cartLoader } from "./clients/loaders"; import './index.css'; @@ -25,7 +25,8 @@ const routes = [ { path: "products/:productId", loader: productLoader, - element: + action: addToCart, + element: , }, { path: "/companies", @@ -68,7 +69,8 @@ const routes = [ { path: "/account/cart", element: , - loader: cartLoader + loader: cartLoader, + action: deleteFromCart }, { path: '/', diff --git a/src/models/product.ts b/src/models/product.ts index b375537..c3323e0 100644 --- a/src/models/product.ts +++ b/src/models/product.ts @@ -5,7 +5,7 @@ export interface Product { unitary_price: number; bulk_price: number; available_quantity: number; - company_name: string; + quantity: number; } export function mapProduct(data: any) { @@ -19,7 +19,7 @@ export function mapProduct(data: any) { unitary_price: data.attributes.unitary_price, bulk_price: data.attributes.bulk_price, available_quantity: data.attributes.available_quantity, - company_name: data.attributes.company.name + quantity: data.attributes.quantity }; return product; diff --git a/src/routes/products/product.tsx b/src/routes/products/product.tsx index 1eecbcf..cca4073 100644 --- a/src/routes/products/product.tsx +++ b/src/routes/products/product.tsx @@ -1,12 +1,18 @@ -import { useLoaderData } from "react-router-dom"; +import { useLoaderData, Form, useActionData } from "react-router-dom"; import { CartPlusFill } from "react-bootstrap-icons" +import { InfoModal } from "../../components/info_modal"; +import { Modal } from "flowbite"; import ProductListing from "../../components/product_listing"; import MainContentLayout from "../../components/main_content_layout"; import Review from "../../components/review"; import "../../components/stylesheets/shared.css" +import { useEffect } from "react"; + export default function Product() { + let quantity_field; const response = useLoaderData(); + const response_status = useActionData(); const product = response[0].data; const reviews = response[1].data.data.map(review =>
  • @@ -14,23 +20,60 @@ export default function Product() {
  • ); + useEffect(() => { + const target = document.getElementById("info-modal"); + const options = { + placement: 'center-center', + backdrop: 'dynamic', + backdropClasses: 'bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40', + closable: true + }; + const modal = new Modal(target, options); + document.getElementById('modal-button')?.addEventListener("click", () => { + modal.hide(); + }); + + if(response_status == 200) + modal.show(); + + }, [response_status]); + + if(response_status == 422) { + quantity_field = ( +
    + +
    + ); + } + else { + quantity_field = ( +
    + +
    + ); + } + return ( <>
    -
    - -
    +
      {reviews}
    +
    ); diff --git a/src/routes/products/products.tsx b/src/routes/products/products.tsx index ea06c15..27192d3 100644 --- a/src/routes/products/products.tsx +++ b/src/routes/products/products.tsx @@ -1,4 +1,4 @@ -import { Link, useLoaderData } from "react-router-dom"; +import { useLoaderData } from "react-router-dom"; import ProductListing from "../../components/product_listing"; import SearchBar from "../../components/search_bar"; import MainContentLayout from "../../components/main_content_layout"; -- cgit v1.2.3