From 8d2b5b14e09994f39d781a8c503883410200a5d5 Mon Sep 17 00:00:00 2001 From: joana Date: Wed, 20 Dec 2023 12:25:40 +0100 Subject: [PATCH 01/14] =?UTF-8?q?=F0=9F=9A=A7=20Installations=20Context?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: javikalsan --- frontend/src/App.jsx | 7 ++- .../src/components/InstallationProvider.jsx | 56 +++++++++++++++++++ .../pages/DetailInstallationPage/index.jsx | 15 +++-- 3 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 frontend/src/components/InstallationProvider.jsx diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 66f184d0..26a6f7ad 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -26,6 +26,7 @@ import InstallationsPage from './pages/InstallationsPage' import DetailInstallationPage from './pages/DetailInstallationPage' import InvoicesPage from './pages/InvoicesPage' import ProductionPage from './pages/ProductionPage' +import InstallationProvider from './components/InstallationProvider' const routes = [ { @@ -77,7 +78,11 @@ const routes = [ }, { path: '/installation/:contract_number', - element: , + element: ( + + + + ), }, { path: '/invoices', diff --git a/frontend/src/components/InstallationProvider.jsx b/frontend/src/components/InstallationProvider.jsx new file mode 100644 index 00000000..2a501c95 --- /dev/null +++ b/frontend/src/components/InstallationProvider.jsx @@ -0,0 +1,56 @@ +import React from 'react' +import { useAuth } from './AuthProvider' +import ovapi from '../services/ovapi' + +const InstallationContext = React.createContext() + +export default function InstallationProvider({ children }) { + // const [installations, setInstallations] = React.useState([]) + const { currentUser } = useAuth() + + //const closeDialog = () => { + // setDialogs((dialogs) => { + // const latestDialog = dialogs.pop() + // if (!latestDialog) return dialogs + // if (latestDialog.onClose) latestDialog.onClose() + // return [...dialogs].concat({ ...latestDialog, open: false }) + // }) + //} + + + // const reloadUser = () => { + // ov.currentUser().then((user) => setCurrentUser(user)) + // } + + const getInstallations = () => { + return ovapi.installations(currentUser) + .then((data) => { + // setInstallations(data); + // setLoading(false); + console.log(data); + return data; + }) + .catch((error) => { + console.error(error); + // setLoading(false); + // throw error; + }); + }; + + + // const getInstallations = () => { + // return [1,2,3]// Use the data here or perform additional actions + // }; + + + + const contextValue = getInstallations() + + return ( + + {children} + + ) +} + +export const useInstallationContext = () => React.useContext(InstallationContext) diff --git a/frontend/src/pages/DetailInstallationPage/index.jsx b/frontend/src/pages/DetailInstallationPage/index.jsx index c95806de..2817e475 100644 --- a/frontend/src/pages/DetailInstallationPage/index.jsx +++ b/frontend/src/pages/DetailInstallationPage/index.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' +import React, { useEffect, useState, useContext } from 'react' import { useParams } from 'react-router-dom' import { useTranslation } from 'react-i18next' import Container from '@mui/material/Container' @@ -15,6 +15,7 @@ import { installationFields } from './detailInstallationData' import transformContractDetails, { transformInstallationDetails, } from './detailInstallationData' +import { useInstallationContext } from '../../components/InstallationProvider' export default function DetailInstallationPage(params) { const { contract_number } = useParams() @@ -22,6 +23,7 @@ export default function DetailInstallationPage(params) { const [installationDetail, setInstallationDetail] = useState(undefined) const [contractDetail, setContractDetail] = useState(undefined) const [error, setError] = useState(false) + const data = useInstallationContext() useEffect(() => { getDetailInstallation() @@ -31,11 +33,9 @@ export default function DetailInstallationPage(params) { setError(false) setInstallationDetail(undefined) setContractDetail(undefined) - var result - try { - result = await ovapi.installationDetails(contract_number) - } catch (e) { - setError(e) + const result = await ovapi.installationDetails(contract_number) + if (!result) { + setError(true) return } const installationData = transformInstallationDetails(result?.installation_details) @@ -53,8 +53,7 @@ export default function DetailInstallationPage(params) { {error ? ( From a69082765be458500b8f7d27a7fa0fb639940497 Mon Sep 17 00:00:00 2001 From: javikalsan <1070397+javikalsan@users.noreply.github.com> Date: Wed, 20 Dec 2023 17:07:41 +0100 Subject: [PATCH 02/14] =?UTF-8?q?=E2=9C=A8=20Compute=20navigation=20inform?= =?UTF-8?q?ation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add tests - Add production code - Adapt navigation buttons component --- frontend/src/components/NavigationButtons.jsx | 17 ++-- .../detailInstallationData.js | 26 ++++++- .../detailInstallationData.test.js | 78 ++++++++++++++++++- .../pages/DetailInstallationPage/index.jsx | 35 +++++++-- 4 files changed, 141 insertions(+), 15 deletions(-) diff --git a/frontend/src/components/NavigationButtons.jsx b/frontend/src/components/NavigationButtons.jsx index fc6e3e3e..8e52f05e 100644 --- a/frontend/src/components/NavigationButtons.jsx +++ b/frontend/src/components/NavigationButtons.jsx @@ -19,6 +19,7 @@ const StyledButton = styled(Button)(({ theme }) => ({ const NavigationButtons = (props) => { const { toBefore, toNext, toReturn, returnIcon } = props + return ( { }} > - - - - - - + {toBefore && ( + + + + )} + {toNext && ( + + + + )} {returnIcon} diff --git a/frontend/src/pages/DetailInstallationPage/detailInstallationData.js b/frontend/src/pages/DetailInstallationPage/detailInstallationData.js index 6cb42549..809c948f 100644 --- a/frontend/src/pages/DetailInstallationPage/detailInstallationData.js +++ b/frontend/src/pages/DetailInstallationPage/detailInstallationData.js @@ -26,6 +26,7 @@ export const contractFields = [ 'discharge_date', 'status', ] + export function transformInstallationDetails(data) { const t = i18n.t const productionTecnologyOptions = { @@ -39,7 +40,7 @@ export function transformInstallationDetails(data) { technology: format.enumeration(data.technology, productionTecnologyOptions), } } -export default function transformContractDetails(contract) { +function transformContractDetails(contract) { const t = i18n.t const billingModeOptions = { index: t('CONTRACT_DETAIL.BILLING_MODE_INDEX'), @@ -88,3 +89,26 @@ export default function transformContractDetails(contract) { return contract } + +function computeNavigationInfo(installations, currentInstallationContractNumber) { + if (installations.length < 2) { + return {} + } + + // Find the index of the current installation + const currentIndex = installations.findIndex( + (installation) => installation.contract_number === currentInstallationContractNumber, + ) + + // Determine the index of the previous and next installations + const previousIndex = currentIndex > 0 ? currentIndex - 1 : installations.length - 1 + const nextIndex = currentIndex < installations.length - 1 ? currentIndex + 1 : 0 + + // Extract the contract numbers for the previous and next installations + const before = installations[previousIndex].contract_number + const next = installations[nextIndex].contract_number + + return { before, next } +} + +export { transformContractDetails, computeNavigationInfo } diff --git a/frontend/src/pages/DetailInstallationPage/detailInstallationData.test.js b/frontend/src/pages/DetailInstallationPage/detailInstallationData.test.js index d72d7080..69065d06 100644 --- a/frontend/src/pages/DetailInstallationPage/detailInstallationData.test.js +++ b/frontend/src/pages/DetailInstallationPage/detailInstallationData.test.js @@ -1,8 +1,10 @@ import { describe, expect, it } from 'vitest' import i18n from '../../i18n/i18n' -import transformContractDetails, { +import { + transformContractDetails, transformInstallationDetails, + computeNavigationInfo, } from './detailInstallationData' describe('transformContractDetails', () => { @@ -138,3 +140,77 @@ describe('transformInstallationDetails', () => { expect(result['rated_power']).toEqual('11 kW') }) }) + +describe('computeNavigationInfo', () => { + it('Returns empty when installations length is smaller than 2', () => { + const installations = [ + { + contract_number: 'a_contract_number', + installation_name: 'an_installation_name', + }, + ] + const currentInstallationContractNumber = 'a_contract_number' + + const result = computeNavigationInfo(installations, currentInstallationContractNumber) + + expect(result).toEqual({}) + }) + + describe('Having the installation 2 elements', () => { + it('Returns the not current element as before and next navigation values', () => { + const installations = [ + { + contract_number: 'a_contract_number', + installation_name: 'an_installation_name', + }, + { + contract_number: 'another_contract_number', + installation_name: 'another_installation_name', + }, + ] + const currentInstallationContractNumber = 'a_contract_number' + + const result = computeNavigationInfo( + installations, + currentInstallationContractNumber, + ) + + const expected_result = { + before: 'another_contract_number', + next: 'another_contract_number', + } + expect(result).toEqual(expected_result) + }) + }) + + describe('Having the installation more than 2 elements', () => { + it('Returns the not current element as before and next navigation values', () => { + const installations = [ + { + contract_number: 'a_contract_number', + installation_name: 'an_installation_name', + }, + { + contract_number: 'another_contract_number', + installation_name: 'another_installation_name', + }, + { + contract_number: 'yet_another_contract_number', + installation_name: 'yet_another_installation_name', + }, + ] + const currentInstallationContractNumber = 'another_contract_number' + + const result = computeNavigationInfo( + installations, + currentInstallationContractNumber, + ) + + const expected_result = { + before: 'a_contract_number', + next: 'yet_another_contract_number', + } + expect(result).toEqual(expected_result) + }) + }) +}) diff --git a/frontend/src/pages/DetailInstallationPage/index.jsx b/frontend/src/pages/DetailInstallationPage/index.jsx index 2817e475..434303ab 100644 --- a/frontend/src/pages/DetailInstallationPage/index.jsx +++ b/frontend/src/pages/DetailInstallationPage/index.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState, useContext } from 'react' +import React, { useEffect, useState } from 'react' import { useParams } from 'react-router-dom' import { useTranslation } from 'react-i18next' import Container from '@mui/material/Container' @@ -13,9 +13,12 @@ import NavigationButtons from '../../components/NavigationButtons' import { contractFields } from './detailInstallationData' import { installationFields } from './detailInstallationData' import transformContractDetails, { + transformContractDetails, transformInstallationDetails, + computeNavigationInfo, } from './detailInstallationData' -import { useInstallationContext } from '../../components/InstallationProvider' +import { useAuth } from '../../components/AuthProvider' +// import { useInstallationContext } from '../../components/InstallationProvider' export default function DetailInstallationPage(params) { const { contract_number } = useParams() @@ -23,11 +26,16 @@ export default function DetailInstallationPage(params) { const [installationDetail, setInstallationDetail] = useState(undefined) const [contractDetail, setContractDetail] = useState(undefined) const [error, setError] = useState(false) - const data = useInstallationContext() + const [rows, setRows] = React.useState([]) + const [navigationBeforeUrl, setNavigationBeforeUrl] = React.useState(undefined) + const [navigationNextUrl, setNavigationNextUrl] = React.useState(undefined) + // const data = useInstallationContext() + const { currentUser } = useAuth() useEffect(() => { getDetailInstallation() - }, [contract_number]) + getNavigationInfo() + }, [contract_number, currentUser]) async function getDetailInstallation() { setError(false) @@ -44,6 +52,20 @@ export default function DetailInstallationPage(params) { setContractDetail(contractData) } + async function getNavigationInfo() { + setError(false) + try { + const installations = await ovapi.installations(currentUser) + const navigationInfo = computeNavigationInfo(installations, installationDetail?.contract_number) + const navigationBeforeUrl = navigationInfo.before ? `/installation/${navigationInfo.before}` : undefined + const navigationNextUrl = navigationInfo.next ? `/installation/${navigationInfo.next}` : undefined + setNavigationBeforeUrl(navigationBeforeUrl) + setNavigationNextUrl(navigationNextUrl) + } catch (error) { + setError(error) + } + } + return !error && (!installationDetail || !contractDetail) ? ( ) : ( @@ -59,10 +81,9 @@ export default function DetailInstallationPage(params) { /> ) : ( <> - {/* TODO: get the before and after user installations */} } /> From 79fcd20d4058316ee668f71a7abc15bbe57294e2 Mon Sep 17 00:00:00 2001 From: javikalsan <1070397+javikalsan@users.noreply.github.com> Date: Wed, 20 Dec 2023 17:09:50 +0100 Subject: [PATCH 03/14] =?UTF-8?q?=F0=9F=A7=B9=20Context=20proposal=20clean?= =?UTF-8?q?up?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/InstallationProvider.jsx | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/frontend/src/components/InstallationProvider.jsx b/frontend/src/components/InstallationProvider.jsx index 2a501c95..391836a1 100644 --- a/frontend/src/components/InstallationProvider.jsx +++ b/frontend/src/components/InstallationProvider.jsx @@ -5,23 +5,8 @@ import ovapi from '../services/ovapi' const InstallationContext = React.createContext() export default function InstallationProvider({ children }) { - // const [installations, setInstallations] = React.useState([]) const { currentUser } = useAuth() - //const closeDialog = () => { - // setDialogs((dialogs) => { - // const latestDialog = dialogs.pop() - // if (!latestDialog) return dialogs - // if (latestDialog.onClose) latestDialog.onClose() - // return [...dialogs].concat({ ...latestDialog, open: false }) - // }) - //} - - - // const reloadUser = () => { - // ov.currentUser().then((user) => setCurrentUser(user)) - // } - const getInstallations = () => { return ovapi.installations(currentUser) .then((data) => { @@ -36,13 +21,6 @@ export default function InstallationProvider({ children }) { // throw error; }); }; - - - // const getInstallations = () => { - // return [1,2,3]// Use the data here or perform additional actions - // }; - - const contextValue = getInstallations() From ac2305b9e058de6824a8435e4997453b14a24705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Garc=C3=ADa=20Garz=C3=B3n?= Date: Fri, 22 Dec 2023 15:03:54 +0100 Subject: [PATCH 04/14] =?UTF-8?q?=F0=9F=90=9B=20dummy=20install=20detalls?= =?UTF-8?q?=20now=20keeps=20the=20contract=20number?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/datasources/dummy.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/datasources/dummy.py b/backend/datasources/dummy.py index 959c4a76..f1b39af7 100644 --- a/backend/datasources/dummy.py +++ b/backend/datasources/dummy.py @@ -209,7 +209,9 @@ def dummy_installation_details(username: str, contract_number: str) -> Installat code=contract_number, error=f"{contract_number} (Dummy error)", )) - return InstallationDetailsResult(**ns.load('frontend/src/data/dummyinstallationdetail.yaml')) + details = InstallationDetailsResult(**ns.load('frontend/src/data/dummyinstallationdetail.yaml')) + details.installation_details.contract_number = contract_number + return details invoice_pdf_exceptions = { e.__name__: e From 9af465a9d309688d4b8f6fcb00e624e9826216c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Garc=C3=ADa=20Garz=C3=B3n?= Date: Fri, 22 Dec 2023 15:22:34 +0100 Subject: [PATCH 05/14] =?UTF-8?q?=F0=9F=92=84=20navigation=20buttons=20ali?= =?UTF-8?q?gned=20with=20title?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - width was misspelled --- frontend/src/components/NavigationButtons.jsx | 3 ++- frontend/src/pages/DetailInstallationPage/index.jsx | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/NavigationButtons.jsx b/frontend/src/components/NavigationButtons.jsx index 8e52f05e..30e2a428 100644 --- a/frontend/src/components/NavigationButtons.jsx +++ b/frontend/src/components/NavigationButtons.jsx @@ -23,7 +23,8 @@ const NavigationButtons = (props) => { return ( {t('INSTALLATION_DETAIL.DETAILS_TITLE')} + } + /> {error ? ( ) : ( <> - } - /> Date: Fri, 22 Dec 2023 21:58:54 +0100 Subject: [PATCH 06/14] =?UTF-8?q?=F0=9F=A7=B9=20...{}=20and=20...undefined?= =?UTF-8?q?=20are=20equivalents?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit oxlint warns --- frontend/src/services/messages.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/services/messages.js b/frontend/src/services/messages.js index c9c7fd5e..340454cd 100644 --- a/frontend/src/services/messages.js +++ b/frontend/src/services/messages.js @@ -25,7 +25,7 @@ IMPORTANT: `subscribe()` returns a function to unsubscribe. Use it. const _subscribers = new Set() function _notify(message, level, extra) { - _subscribers.forEach((l) => l({ message, level, ...(extra || {}) })) + _subscribers.forEach((l) => l({ message, level, ...extra })) } function subscribe(subscriber) { From 3442de462652dbc5f7659d10c82fac0587263b97 Mon Sep 17 00:00:00 2001 From: javikalsan <1070397+javikalsan@users.noreply.github.com> Date: Sat, 23 Dec 2023 00:21:45 +0100 Subject: [PATCH 07/14] =?UTF-8?q?=E2=9C=A8=20Implement=20installation=20co?= =?UTF-8?q?ntext?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/InstallationProvider.jsx | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/frontend/src/components/InstallationProvider.jsx b/frontend/src/components/InstallationProvider.jsx index 391836a1..a9a07bd5 100644 --- a/frontend/src/components/InstallationProvider.jsx +++ b/frontend/src/components/InstallationProvider.jsx @@ -1,34 +1,36 @@ -import React from 'react' +import React, { useEffect, useState, useMemo } from 'react' import { useAuth } from './AuthProvider' import ovapi from '../services/ovapi' const InstallationContext = React.createContext() -export default function InstallationProvider({ children }) { +const InstallationContextProvider = ({ children }) => { const { currentUser } = useAuth() + const [installations, setInstallations] = useState(null) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + const memoizedCurrentUser = useMemo(() => currentUser, [currentUser]) - const getInstallations = () => { - return ovapi.installations(currentUser) - .then((data) => { - // setInstallations(data); - // setLoading(false); - console.log(data); - return data; - }) - .catch((error) => { - console.error(error); - // setLoading(false); - // throw error; - }); - }; + useEffect(() => { + const getInstallations = async () => { + try { + const installationsData = await ovapi.installations(memoizedCurrentUser) + setInstallations(installationsData) + } catch (error) { + setError(error) + } finally { + setLoading(false) + } + } - const contextValue = getInstallations() + getInstallations() + }, [memoizedCurrentUser]) - return ( - + return installations !== null ? ( + {children} - ) + ) : null } -export const useInstallationContext = () => React.useContext(InstallationContext) +export { InstallationContext, InstallationContextProvider } From 68436befa57a820abe70c0d679129d37c0520ab2 Mon Sep 17 00:00:00 2001 From: javikalsan <1070397+javikalsan@users.noreply.github.com> Date: Sat, 23 Dec 2023 00:23:22 +0100 Subject: [PATCH 08/14] =?UTF-8?q?=E2=9C=A8=20Use=20installation=20context?= =?UTF-8?q?=20on=20installation=20detail?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add trailing semicolons for better code readability and to avoid potential issues. --- .../pages/DetailInstallationPage/index.jsx | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/frontend/src/pages/DetailInstallationPage/index.jsx b/frontend/src/pages/DetailInstallationPage/index.jsx index a2f743c4..96891bde 100644 --- a/frontend/src/pages/DetailInstallationPage/index.jsx +++ b/frontend/src/pages/DetailInstallationPage/index.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' +import React, { useEffect, useState, useContext, useMemo } from 'react' import { useParams } from 'react-router-dom' import { useTranslation } from 'react-i18next' import Container from '@mui/material/Container' @@ -12,58 +12,58 @@ import ErrorSplash from '../../components/ErrorSplash' import NavigationButtons from '../../components/NavigationButtons' import { contractFields } from './detailInstallationData' import { installationFields } from './detailInstallationData' -import transformContractDetails, { +import { transformContractDetails, transformInstallationDetails, computeNavigationInfo, } from './detailInstallationData' -import { useAuth } from '../../components/AuthProvider' -// import { useInstallationContext } from '../../components/InstallationProvider' +import { InstallationContext } from '../../components/InstallationProvider' -export default function DetailInstallationPage(params) { +export default function DetailInstallationPage() { const { contract_number } = useParams() const { t } = useTranslation() const [installationDetail, setInstallationDetail] = useState(undefined) const [contractDetail, setContractDetail] = useState(undefined) const [error, setError] = useState(false) - const [rows, setRows] = React.useState([]) const [navigationBeforeUrl, setNavigationBeforeUrl] = React.useState(undefined) const [navigationNextUrl, setNavigationNextUrl] = React.useState(undefined) - // const data = useInstallationContext() - const { currentUser } = useAuth() + const { installations } = useContext(InstallationContext) + const memoizedInstallations = useMemo(() => installations, [installations]) useEffect(() => { getDetailInstallation() - getNavigationInfo() - }, [contract_number, currentUser]) + setNavigationInfo() + }, [contract_number, memoizedInstallations]) async function getDetailInstallation() { setError(false) setInstallationDetail(undefined) setContractDetail(undefined) - const result = await ovapi.installationDetails(contract_number) - if (!result) { + try { + const result = await ovapi.installationDetails(contract_number) + if (!result) { + setError(true) + return + } + setInstallationDetail(result?.installation_details) + const contractData = transformContractDetails(result?.contract_details) + setContractDetail(contractData) + } catch (error) { setError(true) - return } - const installationData = transformInstallationDetails(result?.installation_details) - setInstallationDetail(installationData) - const contractData = transformContractDetails(result?.contract_details) - setContractDetail(contractData) } - async function getNavigationInfo() { - setError(false) - try { - const installations = await ovapi.installations(currentUser) - const navigationInfo = computeNavigationInfo(installations, installationDetail?.contract_number) - const navigationBeforeUrl = navigationInfo.before ? `/installation/${navigationInfo.before}` : undefined - const navigationNextUrl = navigationInfo.next ? `/installation/${navigationInfo.next}` : undefined - setNavigationBeforeUrl(navigationBeforeUrl) - setNavigationNextUrl(navigationNextUrl) - } catch (error) { - setError(error) - } + function setNavigationInfo() { + const navigationInfo = computeNavigationInfo( + memoizedInstallations, + installationDetail?.contract_number, + ) + setNavigationBeforeUrl( + navigationInfo.before ? `/installation/${navigationInfo.before}` : undefined, + ) + setNavigationNextUrl( + navigationInfo.next ? `/installation/${navigationInfo.next}` : undefined, + ) } return !error && (!installationDetail || !contractDetail) ? ( From 38ce52ee52eaa3536b970b08d516cce7f249f888 Mon Sep 17 00:00:00 2001 From: javikalsan <1070397+javikalsan@users.noreply.github.com> Date: Sat, 23 Dec 2023 00:26:10 +0100 Subject: [PATCH 09/14] =?UTF-8?q?=E2=9C=A8=20Use=20installation=20context?= =?UTF-8?q?=20on=20installations=20list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add trailing semicolons for better code readability and to avoid potential issues. --- .../src/pages/InstallationsPage/index.jsx | 72 ++++++++----------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/frontend/src/pages/InstallationsPage/index.jsx b/frontend/src/pages/InstallationsPage/index.jsx index 9ccaa4f3..dfab949d 100644 --- a/frontend/src/pages/InstallationsPage/index.jsx +++ b/frontend/src/pages/InstallationsPage/index.jsx @@ -1,44 +1,31 @@ -import React from 'react' +import React, { useContext, useState, useEffect, useMemo } from 'react' import { useTranslation } from 'react-i18next' -import dummyData from '../../data/dummyinstallations.yaml' import Button from '@mui/material/Button' import TableCell from '@mui/material/TableCell' import TableRow from '@mui/material/TableRow' import Typography from '@mui/material/Typography' -import Box from '@mui/material/Box' import Container from '@mui/material/Container' import ChevronRightIcon from '@mui/icons-material/ChevronRight' import SolarPowerIcon from '@mui/icons-material/SolarPower' import { Link } from 'react-router-dom' import TableEditor from '../../components/TableEditor' -import { useAuth } from '../../components/AuthProvider' -import ovapi from '../../services/ovapi' import PageTitle from '../../components/PageTitle' import Loading from '../../components/Loading' import ErrorSplash from '../../components/ErrorSplash' +import { InstallationContext } from '../../components/InstallationProvider' export default function InstallationsPage(params) { const { t, i18n } = useTranslation() - const [isLoading, beLoading] = React.useState(true) - const [rows, setRows] = React.useState([]) - const [error, setError] = React.useState(false) - const { currentUser } = useAuth() + const [pageLoading, setPageLoading] = useState(true) + const { installations, error } = useContext(InstallationContext) + const memoizedInstallations = useMemo(() => installations, [installations]) - React.useEffect(() => { - getInstallations() - }, [currentUser]) - - async function getInstallations() { - beLoading(true) - setRows([]) - setError(false) - try { - setRows(await ovapi.installations(currentUser)) - } catch (error) { - setError(error) + useEffect(() => { + setPageLoading(true) + if (installations) { + setPageLoading(false) } - beLoading(false) - } + }, [installations]) const columns = [ { @@ -54,27 +41,28 @@ export default function InstallationsPage(params) { numeric: false, }, ] + const actions = [] const selectionActions = [] + const itemActions = [ { title: t('INSTALLATIONS.TOOLTIP_DETAILS'), - view: (contract) => { - return ( - - ) - }, + view: (contract) => ( + + ), }, ] - return isLoading ? ( + + return pageLoading ? ( ) : ( @@ -85,21 +73,21 @@ export default function InstallationsPage(params) { getInstallations()} + backlink="/installation" backtext={t('INSTALLATIONS.RELOAD')} /> ) : ( @@ -111,7 +99,7 @@ export default function InstallationsPage(params) { } - > + /> )} ) From b1aafb297ffbc7a80a2aea9687a682f995ade226 Mon Sep 17 00:00:00 2001 From: javikalsan <1070397+javikalsan@users.noreply.github.com> Date: Sat, 23 Dec 2023 00:27:03 +0100 Subject: [PATCH 10/14] =?UTF-8?q?=E2=9C=A8=20Make=20context=20available=20?= =?UTF-8?q?for=20specific=20children?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.jsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 26a6f7ad..90a6d165 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -26,7 +26,7 @@ import InstallationsPage from './pages/InstallationsPage' import DetailInstallationPage from './pages/DetailInstallationPage' import InvoicesPage from './pages/InvoicesPage' import ProductionPage from './pages/ProductionPage' -import InstallationProvider from './components/InstallationProvider' +import { InstallationContextProvider } from './components/InstallationProvider' const routes = [ { @@ -74,14 +74,18 @@ const routes = [ }, { path: '/installation', - element: , + element: ( + + + + ), }, { path: '/installation/:contract_number', element: ( - + - + ), }, { From 5283fd0c70479a6b9f067a90d6909136e91c3e84 Mon Sep 17 00:00:00 2001 From: javikalsan <1070397+javikalsan@users.noreply.github.com> Date: Sat, 23 Dec 2023 00:50:56 +0100 Subject: [PATCH 11/14] =?UTF-8?q?=F0=9F=90=9B=20Undo=20setNavigationInfo?= =?UTF-8?q?=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/DetailInstallationPage/index.jsx | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/frontend/src/pages/DetailInstallationPage/index.jsx b/frontend/src/pages/DetailInstallationPage/index.jsx index 96891bde..b4eacb82 100644 --- a/frontend/src/pages/DetailInstallationPage/index.jsx +++ b/frontend/src/pages/DetailInstallationPage/index.jsx @@ -25,14 +25,21 @@ export default function DetailInstallationPage() { const [installationDetail, setInstallationDetail] = useState(undefined) const [contractDetail, setContractDetail] = useState(undefined) const [error, setError] = useState(false) - const [navigationBeforeUrl, setNavigationBeforeUrl] = React.useState(undefined) - const [navigationNextUrl, setNavigationNextUrl] = React.useState(undefined) const { installations } = useContext(InstallationContext) const memoizedInstallations = useMemo(() => installations, [installations]) + const navigationInfo = computeNavigationInfo( + memoizedInstallations, + installationDetail?.contract_number, + ) + const navigationBeforeUrl = navigationInfo.before + ? `/installation/${navigationInfo.before}` + : undefined + const navigationNextUrl = navigationInfo.next + ? `/installation/${navigationInfo.next}` + : undefined useEffect(() => { getDetailInstallation() - setNavigationInfo() }, [contract_number, memoizedInstallations]) async function getDetailInstallation() { @@ -53,19 +60,6 @@ export default function DetailInstallationPage() { } } - function setNavigationInfo() { - const navigationInfo = computeNavigationInfo( - memoizedInstallations, - installationDetail?.contract_number, - ) - setNavigationBeforeUrl( - navigationInfo.before ? `/installation/${navigationInfo.before}` : undefined, - ) - setNavigationNextUrl( - navigationInfo.next ? `/installation/${navigationInfo.next}` : undefined, - ) - } - return !error && (!installationDetail || !contractDetail) ? ( ) : ( From 7dd39ad59317ae20fba0413ec734281a156ee088 Mon Sep 17 00:00:00 2001 From: javikalsan <1070397+javikalsan@users.noreply.github.com> Date: Tue, 26 Dec 2023 23:32:44 +0100 Subject: [PATCH 12/14] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Memoize=20values=20t?= =?UTF-8?q?o=20prevent=20unnecessary=20re-renders?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/InstallationProvider.jsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/InstallationProvider.jsx b/frontend/src/components/InstallationProvider.jsx index a9a07bd5..d6602319 100644 --- a/frontend/src/components/InstallationProvider.jsx +++ b/frontend/src/components/InstallationProvider.jsx @@ -1,4 +1,5 @@ import React, { useEffect, useState, useMemo } from 'react' +import PropTypes from 'prop-types' import { useAuth } from './AuthProvider' import ovapi from '../services/ovapi' @@ -25,12 +26,23 @@ const InstallationContextProvider = ({ children }) => { getInstallations() }, [memoizedCurrentUser]) + getInstallations() + }, [memoizedCurrentUser]) + + const contextValue = useMemo( + () => ({ installations, loading, error }), + [installations, loading, error], + ) return installations !== null ? ( - + {children} ) : null } +InstallationContextProvider.propTypes = { + children: PropTypes.node.isRequired, +} + export { InstallationContext, InstallationContextProvider } From 6d9325af6cc2c9829e76d9c880260f82be437dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Garc=C3=ADa=20Garz=C3=B3n?= Date: Fri, 29 Dec 2023 09:32:58 +0100 Subject: [PATCH 13/14] =?UTF-8?q?=F0=9F=8E=A8=20using=20outlets=20and=20hi?= =?UTF-8?q?erarchy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.jsx | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 90a6d165..7ad6a5d0 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -76,17 +76,19 @@ const routes = [ path: '/installation', element: ( - - - ), - }, - { - path: '/installation/:contract_number', - element: ( - - + ), + children: [ + { + path: '', + element: , + }, + { + path: ':contract_number', + element: , + }, + ], }, { path: '/invoices', From 5430ee9c4dd1ed88d121a243361f1d27b27214ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Garc=C3=ADa=20Garz=C3=B3n?= Date: Fri, 29 Dec 2023 10:21:42 +0100 Subject: [PATCH 14/14] =?UTF-8?q?=F0=9F=90=9B=20alignText=20->=20textAlign?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/BreakPointIndicator.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/BreakPointIndicator.jsx b/frontend/src/components/BreakPointIndicator.jsx index 6bbd6051..0e3d118f 100644 --- a/frontend/src/components/BreakPointIndicator.jsx +++ b/frontend/src/components/BreakPointIndicator.jsx @@ -16,7 +16,7 @@ export default function BreakPointIndicator() { minWidth: '4rem', padding: '0.5rem 0.9rem', borderRadius: '5px', - alignText: 'center', + textAlign: 'center', color: 'black', backgroundColor: { xs: '#d99a',