diff --git a/backend/app/src/main/java/eu/viandeendirect/domains/payment/StripeDirectPaymentManager.java b/backend/app/src/main/java/eu/viandeendirect/domains/payment/StripeDirectPaymentManager.java index e6d3d49..e74cd92 100644 --- a/backend/app/src/main/java/eu/viandeendirect/domains/payment/StripeDirectPaymentManager.java +++ b/backend/app/src/main/java/eu/viandeendirect/domains/payment/StripeDirectPaymentManager.java @@ -47,8 +47,8 @@ public StripePayment createPayment(Order order) throws StripeException { .setApplicationFeeAmount(1L).build()) .setMode(SessionCreateParams.Mode.PAYMENT) .setCustomerEmail(order.getCustomer().getUser().getEmail()) - .setSuccessUrl(viandeEnDirectConfiguration.getCustomerFrontendUrl() + "/orders/" + order.getId() + "/payment") - .setCancelUrl(viandeEnDirectConfiguration.getCustomerFrontendUrl() + "/orders/" + order.getId() + "/payment") + .setSuccessUrl(viandeEnDirectConfiguration.getCustomerFrontendUrl() + "/order/" + order.getId() + "/payment") + .setCancelUrl(viandeEnDirectConfiguration.getCustomerFrontendUrl() + "/order/" + order.getId() + "/payment") .setExpiresAt(Instant.now().plusSeconds(30 * 60).getEpochSecond()) .build(); RequestOptions requestOptions = RequestOptions.builder().setStripeAccount(getProducerStripeAccount(order).getStripeAccount().getStripeId()).build(); diff --git a/backend/app/src/main/java/eu/viandeendirect/domains/payment/StripePayAndTransferPaymentManager.java b/backend/app/src/main/java/eu/viandeendirect/domains/payment/StripePayAndTransferPaymentManager.java index 63bce7b..b0526ed 100644 --- a/backend/app/src/main/java/eu/viandeendirect/domains/payment/StripePayAndTransferPaymentManager.java +++ b/backend/app/src/main/java/eu/viandeendirect/domains/payment/StripePayAndTransferPaymentManager.java @@ -41,8 +41,8 @@ public StripePayment createPayment(Order order) throws StripeException { SessionCreateParams params = builder .setPaymentIntentData(SessionCreateParams.PaymentIntentData.builder().setTransferGroup(order.getId().toString()).build()) .setMode(SessionCreateParams.Mode.PAYMENT) - .setSuccessUrl(viandeendirectProducerFrontendUrl + "/orders/" + order.getId() + "/payment") - .setCancelUrl(viandeendirectProducerFrontendUrl + "/orders/" + order.getId() + "/payment") + .setSuccessUrl(viandeendirectProducerFrontendUrl + "/order/" + order.getId() + "/payment") + .setCancelUrl(viandeendirectProducerFrontendUrl + "/order/" + order.getId() + "/payment") .build(); Session session = Session.create(params); StripePayment stripePayment = new StripePayment(); diff --git a/backend/app/src/main/java/eu/viandeendirect/domains/user/CustomerService.java b/backend/app/src/main/java/eu/viandeendirect/domains/user/CustomerService.java index 8f23cfd..0465611 100644 --- a/backend/app/src/main/java/eu/viandeendirect/domains/user/CustomerService.java +++ b/backend/app/src/main/java/eu/viandeendirect/domains/user/CustomerService.java @@ -2,6 +2,7 @@ import eu.viandeendirect.api.CustomersApiDelegate; import eu.viandeendirect.model.Customer; +import eu.viandeendirect.model.User; import eu.viandeendirect.security.specs.AuthenticationServiceSpecs; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -41,13 +42,17 @@ public ResponseEntity getCustomer(String email) { if (producer.isPresent()) { throw new ResponseStatusException(CONFLICT); } else { - return new ResponseEntity<>(NO_CONTENT); + customer = new Customer(); + var user = new User(); + user.setEmail(email); + customer.setUser(user); + return new ResponseEntity<>(customer, OK); } } if (!customer.getUser().getEmail().equals(email)) { throw new ResponseStatusException(HttpStatus.FORBIDDEN); } - return new ResponseEntity<>(customer, HttpStatus.OK); + return new ResponseEntity<>(customer, OK); } diff --git a/backend/app/src/test/java/eu/viandeendirect/domains/payment/StripeEventHandlerTest_getCheckoutSession.java b/backend/app/src/test/java/eu/viandeendirect/domains/payment/StripeEventHandlerTest_getCheckoutSession.java index bcb0a8c..8f0cb5b 100644 --- a/backend/app/src/test/java/eu/viandeendirect/domains/payment/StripeEventHandlerTest_getCheckoutSession.java +++ b/backend/app/src/test/java/eu/viandeendirect/domains/payment/StripeEventHandlerTest_getCheckoutSession.java @@ -41,7 +41,7 @@ void should_deserialize_the_checkout_session_from_event_data() throws SignatureV "status": null }, "billing_address_collection": null, - "cancel_url": "https://customer.sandbox.viandeendirect.eu/orders/14/paymentCancelled", + "cancel_url": "https://customer.sandbox.viandeendirect.eu/order/14/paymentCancelled", "client_reference_id": null, "client_secret": null, "consent": null, @@ -127,7 +127,7 @@ void should_deserialize_the_checkout_session_from_event_data() throws SignatureV "status": "complete", "submit_type": null, "subscription": null, - "success_url": "https://customer.sandbox.viandeendirect.eu/orders/14/paymentSuccessful", + "success_url": "https://customer.sandbox.viandeendirect.eu/order/14/paymentSuccessful", "total_details": { "amount_discount": 0, "amount_shipping": 0, diff --git a/frontend/app/src/api/ApiBuilder.ts b/frontend/app/src/api/ApiBuilder.ts index 8eee6bf..43a0d23 100644 --- a/frontend/app/src/api/ApiBuilder.ts +++ b/frontend/app/src/api/ApiBuilder.ts @@ -34,26 +34,4 @@ export class ApiBuilder { return new DefaultApi(configuration) } } - - /** - * - * @param {*} apiFunction - * @param {Keycloak} keycloak - */ - invokeAuthenticatedApi(apiFunction, keycloak) { - if(process.env.REACT_APP_MOCK_API) { - apiFunction() - } else { - keycloak.updateToken(30).then(function () { - apiFunction() - }).catch(function (error) { - console.log('Failed to refresh token'); - console.log(error); - }) - } - } - - invokeAnonymousApi(apiFunction) { - apiFunction() - } } diff --git a/frontend/app/src/api/ApiInvoker.ts b/frontend/app/src/api/ApiInvoker.ts deleted file mode 100644 index ec65b67..0000000 --- a/frontend/app/src/api/ApiInvoker.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { ApiBuilder } from "./ApiBuilder.ts" - -export class ApiInvoker { - - apiBuilder = new ApiBuilder() - - callApiAnonymously(getApiFunction, arg, successCallbackFunction, errorCallbackFunction) { - this.apiBuilder.getAnonymousApi().then(api => { - this.apiBuilder.invokeAnonymousApi(() => { - const apiFunction = getApiFunction(api) - if (arg) { - apiFunction.call(api, arg, (error, data) => { - if (error) { - errorCallbackFunction(error) - } else { - successCallbackFunction(data) - } - }) - } else { - apiFunction.call(api, (error, data) => { - if (error) { - errorCallbackFunction(error) - } else { - successCallbackFunction(data) - } - }) - } - }) - }) - } - - callApiAuthenticatedly(keycloak, getApiFunction, arg, successCallbackFunction, errorCallbackFunction) { - this.apiBuilder.getAuthenticatedApi(keycloak).then(api => { - this.apiBuilder.invokeAuthenticatedApi(() => { - const apiFunction = getApiFunction(api) - if (arg) { - apiFunction.call(api, arg, (error, data) => { - if (error) { - errorCallbackFunction(error) - } else { - successCallbackFunction(data) - } - }) - } else { - apiFunction.call(api, (error, data) => { - if (error) { - errorCallbackFunction(error) - } else { - successCallbackFunction(data) - } - }) - } - }, keycloak) - }) - } -} \ No newline at end of file diff --git a/frontend/app/src/authentication/service/AuthenticationService.ts b/frontend/app/src/authentication/service/AuthenticationService.ts index f45fc13..a8e6020 100644 --- a/frontend/app/src/authentication/service/AuthenticationService.ts +++ b/frontend/app/src/authentication/service/AuthenticationService.ts @@ -1,4 +1,6 @@ import Keycloak from "keycloak-js" +import { ApiBuilder } from "../../api/ApiBuilder.ts" +import { Producer } from "@viandeendirect/api/dist/models/Producer" export class AuthenticationService { keycloak: Keycloak @@ -11,6 +13,40 @@ export class AuthenticationService { return (!!process.env.REACT_APP_MOCK_API) || (!!this.keycloak.authenticated) } + async isAuthenticatedAsProducer(): Promise { + if (this.isAuthenticated()) { + try { + const userEmail = this.getCurrentUserEmail() + const apiBuilder = new ApiBuilder() + const api = await apiBuilder.getAuthenticatedApi(this.keycloak) + await api.getProducer({'email': userEmail}) + return true + } catch (error) { + if(error.response.status === 409) { + return false + } + } + } + return false + } + + async isAuthenticatedAsCustomer(): Promise { + if (this.isAuthenticated()) { + try { + const userEmail = this.getCurrentUserEmail() + const apiBuilder = new ApiBuilder() + const api = await apiBuilder.getAuthenticatedApi(this.keycloak) + await api.getCustomer({'email': userEmail}) + return true + } catch (error) { + if(error.response.status === 409) { + return false + } + } + } + return false + } + getCurrentUserName(): string | undefined { if(process.env.REACT_APP_MOCK_API) { return "Utilisateur TEST" diff --git a/frontend/app/src/authentication/views/NotAuthorizedForCustomers.tsx b/frontend/app/src/authentication/views/NotAuthorizedForCustomers.tsx index ffc34a7..36c7fce 100644 --- a/frontend/app/src/authentication/views/NotAuthorizedForCustomers.tsx +++ b/frontend/app/src/authentication/views/NotAuthorizedForCustomers.tsx @@ -1,19 +1,21 @@ +import React from 'react' import { Box, Toolbar, Typography, Button, ButtonGroup, AppBar, CssBaseline, IconButton } from '@mui/material' import { useKeycloak } from '@react-keycloak/web' -import React from 'react' -import { useEffect, useState } from 'react' import { UrlService } from '../../domains/commons/service/UrlService.ts' -import { Logout } from '@mui/icons-material' +import { Navigate, useLoaderData } from 'react-router-dom' +import { AuthenticationService } from '../service/AuthenticationService.ts' export default function NotAuthorizedForCustomers() { - const urlService = new UrlService() - const [customerFrontendUrl, setCustomerFrontendUrl] = useState() const {keycloak} = useKeycloak() - - useEffect(() => { - urlService.getCustomerFrontentUrl().then(setCustomerFrontendUrl) - }) + + const data = useLoaderData() + const authenticatedAsCustomer = data.authenticatedAsCustomer + const customerFrontendUrl = data.customerFrontendUrl + + if (!authenticatedAsCustomer) { + return + } return @@ -27,9 +29,6 @@ export default function NotAuthorizedForCustomers() { Viande en direct - - - @@ -39,13 +38,20 @@ export default function NotAuthorizedForCustomers() { +} + +export async function loadNotAuthorizedForCustomerData(keycloak) { + const authenticationService = new AuthenticationService(keycloak) + const authenticatedAsCustomer = await authenticationService.isAuthenticatedAsCustomer() + const urlService = new UrlService() + const customerFrontendUrl = await urlService.getCustomerFrontentUrl() + return {authenticatedAsCustomer: authenticatedAsCustomer, customerFrontendUrl: customerFrontendUrl} } \ No newline at end of file diff --git a/frontend/app/src/authentication/views/NotAuthorizedForProducers.tsx b/frontend/app/src/authentication/views/NotAuthorizedForProducers.tsx index d7bd9c1..b224755 100644 --- a/frontend/app/src/authentication/views/NotAuthorizedForProducers.tsx +++ b/frontend/app/src/authentication/views/NotAuthorizedForProducers.tsx @@ -1,34 +1,56 @@ -import { Box, Toolbar, Typography, Button, ButtonGroup } from '@mui/material' -import { useKeycloak } from '@react-keycloak/web' import React from 'react' -import { useEffect, useState } from 'react' +import { Box, Toolbar, Typography, Button, ButtonGroup, CssBaseline, AppBar } from '@mui/material' +import { useKeycloak } from '@react-keycloak/web' import { UrlService } from '../../domains/commons/service/UrlService.ts' +import { AuthenticationService } from '../service/AuthenticationService.ts' +import { Navigate, useLoaderData } from 'react-router-dom' export default function NotAuthorizedForProducers() { - const urlService = new UrlService() - const [producerFrontendUrl, setProducerFrontendUrl] = useState() - const {keycloak} = useKeycloak() - - useEffect(() => { - urlService.getProducerFrontentUrl().then(setProducerFrontendUrl) - }) + const { keycloak } = useKeycloak() + const data = useLoaderData() + const authenticatedAsProducer = data.authenticatedAsProducer + const producerFrontendUrl = data.producerFrontendUrl + + if (!authenticatedAsProducer) { + return + } return - - Vous êtes dans l'espace client de viandeendirect.eu - Votre compte est un compte producteur. - Il est impossible d'accéder à l'espace client avec un compte producteur - - - - - + + theme.zIndex.drawer + 1, + }} + > + + + Viande en direct + + + + + Vous êtes dans l'espace client de viandeendirect.eu + Votre compte est un compte producteur. + Il est impossible d'accéder à l'espace client avec un compte producteur + + + + + +} + +export async function loadNotAuthorizedForProducerData(keycloak) { + const authenticationService = new AuthenticationService(keycloak) + const authenticatedAsProducer = await authenticationService.isAuthenticatedAsProducer() + const urlService = new UrlService() + const producerFrontendUrl = await urlService.getProducerFrontentUrl() + return {authenticatedAsProducer: authenticatedAsProducer, producerFrontendUrl: producerFrontendUrl} } \ No newline at end of file diff --git a/frontend/app/src/domains/commons/service/ProducerService.ts b/frontend/app/src/domains/commons/service/ProducerService.ts index 02f898b..26e73ae 100644 --- a/frontend/app/src/domains/commons/service/ProducerService.ts +++ b/frontend/app/src/domains/commons/service/ProducerService.ts @@ -1,6 +1,5 @@ import Keycloak from "keycloak-js" import {Producer} from "@viandeendirect/api/dist/models/Producer.js"; -import { ApiInvoker } from "../../../api/ApiInvoker.ts"; import { AuthenticationService } from "../../../authentication/service/AuthenticationService.ts"; import { ApiBuilder } from "../../../api/ApiBuilder.ts"; @@ -15,34 +14,7 @@ export class ProducerService { this.apiBuilder = new ApiBuilder(); } - loadProducer(setProducer, setUnauthorized = unauthorized => {}) { - if(!ProducerService.producer) { - const apiInvoker = new ApiInvoker() - const authenticationService = new AuthenticationService(this.keycloak) - apiInvoker.callApiAuthenticatedly( - this.keycloak, - api => api.getProducer, - {'email': authenticationService.getCurrentUserEmail()}, - producer => { - ProducerService.producer = producer - ProducerService.unauthorized = false - setProducer(ProducerService.producer) - setUnauthorized(ProducerService.unauthorized) - }, - error => { - console.error(error) - ProducerService.unauthorized = true - setProducer(ProducerService.producer) - setUnauthorized(ProducerService.unauthorized) - } - ) - } else { - setProducer(ProducerService.producer) - setUnauthorized(ProducerService.unauthorized) - } - } - - async asyncLoadProducer(): Promise { + async loadProducer(): Promise { const api = await this.apiBuilder.getAuthenticatedApi(this.keycloak) const authenticationService = new AuthenticationService(this.keycloak) return await api.getProducer({'email': authenticationService.getCurrentUserEmail()}) diff --git a/frontend/app/src/domains/customer/views/CustomerCreationForm.tsx b/frontend/app/src/domains/customer/views/CustomerCreationForm.tsx index bbcb810..42f7563 100644 --- a/frontend/app/src/domains/customer/views/CustomerCreationForm.tsx +++ b/frontend/app/src/domains/customer/views/CustomerCreationForm.tsx @@ -2,17 +2,24 @@ import { Box, Button, ButtonGroup, Stepper, Toolbar, Typography } from '@mui/mat import { useKeycloak } from '@react-keycloak/web' import React from 'react' import { FormContainer, TextFieldElement } from 'react-hook-form-mui' -import { Customer, User } from 'viandeendirect_eu' -import { ApiInvoker } from '../../../api/ApiInvoker.ts' +import { Customer } from '@viandeendirect/api/dist/models/Customer' +import { User } from '@viandeendirect/api/dist/models/User' +import { AuthenticationService } from '../../../authentication/service/AuthenticationService.ts' +import { useLoaderData, useNavigate } from 'react-router-dom' +import { ApiBuilder } from '../../../api/ApiBuilder.ts' -export default function CustomerCreationForm({returnCallback: returnCallback, customer: customer}) { +export default function CustomerCreationForm() { const { keycloak } = useKeycloak() - const apiInvoker = new ApiInvoker() + const navigate = useNavigate() + const apiBuilder = new ApiBuilder() + const customer: Customer = useLoaderData() - function storeUserData(userFormData) { + async function storeUserData(userFormData) { customer.user.phone = userFormData.phone - apiInvoker.callApiAuthenticatedly(keycloak, api => api.createCustomer, customer, returnCallback) + const api = await apiBuilder.getAuthenticatedApi(keycloak) + await api.createCustomer({customer: customer}) + navigate(-1) } return @@ -40,4 +47,15 @@ export default function CustomerCreationForm({returnCallback: returnCallback, cu +} + +export function loadCustomerCreationFormData(keycloak): Customer { + const authenticationService = new AuthenticationService(keycloak) + const customer: Customer = {} + const user: User = {} + user.email = authenticationService.getCurrentUserEmail() + user.firstName = authenticationService.getCurrentUserFirstName() + user.lastName = authenticationService.getCurrentUserLastName() + customer.user = user + return customer } \ No newline at end of file diff --git a/frontend/app/src/domains/customer/views/CustomersList.tsx b/frontend/app/src/domains/customer/views/CustomersList.tsx index 2586548..19ba5ad 100644 --- a/frontend/app/src/domains/customer/views/CustomersList.tsx +++ b/frontend/app/src/domains/customer/views/CustomersList.tsx @@ -48,7 +48,7 @@ export default function CustomersList() { export async function loadCustomersListData(keycloak): Promise> { const producerService = new ProducerService(keycloak) - const producer: Producer = await producerService.asyncLoadProducer() + const producer: Producer = await producerService.loadProducer() const apiBuilder = new ApiBuilder(); const api = await apiBuilder.getAuthenticatedApi(keycloak); const customers = await api.getProducerCustomers({producerId: +producer.id}) diff --git a/frontend/app/src/domains/dashboard/components/DashboardAccount.tsx b/frontend/app/src/domains/dashboard/components/DashboardAccount.tsx index d4a6aa4..dea3dfc 100644 --- a/frontend/app/src/domains/dashboard/components/DashboardAccount.tsx +++ b/frontend/app/src/domains/dashboard/components/DashboardAccount.tsx @@ -1,9 +1,7 @@ import React, { useEffect, useState } from 'react' import { Button, Typography } from "@mui/material" -import Producer from '@viandeendirect/api/dist/models/Producer.js' -import { ApiInvoker } from '../../../api/ApiInvoker.ts' +import { Producer } from '@viandeendirect/api/dist/models/Producer.js' import { useKeycloak } from '@react-keycloak/web' -import { AuthenticationService } from '../../../authentication/service/AuthenticationService.ts' import { ProducerService } from '../../commons/service/ProducerService.ts' @@ -14,7 +12,7 @@ function DashboardAccount() { const [producer, setProducer] = useState() useEffect(() => { - producerService.asyncLoadProducer().then(loadedProducer => setProducer(loadedProducer)) + producerService.loadProducer().then(loadedProducer => setProducer(loadedProducer)) }, [keycloak]) diff --git a/frontend/app/src/domains/dashboard/components/DashboardProductions.tsx b/frontend/app/src/domains/dashboard/components/DashboardProductions.tsx index 71b8e0f..655b64a 100644 --- a/frontend/app/src/domains/dashboard/components/DashboardProductions.tsx +++ b/frontend/app/src/domains/dashboard/components/DashboardProductions.tsx @@ -1,7 +1,6 @@ import React, { useEffect, useState } from 'react' import { Button, Typography } from "@mui/material" import Producer from '@viandeendirect/api/dist/models/Producer.js' -import { ApiInvoker } from '../../../api/ApiInvoker.ts' import { useKeycloak } from '@react-keycloak/web' import { AuthenticationService } from '../../../authentication/service/AuthenticationService.ts' diff --git a/frontend/app/src/domains/dashboard/components/DashboardSales.tsx b/frontend/app/src/domains/dashboard/components/DashboardSales.tsx index 379b770..dccf8ad 100644 --- a/frontend/app/src/domains/dashboard/components/DashboardSales.tsx +++ b/frontend/app/src/domains/dashboard/components/DashboardSales.tsx @@ -1,16 +1,10 @@ import React, { useEffect, useState } from 'react' import { Button, Typography } from "@mui/material" -import Producer from '@viandeendirect/api/dist/models/Producer.js' -import { ApiInvoker } from '../../../api/ApiInvoker.ts' -import { useKeycloak } from '@react-keycloak/web' -import { AuthenticationService } from '../../../authentication/service/AuthenticationService.ts' -function DashboardSales() { +export default function DashboardSales() { return <>
Mes prochaines ventes
} - -export default DashboardSales \ No newline at end of file diff --git a/frontend/app/src/domains/producer/views/ProducerAccountView.tsx b/frontend/app/src/domains/producer/views/ProducerAccountView.tsx index 16a5d33..8c13b3c 100644 --- a/frontend/app/src/domains/producer/views/ProducerAccountView.tsx +++ b/frontend/app/src/domains/producer/views/ProducerAccountView.tsx @@ -68,7 +68,7 @@ export default function ProducerAccountView() { export async function loadProducerAccountViewData(keycloak) { const producerService = new ProducerService(keycloak) - const producer: Producer = await producerService.asyncLoadProducer() + const producer: Producer = await producerService.loadProducer() const apiBuilder = new ApiBuilder(); const api = await apiBuilder.getAuthenticatedApi(keycloak); if (producer.stripeAccount) { diff --git a/frontend/app/src/domains/production/components/BeefProductionCustomerCard.tsx b/frontend/app/src/domains/production/components/BeefProductionCustomerCard.tsx index c08ddce..b44a609 100644 --- a/frontend/app/src/domains/production/components/BeefProductionCustomerCard.tsx +++ b/frontend/app/src/domains/production/components/BeefProductionCustomerCard.tsx @@ -61,7 +61,7 @@ export default function BeefProductionCustomerCard({production: production}) { function getLot(lot: PackageLot) { - return + return } } diff --git a/frontend/app/src/domains/sale/components/OrderSummary.tsx b/frontend/app/src/domains/sale/components/OrderSummary.tsx index 7e63431..aa1e2d7 100644 --- a/frontend/app/src/domains/sale/components/OrderSummary.tsx +++ b/frontend/app/src/domains/sale/components/OrderSummary.tsx @@ -2,8 +2,8 @@ import React from 'react' import { Typography } from '@mui/material' -import OrderItem from '@viandeendirect/api/dist/models/OrderItem' -import Order from '@viandeendirect/api/dist/models/Order' +import { OrderItem } from '@viandeendirect/api/dist/models/OrderItem' +import { Order } from '@viandeendirect/api/dist/models/Order' import { OrderStatusUtils } from '../../../enum/OrderStatus.ts' export default function OrderSummary({ order: order }) { @@ -20,7 +20,7 @@ export default function OrderSummary({ order: order }) {
Liste des articles
    - {order.items?.map(item =>
  • {itemDescription(item)}
  • )} + {order.items?.map(item =>
  • {itemDescription(item)}
  • )}
diff --git a/frontend/app/src/domains/sale/components/SaleCard.tsx b/frontend/app/src/domains/sale/components/SaleCard.tsx index c3f8d8b..53610a9 100644 --- a/frontend/app/src/domains/sale/components/SaleCard.tsx +++ b/frontend/app/src/domains/sale/components/SaleCard.tsx @@ -3,7 +3,6 @@ import React, { useEffect, useState } from 'react' import { Button, ButtonGroup, Card, CardActions, CardContent, Typography } from "@mui/material" import dayjs from 'dayjs' import SaleCardBeefProduction from './SaleCardBeefProduction.tsx'; -import { ApiInvoker } from '../../../api/ApiInvoker.ts'; import { useKeycloak } from '@react-keycloak/web'; import { useNavigate } from 'react-router-dom'; import { ApiBuilder } from '../../../api/ApiBuilder.ts'; @@ -13,7 +12,6 @@ import { Production } from '@viandeendirect/api/dist/models/Production' export default function SaleCard({sale: sale}) { - const apiInvoker = new ApiInvoker() const [orders, setOrders] = useState>([]) const [productions, setProductions] = useState>([]) const {keycloak} = useKeycloak() diff --git a/frontend/app/src/domains/sale/components/SaleCardBeefProduction.tsx b/frontend/app/src/domains/sale/components/SaleCardBeefProduction.tsx index 17bd567..1eae79c 100644 --- a/frontend/app/src/domains/sale/components/SaleCardBeefProduction.tsx +++ b/frontend/app/src/domains/sale/components/SaleCardBeefProduction.tsx @@ -2,19 +2,17 @@ import React from 'react' import { useEffect, useState } from 'react'; import { useKeycloak } from '@react-keycloak/web' import { Typography } from "@mui/material" -import { ApiInvoker } from '../../../api/ApiInvoker.ts' import { AnimalTypeUtils } from '../../../enum/AnimalType.ts'; import PieChart from '../../commons/components/PieChart.tsx' -import Production from '@viandeendirect/api/dist/models/BeefProduction' import './SaleCard.css' import { ApiBuilder } from '../../../api/ApiBuilder.ts'; +import { BeefProduction } from '@viandeendirect/api/dist/models/BeefProduction'; export default function SaleCardBeefProduction({production: production}) { const [beefProduction, setBeefProduction] = useState() const [productionPercentageSold, setProductionPercentageSold] = useState([]) const { keycloak } = useKeycloak() - const apiInvoker = new ApiInvoker() const apiBuilder = new ApiBuilder() useEffect(() => { diff --git a/frontend/app/src/domains/sale/components/SaleCustomerCard.tsx b/frontend/app/src/domains/sale/components/SaleCustomerCard.tsx index d9947f5..ecd9694 100644 --- a/frontend/app/src/domains/sale/components/SaleCustomerCard.tsx +++ b/frontend/app/src/domains/sale/components/SaleCustomerCard.tsx @@ -37,12 +37,12 @@ export default function SaleCustomerCard({ sale: sale }) { {sale.productions.map(getProductionContent)} - + function getProductionContent(production: Production) { - return + return } } \ No newline at end of file diff --git a/frontend/app/src/domains/sale/views/CustomerOrderForm.tsx b/frontend/app/src/domains/sale/views/CustomerOrderForm.tsx index 6dd68a4..29b64be 100644 --- a/frontend/app/src/domains/sale/views/CustomerOrderForm.tsx +++ b/frontend/app/src/domains/sale/views/CustomerOrderForm.tsx @@ -5,18 +5,20 @@ import { Button, Checkbox, Stepper, Step, StepLabel, StepContent, Typography, Bo import dayjs from 'dayjs' import { useKeycloak } from '@react-keycloak/web' -import { ApiInvoker } from '../../../api/ApiInvoker.ts' -import Order from "@viandeendirect/api/dist/models/Order" -import Customer from "@viandeendirect/api/dist/models/Customer" -import Production from "@viandeendirect/api/dist/models/Production" -import PackageLot from "@viandeendirect/api/dist/models/PackageLot" +import { Customer } from "@viandeendirect/api/dist/models/Customer" +import { Order } from "@viandeendirect/api/dist/models/Order" +import { Production } from "@viandeendirect/api/dist/models/Production" +import { PackageLot } from "@viandeendirect/api/dist/models/PackageLot" import PackageSelector from '../components/PackageSelector.tsx' import { AuthenticationService } from '../../../authentication/service/AuthenticationService.ts' import { useCookies } from 'react-cookie' +import { ApiBuilder } from '../../../api/ApiBuilder.ts' +import { useLoaderData, useNavigate } from 'react-router-dom' +import { Sale } from '@viandeendirect/api/dist/models/Sale' -export default function CustomerOrderForm({ sale: sale, returnCallback: returnCallback }) { +export default function CustomerOrderForm() { window.scroll(0,0) const SET_ITEMS_STEP = 1 @@ -25,10 +27,14 @@ export default function CustomerOrderForm({ sale: sale, returnCallback: returnCa const PAYMENT_STEP = 4 const { keycloak } = useKeycloak() - const apiInvoker = new ApiInvoker() + const navigate = useNavigate() + const apiBuilder = new ApiBuilder() const authenticationService = new AuthenticationService(keycloak) - - const [productions, setProductions] = useState>([]) + + const data = useLoaderData() + const productions: Array = data.productions + const sale: Sale = data.sale + const [order, setOrder] = useState({sale: sale, items: []}) const [completedSteps, setCompletedSteps] = useState>([]) const [activeStep, setActiveStep] = useState(SET_ITEMS_STEP) @@ -36,9 +42,7 @@ export default function CustomerOrderForm({ sale: sale, returnCallback: returnCa const [cookies, setCookie, removeCookie] = useCookies(['pendingOrder']); - useEffect(() => { - apiInvoker.callApiAnonymously(api => api.getSaleProductions, sale.id, setProductions) if (cookies.pendingOrder) { setOrder({...order, items: cookies.pendingOrder.items}) if(authenticationService.isAuthenticated()) { @@ -188,7 +192,7 @@ export default function CustomerOrderForm({ sale: sale, returnCallback: returnCa function cancel() { removeCookie('pendingOrder') - returnCallback(sale) + navigate('/') } function login() { @@ -203,8 +207,10 @@ export default function CustomerOrderForm({ sale: sale, returnCallback: returnCa keycloak.register() } - function payOrder() { - apiInvoker.callApiAuthenticatedly(keycloak, api => api.createOrderPayment, order, order => redirectToStripePayment(order.payment.paymentUrl), console.error) + async function payOrder() { + const api = await apiBuilder.getAuthenticatedApi(keycloak) + const orderWithPayment = await api.createOrderPayment({order: order}) + redirectToStripePayment(orderWithPayment.payment.paymentUrl) } function redirectToStripePayment(url: string) { @@ -213,3 +219,11 @@ export default function CustomerOrderForm({ sale: sale, returnCallback: returnCa removeCookie('pendingOrder') } } + +export async function loadCustomerOrderFormData(saleId: number) { + const apiBuilder = new ApiBuilder() + const api = await apiBuilder.getAnonymousApi() + const sale = await api.getSale({saleId: saleId}) + const productions = await api.getSaleProductions({saleId: saleId}) + return {productions: productions, sale: sale} +} diff --git a/frontend/app/src/domains/sale/views/ProducerOrderForm.tsx b/frontend/app/src/domains/sale/views/ProducerOrderForm.tsx index 4ff7600..d2ab591 100644 --- a/frontend/app/src/domains/sale/views/ProducerOrderForm.tsx +++ b/frontend/app/src/domains/sale/views/ProducerOrderForm.tsx @@ -136,7 +136,7 @@ class ProducerOrderFormData { export async function loadProducerOrderFormData(saleId: number, keycloakClient): Promise { const producerService = new ProducerService(keycloakClient) - const producer = await producerService.asyncLoadProducer() + const producer = await producerService.loadProducer() const apiBuilder = new ApiBuilder() const api = await apiBuilder.getAuthenticatedApi(keycloakClient) const productions = await api.getSaleProductions({saleId: saleId}) diff --git a/frontend/app/src/domains/sale/views/SaleForm.tsx b/frontend/app/src/domains/sale/views/SaleForm.tsx index d128daa..586f3e7 100644 --- a/frontend/app/src/domains/sale/views/SaleForm.tsx +++ b/frontend/app/src/domains/sale/views/SaleForm.tsx @@ -204,7 +204,7 @@ class SaleFormData { export async function loadSaleFormData(keycloakClient): Promise { const producerService = new ProducerService(keycloakClient) - const producer: Producer = await producerService.asyncLoadProducer() + const producer: Producer = await producerService.loadProducer() const apiBuilder = new ApiBuilder() const api = await apiBuilder.getAuthenticatedApi(keycloakClient) const addresses: Array
= await api.getAddresses() diff --git a/frontend/app/src/domains/sale/views/SalesList.tsx b/frontend/app/src/domains/sale/views/SalesList.tsx index a8a40ca..1b50caa 100644 --- a/frontend/app/src/domains/sale/views/SalesList.tsx +++ b/frontend/app/src/domains/sale/views/SalesList.tsx @@ -25,7 +25,7 @@ export default function SalesList() { export async function loadSalesListData(keycloak): Promise> { const producerService = new ProducerService(keycloak) - const producer: Producer = await producerService.asyncLoadProducer() + const producer: Producer = await producerService.loadProducer() const apiBuilder = new ApiBuilder() const api = await apiBuilder.getAuthenticatedApi(keycloak) const sales: Array = await api.getProducerSales({producerId: +producer.id}) diff --git a/frontend/app/src/domains/welcome/Welcome.tsx b/frontend/app/src/domains/welcome/Welcome.tsx index 5d54b06..a3b3ab0 100644 --- a/frontend/app/src/domains/welcome/Welcome.tsx +++ b/frontend/app/src/domains/welcome/Welcome.tsx @@ -24,7 +24,7 @@ export default function Welcome() { function getSaleCard(sale: Sale) { - return + return } } diff --git a/frontend/app/src/layouts/customer/CustomerLayout.tsx b/frontend/app/src/layouts/customer/CustomerLayout.tsx index 3e3f4e4..290caef 100644 --- a/frontend/app/src/layouts/customer/CustomerLayout.tsx +++ b/frontend/app/src/layouts/customer/CustomerLayout.tsx @@ -2,8 +2,6 @@ import React from 'react' import { AppBar, Box, Button, CssBaseline, IconButton, Toolbar, Typography } from '@mui/material' import { useKeycloak } from '@react-keycloak/web' -import { Customer } from '@viandeendirect/api/dist/models/Customer' - import { AuthenticationService } from '../../authentication/service/AuthenticationService.ts' import { Login, Logout } from '@mui/icons-material' @@ -13,22 +11,19 @@ import { ApiBuilder } from '../../api/ApiBuilder.ts' export default function CustomerLayout() { - const WELCOME = 'WELCOME' - const ORDER_CREATION = 'ORDER_CREATION' - const NOT_AUTHORIZED_FOR_PRODUCER = 'NOT_AUTHORIZED_FOR_PRODUCER' - const {keycloak} = useKeycloak() const authenticationService = new AuthenticationService(keycloak) - const navigate = useNavigate() - - const data = useLoaderData() - const loggedAsProducer = data.loggedAsProducer + const data = useLoaderData() + const authenticatedAsProducer = data.authenticatedAsProducer const customer = data.customer - - if (loggedAsProducer) { + + if (authenticatedAsProducer) { return } + if (authenticationService.isAuthenticated() && !customer.id) { + return + } function displayAuthenticationButton(): React.ReactNode { if (authenticationService.isAuthenticated()) { @@ -67,18 +62,12 @@ export default function CustomerLayout() { export async function loadCustomerLayoutData(keycloak) { const authenticationService = new AuthenticationService(keycloak) - if (!authenticationService.isAuthenticated()) { - return {loggedAsProducer: false, customer: undefined} - } - try { - const userEmail = authenticationService.getCurrentUserEmail() - const apiBuilder = new ApiBuilder() - const api = await apiBuilder.getAuthenticatedApi(keycloak) - const customer: Customer = await api.getCustomer({'email': userEmail}) - return {loggedAsProducer: false, customer: customer} - } catch (error) { - if(error.response.status === 409) { - return {loggedAsProducer: true, customer: undefined} - } + const authenticatedAsProducer = await authenticationService.isAuthenticatedAsProducer() + const apiBuilder = new ApiBuilder() + const api = await apiBuilder.getAuthenticatedApi(keycloak) + if(authenticationService.isAuthenticated()) { + const customer = await api.getCustomer({email: authenticationService.getCurrentUserEmail()}) + return {authenticatedAsProducer: authenticatedAsProducer, customer: customer} } + return {authenticatedAsProducer: authenticatedAsProducer, customer: undefined} } \ No newline at end of file diff --git a/frontend/app/src/layouts/customer/CustomerRouterFactory.tsx b/frontend/app/src/layouts/customer/CustomerRouterFactory.tsx index 8a7fcbe..c57e754 100644 --- a/frontend/app/src/layouts/customer/CustomerRouterFactory.tsx +++ b/frontend/app/src/layouts/customer/CustomerRouterFactory.tsx @@ -2,11 +2,12 @@ import React from "react"; import { createBrowserRouter, Navigate } from "react-router-dom"; -import PaymentLayout from "./PaymentLayout.tsx"; import CustomerLayout, { loadCustomerLayoutData } from "./CustomerLayout.tsx"; -import CustomerOrderForm from "../../domains/sale/views/CustomerOrderForm.tsx"; -import NotAuthorizedForProducers from "../../authentication/views/NotAuthorizedForProducers.tsx"; +import CustomerOrderForm, { loadCustomerOrderFormData } from "../../domains/sale/views/CustomerOrderForm.tsx"; +import CustomerCreationForm, { loadCustomerCreationFormData } from "../../domains/customer/views/CustomerCreationForm.tsx"; +import NotAuthorizedForProducers, { loadNotAuthorizedForProducerData } from "../../authentication/views/NotAuthorizedForProducers.tsx"; import Welcome, { loadWelcomeData } from "../../domains/welcome/Welcome.tsx"; +import PaymentLayout from "./PaymentLayout.tsx"; export class CustomerRouterFactory { getRouter(keycloak) { @@ -26,18 +27,25 @@ export class CustomerRouterFactory { loader: async () => loadWelcomeData() }, { - path: "/order/creation", - element: - }, - { - path: "/orders/:orderId/payment", - element: + path: "sale/:saleId/order/creation", + element: , + loader: async ({params}) => loadCustomerOrderFormData(+params.saleId) } ] }, + { + path: "/order/:orderId/payment", + element: + }, + { + path: '/customer/registration', + element: , + loader: () => loadCustomerCreationFormData(keycloak) + }, { path: "/unauthorized", - element: + element: , + loader: () => loadNotAuthorizedForProducerData(keycloak) } ]) } diff --git a/frontend/app/src/layouts/customer/PaymentLayout.tsx b/frontend/app/src/layouts/customer/PaymentLayout.tsx index 2a40e4d..6bfd0cc 100644 --- a/frontend/app/src/layouts/customer/PaymentLayout.tsx +++ b/frontend/app/src/layouts/customer/PaymentLayout.tsx @@ -1,6 +1,6 @@ import React from 'react' import { useEffect, useState } from 'react' -import { useParams } from 'react-router-dom'; +import { useLoaderData, useParams } from 'react-router-dom'; import { useKeycloak } from '@react-keycloak/web' import { ApiBuilder } from '../../api/ApiBuilder.ts' @@ -8,7 +8,7 @@ import { ApiBuilder } from '../../api/ApiBuilder.ts' import { AppBar, Box, Button, CircularProgress, CssBaseline, Toolbar, Typography } from '@mui/material' import OrderSummary from '../../domains/sale/components/OrderSummary.tsx' -import Order from '@viandeendirect/api/dist/models/Order.js'; +import { Order } from '@viandeendirect/api/dist/models/Order.js'; import { AuthenticationService } from '../../authentication/service/AuthenticationService.ts'; @@ -16,11 +16,10 @@ export default function PaymentLayout() { const { keycloak, initialized } = useKeycloak() const apiBuilder = new ApiBuilder() const authenticationService = new AuthenticationService(keycloak) - let { orderId } = useParams() - - const [order, setOrder] = useState() - const [orderAccessError, setOrderAccessError] = useState(false) + const { orderId } = useParams() const [forbiddenAccess, setForbiddenAccess] = useState(false) + const [order, setOrder] = useState({}) + const [orderAccessError, setOrderAccessError] = useState(false) let intervalId = 0 useEffect(() => { @@ -29,27 +28,21 @@ export default function PaymentLayout() { } }, [initialized]) - function loadOrder() { - apiBuilder.getAuthenticatedApi(keycloak).then(api => { - apiBuilder.invokeAuthenticatedApi(() => { - api.getOrder(orderId, (error, orderLoaded, response) => { - if (error) { - console.error(error) - if (response.statusCode === 403) { - setForbiddenAccess(true) - setOrderAccessError(true) - clearInterval(intervalId) - } - } else { - console.log('api.getOrder called successfully. Returned data: ' + orderLoaded) - if (orderLoaded.status !== 'PAYMENT_PENDING') { - clearInterval(intervalId) - } - setOrder(orderLoaded) - } - }) - }, keycloak) - }) + async function loadOrder() { + const api = await apiBuilder.getAuthenticatedApi(keycloak) + try { + const loadedOrder = await api.getOrder({orderId: +orderId}) + if (loadedOrder.status !== 'PAYMENT_PENDING') { + clearInterval(intervalId) + } + setOrder(loadedOrder) + } catch (error) { + console.error(error) + if (error.response.status === 403 || error.response.status === 401) { + setForbiddenAccess(true) + clearInterval(intervalId) + } + } } return ( @@ -75,18 +68,11 @@ export default function PaymentLayout() { ) function getContent() { - if (orderAccessError) { - if (forbiddenAccess) { - return <> - Désolé, vous n'êtes pas autorisé à consulter cette commande - - - } else { - return <> - Oups... une erreur s'est produite lors de l'accès à la commande {orderId} - - - } + if (forbiddenAccess) { + return <> + Désolé, vous n'êtes pas autorisé à consulter cette commande + + } if (authenticationService.isAuthenticated()) { return <> @@ -139,5 +125,4 @@ export default function PaymentLayout() { } } - } diff --git a/frontend/app/src/layouts/producer/AuthenticatedLayout.tsx b/frontend/app/src/layouts/producer/AuthenticatedLayout.tsx index 4a6e340..b9013d6 100644 --- a/frontend/app/src/layouts/producer/AuthenticatedLayout.tsx +++ b/frontend/app/src/layouts/producer/AuthenticatedLayout.tsx @@ -8,15 +8,16 @@ import {Close, Logout, Menu} from '@mui/icons-material' import SideMenu from './SideMenu.jsx' import { AuthenticationService } from '../../authentication/service/AuthenticationService.ts'; -import { Navigate, Outlet } from 'react-router-dom'; +import { Navigate, Outlet, useLoaderData } from 'react-router-dom'; export default function AuthenticatedLayout() { const { keycloak } = useKeycloak() const [sideMenuOpen, setSideMenuOpen] = useState(false) - const [unauthorized, setUnauthorized] = useState(false) const authenticationService = new AuthenticationService(keycloak) + const authenticatedAsCustomer: boolean = useLoaderData() + const sideMenuWidth = 240; const handleSideMenuToggle = () => { @@ -33,9 +34,6 @@ export default function AuthenticatedLayout() { function getAuthenticatedLayout() { - if(unauthorized) { - return - } return } - function getUnauthenticatedLayout() { - return - } - - return (<> - {authenticationService.isAuthenticated() ? getAuthenticatedLayout() : getUnauthenticatedLayout()} - - ) + if (!authenticationService.isAuthenticated()) { + return + } + if (authenticatedAsCustomer) { + return + } + return getAuthenticatedLayout() } + +export async function loadAuthenticatedLayoutData(keycloak): Promise { + const authenticationService = new AuthenticationService(keycloak) + return await authenticationService.isAuthenticatedAsCustomer() +} \ No newline at end of file diff --git a/frontend/app/src/layouts/producer/ProducerRouterFactory.tsx b/frontend/app/src/layouts/producer/ProducerRouterFactory.tsx index db27be7..41c0523 100644 --- a/frontend/app/src/layouts/producer/ProducerRouterFactory.tsx +++ b/frontend/app/src/layouts/producer/ProducerRouterFactory.tsx @@ -1,12 +1,12 @@ import React from "react"; import { createBrowserRouter, Navigate } from "react-router-dom"; -import AuthenticatedLayout from "./AuthenticatedLayout.tsx"; +import AuthenticatedLayout, { loadAuthenticatedLayoutData } from "./AuthenticatedLayout.tsx"; import CustomerController from "../../domains/customer/CustomerController.tsx"; import ProducerAccountView, { loadProducerAccountViewData } from "../../domains/producer/views/ProducerAccountView.tsx"; import Dashboard from "../../domains/dashboard/views/Dashboard.tsx"; import AnonymousLayout from "./AnonymousLayout.tsx"; -import NotAuthorizedForCustomers from "../../authentication/views/NotAuthorizedForCustomers.tsx"; +import NotAuthorizedForCustomers, { loadNotAuthorizedForCustomerData } from "../../authentication/views/NotAuthorizedForCustomers.tsx"; import BeefProductionView, { loadBeefProductionViewData } from "../../domains/production/views/beefProduction/BeefProductionView.tsx"; import BeefProductionCreator, { loadBeefProductionCreatorData } from "../../domains/production/views/beefProduction/BeefProductionCreator.tsx"; import ProductionsList, { loadProductionListData } from "../../domains/production/views/ProductionsList.tsx"; @@ -23,6 +23,7 @@ export class ProducerRouterFactory { { path: "/", element: , + loader: async () => loadAuthenticatedLayoutData(keycloak), children: [ { index: true, @@ -75,12 +76,12 @@ export class ProducerRouterFactory { { path: '/customers', element: , - loader: async ({params}) => loadCustomersListData(keycloak) + loader: async () => loadCustomersListData(keycloak) }, { path: '/account', element: , - loader: async ({params}) => loadProducerAccountViewData(keycloak) + loader: async () => loadProducerAccountViewData(keycloak) } ] }, @@ -90,7 +91,8 @@ export class ProducerRouterFactory { }, { path: '/unauthorized', - element: + element: , + loader: async () => loadNotAuthorizedForCustomerData(keycloak) } ])