From 4c691b352d61352410aebb32de517eee61311e52 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Wed, 15 May 2024 14:47:29 +0300 Subject: [PATCH 1/8] Use usecontext for the rerender of credentials when we receive a new one --- src/App.js | 60 +++++++-------- src/components/HandlerNotification.js | 49 ++++--------- src/context/CredentialsContext.js | 41 +++++++++++ src/pages/Home/Home.js | 101 +++++++++++--------------- 4 files changed, 128 insertions(+), 123 deletions(-) create mode 100644 src/context/CredentialsContext.js diff --git a/src/App.js b/src/App.js index b85e1c1fc..2736a9bc6 100644 --- a/src/App.js +++ b/src/App.js @@ -6,6 +6,7 @@ import Spinner from './components/Spinner'; // Make sure this Spinner component import { I18nextProvider } from 'react-i18next'; import i18n from './i18n'; +import { CredentialsProvider } from './context/CredentialsContext'; import useCheckURL from './components/useCheckURL'; // Import the custom hook import handleServerMessagesGuard from './hoc/handleServerMessagesGuard'; import HandlerNotification from './components/HandlerNotification'; @@ -81,35 +82,36 @@ function App() { }; return ( - - - - }> - - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - {showSelectCredentialsPopup && - - } - {showPinInputPopup && - - } - {showMessagePopup && - setMessagePopup(false)} /> - } - - - + + + + }> + + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + {showSelectCredentialsPopup && + + } + {showPinInputPopup && + + } + {showMessagePopup && + setMessagePopup(false)} /> + } + + + + ); } diff --git a/src/components/HandlerNotification.js b/src/components/HandlerNotification.js index 62ec5596b..c43814e88 100644 --- a/src/components/HandlerNotification.js +++ b/src/components/HandlerNotification.js @@ -1,8 +1,9 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useContext } from 'react'; import toast, { Toaster } from 'react-hot-toast'; import { onMessageListener } from '../firebase'; import { AiOutlineClose } from 'react-icons/ai'; import logo from '../assets/images/logo.png'; +import CredentialsContext from '../context/CredentialsContext'; const ToastDisplay = ({ id, notification }) => { return ( @@ -31,14 +32,10 @@ const ToastDisplay = ({ id, notification }) => { const HandlerNotification = ({ children }) => { const [notification, setNotification] = useState({ title: '', body: '' }); - const [isMessageReceived, setMessageReceived] = useState(null); + const { refreshCredentials } = useContext(CredentialsContext); const showToast = () => - toast((t) => , { - onClick: () => { - window.location.href = '/'; - }, - }); + toast((t) => ); useEffect(() => { if (notification?.title) { @@ -47,47 +44,31 @@ const HandlerNotification = ({ children }) => { }, [notification]); useEffect(() => { - let messageReceived = false; - const unregisterMessageListener = onMessageListener() + const messageListener = onMessageListener() .then((payload) => { - // Process the received message setNotification({ title: payload?.notification?.title, body: payload?.notification?.body, }); - setMessageReceived(true); // Message has been received + refreshCredentials(); }) .catch((err) => { console.log('Failed to receive message:', err); - setMessageReceived(false); // Set isMessageReceived to false if there's an error }); - return () => { - if (!messageReceived) { - setMessageReceived(false); // Set isMessageReceived to false if no message was received before unmount + if (messageListener && typeof messageListener === 'function') { + messageListener(); } }; - }, []); - - // Render just children when waiting for message reception - if (isMessageReceived === null || isMessageReceived === false) { - // Render children when waiting for a message - return ( -
- {children} -
- ); - } else { - // Render Toaster and children when a message is received - return ( -
- - {children} -
- ); - } + }, [refreshCredentials]); + return ( +
+ + {children} +
+ ); }; export default HandlerNotification; diff --git a/src/context/CredentialsContext.js b/src/context/CredentialsContext.js new file mode 100644 index 000000000..1e125f1ce --- /dev/null +++ b/src/context/CredentialsContext.js @@ -0,0 +1,41 @@ +import React, { createContext, useState, useEffect } from 'react'; +import { useApi } from '../api'; +import { extractCredentialFriendlyName } from '../functions/extractCredentialFriendlyName'; + +const CredentialsContext = createContext(); + +export const CredentialsProvider = ({ children }) => { + const api = useApi(); + const [vcEntityList, setVcEntityList] = useState([]); + + useEffect(() => { + const getData = async () => { + const response = await api.get('/storage/vc'); + const vcEntityList = await Promise.all(response.data.vc_list.map(async vcEntity => { + const name = await extractCredentialFriendlyName(vcEntity.credential); + return { ...vcEntity, friendlyName: name }; + })); + vcEntityList.sort((vcA, vcB) => vcB.issuanceDate - vcA.issuanceDate); + setVcEntityList(vcEntityList); + }; + getData(); + }, [api]); + + const refreshCredentials = async () => { + const response = await api.get('/storage/vc'); + const vcEntityList = await Promise.all(response.data.vc_list.map(async vcEntity => { + const name = await extractCredentialFriendlyName(vcEntity.credential); + return { ...vcEntity, friendlyName: name }; + })); + vcEntityList.sort((vcA, vcB) => vcB.issuanceDate - vcA.issuanceDate); + setVcEntityList(vcEntityList); + }; + + return ( + + {children} + + ); +}; + +export default CredentialsContext; diff --git a/src/pages/Home/Home.js b/src/pages/Home/Home.js index 35c049921..3c95dcbee 100644 --- a/src/pages/Home/Home.js +++ b/src/pages/Home/Home.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useRef } from 'react'; +import React, { useState, useEffect, useRef, useContext } from 'react'; import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; @@ -20,11 +20,11 @@ import FullscreenPopup from '../../components/Popups/FullscreenImg'; import DeletePopup from '../../components/Popups/DeletePopup'; import { CredentialImage } from '../../components/Credentials/CredentialImage'; import QRButton from '../../components/Buttons/QRButton'; -import { extractCredentialFriendlyName } from "../../functions/extractCredentialFriendlyName"; +import CredentialsContext from '../../context/CredentialsContext'; const Home = () => { const api = useApi(); - const [vcEntityList, setVcEntityList] = useState([]); + const { vcEntityList, refreshCredentials } = useContext(CredentialsContext); const [isSmallScreen, setIsSmallScreen] = useState(window.innerWidth < 768); const [currentSlide, setCurrentSlide] = useState(1); const [showFullscreenImgPopup, setShowFullscreenImgPopup] = useState(false); @@ -63,19 +63,6 @@ const Home = () => { }; }, []); - useEffect(() => { - const getData = async () => { - const response = await api.get('/storage/vc'); - const vcEntityList = await Promise.all(response.data.vc_list.map(async vcEntity => { - const name = await extractCredentialFriendlyName(vcEntity.credential); - return { ...vcEntity, friendlyName: name }; - })); - vcEntityList.sort((vcA, vcB) => vcB.issuanceDate - vcA.issuanceDate); - setVcEntityList(vcEntityList); - }; - getData(); - }, [api]); - const handleAddCredential = () => { navigate('/add'); }; @@ -99,12 +86,12 @@ const Home = () => { setLoading(true); try { await api.del(`/storage/vc/${selectedVcEntity.credentialIdentifier}`); + await refreshCredentials(); } catch (error) { console.error('Failed to delete data', error); } setLoading(false); setShowDeletePopup(false); - window.location.href = '/'; }; return ( @@ -137,53 +124,48 @@ const Home = () => { ) : ( <> - {vcEntityList && vcEntityList.map((vcEntity, index) => ( - <> - - {(currentSlide === index + 1 ? 'button' : 'div') - .split() - .map(Tag => ( - <> - { setShowFullscreenImgPopup(true); setSelectedVcEntity(vcEntity); }} - aria-label={`${vcEntity.friendlyName}`} - title={t('pageCredentials.credentialFullScreenTitle', { friendlyName: vcEntity.friendlyName })} - > - - -
- {currentSlide} of {vcEntityList.length} - sliderRef.current.slickPrev()} - aria-label={currentSlide === 1 ? t('pageCredentials.slideButtonAriaLabelDisable', { direction: t('pageCredentials.slidePrevious') }) : t('pageCredentials.slideButtonAriaLabelEnable', { direction: t('pageCredentials.slidePrevious') })} - title={currentSlide === 1 ? t('pageCredentials.slideButtonTitleDisable', { direction: t('pageCredentials.slidePrevious') }) : t('pageCredentials.slideButtonTitleEnable', { direction: t('pageCredentials.slidePrevious') })} - disabled={currentSlide === 1} - className={`${currentSlide === 1 ? 'opacity-50 cursor-not-allowed dark:text-gray-400' : 'text-primary dark:text-white hover:text-primary-hover dark:hover:text-gray-300'}`} - > - - - sliderRef.current.slickNext()} - aria-label={currentSlide === vcEntityList.length ? t('pageCredentials.slideButtonAriaLabelDisable', { direction: t('pageCredentials.slideNext') }) : t('pageCredentials.slideButtonAriaLabelEnable', { direction: t('pageCredentials.slideNext') })} - title={currentSlide === vcEntityList.length ? t('pageCredentials.slideButtonTitleDisable', { direction: t('pageCredentials.slideNext') }) : t('pageCredentials.slideButtonTitleEnable', { direction: t('pageCredentials.slideNext') })} - disabled={currentSlide === vcEntityList.length} - className={`${currentSlide === vcEntityList.length ? 'opacity-50 cursor-not-allowed dark:text-gray-400' : 'text-primary dark:text-white hover:text-primary-hover dark:hover:text-gray-300'}`} - > - - -
- - ))} - -
- + {vcEntityList.map((vcEntity, index) => ( +
+ {(currentSlide === index + 1 ? 'button' : 'div') + .split() + .map(Tag => ( + { setShowFullscreenImgPopup(true); setSelectedVcEntity(vcEntity); }} + aria-label={`${vcEntity.friendlyName}`} + title={t('pageCredentials.credentialFullScreenTitle', { friendlyName: vcEntity.friendlyName })} + > + + + ))} +
+ {currentSlide} of {vcEntityList.length} + + +
{ setShowDeletePopup(true); setSelectedVcEntity(vcEntity); }} />
- - +
))}
@@ -202,7 +184,6 @@ const Home = () => { ))} - ))} +
+
+ {currentSlide} of {vcEntityList.length} + - -
-
+ + + +
{ setShowDeletePopup(true); setSelectedVcEntity(vcEntity); }} /> From 07bf477f36449cf2f1df31b719e4d4b23f60af8a Mon Sep 17 00:00:00 2001 From: gregory1996 Date: Fri, 17 May 2024 13:17:21 +0300 Subject: [PATCH 5/8] Style: reduce animation time if highlight filter and the time of set null the new credentials --- src/context/CredentialsContext.js | 2 +- src/index.css | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/context/CredentialsContext.js b/src/context/CredentialsContext.js index c5f456cd2..6d64aa0e1 100644 --- a/src/context/CredentialsContext.js +++ b/src/context/CredentialsContext.js @@ -26,7 +26,7 @@ export const CredentialsProvider = ({ children }) => { setLatestCredentials(latestCreds); setTimeout(() => { setLatestCredentials(new Set()); - }, 8000); // Clear the highlight after 5 seconds + }, 4000); } setVcEntityList(vcEntityList); diff --git a/src/index.css b/src/index.css index c992ef822..69823a76c 100644 --- a/src/index.css +++ b/src/index.css @@ -103,7 +103,7 @@ button.reactour__close { filter: brightness(1); } 50% { - filter: brightness(1.15); + filter: brightness(1.17); } } @@ -119,7 +119,7 @@ button.reactour__close { } .highlight-filter { - animation: highlight-filter 5s ease-in-out; + animation: highlight-filter 3s ease-in-out; } .fade-in { From 4de148a4cc62cd8c7957aecd2c8041c45c23a1a4 Mon Sep 17 00:00:00 2001 From: gkatrakazas Date: Mon, 20 May 2024 11:23:03 +0300 Subject: [PATCH 6/8] Add custom styles for autofilled input fields in light and dark themes --- src/components/Popups/PinInput.js | 2 +- src/index.css | 12 ++++++++++++ src/pages/AddCredentials/AddCredentials.js | 2 +- src/pages/Login/Login.js | 2 +- src/pages/SendCredentials/SendCredentials.js | 2 +- src/pages/Settings/Settings.tsx | 4 ++-- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/components/Popups/PinInput.js b/src/components/Popups/PinInput.js index fa36c6ab2..acc85d6c8 100644 --- a/src/components/Popups/PinInput.js +++ b/src/components/Popups/PinInput.js @@ -144,7 +144,7 @@ function PinInput({ showPopup, setShowPopup }) { onClick={() => handleInputClick(index)} onPaste={(e) => handleInputPaste(e.clipboardData.getData('Text'))} onKeyPress={(e) => handleInputKeyPress(e)} - className="w-10 px-3 mx-1 my-2 py-2 dark:bg-gray-700 dark:text-white border border-gray-300 dark:border-gray-500 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500" + className="w-10 px-3 mx-1 my-2 py-2 dark:bg-gray-700 dark:text-white border border-gray-300 dark:border-gray-500 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:inputDarkModeOverride" ref={inputRefs[index]} /> ))} diff --git a/src/index.css b/src/index.css index 114fc50dd..1d5471da7 100644 --- a/src/index.css +++ b/src/index.css @@ -96,3 +96,15 @@ button.reactour__close { top: 12px; right: 12px; } + +/* Light and Dark mode input autofill */ +input:-webkit-autofill { + -webkit-box-shadow: 0 0 0 30px rgb(245, 245, 245) inset !important; +} + +@layer components { + .inputDarkModeOverride:-webkit-autofill { + -webkit-box-shadow: 0 0 0 30px rgb(70, 70, 70) inset !important; + -webkit-text-fill-color: white; + } +} diff --git a/src/pages/AddCredentials/AddCredentials.js b/src/pages/AddCredentials/AddCredentials.js index a91bf4c85..66ddc17e0 100644 --- a/src/pages/AddCredentials/AddCredentials.js +++ b/src/pages/AddCredentials/AddCredentials.js @@ -137,7 +137,7 @@ const Issuers = () => { diff --git a/src/pages/Login/Login.js b/src/pages/Login/Login.js index 6ffb4ab5c..40c7e538e 100644 --- a/src/pages/Login/Login.js +++ b/src/pages/Login/Login.js @@ -59,7 +59,7 @@ const FormInputField = ({ return (
{ diff --git a/src/pages/Settings/Settings.tsx b/src/pages/Settings/Settings.tsx index fbd6fcfc6..f61e92da3 100644 --- a/src/pages/Settings/Settings.tsx +++ b/src/pages/Settings/Settings.tsx @@ -202,7 +202,7 @@ const WebauthnRegistation = ({

{t('pageSettings.registerPasskey.giveNickname')}

Date: Fri, 24 May 2024 16:07:51 +0300 Subject: [PATCH 7/8] Fix missing bracket --- src/index.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.css b/src/index.css index dd4cbd468..6f080c6d7 100644 --- a/src/index.css +++ b/src/index.css @@ -124,6 +124,8 @@ button.reactour__close { .fade-in { animation: fade-in 1s ease-in-out; +} + /* Light and Dark mode input autofill */ input:-webkit-autofill { -webkit-box-shadow: 0 0 0 30px rgb(245, 245, 245) inset !important; From fc628ceecdf5fd7bc2978b458ce8ab2338a49b72 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 3 Jun 2024 16:10:46 +0300 Subject: [PATCH 8/8] workflows --- .github/workflows/docker-build.yml | 5 +++-- .github/workflows/docker-push.yml | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index e486ff3c6..443324db7 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -3,6 +3,7 @@ on: push: branches-ignore: - master + - dc4eu-rome pull_request: jobs: @@ -11,9 +12,9 @@ jobs: contents: read packages: read - uses: wwwallet/wallet-ecosystem/.github/workflows/docker-build-push.yml@master + uses: gunet/wallet-ecosystem/.github/workflows/docker-build-push.yml@dc4eu-rome secrets: inherit with: - image-tag: ghcr.io/wwwallet/wallet-frontend:latest + image-tag: ghcr.io/gunet/wallet-frontend:latest docker-push: false dockerfile-path: ./Dockerfile diff --git a/.github/workflows/docker-push.yml b/.github/workflows/docker-push.yml index a44eb6b0e..e26139008 100644 --- a/.github/workflows/docker-push.yml +++ b/.github/workflows/docker-push.yml @@ -12,9 +12,9 @@ jobs: contents: read packages: write - uses: wwwallet/wallet-ecosystem/.github/workflows/docker-build-push.yml@master + uses: gunet/wallet-ecosystem/.github/workflows/docker-build-push.yml@dc4eu-rome secrets: inherit with: - image-tag: ghcr.io/wwwallet/wallet-frontend:${{ github.ref_name }} + image-tag: ghcr.io/gunet/wallet-frontend:${{ github.ref_name }} docker-push: true dockerfile-path: ./Dockerfile