From 6cdb869bd3c247ac1b2478edeb9f72a1e1dd7802 Mon Sep 17 00:00:00 2001 From: gregory1996 Date: Thu, 16 May 2024 17:40:44 +0300 Subject: [PATCH] Minor improve to handle Notfication component, make sure call get credentials only logged in and Add animation on new credentials cards --- src/App.js | 3 +- src/components/HandlerNotification.js | 11 ++--- src/context/CredentialsContext.js | 68 ++++++++++++++------------- src/index.css | 29 ++++++++++++ src/pages/Home/Home.js | 18 +++---- 5 files changed, 80 insertions(+), 49 deletions(-) diff --git a/src/App.js b/src/App.js index 2736a9bc..567dc38b 100644 --- a/src/App.js +++ b/src/App.js @@ -86,7 +86,7 @@ function App() { }> - + } /> } /> @@ -108,7 +108,6 @@ function App() { {showMessagePopup && setMessagePopup(false)} /> } - diff --git a/src/components/HandlerNotification.js b/src/components/HandlerNotification.js index c43814e8..9d984bac 100644 --- a/src/components/HandlerNotification.js +++ b/src/components/HandlerNotification.js @@ -30,9 +30,9 @@ const ToastDisplay = ({ id, notification }) => { ); }; -const HandlerNotification = ({ children }) => { +const HandlerNotification = () => { const [notification, setNotification] = useState({ title: '', body: '' }); - const { refreshCredentials } = useContext(CredentialsContext); + const { getData } = useContext(CredentialsContext); const showToast = () => toast((t) => ); @@ -50,7 +50,7 @@ const HandlerNotification = ({ children }) => { title: payload?.notification?.title, body: payload?.notification?.body, }); - refreshCredentials(); + getData(); }) .catch((err) => { console.log('Failed to receive message:', err); @@ -61,13 +61,10 @@ const HandlerNotification = ({ children }) => { messageListener(); } }; - }, [refreshCredentials]); + }, [getData]); return ( -
- {children} -
); }; diff --git a/src/context/CredentialsContext.js b/src/context/CredentialsContext.js index 1e125f1c..c3cf0329 100644 --- a/src/context/CredentialsContext.js +++ b/src/context/CredentialsContext.js @@ -1,41 +1,45 @@ -import React, { createContext, useState, useEffect } from 'react'; +import React, { createContext, useState, useEffect, useCallback } 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} - - ); + const api = useApi(); + const [vcEntityList, setVcEntityList] = useState([]); + const [latestCredentials, setLatestCredentials] = useState(new Set()); + + const getData = useCallback(async () => { + try { + const response = await api.get('/storage/vc'); + const fetchedVcList = response.data.vc_list; + const vcEntityList = await Promise.all(fetchedVcList.map(async vcEntity => { + const name = await extractCredentialFriendlyName(vcEntity.credential); + return { ...vcEntity, friendlyName: name }; + })); + vcEntityList.sort((vcA, vcB) => new Date(vcB.issuanceDate) - new Date(vcA.issuanceDate)); + + const latestIssuanceDate = vcEntityList[0]?.issuanceDate; + const latestCreds = new Set(vcEntityList.filter(vc => vc.issuanceDate === latestIssuanceDate).map(vc => vc.id)); + + if (window.location.pathname.includes('/cb')) { + setLatestCredentials(latestCreds); + setTimeout(() => { + setLatestCredentials(new Set()); + }, 8000); // Clear the highlight after 5 seconds + } + + setVcEntityList(vcEntityList); + } catch (error) { + console.error('Failed to fetch data', error); + } + }, [api]); + + return ( + + {children} + + ); }; export default CredentialsContext; diff --git a/src/index.css b/src/index.css index 114fc50d..c992ef82 100644 --- a/src/index.css +++ b/src/index.css @@ -96,3 +96,32 @@ button.reactour__close { top: 12px; right: 12px; } + +/* Animations for new credentials */ +@keyframes highlight-filter { + 0%, 100% { + filter: brightness(1); + } + 50% { + filter: brightness(1.15); + } +} + +@keyframes fade-in { + 0% { + opacity: 0; + transform: translateY(-300px); + } + 100% { + opacity: 1; + transform: translateY(0); + } +} + +.highlight-filter { + animation: highlight-filter 5s ease-in-out; +} + +.fade-in { + animation: fade-in 1s ease-in-out; +} diff --git a/src/pages/Home/Home.js b/src/pages/Home/Home.js index 3c95dcbe..36a8fb71 100644 --- a/src/pages/Home/Home.js +++ b/src/pages/Home/Home.js @@ -24,7 +24,7 @@ import CredentialsContext from '../../context/CredentialsContext'; const Home = () => { const api = useApi(); - const { vcEntityList, refreshCredentials } = useContext(CredentialsContext); + const { vcEntityList,latestCredentials, getData } = useContext(CredentialsContext); const [isSmallScreen, setIsSmallScreen] = useState(window.innerWidth < 768); const [currentSlide, setCurrentSlide] = useState(1); const [showFullscreenImgPopup, setShowFullscreenImgPopup] = useState(false); @@ -51,6 +51,10 @@ const Home = () => { style: { margin: '0 10px' }, }; + useEffect(() => { + getData(); + }, [getData]); + useEffect(() => { const handleResize = () => { setIsSmallScreen(window.innerWidth < 768); @@ -86,7 +90,7 @@ const Home = () => { setLoading(true); try { await api.del(`/storage/vc/${selectedVcEntity.credentialIdentifier}`); - await refreshCredentials(); + await getData(); } catch (error) { console.error('Failed to delete data', error); } @@ -129,14 +133,12 @@ const Home = () => { {(currentSlide === index + 1 ? 'button' : 'div') .split() .map(Tag => ( - { setShowFullscreenImgPopup(true); setSelectedVcEntity(vcEntity); }} aria-label={`${vcEntity.friendlyName}`} title={t('pageCredentials.credentialFullScreenTitle', { friendlyName: vcEntity.friendlyName })} > - + ))}
@@ -176,12 +178,12 @@ const Home = () => { {vcEntityList.map((vcEntity) => ( ))}