diff options
author | HombreLaser <sebastian-440@live.com> | 2023-05-11 19:28:47 -0600 |
---|---|---|
committer | HombreLaser <sebastian-440@live.com> | 2023-05-11 19:28:47 -0600 |
commit | 385606ee05a8ceb9073169639eb1a311f81cac10 (patch) | |
tree | ac8af50a15ce3e834009afef773988213c961cdb | |
parent | ab540055c99074c1c67fd65b45d0afb785ca5a0b (diff) |
Añade información a la vista de usuario
-rw-r--r-- | src/clients/api_client.ts | 33 | ||||
-rw-r--r-- | src/clients/loaders.ts | 15 | ||||
-rw-r--r-- | src/components/address.tsx | 28 | ||||
-rw-r--r-- | src/components/addresses_table.tsx | 42 | ||||
-rw-r--r-- | src/components/payment_method.tsx | 23 | ||||
-rw-r--r-- | src/components/payment_methods_table.tsx | 40 | ||||
-rw-r--r-- | src/components/stylesheets/shared.css | 12 | ||||
-rw-r--r-- | src/lib/token.ts | 23 | ||||
-rw-r--r-- | src/routes/account/account.tsx | 35 |
9 files changed, 229 insertions, 22 deletions
diff --git a/src/clients/api_client.ts b/src/clients/api_client.ts index 7d2cf34..fc2d361 100644 --- a/src/clients/api_client.ts +++ b/src/clients/api_client.ts @@ -1,11 +1,38 @@ -import axios from "axios"; +import axios, { AxiosResponse } from "axios"; +import Token from "../lib/token"; export class ApiClient { readonly url = "http://localhost:3000/api"; + token = new Token(); - async get(path: string, params?: URLSearchParams, headers?: object) { + async authenticatedGet(path: string) { const request_url = `${ this.url }${ path }`; - const response = await this.makeGetRequest(request_url, headers); + let request: any; + let options = { + headers: { + Authorization: this.token.get() + } + }; + + request = await this.makeGetRequest(request_url, options); + + if(request.response) { + // Let's try with a refreshed token. + this.token.refresh() + options = { + headers: { + Authorization: this.token.getRefresh() + } + }; + request = await this.makeGetRequest(request_url, options); + } + + return request; + } + + async get(path: string) { + const request_url = `${ this.url }${ path }`; + const response = await this.makeGetRequest(request_url); return response; } diff --git a/src/clients/loaders.ts b/src/clients/loaders.ts index 2af7770..d9972d5 100644 --- a/src/clients/loaders.ts +++ b/src/clients/loaders.ts @@ -12,17 +12,16 @@ export async function loader({ request }) { export async function accountLoader() { const client = new ApiClient(); - const token = new Token(); + + const account_response = await client.authenticatedGet("/account"); + const addresses_response = await client.authenticatedGet("/account/addresses"); + const cards_response = await client.authenticatedGet("/account/cards"); - if(!token.present()) + // Authentication error handling. + if(account_response.response || addresses_response.response || cards_response.response) return redirect("/products"); - const headers = { - "Authentication": `Bearer ${ token.get() }` - }; - - const response = await client.get("/account", undefined, headers); - return response; + return [account_response, addresses_response, cards_response]; } export async function productLoader({ params }) { diff --git a/src/components/address.tsx b/src/components/address.tsx new file mode 100644 index 0000000..1701fd1 --- /dev/null +++ b/src/components/address.tsx @@ -0,0 +1,28 @@ +import countryList from "react-select-country-list"; + +export default function Address({ address }) { + return( + <tr className="bg-white border-b dark:bg-gray-800 dark:border-gray-700"> + <th scope="row" className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white"> + {address.attributes.street} + </th> + <td className="px-6 py-4"> + {address.attributes.number} + </td> + <td className="px-6 py-4"> + {address.attributes.zip_code} + </td> + <td className="px-6 py-4"> + {address.attributes.city} + </td> + <td className="px-6 py-4"> + {countryList().getLabel(address.attributes.country)} + </td> + <td className="px-6 py-4"> + <button type="button" className="focus:outline-none text-white bg-green-700 hover:bg-green-800 focus:ring-4 focus:ring-green-300 font-medium rounded-lg text-sm px-5 py-2.5 mr-2 mb-2 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800"> + Editar + </button> + </td> + </tr> + ); +}
\ No newline at end of file diff --git a/src/components/addresses_table.tsx b/src/components/addresses_table.tsx new file mode 100644 index 0000000..ae46f21 --- /dev/null +++ b/src/components/addresses_table.tsx @@ -0,0 +1,42 @@ +import Address from "./address"; + +export default function AddressesTable({ addresses }) { + const digested_addresses = addresses.map(address => + <Address address={address}/> + ); + + return( + <div className="w-4/5 relative overflow-x-auto"> + <h1 className="text-2xl my-2"> + Direcciones de envío + </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"> + Calle + </th> + <th scope="col" className="px-6 py-3"> + Número + </th> + <th scope="col" className="px-6 py-3"> + Código postal + </th> + <th scope="col" className="px-6 py-3"> + Ciudad + </th> + <th scope="col" className="px-6 py-3"> + País + </th> + <th scope="col" className="px-6 py-3"> + Editar + </th> + </tr> + </thead> + <tbody> + {digested_addresses} + </tbody> + </table> + </div> + ); +}
\ No newline at end of file diff --git a/src/components/payment_method.tsx b/src/components/payment_method.tsx new file mode 100644 index 0000000..66f7e54 --- /dev/null +++ b/src/components/payment_method.tsx @@ -0,0 +1,23 @@ +export default function PaymentMethod({ payment_method }) { + return( + <tr className="bg-white border-b dark:bg-gray-800 dark:border-gray-700"> + <th scope="row" className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white"> + {payment_method.attributes.number} + </th> + <td className="px-6 py-4"> + {payment_method.attributes.expiration_day} + </td> + <td className="px-6 py-4"> + {payment_method.attributes.expiration_month} + </td> + <td className="px-6 py-4"> + {payment_method.attributes.expiration_year} + </td> + <td className="px-6 py-4"> + <button type="button" className="focus:outline-none text-white bg-green-700 hover:bg-green-800 focus:ring-4 focus:ring-green-300 font-medium rounded-lg text-sm px-5 py-2.5 mr-2 mb-2 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800"> + Editar + </button> + </td> + </tr> + ); +}
\ No newline at end of file diff --git a/src/components/payment_methods_table.tsx b/src/components/payment_methods_table.tsx new file mode 100644 index 0000000..e9ac639 --- /dev/null +++ b/src/components/payment_methods_table.tsx @@ -0,0 +1,40 @@ +import PaymentMethod from "./payment_method"; +import "./stylesheets/shared.css"; + +export default function PaymentMethodsTable({ payment_methods }) { + const digested_payment_methods = payment_methods.map(payment_method => + <PaymentMethod payment_method={payment_method}/> + ); + + return( + <div className="my-2 w-4/5 relative overflow-x-auto"> + <h1 className="text-2xl my-2"> + Métodos de pago + </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 + </th> + <th scope="col" className="px-6 py-3"> + Día de expiración + </th> + <th scope="col" className="px-6 py-3"> + Mes de expiración + </th> + <th scope="col" className="px-6 py-3"> + Año de expiración + </th> + <th scope="col" className="px-6 py-3"> + Editar + </th> + </tr> + </thead> + <tbody> + {digested_payment_methods} + </tbody> + </table> + </div> + ); +}
\ No newline at end of file diff --git a/src/components/stylesheets/shared.css b/src/components/stylesheets/shared.css index 9bda368..cc9e4a2 100644 --- a/src/components/stylesheets/shared.css +++ b/src/components/stylesheets/shared.css @@ -6,6 +6,18 @@ left: 50%; } +h1 { + color: #394490; +} + +.field_name { + color: #394490; +} + +.bg-blue-arma { + background-color: #394490 !important; +} + .button { background-color: #394490 !important; } diff --git a/src/lib/token.ts b/src/lib/token.ts index f838ac0..05de87e 100644 --- a/src/lib/token.ts +++ b/src/lib/token.ts @@ -1,12 +1,7 @@ import { ApiClient } from "../clients/api_client"; +import axios from "axios"; export default class Token { - client: ApiClient; - - constructor() { - this.client = new ApiClient(); - } - get() { return sessionStorage.getItem("token"); } @@ -16,7 +11,7 @@ export default class Token { } getRefresh() { - sessionStorage.getItem("refresh"); + return sessionStorage.getItem("refresh"); } setRefresh(refresh_token: string) { @@ -33,6 +28,18 @@ export default class Token { } refresh() { - this.client.post("/refresh_tokens") + const options = { + headers: { + Authorization: `Bearer ${this.getRefresh()}` + } + } + + try { + const response = axios.post('/refresh_tokens', null, options); + this.setRefresh(response.data.refresh); + this.set(response.data.token); + } catch(error) { + this.logout(); + } } }
\ No newline at end of file diff --git a/src/routes/account/account.tsx b/src/routes/account/account.tsx index baca1a5..8458285 100644 --- a/src/routes/account/account.tsx +++ b/src/routes/account/account.tsx @@ -1,13 +1,42 @@ import { useLoaderData } from "react-router-dom"; +import { PersonCircle } from "react-bootstrap-icons"; +import AddressesTable from "../../components/addresses_table"; +import PaymentMethodsTable from "../../components/payment_methods_table"; import MainContentLayout from "../../components/main_content_layout"; +import "../../components/stylesheets/shared.css"; export default function Account() { + const response = useLoaderData(); + const full_name = response[0].data.data.attributes.first_name + ' ' + response[0].data.data.attributes.last_name + const email = response[0].data.data.attributes.email + const addresses = response[1].data.data; + const payment_methods = response[2].data.data; + return( <> <MainContentLayout> - <h2> - Cuenta - </h2> + <div className="grid my-6 w-4/5 grid-cols-10 gap-2"> + <div className="w-2/5 col-span-1"> + <PersonCircle size={128} color="#394490"/> + </div> + <div className="grid grid-rows-3 col-span-9 mx-4"> + <div className="my-2"> + <h1 className="text-4xl"> + {full_name} + </h1> + </div> + <div className="text-2xl"> + <span className="mx-1 field_name">Correo electrónico:</span> {email} + </div> + <div> + <a type="button" className="button text-white hover:bg-blue-300 hover:text-gray focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 mr-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800" href="#"> + Editar + </a> + </div> + </div> + </div> + <AddressesTable addresses={addresses}/> + <PaymentMethodsTable payment_methods={payment_methods}/> </MainContentLayout> </> ); |