From 762c796a24754ba08ebe4b4bb65bf3434d73fa3e Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Tue, 9 Apr 2024 15:09:57 +0200 Subject: [PATCH 01/41] added newsbanner --- src/components/Newsbanner/Newsbanner.tsx | 21 +++++++++++++++++++++ src/components/index.ts | 1 + src/pages/MainFrame/MainFrame.tsx | 3 ++- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/components/Newsbanner/Newsbanner.tsx diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx new file mode 100644 index 000000000..860d2c33c --- /dev/null +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -0,0 +1,21 @@ +import { Alert, Box, Collapse, IconButton } from "@mui/material"; +import CloseIcon from '@mui/icons-material/Close'; +import { useState } from "react"; +const Newsbanner=()=>{ + const [open, setOpen]=useState(true) + //fetch von backend, localStorage abfrage ob schon gesehen, date, expirationdate, + return( + + + {setOpen(false)}}> + + + } + > + Current news + + + + ) +} +export default Newsbanner \ No newline at end of file diff --git a/src/components/index.ts b/src/components/index.ts index f8039ed86..25f2d74db 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -48,5 +48,6 @@ export { default as LinearProgressWithLabel } from './StyledLinearProgress/Linea export { StyledLinearProgress } from './StyledLinearProgress/StyledLinearProgress' export { default as LabeledSwitch } from './LabeledSwitch/LabeledSwitch' export { default as ResponsiveMiniMap } from './ResponsiveMiniMap/ResponsiveMiniMap' +export { default as Newsbanner } from './Newsbanner/Newsbanner' export * from './Nodes' // This stays as is because it's not following the Component/Component structure diff --git a/src/pages/MainFrame/MainFrame.tsx b/src/pages/MainFrame/MainFrame.tsx index d536c27ed..fdb599845 100644 --- a/src/pages/MainFrame/MainFrame.tsx +++ b/src/pages/MainFrame/MainFrame.tsx @@ -1,6 +1,6 @@ import { Outlet, useParams } from 'react-router-dom' import { Box, Divider, Grid, Stack } from '@common/components' -import { BreadcrumbsContainer, Footer, LocalNav, MenuBar, OpenQuestionnaire, PrivacyModal } from '@components' +import { BreadcrumbsContainer, Footer, LocalNav, MenuBar, OpenQuestionnaire, PrivacyModal, Newsbanner } from '@components' /** * # MainFrame Page @@ -27,6 +27,7 @@ export const MainFrame = () => { <> {renderMenuBar ? : } + From 25cd16730e0c733072e08d18105b6207c6cd87ec Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Wed, 10 Apr 2024 11:55:59 +0200 Subject: [PATCH 02/41] added NewsSlice and News.hooks --- src/components/Newsbanner/Newsbanner.tsx | 4 +-- src/core/News/News.hooks.tsx | 10 ++++++++ src/core/News/News.ts | 5 ++++ src/core/index.ts | 2 ++ src/services/News/fetchNews.tsx | 17 +++++++++++++ src/services/index.ts | 1 + src/store/Slices/NewsSlice.ts | 31 ++++++++++++++++++++++++ src/store/Zustand/Store.ts | 5 +++- 8 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 src/core/News/News.hooks.tsx create mode 100644 src/core/News/News.ts create mode 100644 src/services/News/fetchNews.tsx create mode 100644 src/store/Slices/NewsSlice.ts diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index 860d2c33c..a3631fe91 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -7,12 +7,12 @@ const Newsbanner=()=>{ return( - {setOpen(false)}}> + {setOpen(false)}}> } > - Current news + Due to unforseen circumstances we regret to inform you that aliens have taken over humanity and we are doomed on another note the animalpark munich just had another cute lion baby diff --git a/src/core/News/News.hooks.tsx b/src/core/News/News.hooks.tsx new file mode 100644 index 000000000..28db86485 --- /dev/null +++ b/src/core/News/News.hooks.tsx @@ -0,0 +1,10 @@ +import {fetchNews}from'@services' + +export type NewsbannerHookReturn = { + readonly handleClose:()=> void +} + +export const useNewsbanner = ():NewsbannerHookReturn=> { + const fetchNews = usw. + return useMemo() +} \ No newline at end of file diff --git a/src/core/News/News.ts b/src/core/News/News.ts new file mode 100644 index 000000000..cc8577d6c --- /dev/null +++ b/src/core/News/News.ts @@ -0,0 +1,5 @@ +type News = { + expiration_date: Date + news_content: string +} +export default News diff --git a/src/core/index.ts b/src/core/index.ts index 73adf2709..8b8f329a1 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -30,6 +30,7 @@ import LearningPathLearningElement from './LearningPathLearningElement/LearningP import LearningPathTopic from './LearningPathTopic/LearningPathTopic' import ILS from './QuestionnaireResults/ILS' import ListK from './QuestionnaireResults/ListK' +import News from './News/News' import StudentLearningElement from './StudentLearningElement/StudentLearningElement' import Topic from './Topic/Topic' import User from './User/User' @@ -46,6 +47,7 @@ export type { LearningPathElement, LearningPathLearningElement, LearningPathElementStatus, + News, Topic, StudentLearningElement, ILS, diff --git a/src/services/News/fetchNews.tsx b/src/services/News/fetchNews.tsx new file mode 100644 index 000000000..3ccad46b9 --- /dev/null +++ b/src/services/News/fetchNews.tsx @@ -0,0 +1,17 @@ +import { getConfig } from '@shared' +import {fetchData} from '../RequestResponse' +import { News } from '@core' + +/** + * + * @returns {@link News} object + */ +export const fetchNews =async():Promise=>{ + return fetchData(getConfig().BACKEND + '/news',{ + method:'GET', + credentials:'include', + headers:{ + 'Content-Type': 'application/json' + } + }) +} \ No newline at end of file diff --git a/src/services/index.ts b/src/services/index.ts index d0aaa99ed..1b9de0e9b 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -20,4 +20,5 @@ export * from './xAPI' export { fetchILS, fetchListK, postILS, postListK } from './Questionnaire' export * from './debounce' export * from './Viewport' +export { fetchNews } from './News/fetchNews' export { postCalculateLearningPathILS } from './LearningPath' diff --git a/src/store/Slices/NewsSlice.ts b/src/store/Slices/NewsSlice.ts new file mode 100644 index 000000000..d010a0594 --- /dev/null +++ b/src/store/Slices/NewsSlice.ts @@ -0,0 +1,31 @@ +import { StateCreator } from 'zustand' +import { News } from '@core' +import { fetchNews } from '@services' +import { PersistedStoreState } from '@store' +import { resetters } from '../Zustand/Store' + +export default interface NewsSlice { + _news: News | undefined + getNews: (news?: News) => Promise +} + +export const createNewsSlice: StateCreator = (set, get) => { + resetters.push(() => set({ _news: undefined })) + return { + _news: undefined, + getNews: async (news?: News) => { + if (news) { + set({ _news: news }) + return news + } + + const cached = get()._news + + if (!cached) { + const news = await fetchNews() + set({ _news: news }) + return news + } else return cached + } + } +} diff --git a/src/store/Zustand/Store.ts b/src/store/Zustand/Store.ts index c28a652ae..f21dcbfb8 100644 --- a/src/store/Zustand/Store.ts +++ b/src/store/Zustand/Store.ts @@ -13,13 +13,14 @@ import LearningPathElementStatusSlice, { } from '../Slices/LearningPathElementStatusSlice' import LearningPathTopicSlice, { createLearningPathTopicSlice } from '../Slices/LearningPathTopicSlice' import UserSlice, { createUserSlice } from '../Slices/UserSlice' +import NewsSlice, { createNewsSlice } from '../Slices/NewsSlice' export type StoreState = LearningPathElementSlice & CourseSlice & CoursesSlice & LearningPathTopicSlice & LearningPathElementSpecificStatusSlice -export type PersistedStoreState = UserSlice & AuthSlice & LearningPathElementStatusSlice +export type PersistedStoreState = UserSlice & AuthSlice & LearningPathElementStatusSlice & NewsSlice export const resetters: (() => void)[] = [] @@ -36,6 +37,7 @@ export const usePersistedStore = create()( persist( (...a) => ({ ...createUserSlice(...a), + ...createNewsSlice(...a), ...createLearningPathElementStatusSlice(...a), ...createAuthSlice(...a) }), @@ -44,6 +46,7 @@ export const usePersistedStore = create()( // Here we can whitelist the keys we want to persist partialize: (state) => ({ _user: state._user, + _news: state._news, _learningPathElementStatus: state._learningPathElementStatus, expire: state.expire }), From 98ecad3057a6a820e30da3c870a09904418244e0 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Wed, 10 Apr 2024 12:18:42 +0200 Subject: [PATCH 03/41] added a checkNews to the hooks --- src/core/News/News.hooks.tsx | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/core/News/News.hooks.tsx b/src/core/News/News.hooks.tsx index 28db86485..3a4778e27 100644 --- a/src/core/News/News.hooks.tsx +++ b/src/core/News/News.hooks.tsx @@ -1,10 +1,29 @@ -import {fetchNews}from'@services' +import log from 'loglevel' +import { useMemo } from 'react' +import { usePersistedStore } from "@store" export type NewsbannerHookReturn = { - readonly handleClose:()=> void + //readonly handleClose:()=> void + readonly checkNews:()=>Promise } export const useNewsbanner = ():NewsbannerHookReturn=> { - const fetchNews = usw. - return useMemo() + const getNews = usePersistedStore((state)=>state.getNews) + + //** Logic **/ + //get the content of the news + const checkNews = async()=>{ + return getNews() + .then((news)=>{ + return news.news_content + }) + .catch((reason)=>{ + log.error(reason) + return '' + }) + } + return useMemo( + () =>({checkNews}), + [checkNews] + ) } \ No newline at end of file From fe82dd973b2f0da4197611b5d81854ae94bbe1a7 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Wed, 10 Apr 2024 13:41:03 +0200 Subject: [PATCH 04/41] newsbanner automatically scrolls --- src/components/Newsbanner/Newsbanner.tsx | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index a3631fe91..dad3cf425 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -1,18 +1,37 @@ -import { Alert, Box, Collapse, IconButton } from "@mui/material"; +import { Alert, Box, Collapse, IconButton, makeStyles } from "@mui/material"; import CloseIcon from '@mui/icons-material/Close'; import { useState } from "react"; +import {css, keyframes} from "@emotion/react" + +const animatedItem = css `{ + animation: $scrolling 3s linear infinite + }`; + +const scrolling = keyframes` + from { + transform: translateX(100%) + }, + to { + transform: translateX(-100%) + } +`; + const Newsbanner=()=>{ const [open, setOpen]=useState(true) //fetch von backend, localStorage abfrage ob schon gesehen, date, expirationdate, return( + + - {setOpen(false)}}> + {setOpen(false)}}> } > + Due to unforseen circumstances we regret to inform you that aliens have taken over humanity and we are doomed on another note the animalpark munich just had another cute lion baby + From 509ffdde2d6434de40a5463601a1c4ff36894a8e Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Thu, 11 Apr 2024 12:38:51 +0200 Subject: [PATCH 05/41] removed scrollbar --- src/components/Newsbanner/Newsbanner.tsx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index dad3cf425..c2d95dcf5 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -1,11 +1,7 @@ -import { Alert, Box, Collapse, IconButton, makeStyles } from "@mui/material"; +import { Alert, Box, Collapse, IconButton } from "@mui/material"; import CloseIcon from '@mui/icons-material/Close'; import { useState } from "react"; -import {css, keyframes} from "@emotion/react" - -const animatedItem = css `{ - animation: $scrolling 3s linear infinite - }`; +import { keyframes} from "@emotion/react" const scrolling = keyframes` from { @@ -19,17 +15,22 @@ const scrolling = keyframes` const Newsbanner=()=>{ const [open, setOpen]=useState(true) //fetch von backend, localStorage abfrage ob schon gesehen, date, expirationdate, + //TODO: Text anpassen auf Bildschrimgroesse und textlaenge return( - - {setOpen(false)}}> + + {setOpen(false)}}> } > - + + Due to unforseen circumstances we regret to inform you that aliens have taken over humanity and we are doomed on another note the animalpark munich just had another cute lion baby From fa39cb9286ffed93b9d1d4e04816043f37088b3b Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Mon, 15 Apr 2024 10:13:53 +0200 Subject: [PATCH 06/41] added NewsList --- .../Newsbanner/Newsbanner.hooks.tsx} | 0 src/components/Newsbanner/Newsbanner.tsx | 34 +++++++++++++++++-- src/core/News/News.ts | 5 +++ src/core/index.ts | 3 +- src/services/News/fetchNews.tsx | 18 ++++++++-- 5 files changed, 54 insertions(+), 6 deletions(-) rename src/{core/News/News.hooks.tsx => components/Newsbanner/Newsbanner.hooks.tsx} (100%) diff --git a/src/core/News/News.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx similarity index 100% rename from src/core/News/News.hooks.tsx rename to src/components/Newsbanner/Newsbanner.hooks.tsx diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index c2d95dcf5..74fa54eb7 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -1,7 +1,9 @@ import { Alert, Box, Collapse, IconButton } from "@mui/material"; import CloseIcon from '@mui/icons-material/Close'; -import { useState } from "react"; +import { useCallback, useState } from "react"; import { keyframes} from "@emotion/react" +import { useTranslation } from "react-i18next"; +import { NewsbannerHookReturn, useNewsbanner as _useNewsbanner } from "./Newsbanner.hooks"; const scrolling = keyframes` from { @@ -11,12 +13,36 @@ const scrolling = keyframes` transform: translateX(-100%) } `; +export type NewsbannerProps={ + useNewsbanner?:()=>NewsbannerHookReturn +} + +/** + * Newsbanner component + * @remarks + * Newsbanner shows a banner between the menubar and the breadcrumbs, + * but only if there are news. + * @category Components + */ -const Newsbanner=()=>{ +const Newsbanner=({useNewsbanner=_useNewsbanner}:NewsbannerProps)=>{ const [open, setOpen]=useState(true) + const {t} = useTranslation() + const {checkNews}=useNewsbanner() + const handleNews = + checkNews().then((content)=>{ + if(content){ + return false + } + }) + //fetch von backend, localStorage abfrage ob schon gesehen, date, expirationdate, //TODO: Text anpassen auf Bildschrimgroesse und textlaenge return( + <> + { + !(handleNews)&&( + @@ -30,12 +56,16 @@ const Newsbanner=()=>{ } > + Due to unforseen circumstances we regret to inform you that aliens have taken over humanity and we are doomed on another note the animalpark munich just had another cute lion baby + ) +} + ) } export default Newsbanner \ No newline at end of file diff --git a/src/core/News/News.ts b/src/core/News/News.ts index cc8577d6c..37da58d9b 100644 --- a/src/core/News/News.ts +++ b/src/core/News/News.ts @@ -1,5 +1,10 @@ +type NewsList = { + newslist: News[] +} + type News = { expiration_date: Date news_content: string } export default News +export type { NewsList } diff --git a/src/core/index.ts b/src/core/index.ts index 8b8f329a1..714cc5644 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -30,7 +30,7 @@ import LearningPathLearningElement from './LearningPathLearningElement/LearningP import LearningPathTopic from './LearningPathTopic/LearningPathTopic' import ILS from './QuestionnaireResults/ILS' import ListK from './QuestionnaireResults/ListK' -import News from './News/News' +import News, { NewsList } from './News/News' import StudentLearningElement from './StudentLearningElement/StudentLearningElement' import Topic from './Topic/Topic' import User from './User/User' @@ -48,6 +48,7 @@ export type { LearningPathLearningElement, LearningPathElementStatus, News, + NewsList, Topic, StudentLearningElement, ILS, diff --git a/src/services/News/fetchNews.tsx b/src/services/News/fetchNews.tsx index 3ccad46b9..ff1943580 100644 --- a/src/services/News/fetchNews.tsx +++ b/src/services/News/fetchNews.tsx @@ -1,17 +1,29 @@ import { getConfig } from '@shared' import {fetchData} from '../RequestResponse' -import { News } from '@core' +import { NewsList } from '@core' /** * * @returns {@link News} object */ -export const fetchNews =async():Promise=>{ - return fetchData(getConfig().BACKEND + '/news',{ +export const fetchNews =async():Promise=>{ + return fetchData(getConfig().BACKEND + '/news',{ method:'GET', credentials:'include', headers:{ 'Content-Type': 'application/json' } + + /* + Backend Response: + {"message": [ + {"message": "", + "until":}, + {"message": [ + {"message": "", + "until":}, + ... + ]} + */ }) } \ No newline at end of file From ebaa37afc9530f3bd777539cf6d28d8c67ec1d59 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Wed, 24 Apr 2024 12:53:09 +0200 Subject: [PATCH 07/41] fetchNews works and displays the news in the banner --- .../Newsbanner/Newsbanner.hooks.tsx | 27 ++++++++++++---- src/components/Newsbanner/Newsbanner.tsx | 31 +++++++++++-------- src/core/News/News.ts | 3 +- src/services/News/fetchNews.tsx | 4 +-- src/store/Slices/NewsSlice.ts | 10 +++--- 5 files changed, 47 insertions(+), 28 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index 3a4778e27..ac49f8de5 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -4,7 +4,8 @@ import { usePersistedStore } from "@store" export type NewsbannerHookReturn = { //readonly handleClose:()=> void - readonly checkNews:()=>Promise + readonly checkForNews:()=>Promise + readonly receiveContent:()=>Promise } export const useNewsbanner = ():NewsbannerHookReturn=> { @@ -12,18 +13,32 @@ export const useNewsbanner = ():NewsbannerHookReturn=> { //** Logic **/ //get the content of the news - const checkNews = async()=>{ + const checkForNews = async()=>{ return getNews() .then((news)=>{ - return news.news_content + console.log(`New count ${news.length}`) + return news.length != 0 }) .catch((reason)=>{ log.error(reason) - return '' + return false }) } + + const receiveContent = async()=>{ + return getNews() + .then((news)=>{ + console.log(`Newscontent ${JSON.stringify(news[0].news_content)}`) + return JSON.stringify(news[0].news_content) + }) + .catch((reason)=>{ + log.error(reason) + return null + }) + } + return useMemo( - () =>({checkNews}), - [checkNews] + () =>({checkForNews, receiveContent}), + [checkForNews, receiveContent] ) } \ No newline at end of file diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index 74fa54eb7..05073e665 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -1,8 +1,7 @@ import { Alert, Box, Collapse, IconButton } from "@mui/material"; import CloseIcon from '@mui/icons-material/Close'; -import { useCallback, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { keyframes} from "@emotion/react" -import { useTranslation } from "react-i18next"; import { NewsbannerHookReturn, useNewsbanner as _useNewsbanner } from "./Newsbanner.hooks"; const scrolling = keyframes` @@ -26,22 +25,26 @@ export type NewsbannerProps={ */ const Newsbanner=({useNewsbanner=_useNewsbanner}:NewsbannerProps)=>{ - const [open, setOpen]=useState(true) - const {t} = useTranslation() - const {checkNews}=useNewsbanner() - const handleNews = - checkNews().then((content)=>{ - if(content){ - return false - } - }) + const [open, setOpen]=useState(false) + const [text, setText]=useState('') + const {checkForNews, receiveContent}=useNewsbanner() + + useEffect(() => {checkForNews().then(isNewsAvaliable => { + console.log(isNewsAvaliable) + setOpen(isNewsAvaliable) + })}, []) + + useEffect(() => {receiveContent().then(showNews => { + console.log(showNews) + setText(showNews) + })}, []) //fetch von backend, localStorage abfrage ob schon gesehen, date, expirationdate, //TODO: Text anpassen auf Bildschrimgroesse und textlaenge return( <> { - !(handleNews)&&( + (open)&&( @@ -56,7 +59,9 @@ const Newsbanner=({useNewsbanner=_useNewsbanner}:NewsbannerProps)=>{ } > - + <> + {text} + Due to unforseen circumstances we regret to inform you that aliens have taken over humanity and we are doomed on another note the animalpark munich just had another cute lion baby diff --git a/src/core/News/News.ts b/src/core/News/News.ts index 37da58d9b..270c71df9 100644 --- a/src/core/News/News.ts +++ b/src/core/News/News.ts @@ -3,8 +3,7 @@ type NewsList = { } type News = { - expiration_date: Date - news_content: string + newsContent: string } export default News export type { NewsList } diff --git a/src/services/News/fetchNews.tsx b/src/services/News/fetchNews.tsx index ff1943580..82cdfc7b6 100644 --- a/src/services/News/fetchNews.tsx +++ b/src/services/News/fetchNews.tsx @@ -6,8 +6,8 @@ import { NewsList } from '@core' * * @returns {@link News} object */ -export const fetchNews =async():Promise=>{ - return fetchData(getConfig().BACKEND + '/news',{ +export const fetchNews =async(languageId?:string):Promise=>{ + return fetchData(getConfig().BACKEND + `/news?language_id=${languageId}`,{ method:'GET', credentials:'include', headers:{ diff --git a/src/store/Slices/NewsSlice.ts b/src/store/Slices/NewsSlice.ts index d010a0594..616bb42ca 100644 --- a/src/store/Slices/NewsSlice.ts +++ b/src/store/Slices/NewsSlice.ts @@ -1,19 +1,19 @@ import { StateCreator } from 'zustand' -import { News } from '@core' +import { NewsList } from '@core' import { fetchNews } from '@services' import { PersistedStoreState } from '@store' import { resetters } from '../Zustand/Store' export default interface NewsSlice { - _news: News | undefined - getNews: (news?: News) => Promise + _news: NewsList | undefined + getNews: (news?: NewsList) => Promise } export const createNewsSlice: StateCreator = (set, get) => { resetters.push(() => set({ _news: undefined })) return { _news: undefined, - getNews: async (news?: News) => { + getNews: async (news?: NewsList) => { if (news) { set({ _news: news }) return news @@ -22,7 +22,7 @@ export const createNewsSlice: StateCreator Date: Tue, 30 Apr 2024 12:06:20 +0200 Subject: [PATCH 08/41] Changed Slice --- .../Newsbanner/Newsbanner.hooks.tsx | 4 +-- src/components/Newsbanner/Newsbanner.tsx | 4 --- src/services/News/fetchNews.tsx | 12 -------- src/store/Slices/NewsSlice.ts | 30 ++++++++++--------- src/store/Zustand/Store.ts | 6 ++-- 5 files changed, 21 insertions(+), 35 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index ac49f8de5..60ba7f52d 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -1,6 +1,6 @@ import log from 'loglevel' import { useMemo } from 'react' -import { usePersistedStore } from "@store" +import { useStore } from "@store" export type NewsbannerHookReturn = { //readonly handleClose:()=> void @@ -9,7 +9,7 @@ export type NewsbannerHookReturn = { } export const useNewsbanner = ():NewsbannerHookReturn=> { - const getNews = usePersistedStore((state)=>state.getNews) + const getNews = useStore((state)=>state.getNews) //** Logic **/ //get the content of the news diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index 05073e665..8e19c968b 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -59,11 +59,7 @@ const Newsbanner=({useNewsbanner=_useNewsbanner}:NewsbannerProps)=>{ } > - <> {text} - - - Due to unforseen circumstances we regret to inform you that aliens have taken over humanity and we are doomed on another note the animalpark munich just had another cute lion baby diff --git a/src/services/News/fetchNews.tsx b/src/services/News/fetchNews.tsx index 82cdfc7b6..96f4134e9 100644 --- a/src/services/News/fetchNews.tsx +++ b/src/services/News/fetchNews.tsx @@ -13,17 +13,5 @@ export const fetchNews =async(languageId?:string):Promise=>{ headers:{ 'Content-Type': 'application/json' } - - /* - Backend Response: - {"message": [ - {"message": "", - "until":}, - {"message": [ - {"message": "", - "until":}, - ... - ]} - */ }) } \ No newline at end of file diff --git a/src/store/Slices/NewsSlice.ts b/src/store/Slices/NewsSlice.ts index 616bb42ca..15ce6584e 100644 --- a/src/store/Slices/NewsSlice.ts +++ b/src/store/Slices/NewsSlice.ts @@ -1,29 +1,31 @@ import { StateCreator } from 'zustand' -import { NewsList } from '@core' +import { News, NewsList } from '@core' import { fetchNews } from '@services' -import { PersistedStoreState } from '@store' +import { StoreState } from '@store' import { resetters } from '../Zustand/Store' export default interface NewsSlice { - _news: NewsList | undefined - getNews: (news?: NewsList) => Promise + _news: Record + getNews: (user?: NewsList) => Promise } -export const createNewsSlice: StateCreator = (set, get) => { - resetters.push(() => set({ _news: undefined })) +export const createNewsSlice: StateCreator = (set, get) => { + resetters.push(() => set({ _news: {} })) return { - _news: undefined, - getNews: async (news?: NewsList) => { - if (news) { - set({ _news: news }) - return news - } + _news: {}, + getNews: async (...arg) => { + const [languageId] = arg - const cached = get()._news + const cached = get()._news[`${languageId}`] if (!cached) { const news = await fetchNews('eng') - set({ _news: news }) + set({ + _news: { + ...get()._news, + [`${languageId}`]: news + } + }) return news } else return cached } diff --git a/src/store/Zustand/Store.ts b/src/store/Zustand/Store.ts index f21dcbfb8..589a8bcd9 100644 --- a/src/store/Zustand/Store.ts +++ b/src/store/Zustand/Store.ts @@ -18,9 +18,10 @@ import NewsSlice, { createNewsSlice } from '../Slices/NewsSlice' export type StoreState = LearningPathElementSlice & CourseSlice & CoursesSlice & + NewsSlice & LearningPathTopicSlice & LearningPathElementSpecificStatusSlice -export type PersistedStoreState = UserSlice & AuthSlice & LearningPathElementStatusSlice & NewsSlice +export type PersistedStoreState = UserSlice & AuthSlice & LearningPathElementStatusSlice export const resetters: (() => void)[] = [] @@ -29,6 +30,7 @@ export const useStore = create()((...a) => ({ ...createLearningPathTopicSlice(...a), ...createCourseSlice(...a), ...createCoursesSlice(...a), + ...createNewsSlice(...a), ...createLearningPathElementSpecificStatusSlice(...a) })) @@ -37,7 +39,6 @@ export const usePersistedStore = create()( persist( (...a) => ({ ...createUserSlice(...a), - ...createNewsSlice(...a), ...createLearningPathElementStatusSlice(...a), ...createAuthSlice(...a) }), @@ -46,7 +47,6 @@ export const usePersistedStore = create()( // Here we can whitelist the keys we want to persist partialize: (state) => ({ _user: state._user, - _news: state._news, _learningPathElementStatus: state._learningPathElementStatus, expire: state.expire }), From 7d1487b97254b3b1764f292cd9dd8d1c5b7a106e Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Mon, 6 May 2024 15:57:23 +0200 Subject: [PATCH 09/41] fixed the type issue --- src/components/Newsbanner/Newsbanner.hooks.tsx | 12 ++++++------ src/core/News/News.ts | 4 ++-- src/store/Slices/NewsSlice.ts | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index 60ba7f52d..b44596ead 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -4,7 +4,7 @@ import { useStore } from "@store" export type NewsbannerHookReturn = { //readonly handleClose:()=> void - readonly checkForNews:()=>Promise + readonly checkForNews:()=>Promise readonly receiveContent:()=>Promise } @@ -16,8 +16,8 @@ export const useNewsbanner = ():NewsbannerHookReturn=> { const checkForNews = async()=>{ return getNews() .then((news)=>{ - console.log(`New count ${news.length}`) - return news.length != 0 + console.log(`New count ${news.news.length}`) + return news.news.length != 0 }) .catch((reason)=>{ log.error(reason) @@ -28,12 +28,12 @@ export const useNewsbanner = ():NewsbannerHookReturn=> { const receiveContent = async()=>{ return getNews() .then((news)=>{ - console.log(`Newscontent ${JSON.stringify(news[0].news_content)}`) - return JSON.stringify(news[0].news_content) + console.log(`Newscontent ${JSON.stringify(news.news[0].news_content)}`) + return JSON.stringify(news.news[0].news_content) }) .catch((reason)=>{ log.error(reason) - return null + return "" }) } diff --git a/src/core/News/News.ts b/src/core/News/News.ts index 270c71df9..15d479d66 100644 --- a/src/core/News/News.ts +++ b/src/core/News/News.ts @@ -1,9 +1,9 @@ type NewsList = { - newslist: News[] + news: News[] } type News = { - newsContent: string + news_content: string } export default News export type { NewsList } diff --git a/src/store/Slices/NewsSlice.ts b/src/store/Slices/NewsSlice.ts index 15ce6584e..fe5a042fd 100644 --- a/src/store/Slices/NewsSlice.ts +++ b/src/store/Slices/NewsSlice.ts @@ -1,5 +1,5 @@ import { StateCreator } from 'zustand' -import { News, NewsList } from '@core' +import { NewsList } from '@core' import { fetchNews } from '@services' import { StoreState } from '@store' import { resetters } from '../Zustand/Store' From 586ca91e48018ce2c3ae6776842f81340e1772ea Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Tue, 7 May 2024 15:07:48 +0200 Subject: [PATCH 10/41] added university to fetch --- .../Newsbanner/Newsbanner.hooks.tsx | 24 ++++++++++++++----- src/components/Newsbanner/Newsbanner.tsx | 1 - src/services/News/fetchNews.tsx | 4 ++-- src/store/Slices/NewsSlice.ts | 10 ++++---- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index b44596ead..a14d91e69 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -1,17 +1,22 @@ import log from 'loglevel' -import { useMemo } from 'react' +import { useCallback, useMemo } from 'react' import { useStore } from "@store" export type NewsbannerHookReturn = { - //readonly handleClose:()=> void readonly checkForNews:()=>Promise readonly receiveContent:()=>Promise + readonly checkLanguage:()=>void } export const useNewsbanner = ():NewsbannerHookReturn=> { const getNews = useStore((state)=>state.getNews) //** Logic **/ + const checkLanguage=()=>{ + const lang=localStorage.getItem('i18nextLng')?.toLowerCase() + return lang + } + //get the content of the news const checkForNews = async()=>{ return getNews() @@ -28,8 +33,15 @@ export const useNewsbanner = ():NewsbannerHookReturn=> { const receiveContent = async()=>{ return getNews() .then((news)=>{ - console.log(`Newscontent ${JSON.stringify(news.news[0].news_content)}`) - return JSON.stringify(news.news[0].news_content) + const contentA=news.news.map(({news_content})=>({news_content})) + console.log(contentA) + const joined=contentA.concat() + /*console.log(JSON.stringify(joined)) + news.news.forEach(element => { + //console.log(element.news_content) + JSON.stringify(element.news_content) + });*/ + return JSON.stringify(joined) }) .catch((reason)=>{ log.error(reason) @@ -38,7 +50,7 @@ export const useNewsbanner = ():NewsbannerHookReturn=> { } return useMemo( - () =>({checkForNews, receiveContent}), - [checkForNews, receiveContent] + () =>({checkForNews, receiveContent, checkLanguage}), + [checkForNews, receiveContent, checkLanguage] ) } \ No newline at end of file diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index 8e19c968b..758f9a5fe 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -30,7 +30,6 @@ const Newsbanner=({useNewsbanner=_useNewsbanner}:NewsbannerProps)=>{ const {checkForNews, receiveContent}=useNewsbanner() useEffect(() => {checkForNews().then(isNewsAvaliable => { - console.log(isNewsAvaliable) setOpen(isNewsAvaliable) })}, []) diff --git a/src/services/News/fetchNews.tsx b/src/services/News/fetchNews.tsx index 96f4134e9..82fdf5121 100644 --- a/src/services/News/fetchNews.tsx +++ b/src/services/News/fetchNews.tsx @@ -6,8 +6,8 @@ import { NewsList } from '@core' * * @returns {@link News} object */ -export const fetchNews =async(languageId?:string):Promise=>{ - return fetchData(getConfig().BACKEND + `/news?language_id=${languageId}`,{ +export const fetchNews =async(languageId?:string, university?:string):Promise=>{ + return fetchData(getConfig().BACKEND + `/news?language_id=${languageId}&university=${university}`,{ method:'GET', credentials:'include', headers:{ diff --git a/src/store/Slices/NewsSlice.ts b/src/store/Slices/NewsSlice.ts index fe5a042fd..a7a6b94cb 100644 --- a/src/store/Slices/NewsSlice.ts +++ b/src/store/Slices/NewsSlice.ts @@ -6,7 +6,7 @@ import { resetters } from '../Zustand/Store' export default interface NewsSlice { _news: Record - getNews: (user?: NewsList) => Promise + getNews: (languageId?: NewsList, university?: NewsList) => Promise } export const createNewsSlice: StateCreator = (set, get) => { @@ -14,16 +14,16 @@ export const createNewsSlice: StateCreator = (set return { _news: {}, getNews: async (...arg) => { - const [languageId] = arg + const [languageId, university] = arg - const cached = get()._news[`${languageId}`] + const cached = get()._news[`${languageId}-${university}`] if (!cached) { - const news = await fetchNews('eng') + const news = await fetchNews('eng', 'HS-KE') set({ _news: { ...get()._news, - [`${languageId}`]: news + [`${languageId}-${university}`]: news } }) return news From 356ce14a62a59ef00cbfb7ba9e9ee06165d4d40d Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Wed, 8 May 2024 10:39:21 +0200 Subject: [PATCH 11/41] combines news when there are multiple --- .../Newsbanner/Newsbanner.hooks.tsx | 93 ++++++++-------- src/components/Newsbanner/Newsbanner.tsx | 105 ++++++++++-------- src/pages/MainFrame/MainFrame.tsx | 12 +- src/services/News/fetchNews.tsx | 22 ++-- 4 files changed, 123 insertions(+), 109 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index a14d91e69..a7a4d41d7 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -1,56 +1,53 @@ import log from 'loglevel' -import { useCallback, useMemo } from 'react' -import { useStore } from "@store" +import { useCallback, useMemo, useState } from 'react' +import { useStore } from '@store' export type NewsbannerHookReturn = { - readonly checkForNews:()=>Promise - readonly receiveContent:()=>Promise - readonly checkLanguage:()=>void + readonly checkForNews: () => Promise + readonly receiveContent: () => Promise + readonly currentNewsLength: 0 } -export const useNewsbanner = ():NewsbannerHookReturn=> { - const getNews = useStore((state)=>state.getNews) +export const useNewsbanner = (): NewsbannerHookReturn => { + const getNews = useStore((state) => state.getNews) - //** Logic **/ - const checkLanguage=()=>{ - const lang=localStorage.getItem('i18nextLng')?.toLowerCase() - return lang - } - - //get the content of the news - const checkForNews = async()=>{ - return getNews() - .then((news)=>{ - console.log(`New count ${news.news.length}`) - return news.news.length != 0 - }) - .catch((reason)=>{ - log.error(reason) - return false - }) - } + //stores the character length of the news + const [newsLength, setNewsLength] = useState(0) - const receiveContent = async()=>{ - return getNews() - .then((news)=>{ - const contentA=news.news.map(({news_content})=>({news_content})) - console.log(contentA) - const joined=contentA.concat() - /*console.log(JSON.stringify(joined)) - news.news.forEach(element => { - //console.log(element.news_content) - JSON.stringify(element.news_content) - });*/ - return JSON.stringify(joined) - }) - .catch((reason)=>{ - log.error(reason) - return "" - }) - } + //** Logic **/ + const checkLanguage = () => { + const lang = localStorage.getItem('i18nextLng')?.toLowerCase() + return lang + } - return useMemo( - () =>({checkForNews, receiveContent, checkLanguage}), - [checkForNews, receiveContent, checkLanguage] - ) -} \ No newline at end of file + //check if there are any news + const checkForNews = async () => { + return getNews() + .then((news) => { + return news.news.length != 0 + }) + .catch((reason) => { + log.error(reason) + return false + }) + } + + //returns combined string of all the news + const receiveContent = async () => { + return getNews() + .then((news) => { + const contentA = news.news.map(({ news_content }) => news_content).join(', ') + setNewsLength(contentA.length) + return JSON.stringify(contentA) + }) + .catch((reason) => { + log.error(reason) + return '' + }) + } + + return useMemo( + () => ({ checkForNews, receiveContent, checkLanguage, newsLength }), + [checkForNews, receiveContent, checkLanguage, newsLength] + ) +} diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index 758f9a5fe..ee8a3fc28 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -1,8 +1,8 @@ -import { Alert, Box, Collapse, IconButton } from "@mui/material"; -import CloseIcon from '@mui/icons-material/Close'; -import { useCallback, useEffect, useState } from "react"; -import { keyframes} from "@emotion/react" -import { NewsbannerHookReturn, useNewsbanner as _useNewsbanner } from "./Newsbanner.hooks"; +import { Alert, Box, Collapse, IconButton } from '@mui/material' +import CloseIcon from '@mui/icons-material/Close' +import { useCallback, useEffect, useState } from 'react' +import { keyframes } from '@emotion/react' +import { NewsbannerHookReturn, useNewsbanner as _useNewsbanner } from './Newsbanner.hooks' const scrolling = keyframes` from { @@ -11,61 +11,70 @@ const scrolling = keyframes` to { transform: translateX(-100%) } -`; -export type NewsbannerProps={ - useNewsbanner?:()=>NewsbannerHookReturn +` +export type NewsbannerProps = { + useNewsbanner?: () => NewsbannerHookReturn } /** * Newsbanner component * @remarks - * Newsbanner shows a banner between the menubar and the breadcrumbs, + * Newsbanner shows a banner between the menubar and the breadcrumbs, * but only if there are news. * @category Components */ -const Newsbanner=({useNewsbanner=_useNewsbanner}:NewsbannerProps)=>{ - const [open, setOpen]=useState(false) - const [text, setText]=useState('') - const {checkForNews, receiveContent}=useNewsbanner() +const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { + const [open, setOpen] = useState(false) + const [text, setText] = useState('') + const { checkForNews, receiveContent } = useNewsbanner() - useEffect(() => {checkForNews().then(isNewsAvaliable => { - setOpen(isNewsAvaliable) - })}, []) + useEffect(() => { + checkForNews().then((isNewsAvaliable) => { + setOpen(isNewsAvaliable) + }) + }, []) - useEffect(() => {receiveContent().then(showNews => { - console.log(showNews) - setText(showNews) - })}, []) - - //fetch von backend, localStorage abfrage ob schon gesehen, date, expirationdate, - //TODO: Text anpassen auf Bildschrimgroesse und textlaenge - return( - <> - { - (open)&&( + useEffect(() => { + receiveContent().then((showNews) => { + setText(showNews) + }) + }, []) - - - - - {setOpen(false)}}> - - + //fetch von backend, localStorage abfrage ob schon gesehen, date, expirationdate, + //TODO: Text anpassen auf Bildschrimgroesse und textlaenge + return ( + <> + {open && ( + + + - - {text} - - - + }} + action={ + { + setOpen(false) + }}> + + + }> + + {text} + + + - ) -} - - ) + )} + + ) } -export default Newsbanner \ No newline at end of file +export default Newsbanner diff --git a/src/pages/MainFrame/MainFrame.tsx b/src/pages/MainFrame/MainFrame.tsx index fdb599845..e09f7f32c 100644 --- a/src/pages/MainFrame/MainFrame.tsx +++ b/src/pages/MainFrame/MainFrame.tsx @@ -1,6 +1,14 @@ import { Outlet, useParams } from 'react-router-dom' import { Box, Divider, Grid, Stack } from '@common/components' -import { BreadcrumbsContainer, Footer, LocalNav, MenuBar, OpenQuestionnaire, PrivacyModal, Newsbanner } from '@components' +import { + BreadcrumbsContainer, + Footer, + LocalNav, + MenuBar, + OpenQuestionnaire, + PrivacyModal, + Newsbanner +} from '@components' /** * # MainFrame Page @@ -27,7 +35,7 @@ export const MainFrame = () => { <> {renderMenuBar ? : } - + diff --git a/src/services/News/fetchNews.tsx b/src/services/News/fetchNews.tsx index 82fdf5121..818d5487c 100644 --- a/src/services/News/fetchNews.tsx +++ b/src/services/News/fetchNews.tsx @@ -1,17 +1,17 @@ import { getConfig } from '@shared' -import {fetchData} from '../RequestResponse' +import { fetchData } from '../RequestResponse' import { NewsList } from '@core' /** - * + * * @returns {@link News} object */ -export const fetchNews =async(languageId?:string, university?:string):Promise=>{ - return fetchData(getConfig().BACKEND + `/news?language_id=${languageId}&university=${university}`,{ - method:'GET', - credentials:'include', - headers:{ - 'Content-Type': 'application/json' - } - }) -} \ No newline at end of file +export const fetchNews = async (languageId?: string, university?: string): Promise => { + return fetchData(getConfig().BACKEND + `/news?language_id=${languageId}&university=${university}`, { + method: 'GET', + credentials: 'include', + headers: { + 'Content-Type': 'application/json' + } + }) +} From 24db5602eabc0241fe79b8c48eaaf5b5390528b1 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Wed, 8 May 2024 13:55:28 +0200 Subject: [PATCH 12/41] added university as a value to the get --- src/common/utils/UniversityCheck.tsx | 29 +++++++++++++++++++ src/common/utils/index.ts | 2 +- .../Newsbanner/Newsbanner.hooks.tsx | 22 ++++++++++---- .../PrivacyModal/PrivacyModal.hooks.tsx | 21 ++------------ src/components/PrivacyModal/PrivacyModal.tsx | 10 +++++-- src/core/News/News.ts | 4 ++- src/core/index.ts | 1 + src/store/Slices/NewsSlice.ts | 6 ++-- 8 files changed, 63 insertions(+), 32 deletions(-) create mode 100644 src/common/utils/UniversityCheck.tsx diff --git a/src/common/utils/UniversityCheck.tsx b/src/common/utils/UniversityCheck.tsx new file mode 100644 index 000000000..06f958912 --- /dev/null +++ b/src/common/utils/UniversityCheck.tsx @@ -0,0 +1,29 @@ +import log from 'loglevel' +import { usePersistedStore } from '@store' +import { useMemo } from 'react' + +export type UniversityCheckReturn = { + readonly checkUniversity: () => Promise +} + +export const UniversityCheck = (): UniversityCheckReturn => { + const getUser = usePersistedStore((state) => state.getUser) + //fetch the university from the current user and return university + const checkUniversity = async () => { + return getUser() + .then((user) => { + return user.university + }) + .catch((reason) => { + log.error(reason) + return '' + }) + } + + return useMemo( + () => ({ + checkUniversity + }), + [checkUniversity] + ) +} diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts index a4ac20c38..092843643 100644 --- a/src/common/utils/index.ts +++ b/src/common/utils/index.ts @@ -1,5 +1,5 @@ import { HaskiTheme } from './Theme/HaskiTheme' import { Theme } from './Theme/Theme' import { reportWebVitals, sendToAnalytics } from './Webvitals/Webvitals' - +export * from './UniversityCheck' export { reportWebVitals, sendToAnalytics, Theme, HaskiTheme } diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index a7a4d41d7..8a25fa264 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -1,18 +1,20 @@ import log from 'loglevel' import { useCallback, useMemo, useState } from 'react' +import { UniversityCheck as _UniversityCheck, UniversityCheck, UniversityCheckReturn } from '@common/utils' import { useStore } from '@store' export type NewsbannerHookReturn = { readonly checkForNews: () => Promise readonly receiveContent: () => Promise - readonly currentNewsLength: 0 + readonly receiveUni:()=>void } export const useNewsbanner = (): NewsbannerHookReturn => { const getNews = useStore((state) => state.getNews) - + const {checkUniversity} = UniversityCheck() //stores the character length of the news const [newsLength, setNewsLength] = useState(0) + const [uni, setUni] = useState("") //** Logic **/ const checkLanguage = () => { @@ -20,9 +22,17 @@ export const useNewsbanner = (): NewsbannerHookReturn => { return lang } + const receiveUni = () => { + return checkUniversity().then((university) => { + setUni( university) + }) + + } + //check if there are any news const checkForNews = async () => { - return getNews() + console.log(receiveUni()) + return getNews(checkLanguage(), uni) .then((news) => { return news.news.length != 0 }) @@ -34,7 +44,7 @@ export const useNewsbanner = (): NewsbannerHookReturn => { //returns combined string of all the news const receiveContent = async () => { - return getNews() + return getNews(checkLanguage(), uni) .then((news) => { const contentA = news.news.map(({ news_content }) => news_content).join(', ') setNewsLength(contentA.length) @@ -47,7 +57,7 @@ export const useNewsbanner = (): NewsbannerHookReturn => { } return useMemo( - () => ({ checkForNews, receiveContent, checkLanguage, newsLength }), - [checkForNews, receiveContent, checkLanguage, newsLength] + () => ({ checkForNews, receiveContent, checkLanguage, receiveUni }), + [checkForNews, receiveContent, checkLanguage, receiveUni] ) } diff --git a/src/components/PrivacyModal/PrivacyModal.hooks.tsx b/src/components/PrivacyModal/PrivacyModal.hooks.tsx index b2a900ad4..22b9677d0 100644 --- a/src/components/PrivacyModal/PrivacyModal.hooks.tsx +++ b/src/components/PrivacyModal/PrivacyModal.hooks.tsx @@ -1,9 +1,7 @@ -import log from 'loglevel' import { useCallback, useContext, useMemo } from 'react' import { CookiesProvider, useCookies } from 'react-cookie' import { useTranslation } from 'react-i18next' import { SnackbarContext } from '@services' -import { usePersistedStore } from '@store' /** * @prop privacyPolicyCookie - The currently set cookie @@ -16,7 +14,6 @@ import { usePersistedStore } from '@store' export type PrivacyModalHookReturn = { readonly privacyPolicyCookie: CookiesProvider readonly handleAccept: (isAccepted: boolean) => void - readonly checkUniversity: () => Promise } /** @@ -35,21 +32,8 @@ export const usePrivacyModal = (): PrivacyModalHookReturn => { const { addSnackbar } = useContext(SnackbarContext) const [cookies, setCookie] = useCookies(['privacy_accept_token']) const privacyPolicyCookie = cookies['privacy_accept_token'] - const getUser = usePersistedStore((state) => state.getUser) //**Logic **// - //fetch the university from the current user and return university - const checkUniversity = async () => { - return getUser() - .then((user) => { - return user.university - }) - .catch((reason) => { - log.error(reason) - return '' - }) - } - const handleAccept = useCallback( (isAccepted: boolean) => { if (isAccepted) { @@ -76,9 +60,8 @@ export const usePrivacyModal = (): PrivacyModalHookReturn => { return useMemo( () => ({ privacyPolicyCookie, - handleAccept, - checkUniversity + handleAccept }), - [privacyPolicyCookie, handleAccept, checkUniversity] + [privacyPolicyCookie, handleAccept] ) } diff --git a/src/components/PrivacyModal/PrivacyModal.tsx b/src/components/PrivacyModal/PrivacyModal.tsx index c6251df7d..b4c34d791 100644 --- a/src/components/PrivacyModal/PrivacyModal.tsx +++ b/src/components/PrivacyModal/PrivacyModal.tsx @@ -13,6 +13,7 @@ import { Typography } from '@common/components' import { PrivacyModalHookReturn, usePrivacyModal as _usePrivacyModal } from './PrivacyModal.hooks' +import { UniversityCheck as _UniversityCheck, UniversityCheckReturn } from '@common/utils' const style = { position: 'absolute', @@ -34,6 +35,7 @@ const style = { export type PrivacyModalProps = { usePrivacyModal?: () => PrivacyModalHookReturn + UniversityCheck?: () => UniversityCheckReturn } /** @@ -49,12 +51,16 @@ export type PrivacyModalProps = { * @category Components */ -const PrivacyModal = ({ usePrivacyModal = _usePrivacyModal }: PrivacyModalProps) => { +const PrivacyModal = ({ + usePrivacyModal = _usePrivacyModal, + UniversityCheck = _UniversityCheck +}: PrivacyModalProps) => { const { t } = useTranslation() const navigate = useNavigate() const [open, setOpen] = useState(true) const [checked, setChecked] = useState(false) - const { privacyPolicyCookie, handleAccept, checkUniversity } = usePrivacyModal() + const { privacyPolicyCookie, handleAccept } = usePrivacyModal() + const { checkUniversity } = UniversityCheck() const currentLocation = useLocation() //Disable backdropClick so the Modal only closes via the buttons diff --git a/src/core/News/News.ts b/src/core/News/News.ts index 15d479d66..61a22e1b5 100644 --- a/src/core/News/News.ts +++ b/src/core/News/News.ts @@ -1,3 +1,5 @@ +type NewsReturn = (languageId?: string, university?: string) => Promise + type NewsList = { news: News[] } @@ -6,4 +8,4 @@ type News = { news_content: string } export default News -export type { NewsList } +export type { NewsList, NewsReturn } diff --git a/src/core/index.ts b/src/core/index.ts index 714cc5644..37a95d2bf 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -61,3 +61,4 @@ export type { LearningPathTopicReturn } from './LearningPathTopic/LearningPathTo export type { ListKReturn } from './QuestionnaireResults/ListK' export type { CourseReturn } from './Course/Course' export type { ILSReturn } from './QuestionnaireResults/ILS' +export type { NewsReturn } from './News/News' diff --git a/src/store/Slices/NewsSlice.ts b/src/store/Slices/NewsSlice.ts index a7a6b94cb..1ca0e2ac6 100644 --- a/src/store/Slices/NewsSlice.ts +++ b/src/store/Slices/NewsSlice.ts @@ -1,12 +1,12 @@ import { StateCreator } from 'zustand' -import { NewsList } from '@core' +import { NewsList, NewsReturn } from '@core' import { fetchNews } from '@services' import { StoreState } from '@store' import { resetters } from '../Zustand/Store' export default interface NewsSlice { _news: Record - getNews: (languageId?: NewsList, university?: NewsList) => Promise + getNews: NewsReturn } export const createNewsSlice: StateCreator = (set, get) => { @@ -19,7 +19,7 @@ export const createNewsSlice: StateCreator = (set const cached = get()._news[`${languageId}-${university}`] if (!cached) { - const news = await fetchNews('eng', 'HS-KE') + const news = await fetchNews(languageId, university) set({ _news: { ...get()._news, From 367fcb02fcb747936ac8641dbb93c1ac198702cd Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Tue, 14 May 2024 13:58:00 +0200 Subject: [PATCH 13/41] university works --- src/components/Newsbanner/Newsbanner.hooks.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index 8a25fa264..2f49bd3c4 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -24,16 +24,20 @@ export const useNewsbanner = (): NewsbannerHookReturn => { const receiveUni = () => { return checkUniversity().then((university) => { - setUni( university) + setUni(university) + console.log("university:", uni) + }) + .catch((reason) =>{ + log.error(reason) + return '' }) - } //check if there are any news const checkForNews = async () => { - console.log(receiveUni()) return getNews(checkLanguage(), uni) .then((news) => { + console.log("news:",news, "lang", checkLanguage()) return news.news.length != 0 }) .catch((reason) => { From a09154bfd3025c0f0f3d04794edf13a29776c748 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Wed, 15 May 2024 13:13:35 +0200 Subject: [PATCH 14/41] merged checkForNews and receiveContent --- .../Newsbanner/Newsbanner.hooks.tsx | 63 +++++++------------ src/components/Newsbanner/Newsbanner.tsx | 11 ++-- 2 files changed, 27 insertions(+), 47 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index 2f49bd3c4..c9e87e3a9 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -1,20 +1,17 @@ import log from 'loglevel' -import { useCallback, useMemo, useState } from 'react' +import { useCallback, useEffect, useMemo, useState } from 'react' import { UniversityCheck as _UniversityCheck, UniversityCheck, UniversityCheckReturn } from '@common/utils' import { useStore } from '@store' export type NewsbannerHookReturn = { - readonly checkForNews: () => Promise - readonly receiveContent: () => Promise - readonly receiveUni:()=>void + readonly checkForNews: () => Promise } export const useNewsbanner = (): NewsbannerHookReturn => { const getNews = useStore((state) => state.getNews) - const {checkUniversity} = UniversityCheck() - //stores the character length of the news - const [newsLength, setNewsLength] = useState(0) - const [uni, setUni] = useState("") + const { checkUniversity } = UniversityCheck() + const [newsItem, setNewsItem] = useState(false) + const [toggle, setToggle] = useState(false) //** Logic **/ const checkLanguage = () => { @@ -22,37 +19,22 @@ export const useNewsbanner = (): NewsbannerHookReturn => { return lang } - const receiveUni = () => { - return checkUniversity().then((university) => { - setUni(university) - console.log("university:", uni) - }) - .catch((reason) =>{ - log.error(reason) - return '' - }) - } - - //check if there are any news - const checkForNews = async () => { - return getNews(checkLanguage(), uni) - .then((news) => { - console.log("news:",news, "lang", checkLanguage()) - return news.news.length != 0 - }) - .catch((reason) => { - log.error(reason) - return false - }) - } - //returns combined string of all the news - const receiveContent = async () => { - return getNews(checkLanguage(), uni) - .then((news) => { - const contentA = news.news.map(({ news_content }) => news_content).join(', ') - setNewsLength(contentA.length) - return JSON.stringify(contentA) + const checkForNews = async () => { + return checkUniversity() + .then((university) => { + return getNews(checkLanguage(), university) + .then((news) => { + setNewsItem(news.news.length != 0) + console.log('hookItem',newsItem) + const contentA = news.news.map(({ news_content }) => news_content).join(', ') + console.log('news:', news, 'lang', checkLanguage(), 'university:', university) + return JSON.stringify(contentA) + }) + .catch((reason) => { + log.error(reason) + return '' + }) }) .catch((reason) => { log.error(reason) @@ -60,8 +42,5 @@ export const useNewsbanner = (): NewsbannerHookReturn => { }) } - return useMemo( - () => ({ checkForNews, receiveContent, checkLanguage, receiveUni }), - [checkForNews, receiveContent, checkLanguage, receiveUni] - ) + return useMemo(() => ({ checkForNews, checkLanguage, newsItem }), [checkForNews, checkLanguage, newsItem]) } diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index ee8a3fc28..32bccb815 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -27,16 +27,17 @@ export type NewsbannerProps = { const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { const [open, setOpen] = useState(false) const [text, setText] = useState('') - const { checkForNews, receiveContent } = useNewsbanner() + const { checkForNews, newsItem } = useNewsbanner() useEffect(() => { - checkForNews().then((isNewsAvaliable) => { - setOpen(isNewsAvaliable) - }) + if (newsItem){ + setOpen(true) + console.log('bannerItem',newsItem) + } }, []) useEffect(() => { - receiveContent().then((showNews) => { + checkForNews().then((showNews) => { setText(showNews) }) }, []) From 9565f681f6350184dc1b904395fca7a4157ac2a3 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Wed, 15 May 2024 13:57:17 +0200 Subject: [PATCH 15/41] function for showing newsbanner --- src/components/Newsbanner/Newsbanner.hooks.tsx | 10 +++++++--- src/components/Newsbanner/Newsbanner.tsx | 15 ++++++++------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index c9e87e3a9..f68f924e1 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -5,6 +5,7 @@ import { useStore } from '@store' export type NewsbannerHookReturn = { readonly checkForNews: () => Promise + readonly hasItem:()=>boolean } export const useNewsbanner = (): NewsbannerHookReturn => { @@ -19,14 +20,17 @@ export const useNewsbanner = (): NewsbannerHookReturn => { return lang } + const hasItem =()=>{ + return newsItem + } + //returns combined string of all the news const checkForNews = async () => { return checkUniversity() .then((university) => { return getNews(checkLanguage(), university) .then((news) => { - setNewsItem(news.news.length != 0) - console.log('hookItem',newsItem) + setNewsItem(news.news.length!=0) const contentA = news.news.map(({ news_content }) => news_content).join(', ') console.log('news:', news, 'lang', checkLanguage(), 'university:', university) return JSON.stringify(contentA) @@ -42,5 +46,5 @@ export const useNewsbanner = (): NewsbannerHookReturn => { }) } - return useMemo(() => ({ checkForNews, checkLanguage, newsItem }), [checkForNews, checkLanguage, newsItem]) + return useMemo(() => ({ checkForNews, checkLanguage, hasItem, newsItem }), [checkForNews, checkLanguage, hasItem, newsItem]) } diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index 32bccb815..7a8f11d1f 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -27,20 +27,21 @@ export type NewsbannerProps = { const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { const [open, setOpen] = useState(false) const [text, setText] = useState('') - const { checkForNews, newsItem } = useNewsbanner() + const { checkForNews, hasItem } = useNewsbanner() useEffect(() => { - if (newsItem){ - setOpen(true) - console.log('bannerItem',newsItem) - } - }, []) + checkForNews().then((showNews) => { + if(hasItem()){ + setOpen(true) + } + }) + }, [hasItem]) useEffect(() => { checkForNews().then((showNews) => { setText(showNews) }) - }, []) + }, [checkForNews]) //fetch von backend, localStorage abfrage ob schon gesehen, date, expirationdate, //TODO: Text anpassen auf Bildschrimgroesse und textlaenge From 39d2df3c00922bc709277142957de8c46a90fb9f Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Thu, 16 May 2024 12:48:13 +0200 Subject: [PATCH 16/41] language change works --- src/components/Newsbanner/Newsbanner.hooks.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index f68f924e1..7d5693052 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -2,6 +2,7 @@ import log from 'loglevel' import { useCallback, useEffect, useMemo, useState } from 'react' import { UniversityCheck as _UniversityCheck, UniversityCheck, UniversityCheckReturn } from '@common/utils' import { useStore } from '@store' +import i18next from 'i18next' export type NewsbannerHookReturn = { readonly checkForNews: () => Promise @@ -11,12 +12,18 @@ export type NewsbannerHookReturn = { export const useNewsbanner = (): NewsbannerHookReturn => { const getNews = useStore((state) => state.getNews) const { checkUniversity } = UniversityCheck() + const [lang, setLang]=useState(localStorage.getItem('i18nextLng')?.toLowerCase()) const [newsItem, setNewsItem] = useState(false) const [toggle, setToggle] = useState(false) + i18next.on('languageChanged', (lng: string) => { + console.log('Language changed to:', lng); + setLang(lng) + // Translate and log the new language + console.log(i18next.t('key')); + }) //** Logic **/ const checkLanguage = () => { - const lang = localStorage.getItem('i18nextLng')?.toLowerCase() return lang } From 6b5ae6b8fbe6c4029732e8c69070814f3261ceac Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Tue, 21 May 2024 13:19:59 +0200 Subject: [PATCH 17/41] added snackbar and errormessage --- .../Newsbanner/Newsbanner.hooks.tsx | 29 ++++++++++++++----- .../translation/translationEnglish.json | 2 ++ src/shared/translation/translationGerman.json | 2 ++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index 7d5693052..27f2abdbd 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -1,7 +1,9 @@ import log from 'loglevel' -import { useCallback, useEffect, useMemo, useState } from 'react' +import { useCallback, useMemo, useState, useContext } from 'react' import { UniversityCheck as _UniversityCheck, UniversityCheck, UniversityCheckReturn } from '@common/utils' +import { SnackbarContext } from '@services' import { useStore } from '@store' +import { useTranslation } from 'react-i18next' import i18next from 'i18next' export type NewsbannerHookReturn = { @@ -10,17 +12,17 @@ export type NewsbannerHookReturn = { } export const useNewsbanner = (): NewsbannerHookReturn => { + const {t}=useTranslation() + const { addSnackbar } = useContext(SnackbarContext) const getNews = useStore((state) => state.getNews) const { checkUniversity } = UniversityCheck() const [lang, setLang]=useState(localStorage.getItem('i18nextLng')?.toLowerCase()) const [newsItem, setNewsItem] = useState(false) - const [toggle, setToggle] = useState(false) + i18next.on('languageChanged', (lng: string) => { console.log('Language changed to:', lng); setLang(lng) - // Translate and log the new language - console.log(i18next.t('key')); }) //** Logic **/ const checkLanguage = () => { @@ -32,6 +34,7 @@ export const useNewsbanner = (): NewsbannerHookReturn => { } //returns combined string of all the news + //and the amount of messages const checkForNews = async () => { return checkUniversity() .then((university) => { @@ -42,13 +45,23 @@ export const useNewsbanner = (): NewsbannerHookReturn => { console.log('news:', news, 'lang', checkLanguage(), 'university:', university) return JSON.stringify(contentA) }) - .catch((reason) => { - log.error(reason) + .catch((error) => { + addSnackbar({ + message: t('error.getNews') + error, + severity: 'error', + autoHideDuration: 3000 + }) + log.error('error.getNews', 'Error: '+ error) return '' }) }) - .catch((reason) => { - log.error(reason) + .catch((error) => { + addSnackbar({ + message: t('error.getUniversity') + error, + severity: 'error', + autoHideDuration: 3000 + }) + log.error('error.getUniversity', 'Error: '+ error) return '' }) } diff --git a/src/shared/translation/translationEnglish.json b/src/shared/translation/translationEnglish.json index 5b9d9218d..44c5e4268 100644 --- a/src/shared/translation/translationEnglish.json +++ b/src/shared/translation/translationEnglish.json @@ -1138,6 +1138,8 @@ "error.postCalculateLearningPathILS": "There was an error calculating the Learning Path based on the ILS questionnaire data", "error.postILS": "ILS Questionnaire could not be sent.", "error.postListK": "ListK Questionnaire could not be sent.", + "error.getNews": "There was an Error fetching the news data.", + "error.getUniversity": "There was an Error fetching the university. Check if the user is valid.", "info": "Info", "pages.1": "1", "pages.10": "10", diff --git a/src/shared/translation/translationGerman.json b/src/shared/translation/translationGerman.json index a7c36d43c..2e76cc1da 100644 --- a/src/shared/translation/translationGerman.json +++ b/src/shared/translation/translationGerman.json @@ -1138,6 +1138,8 @@ "error.postCalculateLearningPathILS": "Es gab einen Fehler beim Berechnen des Lernpfades auf Basis des ILS Fragebogens.", "error.postILS": "ILS Fragebogen konnte nicht gesendet werden.", "error.postListK": "ListK Fragebogen konnte nicht gesendet werden.", + "error.getNews": "Es gab einen Fehler beim Abrufen der news.", + "error.getUniversity": "Es gab einen Fehler beim Abrufen der Universität. Prüfen Sie ob ein Benutzer vorhanden ist.", "info": "Info", "pages.1": "1", "pages.10": "10", From 47b62e4205152721c756929cb4c629241bdffffe Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Thu, 23 May 2024 12:51:14 +0200 Subject: [PATCH 18/41] fitting text to the banner --- src/components/Newsbanner/Newsbanner.tsx | 25 +++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index 7a8f11d1f..fd6fb3364 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -4,14 +4,7 @@ import { useCallback, useEffect, useState } from 'react' import { keyframes } from '@emotion/react' import { NewsbannerHookReturn, useNewsbanner as _useNewsbanner } from './Newsbanner.hooks' -const scrolling = keyframes` - from { - transform: translateX(100%) - }, - to { - transform: translateX(-100%) - } -` + export type NewsbannerProps = { useNewsbanner?: () => NewsbannerHookReturn } @@ -43,6 +36,20 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { }) }, [checkForNews]) + + const text_len = text.length * 10 + const screen_width = 1360 + const text_percent = text_len / screen_width + + const scrolling = keyframes` + from { + transform: translateX(100%) + }, + to { + transform: translateX(-${text_percent * 100}%) + } +` + //fetch von backend, localStorage abfrage ob schon gesehen, date, expirationdate, //TODO: Text anpassen auf Bildschrimgroesse und textlaenge return ( @@ -69,7 +76,7 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { }> + sx={{ animation: `${scrolling} 30s linear infinite`, transform: `translateX(100%)`, width: '1360px' }}> {text} From 3a6a10810bd7462a192cab694dbc210a09221040 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Mon, 27 May 2024 12:35:09 +0200 Subject: [PATCH 19/41] screen resize works --- src/components/Newsbanner/Newsbanner.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index fd6fb3364..9613e8c9a 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -38,8 +38,8 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { const text_len = text.length * 10 - const screen_width = 1360 - const text_percent = text_len / screen_width + const window_width = window.innerWidth + const text_percent = text_len / window_width const scrolling = keyframes` from { @@ -51,7 +51,6 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { ` //fetch von backend, localStorage abfrage ob schon gesehen, date, expirationdate, - //TODO: Text anpassen auf Bildschrimgroesse und textlaenge return ( <> {open && ( @@ -76,7 +75,7 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { }> + sx={{ animation: `${scrolling} 30s linear infinite`, transform: `translateX(100%)`, width: window_width }}> {text} From 97d9b6573f16f392cbfde21d47c36f897d8f73ea Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Wed, 29 May 2024 10:26:56 +0200 Subject: [PATCH 20/41] added storage, removed console.log --- src/components/Newsbanner/Newsbanner.hooks.tsx | 3 +-- src/components/Newsbanner/Newsbanner.tsx | 16 ++++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index 27f2abdbd..b179daafa 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -21,7 +21,6 @@ export const useNewsbanner = (): NewsbannerHookReturn => { i18next.on('languageChanged', (lng: string) => { - console.log('Language changed to:', lng); setLang(lng) }) //** Logic **/ @@ -42,7 +41,7 @@ export const useNewsbanner = (): NewsbannerHookReturn => { .then((news) => { setNewsItem(news.news.length!=0) const contentA = news.news.map(({ news_content }) => news_content).join(', ') - console.log('news:', news, 'lang', checkLanguage(), 'university:', university) + //console.log('news:', news, 'lang', checkLanguage(), 'university:', university) return JSON.stringify(contentA) }) .catch((error) => { diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index 9613e8c9a..79d8c088e 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -13,15 +13,18 @@ export type NewsbannerProps = { * Newsbanner component * @remarks * Newsbanner shows a banner between the menubar and the breadcrumbs, - * but only if there are news. + * but only if there are news. The news get fitted by their charakter length. + * The closed state gets saved in the localstorage * @category Components */ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { const [open, setOpen] = useState(false) + const [close, setClose] = useState(localStorage.getItem('newsCloseState') == "true") const [text, setText] = useState('') const { checkForNews, hasItem } = useNewsbanner() + //checks if there are any news useEffect(() => { checkForNews().then((showNews) => { if(hasItem()){ @@ -30,13 +33,14 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { }) }, [hasItem]) + //sets Text to be displayed useEffect(() => { checkForNews().then((showNews) => { setText(showNews) }) }, [checkForNews]) - + //Animation logic const text_len = text.length * 10 const window_width = window.innerWidth const text_percent = text_len / window_width @@ -49,11 +53,10 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { transform: translateX(-${text_percent * 100}%) } ` - - //fetch von backend, localStorage abfrage ob schon gesehen, date, expirationdate, + //+TODO: Option for reopening news return ( <> - {open && ( + {open && !close && ( { color="inherit" size="small" onClick={() => { - setOpen(false) + setClose(true) + localStorage.setItem('newsCloseState', true ? "true" : "false") }}> From 5ef6443510015a0d2d0dc8e0ee7d2facac966843 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Wed, 29 May 2024 12:42:13 +0200 Subject: [PATCH 21/41] added NewsSlice test --- .../Newsbanner/Newsbanner.hooks.tsx | 2 +- src/components/Newsbanner/Newsbanner.tsx | 9 ++- src/store/Slices/NewsSlice.test.ts | 74 +++++++++++++++++++ 3 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 src/store/Slices/NewsSlice.test.ts diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index b179daafa..416f3837e 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -1,5 +1,5 @@ import log from 'loglevel' -import { useCallback, useMemo, useState, useContext } from 'react' +import { useMemo, useState, useContext } from 'react' import { UniversityCheck as _UniversityCheck, UniversityCheck, UniversityCheckReturn } from '@common/utils' import { SnackbarContext } from '@services' import { useStore } from '@store' diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index 79d8c088e..c3fafbdc2 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -1,6 +1,6 @@ import { Alert, Box, Collapse, IconButton } from '@mui/material' import CloseIcon from '@mui/icons-material/Close' -import { useCallback, useEffect, useState } from 'react' +import { useEffect, useState } from 'react' import { keyframes } from '@emotion/react' import { NewsbannerHookReturn, useNewsbanner as _useNewsbanner } from './Newsbanner.hooks' @@ -14,13 +14,13 @@ export type NewsbannerProps = { * @remarks * Newsbanner shows a banner between the menubar and the breadcrumbs, * but only if there are news. The news get fitted by their charakter length. - * The closed state gets saved in the localstorage + * The closed state gets saved in the sessionStorage and removed when the window closes. * @category Components */ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { const [open, setOpen] = useState(false) - const [close, setClose] = useState(localStorage.getItem('newsCloseState') == "true") + const [close, setClose] = useState(sessionStorage.getItem('newsCloseState') == "true") const [text, setText] = useState('') const { checkForNews, hasItem } = useNewsbanner() @@ -54,6 +54,7 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { } ` //+TODO: Option for reopening news + // Reopen new news return ( <> {open && !close && ( @@ -73,7 +74,7 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { size="small" onClick={() => { setClose(true) - localStorage.setItem('newsCloseState', true ? "true" : "false") + sessionStorage.setItem('newsCloseState', true ? "true" : "false") }}> diff --git a/src/store/Slices/NewsSlice.test.ts b/src/store/Slices/NewsSlice.test.ts new file mode 100644 index 000000000..0effb38e7 --- /dev/null +++ b/src/store/Slices/NewsSlice.test.ts @@ -0,0 +1,74 @@ +import '@testing-library/jest-dom' +import { mockServices } from 'jest.setup' +import { useStore } from '../Zustand/Store' + +describe('NewsSlice', () => { + afterEach(() => { + jest.clearAllMocks() + }) + + it('should fetch news and cache them', async () => { + const { getNews } = useStore.getState() + const news = { + news: [ + { + date: 'Thu, 13 Jul 2023 16:00:00 GMT', + expiration_date: 'Sun, 20 Apr 2025 16:00:00 GMT', + id: 1, + language_id: 'de', + news_content: 'We are currently testing the site', + university: null + }, + { + date: 'Thu, 13 Jul 2023 16:00:00 GMT', + expiration_date: 'Sun, 20 Apr 2025 16:00:00 GMT', + id: 1, + language_id: 'de', + news_content: 'We are currently testing the site', + university: null + } + ] + } + + const languageId = 'en' + const university = 'HS-AS' + + const result = await getNews(languageId, university) + + expect(result).toEqual(news) + expect(getNews).toBeDefined() + expect(getNews).toBeInstanceOf(Function) + expect(mockServices.fetchNews).toHaveBeenCalledTimes(1) + expect(mockServices.fetchNews).toHaveBeenCalledWith('en', 'HS-AS') + expect(useStore.getState()._news[`${languageId}-${university}`]).toEqual(news) + expect(getNews).not.toThrow() // counts as function call (getCourses), here it would be Called 2 times instead of 1 + }) + + it('should return cached news if available', async () => { + const { getNews } = useStore.getState() + const news = [ + { + date: 'Thu, 13 Jul 2023 16:00:00 GMT', + expiration_date: 'Sun, 20 Apr 2025 16:00:00 GMT', + id: 1, + language_id: 'de', + news_content: 'We are currently testing the site', + university: null + } + ] + mockServices.fetchNews = jest.fn().mockResolvedValueOnce(news) + + const languageId = 'en' + const university = 'HS-AS' + + await getNews(languageId, university) + + expect(useStore.getState()._news[`${languageId}-${university}`]).toEqual(news) + + const cached = await getNews('en', 'HS-AS') + + expect(mockServices.fetchNews).toHaveBeenCalledTimes(1) + + expect(cached).toEqual(news) + }) +}) From 4fc04bd9ba5006c1adc6eec76529d38d58c949dd Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Tue, 4 Jun 2024 11:39:23 +0200 Subject: [PATCH 22/41] fixed the NewsSlice.test --- jest.setup.ts | 22 +++++++++++++++ src/common/utils/UniversityCheck.test.tsx | 28 +++++++++++++++++++ .../PrivacyModal/PrivacyModal.test.tsx | 2 ++ src/store/Slices/NewsSlice.test.ts | 10 +++---- 4 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 src/common/utils/UniversityCheck.test.tsx diff --git a/jest.setup.ts b/jest.setup.ts index 92c9b45df..df982b9b5 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -348,6 +348,28 @@ const mockDataServices: MockDataServices = { timecompleted: '1699967821' } ]) + ), + fetchNews: jest.fn(() => + Promise.resolve({ + news: [ + { + date: 'Thu, 13 Jul 2023 16:00:00 GMT', + expiration_date: 'Sun, 20 Apr 2025 16:00:00 GMT', + id: 1, + language_id: 'en', + news_content: 'We are currently testing the site', + university: 'HS-AS' + }, + { + date: 'Thu, 13 Jul 2023 16:00:00 GMT', + expiration_date: 'Sun, 20 Apr 2025 16:00:00 GMT', + id: 2, + language_id: 'en', + news_content: 'We are currently testing the site', + university: 'HS-AS' + } + ] + }) ) } /** diff --git a/src/common/utils/UniversityCheck.test.tsx b/src/common/utils/UniversityCheck.test.tsx new file mode 100644 index 000000000..312abdba0 --- /dev/null +++ b/src/common/utils/UniversityCheck.test.tsx @@ -0,0 +1,28 @@ +import '@testing-library/jest-dom' +import { mockServices } from 'jest.setup' +import { UniversityCheck } from './UniversityCheck' + +const {checkUniversity}=UniversityCheck() + +describe('Test the UniversityCheck utility', ()=>{ + test('Should return the university', async()=>{ + mockServices.fetchUser = jest.fn().mockImplementationOnce(() => + Promise.resolve({ + id: 1, + lms_user_id: 1, + name: 'Thaddäus Tentakel', + role: 'Tester', + role_id: 1, + settings: { + id: 1, + user_id: 1, + pswd: '1234', + theme: 'test' + }, + university: 'TH-AB' + }) + ) + const currentUni=checkUniversity() + expect(await currentUni).toBe('TH-AB') + }) +}) \ No newline at end of file diff --git a/src/components/PrivacyModal/PrivacyModal.test.tsx b/src/components/PrivacyModal/PrivacyModal.test.tsx index ed559de84..90d86ccfd 100644 --- a/src/components/PrivacyModal/PrivacyModal.test.tsx +++ b/src/components/PrivacyModal/PrivacyModal.test.tsx @@ -5,8 +5,10 @@ import * as router from 'react-router' import { MemoryRouter } from 'react-router-dom' import PrivacyModal from './PrivacyModal' import { usePrivacyModal } from './PrivacyModal.hooks' +import { UniversityCheck } from '@common/utils' const navigate = jest.fn() +const { checkUniversity } = UniversityCheck() beforeEach(() => { jest.spyOn(router, 'useNavigate').mockImplementation(() => navigate) diff --git a/src/store/Slices/NewsSlice.test.ts b/src/store/Slices/NewsSlice.test.ts index 0effb38e7..cdf013ea2 100644 --- a/src/store/Slices/NewsSlice.test.ts +++ b/src/store/Slices/NewsSlice.test.ts @@ -15,17 +15,17 @@ describe('NewsSlice', () => { date: 'Thu, 13 Jul 2023 16:00:00 GMT', expiration_date: 'Sun, 20 Apr 2025 16:00:00 GMT', id: 1, - language_id: 'de', + language_id: 'en', news_content: 'We are currently testing the site', - university: null + university: 'HS-AS' }, { date: 'Thu, 13 Jul 2023 16:00:00 GMT', expiration_date: 'Sun, 20 Apr 2025 16:00:00 GMT', - id: 1, - language_id: 'de', + id: 2, + language_id: 'en', news_content: 'We are currently testing the site', - university: null + university: 'HS-AS' } ] } From 296a8af3d497e9b9e210f7189379cf0a9d27e8a7 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Wed, 5 Jun 2024 12:27:46 +0200 Subject: [PATCH 23/41] added fetchNews.test --- src/common/utils/UniversityCheck.test.tsx | 1 + src/services/News/fetchNews.test.tsx | 78 +++++++++++++++++++++++ src/store/Slices/NewsSlice.ts | 9 ++- 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 src/services/News/fetchNews.test.tsx diff --git a/src/common/utils/UniversityCheck.test.tsx b/src/common/utils/UniversityCheck.test.tsx index 312abdba0..1efe767e0 100644 --- a/src/common/utils/UniversityCheck.test.tsx +++ b/src/common/utils/UniversityCheck.test.tsx @@ -1,5 +1,6 @@ import '@testing-library/jest-dom' import { mockServices } from 'jest.setup' +import { renderHook } from '@testing-library/react' import { UniversityCheck } from './UniversityCheck' const {checkUniversity}=UniversityCheck() diff --git a/src/services/News/fetchNews.test.tsx b/src/services/News/fetchNews.test.tsx new file mode 100644 index 000000000..96e709137 --- /dev/null +++ b/src/services/News/fetchNews.test.tsx @@ -0,0 +1,78 @@ +import { getConfig } from '@shared' +import { fetchNews } from './fetchNews' + +global.fetch = jest.fn(() => + Promise.resolve({ + json: () => Promise.resolve({ status: 200 }), + ok: true, + headers: { + get: () => 'application/json' + } + }) +) as jest.Mock + +describe('Test the fetchNews functionalities', () => { + it('should return the news when the response is successful', async () => { + const expectedData = { news: 'News in english' } + const mockResponse = { + ok: true, + json: jest.fn().mockResolvedValue(expectedData) + } + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + fetch.mockResolvedValue(mockResponse) + + const languageId='en' + const university='HS-AS' + + const result = await fetchNews(languageId, university) + + expect(fetch).toHaveBeenCalledWith( + `${getConfig().BACKEND}/news?language_id=${languageId}&university=${university}`, + { + method: 'GET', + credentials: 'include', + headers: { + 'Content-Type': 'application/json' + } + } + ) + expect(result).toEqual(expectedData) + }) + + it('should throw a specific error when the response has an error variable', async () => { + const expectedError = 'Error: HTTP error undefined' + const expectedMessage = 'Error: HTTP error undefined' + + const mockResponse = { + ok: false, + json: jest.fn().mockResolvedValue({ error: expectedError, message: expectedMessage }) + } + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + fetch.mockResolvedValue(mockResponse) + + const languageId='en' + const university='HS-AS' + + await expect(fetchNews(languageId, university)).rejects.toThrow(`${expectedMessage}`) + }) + + it('should throw an unknown error when the response does not have an error variable', async () => { + const mockResponse = { + ok: false, + json: jest.fn().mockResolvedValue({}) + } + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + fetch.mockResolvedValue(mockResponse) + + const languageId='en' + const university='HS-AS' + + await expect(fetchNews(languageId, university)).rejects.toThrow('') + }) +}) diff --git a/src/store/Slices/NewsSlice.ts b/src/store/Slices/NewsSlice.ts index 1ca0e2ac6..38ae35ce9 100644 --- a/src/store/Slices/NewsSlice.ts +++ b/src/store/Slices/NewsSlice.ts @@ -7,11 +7,18 @@ import { resetters } from '../Zustand/Store' export default interface NewsSlice { _news: Record getNews: NewsReturn + setNewsCloseState(closeState: boolean): boolean + closeState: boolean } export const createNewsSlice: StateCreator = (set, get) => { - resetters.push(() => set({ _news: {} })) + resetters.push(() => set({ _news: {} })), set({ closeState: {} as boolean }) return { + closeState: {} as boolean, + setNewsCloseState: (closeState) => { + set({ closeState }) + return closeState + }, _news: {}, getNews: async (...arg) => { const [languageId, university] = arg From 1182251b24b4a39e3c402289e3903a11f1c0df85 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Wed, 5 Jun 2024 12:50:01 +0200 Subject: [PATCH 24/41] fixed tests for the PrivacyModal --- src/components/PrivacyModal/PrivacyModal.test.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/PrivacyModal/PrivacyModal.test.tsx b/src/components/PrivacyModal/PrivacyModal.test.tsx index 90d86ccfd..fa39dea11 100644 --- a/src/components/PrivacyModal/PrivacyModal.test.tsx +++ b/src/components/PrivacyModal/PrivacyModal.test.tsx @@ -8,7 +8,6 @@ import { usePrivacyModal } from './PrivacyModal.hooks' import { UniversityCheck } from '@common/utils' const navigate = jest.fn() -const { checkUniversity } = UniversityCheck() beforeEach(() => { jest.spyOn(router, 'useNavigate').mockImplementation(() => navigate) @@ -129,7 +128,7 @@ describe('Test PrivacyModal', () => { }) ) - const { result } = renderHook(() => usePrivacyModal(), { + const { result } = renderHook(() => UniversityCheck(), { wrapper: ({ children }) => {children} }) expect(await result.current.checkUniversity()).toBe('TH-AB') @@ -163,7 +162,7 @@ describe('Test PrivacyModal', () => { test('checkUniversity returns empty string when fetch fails', async () => { mockServices.fetchUser = jest.fn().mockImplementationOnce(() => Promise.reject(new Error('error'))) - const { result } = renderHook(() => usePrivacyModal(), { + const { result } = renderHook(() => UniversityCheck(), { wrapper: ({ children }) => {children} }) expect(await result.current.checkUniversity()).toBe('') From 3a914f6d30b87c3faf5768bd21e28917bed02da9 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Mon, 24 Jun 2024 17:07:48 +0200 Subject: [PATCH 25/41] added Newsbanner.test --- src/common/utils/UniversityCheck.test.tsx | 29 ------ src/components/Newsbanner/Newsbanner.test.tsx | 96 +++++++++++++++++++ src/components/Newsbanner/Newsbanner.tsx | 1 + .../PrivacyModal/PrivacyModal.test.tsx | 1 - 4 files changed, 97 insertions(+), 30 deletions(-) delete mode 100644 src/common/utils/UniversityCheck.test.tsx create mode 100644 src/components/Newsbanner/Newsbanner.test.tsx diff --git a/src/common/utils/UniversityCheck.test.tsx b/src/common/utils/UniversityCheck.test.tsx deleted file mode 100644 index 1efe767e0..000000000 --- a/src/common/utils/UniversityCheck.test.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import '@testing-library/jest-dom' -import { mockServices } from 'jest.setup' -import { renderHook } from '@testing-library/react' -import { UniversityCheck } from './UniversityCheck' - -const {checkUniversity}=UniversityCheck() - -describe('Test the UniversityCheck utility', ()=>{ - test('Should return the university', async()=>{ - mockServices.fetchUser = jest.fn().mockImplementationOnce(() => - Promise.resolve({ - id: 1, - lms_user_id: 1, - name: 'Thaddäus Tentakel', - role: 'Tester', - role_id: 1, - settings: { - id: 1, - user_id: 1, - pswd: '1234', - theme: 'test' - }, - university: 'TH-AB' - }) - ) - const currentUni=checkUniversity() - expect(await currentUni).toBe('TH-AB') - }) -}) \ No newline at end of file diff --git a/src/components/Newsbanner/Newsbanner.test.tsx b/src/components/Newsbanner/Newsbanner.test.tsx new file mode 100644 index 000000000..6fa6d7a91 --- /dev/null +++ b/src/components/Newsbanner/Newsbanner.test.tsx @@ -0,0 +1,96 @@ +import '@testing-library/jest-dom' +import { fireEvent, render, act, renderHook } from '@testing-library/react' +import { mockServices } from 'jest.setup' +import Newsbanner from './Newsbanner' +import { MemoryRouter } from 'react-router-dom' +import { UniversityCheck } from '@common/utils' + +describe("Newsbanner tests", ()=>{ + + beforeEach(() => { + window.localStorage.clear(); + }) + + test("Close the open Newsbanner", async ()=>{ + mockServices.fetchUser = jest.fn().mockImplementationOnce(() => + Promise.resolve({ + id: 1, + lms_user_id: 1, + name: 'Thaddäus Tentakel', + role: 'Tester', + role_id: 1, + settings: { + id: 1, + user_id: 1, + pswd: '1234', + theme: 'test' + }, + university: 'TH-AB' + }) + ) + + const { result } = renderHook(() => UniversityCheck(), { + wrapper: ({ children }) => {children} + }) + + expect(await result.current.checkUniversity()).toBe('TH-AB') + + mockServices.fetchNews = jest.fn().mockImplementation(()=> + Promise.resolve({ + news:[ + { + date: 'Thu, 13 Jul 2023 16:00:00 GMT', + expiration_date: 'Sun, 20 Apr 2025 16:00:00 GMT', + id: 1, + language_id: 'en', + news_content: 'We are currently testing the site', + university: 'TH-AB' + } + ] + })) + + const {container, getByTestId, rerender} = render( + + + ) + + await new Promise(process.nextTick) + + await new Promise(process.nextTick) + await new Promise(process.nextTick) + + + rerender( + + + + ) + + await new Promise(process.nextTick) + + + rerender( + + + + ) + + await act(async() => { + const closeButton = getByTestId('IconButton') + //fireEvent.click(closeButton) + expect(closeButton).toBeInTheDocument() + }) + + + }) + test("Newsbanner doesnt open because no news", ()=>{ + mockServices.fetchNews = jest.fn().mockImplementationOnce(()=> + Promise.resolve({ + news:[ + {} + ] + })) + const form = render( ) + + }) +}) \ No newline at end of file diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index c3fafbdc2..c7e11cb9c 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -72,6 +72,7 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { aria-label="close" color="inherit" size="small" + data-testid="IconButton" onClick={() => { setClose(true) sessionStorage.setItem('newsCloseState', true ? "true" : "false") diff --git a/src/components/PrivacyModal/PrivacyModal.test.tsx b/src/components/PrivacyModal/PrivacyModal.test.tsx index fa39dea11..cbee6d693 100644 --- a/src/components/PrivacyModal/PrivacyModal.test.tsx +++ b/src/components/PrivacyModal/PrivacyModal.test.tsx @@ -4,7 +4,6 @@ import { mockServices } from 'jest.setup' import * as router from 'react-router' import { MemoryRouter } from 'react-router-dom' import PrivacyModal from './PrivacyModal' -import { usePrivacyModal } from './PrivacyModal.hooks' import { UniversityCheck } from '@common/utils' const navigate = jest.fn() From 4a44b6bbdb6fc645fe831965fb081d6e6802cce3 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Thu, 27 Jun 2024 14:21:07 +0200 Subject: [PATCH 26/41] added tests and lint --- .../Newsbanner/Newsbanner.hooks.tsx | 65 +++-- src/components/Newsbanner/Newsbanner.test.tsx | 238 ++++++++++++------ src/components/Newsbanner/Newsbanner.tsx | 15 +- src/services/News/fetchNews.test.tsx | 12 +- .../translation/translationEnglish.json | 4 +- src/shared/translation/translationGerman.json | 4 +- 6 files changed, 209 insertions(+), 129 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index 416f3837e..3b6c794e0 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -1,6 +1,6 @@ import log from 'loglevel' import { useMemo, useState, useContext } from 'react' -import { UniversityCheck as _UniversityCheck, UniversityCheck, UniversityCheckReturn } from '@common/utils' +import { UniversityCheck as _UniversityCheck, UniversityCheck } from '@common/utils' import { SnackbarContext } from '@services' import { useStore } from '@store' import { useTranslation } from 'react-i18next' @@ -8,62 +8,57 @@ import i18next from 'i18next' export type NewsbannerHookReturn = { readonly checkForNews: () => Promise - readonly hasItem:()=>boolean + readonly hasItem: () => boolean } export const useNewsbanner = (): NewsbannerHookReturn => { - const {t}=useTranslation() + const { t } = useTranslation() const { addSnackbar } = useContext(SnackbarContext) const getNews = useStore((state) => state.getNews) const { checkUniversity } = UniversityCheck() - const [lang, setLang]=useState(localStorage.getItem('i18nextLng')?.toLowerCase()) + const [lang, setLang] = useState(localStorage.getItem('i18nextLng')?.toLowerCase()) const [newsItem, setNewsItem] = useState(false) - - i18next.on('languageChanged', (lng: string) => { + const handleLangChange = (lng: string) => { setLang(lng) - }) + } + + i18next.on('languageChanged', handleLangChange ) + //** Logic **/ const checkLanguage = () => { return lang } - const hasItem =()=>{ + const hasItem = () => { return newsItem } //returns combined string of all the news //and the amount of messages const checkForNews = async () => { - return checkUniversity() - .then((university) => { - return getNews(checkLanguage(), university) - .then((news) => { - setNewsItem(news.news.length!=0) - const contentA = news.news.map(({ news_content }) => news_content).join(', ') - //console.log('news:', news, 'lang', checkLanguage(), 'university:', university) - return JSON.stringify(contentA) - }) - .catch((error) => { - addSnackbar({ - message: t('error.getNews') + error, - severity: 'error', - autoHideDuration: 3000 - }) - log.error('error.getNews', 'Error: '+ error) - return '' + return checkUniversity().then((university) => { + return getNews(checkLanguage(), university) + .then((news) => { + setNewsItem(news.news.length != 0) + const contentA = news.news.map(({ news_content }) => news_content).join(', ') + //console.log('news:', news, 'lang', checkLanguage(), 'university:', university) + return JSON.stringify(contentA) + }) + .catch((error) => { + addSnackbar({ + message: t('error.getNews') + error, + severity: 'error', + autoHideDuration: 3000 }) - }) - .catch((error) => { - addSnackbar({ - message: t('error.getUniversity') + error, - severity: 'error', - autoHideDuration: 3000 + log.error('error.getNews', 'Error: ' + error) + return '' }) - log.error('error.getUniversity', 'Error: '+ error) - return '' - }) + }) } - return useMemo(() => ({ checkForNews, checkLanguage, hasItem, newsItem }), [checkForNews, checkLanguage, hasItem, newsItem]) + return useMemo( + () => ({ checkForNews, checkLanguage, hasItem, newsItem }), + [checkForNews, checkLanguage, hasItem, newsItem] + ) } diff --git a/src/components/Newsbanner/Newsbanner.test.tsx b/src/components/Newsbanner/Newsbanner.test.tsx index 6fa6d7a91..df12b83d5 100644 --- a/src/components/Newsbanner/Newsbanner.test.tsx +++ b/src/components/Newsbanner/Newsbanner.test.tsx @@ -1,96 +1,178 @@ import '@testing-library/jest-dom' -import { fireEvent, render, act, renderHook } from '@testing-library/react' +import { fireEvent, render, act, renderHook, getByTestId } from '@testing-library/react' import { mockServices } from 'jest.setup' import Newsbanner from './Newsbanner' import { MemoryRouter } from 'react-router-dom' import { UniversityCheck } from '@common/utils' +import { LanguageMenu } from '@components' +import { I18nextProvider } from 'react-i18next' +import { useNewsbanner } from './Newsbanner.hooks' -describe("Newsbanner tests", ()=>{ +describe('Newsbanner tests', () => { + beforeEach(() => { + window.localStorage.clear() + }) + const useNewsbanner = jest.fn(()=>{ + return{ handleLangChange: 'en'} + }) + test('Newsbanner is open', async () => { + mockServices.fetchNews = jest.fn().mockImplementation(() => + Promise.resolve({ + news: [ + { + date: 'Thu, 13 Jul 2023 16:00:00 GMT', + expiration_date: 'Sun, 20 Apr 2025 16:00:00 GMT', + id: 1, + language_id: 'en', + news_content: 'We are currently testing the site', + university: 'TH-AB' + } + ] + }) + ) - beforeEach(() => { - window.localStorage.clear(); + const { container, getByTestId, rerender } = render( + + + + ) + + await new Promise(process.nextTick) + + rerender( + + + + ) + + await new Promise(process.nextTick) + + rerender( + + + + ) + await act(async () => { + const closeButton = getByTestId('IconButton') + expect(closeButton).toBeInTheDocument() }) - - test("Close the open Newsbanner", async ()=>{ - mockServices.fetchUser = jest.fn().mockImplementationOnce(() => - Promise.resolve({ - id: 1, - lms_user_id: 1, - name: 'Thaddäus Tentakel', - role: 'Tester', - role_id: 1, - settings: { - id: 1, - user_id: 1, - pswd: '1234', - theme: 'test' - }, - university: 'TH-AB' - }) - ) - - const { result } = renderHook(() => UniversityCheck(), { - wrapper: ({ children }) => {children} - }) - - expect(await result.current.checkUniversity()).toBe('TH-AB') - - mockServices.fetchNews = jest.fn().mockImplementation(()=> - Promise.resolve({ - news:[ - { - date: 'Thu, 13 Jul 2023 16:00:00 GMT', - expiration_date: 'Sun, 20 Apr 2025 16:00:00 GMT', - id: 1, - language_id: 'en', - news_content: 'We are currently testing the site', - university: 'TH-AB' - } - ] - })) - - const {container, getByTestId, rerender} = render( - - - ) + }) - await new Promise(process.nextTick) + test('Close the open Newsbanner', async () => { + mockServices.fetchNews = jest.fn().mockImplementation(() => + Promise.resolve({ + news: [ + { + date: 'Thu, 13 Jul 2023 16:00:00 GMT', + expiration_date: 'Sun, 20 Apr 2025 16:00:00 GMT', + id: 1, + language_id: 'en', + news_content: 'We are currently testing the site', + university: 'TH-AB' + } + ] + }) + ) - await new Promise(process.nextTick) - await new Promise(process.nextTick) + const { container, getByTestId, rerender } = render( + + + + ) + await new Promise(process.nextTick) - rerender( - - - - ) + rerender( + + + + ) - await new Promise(process.nextTick) + await new Promise(process.nextTick) + rerender( + + + + ) - rerender( - - - - ) + await act(async () => { + const closeButton = getByTestId('IconButton') + fireEvent.click(closeButton) + }) + }) - await act(async() => { - const closeButton = getByTestId('IconButton') - //fireEvent.click(closeButton) - expect(closeButton).toBeInTheDocument() - }) - - + test('Newsbanner has an error when fetching the News', () => { + mockServices.fetchNews = jest.fn().mockImplementationOnce(() => { + throw new Error('Error') }) - test("Newsbanner doesnt open because no news", ()=>{ - mockServices.fetchNews = jest.fn().mockImplementationOnce(()=> - Promise.resolve({ - news:[ - {} - ] - })) - const form = render( ) - + const form = render() + }) + + test('Newsbanner has an error when fetching the University', async () => { + mockServices.fetchUser = jest.fn().mockImplementationOnce(() => { + throw new Error('Error') }) -}) \ No newline at end of file + + const { result } = renderHook(() => UniversityCheck(), { + wrapper: ({ children }) => {children} + }) + expect(await result.current.checkUniversity()).toBe('') + }) + + test('Handle language change for the Newsbanner', async() => { + mockServices.fetchNews = jest.fn().mockImplementation(() => + Promise.resolve({ + news: [ + { + date: 'Thu, 13 Jul 2023 16:00:00 GMT', + expiration_date: 'Sun, 20 Apr 2025 16:00:00 GMT', + id: 1, + language_id: 'en', + news_content: 'We are currently testing the site', + university: 'TH-AB' + } + ] + }) + ) + + const { getByTestId, rerender } = render( + + + + ) + + await new Promise(process.nextTick) + + rerender( + + + + ) + + await new Promise(process.nextTick) + + rerender( + + + + ) + const result = renderHook( + ()=>{ + const onLngChange = useNewsbanner({handleLangChange:'de'}) + return + }) + const onLngChange = result.result.current + expect(useNewsbanner).toBeCalled() + + }) + + test('Newsbanner doesnt open because no news', () => { + mockServices.fetchNews = jest.fn().mockImplementationOnce(() => + Promise.resolve({ + news: [{}] + }) + ) + const form = render() + }) +}) diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index c7e11cb9c..a1b81c5d9 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -4,7 +4,6 @@ import { useEffect, useState } from 'react' import { keyframes } from '@emotion/react' import { NewsbannerHookReturn, useNewsbanner as _useNewsbanner } from './Newsbanner.hooks' - export type NewsbannerProps = { useNewsbanner?: () => NewsbannerHookReturn } @@ -13,21 +12,21 @@ export type NewsbannerProps = { * Newsbanner component * @remarks * Newsbanner shows a banner between the menubar and the breadcrumbs, - * but only if there are news. The news get fitted by their charakter length. + * but only if there are news. The news get fitted by their charakter length. * The closed state gets saved in the sessionStorage and removed when the window closes. * @category Components */ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { const [open, setOpen] = useState(false) - const [close, setClose] = useState(sessionStorage.getItem('newsCloseState') == "true") + const [close, setClose] = useState(sessionStorage.getItem('newsCloseState') == 'true') const [text, setText] = useState('') const { checkForNews, hasItem } = useNewsbanner() //checks if there are any news useEffect(() => { checkForNews().then((showNews) => { - if(hasItem()){ + if (hasItem()) { setOpen(true) } }) @@ -75,13 +74,17 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { data-testid="IconButton" onClick={() => { setClose(true) - sessionStorage.setItem('newsCloseState', true ? "true" : "false") + sessionStorage.setItem('newsCloseState', 'true') }}> }> + sx={{ + animation: `${scrolling} 30s linear infinite`, + transform: `translateX(100%)`, + width: window_width + }}> {text} diff --git a/src/services/News/fetchNews.test.tsx b/src/services/News/fetchNews.test.tsx index 96e709137..d37cfec80 100644 --- a/src/services/News/fetchNews.test.tsx +++ b/src/services/News/fetchNews.test.tsx @@ -23,8 +23,8 @@ describe('Test the fetchNews functionalities', () => { // @ts-ignore fetch.mockResolvedValue(mockResponse) - const languageId='en' - const university='HS-AS' + const languageId = 'en' + const university = 'HS-AS' const result = await fetchNews(languageId, university) @@ -54,8 +54,8 @@ describe('Test the fetchNews functionalities', () => { // @ts-ignore fetch.mockResolvedValue(mockResponse) - const languageId='en' - const university='HS-AS' + const languageId = 'en' + const university = 'HS-AS' await expect(fetchNews(languageId, university)).rejects.toThrow(`${expectedMessage}`) }) @@ -70,8 +70,8 @@ describe('Test the fetchNews functionalities', () => { // @ts-ignore fetch.mockResolvedValue(mockResponse) - const languageId='en' - const university='HS-AS' + const languageId = 'en' + const university = 'HS-AS' await expect(fetchNews(languageId, university)).rejects.toThrow('') }) diff --git a/src/shared/translation/translationEnglish.json b/src/shared/translation/translationEnglish.json index 44c5e4268..8ef0d22ac 100644 --- a/src/shared/translation/translationEnglish.json +++ b/src/shared/translation/translationEnglish.json @@ -1134,12 +1134,12 @@ "error.fetchILS": "There was an Error fetching ILS Questionnaire data", "error.fetchListK": "There was an Error fetching ListK Questionnaire data", "error.getCourses": "There was an Error fetching Courses data", + "error.getNews": "There was an Error fetching the news data.", + "error.getUniversity": "There was an Error fetching the university. Check if the user is valid.", "error.getUser": "There was an Error fetching User data", "error.postCalculateLearningPathILS": "There was an error calculating the Learning Path based on the ILS questionnaire data", "error.postILS": "ILS Questionnaire could not be sent.", "error.postListK": "ListK Questionnaire could not be sent.", - "error.getNews": "There was an Error fetching the news data.", - "error.getUniversity": "There was an Error fetching the university. Check if the user is valid.", "info": "Info", "pages.1": "1", "pages.10": "10", diff --git a/src/shared/translation/translationGerman.json b/src/shared/translation/translationGerman.json index 2e76cc1da..ead2df603 100644 --- a/src/shared/translation/translationGerman.json +++ b/src/shared/translation/translationGerman.json @@ -1134,12 +1134,12 @@ "error.fetchILS": "Es gab einen Fehler beim Abrufen der ILS Fragebogen Daten.", "error.fetchListK": "Es gab einen Fehler beim Abrufen der ListK Fragebogen Daten.", "error.getCourses": "Es gab einen Fehler beim Abrufen der Kursdaten.", + "error.getNews": "Es gab einen Fehler beim Abrufen der news.", + "error.getUniversity": "Es gab einen Fehler beim Abrufen der Universität. Prüfen Sie ob ein Benutzer vorhanden ist.", "error.getUser": "Es gab einen Fehler beim Abrufen der Benutzerdaten.", "error.postCalculateLearningPathILS": "Es gab einen Fehler beim Berechnen des Lernpfades auf Basis des ILS Fragebogens.", "error.postILS": "ILS Fragebogen konnte nicht gesendet werden.", "error.postListK": "ListK Fragebogen konnte nicht gesendet werden.", - "error.getNews": "Es gab einen Fehler beim Abrufen der news.", - "error.getUniversity": "Es gab einen Fehler beim Abrufen der Universität. Prüfen Sie ob ein Benutzer vorhanden ist.", "info": "Info", "pages.1": "1", "pages.10": "10", From 02f52d480954eecd8f81e5e8b8861c71aa8661ff Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Tue, 2 Jul 2024 11:47:33 +0200 Subject: [PATCH 27/41] working tests --- .../Newsbanner/Newsbanner.hooks.tsx | 11 +--- src/components/Newsbanner/Newsbanner.test.tsx | 63 +++---------------- 2 files changed, 11 insertions(+), 63 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index 3b6c794e0..85fa85651 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -4,7 +4,6 @@ import { UniversityCheck as _UniversityCheck, UniversityCheck } from '@common/ut import { SnackbarContext } from '@services' import { useStore } from '@store' import { useTranslation } from 'react-i18next' -import i18next from 'i18next' export type NewsbannerHookReturn = { readonly checkForNews: () => Promise @@ -12,22 +11,16 @@ export type NewsbannerHookReturn = { } export const useNewsbanner = (): NewsbannerHookReturn => { - const { t } = useTranslation() + const { t, i18n } = useTranslation() const { addSnackbar } = useContext(SnackbarContext) const getNews = useStore((state) => state.getNews) const { checkUniversity } = UniversityCheck() - const [lang, setLang] = useState(localStorage.getItem('i18nextLng')?.toLowerCase()) const [newsItem, setNewsItem] = useState(false) - const handleLangChange = (lng: string) => { - setLang(lng) - } - - i18next.on('languageChanged', handleLangChange ) //** Logic **/ const checkLanguage = () => { - return lang + return i18n.language } const hasItem = () => { diff --git a/src/components/Newsbanner/Newsbanner.test.tsx b/src/components/Newsbanner/Newsbanner.test.tsx index df12b83d5..8a53bd0b2 100644 --- a/src/components/Newsbanner/Newsbanner.test.tsx +++ b/src/components/Newsbanner/Newsbanner.test.tsx @@ -1,20 +1,21 @@ import '@testing-library/jest-dom' -import { fireEvent, render, act, renderHook, getByTestId } from '@testing-library/react' +import { fireEvent, render, act, renderHook } from '@testing-library/react' import { mockServices } from 'jest.setup' import Newsbanner from './Newsbanner' import { MemoryRouter } from 'react-router-dom' import { UniversityCheck } from '@common/utils' import { LanguageMenu } from '@components' import { I18nextProvider } from 'react-i18next' -import { useNewsbanner } from './Newsbanner.hooks' +import i18next from 'i18next' +import { useNewsbanner, NewsbannerHookReturn } from './Newsbanner.hooks' +import React from 'react' +import { SnackbarContextType } from '@services' describe('Newsbanner tests', () => { beforeEach(() => { - window.localStorage.clear() - }) - const useNewsbanner = jest.fn(()=>{ - return{ handleLangChange: 'en'} + window.sessionStorage.clear() }) + test('Newsbanner is open', async () => { mockServices.fetchNews = jest.fn().mockImplementation(() => Promise.resolve({ @@ -31,7 +32,8 @@ describe('Newsbanner tests', () => { }) ) - const { container, getByTestId, rerender } = render( + const { getByTestId, rerender } = render( + @@ -120,53 +122,6 @@ describe('Newsbanner tests', () => { expect(await result.current.checkUniversity()).toBe('') }) - test('Handle language change for the Newsbanner', async() => { - mockServices.fetchNews = jest.fn().mockImplementation(() => - Promise.resolve({ - news: [ - { - date: 'Thu, 13 Jul 2023 16:00:00 GMT', - expiration_date: 'Sun, 20 Apr 2025 16:00:00 GMT', - id: 1, - language_id: 'en', - news_content: 'We are currently testing the site', - university: 'TH-AB' - } - ] - }) - ) - - const { getByTestId, rerender } = render( - - - - ) - - await new Promise(process.nextTick) - - rerender( - - - - ) - - await new Promise(process.nextTick) - - rerender( - - - - ) - const result = renderHook( - ()=>{ - const onLngChange = useNewsbanner({handleLangChange:'de'}) - return - }) - const onLngChange = result.result.current - expect(useNewsbanner).toBeCalled() - - }) - test('Newsbanner doesnt open because no news', () => { mockServices.fetchNews = jest.fn().mockImplementationOnce(() => Promise.resolve({ From 835e6521a20952568604db974655f258a050100b Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Tue, 2 Jul 2024 12:23:49 +0200 Subject: [PATCH 28/41] added expects to test --- src/components/Newsbanner/Newsbanner.test.tsx | 16 +++++++--------- src/store/Slices/NewsSlice.ts | 9 +-------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.test.tsx b/src/components/Newsbanner/Newsbanner.test.tsx index 8a53bd0b2..34fb47d58 100644 --- a/src/components/Newsbanner/Newsbanner.test.tsx +++ b/src/components/Newsbanner/Newsbanner.test.tsx @@ -4,12 +4,6 @@ import { mockServices } from 'jest.setup' import Newsbanner from './Newsbanner' import { MemoryRouter } from 'react-router-dom' import { UniversityCheck } from '@common/utils' -import { LanguageMenu } from '@components' -import { I18nextProvider } from 'react-i18next' -import i18next from 'i18next' -import { useNewsbanner, NewsbannerHookReturn } from './Newsbanner.hooks' -import React from 'react' -import { SnackbarContextType } from '@services' describe('Newsbanner tests', () => { beforeEach(() => { @@ -76,7 +70,7 @@ describe('Newsbanner tests', () => { }) ) - const { container, getByTestId, rerender } = render( + const {container, getByTestId, rerender } = render( @@ -102,13 +96,16 @@ describe('Newsbanner tests', () => { const closeButton = getByTestId('IconButton') fireEvent.click(closeButton) }) + + expect(container).toBeEmptyDOMElement() }) test('Newsbanner has an error when fetching the News', () => { mockServices.fetchNews = jest.fn().mockImplementationOnce(() => { throw new Error('Error') }) - const form = render() + const {container} = render() + expect(container).toBeEmptyDOMElement() }) test('Newsbanner has an error when fetching the University', async () => { @@ -128,6 +125,7 @@ describe('Newsbanner tests', () => { news: [{}] }) ) - const form = render() + const {container} = render() + expect(container).toBeEmptyDOMElement() }) }) diff --git a/src/store/Slices/NewsSlice.ts b/src/store/Slices/NewsSlice.ts index 38ae35ce9..1ca0e2ac6 100644 --- a/src/store/Slices/NewsSlice.ts +++ b/src/store/Slices/NewsSlice.ts @@ -7,18 +7,11 @@ import { resetters } from '../Zustand/Store' export default interface NewsSlice { _news: Record getNews: NewsReturn - setNewsCloseState(closeState: boolean): boolean - closeState: boolean } export const createNewsSlice: StateCreator = (set, get) => { - resetters.push(() => set({ _news: {} })), set({ closeState: {} as boolean }) + resetters.push(() => set({ _news: {} })) return { - closeState: {} as boolean, - setNewsCloseState: (closeState) => { - set({ closeState }) - return closeState - }, _news: {}, getNews: async (...arg) => { const [languageId, university] = arg From 4ab3b8d1ff8795a072bf06a6eade93149eecad72 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Tue, 2 Jul 2024 12:43:34 +0200 Subject: [PATCH 29/41] added doku and ran lint --- .../Newsbanner/Newsbanner.hooks.tsx | 23 +++++++++++++++++-- src/components/Newsbanner/Newsbanner.test.tsx | 7 +++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index 85fa85651..2ee83cbcf 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -5,11 +5,31 @@ import { SnackbarContext } from '@services' import { useStore } from '@store' import { useTranslation } from 'react-i18next' +/** + * @prop checkForNews - sets the newsItem if there is atleast one news + * and returns a string of all news + * @prop hasItem - check if there are any news + * @category Hooks + * @interface + */ + export type NewsbannerHookReturn = { readonly checkForNews: () => Promise readonly hasItem: () => boolean } +/** + * useNewsbanner hook. + * @remarks + * Hook for the Newsbanner logic. + * first checks if there are any news and then returns a string with all news items. + * also changes news if the language gets changed + * + * @returns - hasItem and all news as a string + * + * @category Hooks + */ + export const useNewsbanner = (): NewsbannerHookReturn => { const { t, i18n } = useTranslation() const { addSnackbar } = useContext(SnackbarContext) @@ -17,7 +37,6 @@ export const useNewsbanner = (): NewsbannerHookReturn => { const { checkUniversity } = UniversityCheck() const [newsItem, setNewsItem] = useState(false) - //** Logic **/ const checkLanguage = () => { return i18n.language @@ -28,7 +47,7 @@ export const useNewsbanner = (): NewsbannerHookReturn => { } //returns combined string of all the news - //and the amount of messages + //and checks if there are news const checkForNews = async () => { return checkUniversity().then((university) => { return getNews(checkLanguage(), university) diff --git a/src/components/Newsbanner/Newsbanner.test.tsx b/src/components/Newsbanner/Newsbanner.test.tsx index 34fb47d58..0c07446fe 100644 --- a/src/components/Newsbanner/Newsbanner.test.tsx +++ b/src/components/Newsbanner/Newsbanner.test.tsx @@ -27,7 +27,6 @@ describe('Newsbanner tests', () => { ) const { getByTestId, rerender } = render( - @@ -70,7 +69,7 @@ describe('Newsbanner tests', () => { }) ) - const {container, getByTestId, rerender } = render( + const { container, getByTestId, rerender } = render( @@ -104,7 +103,7 @@ describe('Newsbanner tests', () => { mockServices.fetchNews = jest.fn().mockImplementationOnce(() => { throw new Error('Error') }) - const {container} = render() + const { container } = render() expect(container).toBeEmptyDOMElement() }) @@ -125,7 +124,7 @@ describe('Newsbanner tests', () => { news: [{}] }) ) - const {container} = render() + const { container } = render() expect(container).toBeEmptyDOMElement() }) }) From 252304ecf8fac68850cee32464d5045ee519c4fd Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:09:24 +0200 Subject: [PATCH 30/41] lint changes --- .../PrivacyModal/PrivacyModal.hooks.tsx | 1 + src/pages/Course/Course.tsx | 2 +- src/pages/Home/Home.tsx | 46 +++++++++---------- src/pages/MainFrame/MainFrame.tsx | 12 ++++- .../translation/translationEnglish.json | 5 +- src/shared/translation/translationGerman.json | 4 +- 6 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/components/PrivacyModal/PrivacyModal.hooks.tsx b/src/components/PrivacyModal/PrivacyModal.hooks.tsx index a6006901b..6c2dae546 100644 --- a/src/components/PrivacyModal/PrivacyModal.hooks.tsx +++ b/src/components/PrivacyModal/PrivacyModal.hooks.tsx @@ -1,3 +1,4 @@ +import log from 'loglevel' import { useCallback, useContext, useMemo } from 'react' import { CookiesProvider, useCookies } from 'react-cookie' import { useTranslation } from 'react-i18next' diff --git a/src/pages/Course/Course.tsx b/src/pages/Course/Course.tsx index e4e752dd1..fd46934f2 100644 --- a/src/pages/Course/Course.tsx +++ b/src/pages/Course/Course.tsx @@ -17,7 +17,7 @@ const Course = () => { // Hooks const theme = useTheme() const isSmOrDown = useMediaQuery(theme.breakpoints.down('sm')) - const { courseId } = useParams<{courseId: string}>() + const { courseId } = useParams<{ courseId: string }>() const { topicProgress, isLoading, topics } = useLearningPathTopicProgress({ courseId }) return ( diff --git a/src/pages/Home/Home.tsx b/src/pages/Home/Home.tsx index 7ffeea650..3eeae20bf 100644 --- a/src/pages/Home/Home.tsx +++ b/src/pages/Home/Home.tsx @@ -28,32 +28,32 @@ export const Home = () => { const getCourses = useStore((state) => state.getCourses) useEffect(() => { - if (isAuth) { - getUser() - .then((user) => { - getCourses(user.settings.user_id, user.lms_user_id, user.id) - .then((CourseResponse) => { - setCourses(CourseResponse.courses) - }) - .catch((error) => { - addSnackbar({ - message: t('error.getCourses'), - severity: 'error', - autoHideDuration: 5000 - }) - log.error(t('error.getCourses') + ' ' + error) + if (isAuth) { + getUser() + .then((user) => { + getCourses(user.settings.user_id, user.lms_user_id, user.id) + .then((CourseResponse) => { + setCourses(CourseResponse.courses) + }) + .catch((error) => { + addSnackbar({ + message: t('error.getCourses'), + severity: 'error', + autoHideDuration: 5000 }) - }) - .catch((error) => { - addSnackbar({ - message: t('error.getUser'), - severity: 'error', - autoHideDuration: 5000 + log.error(t('error.getCourses') + ' ' + error) }) - log.error(t('error.getUser') + ' ' + error) + }) + .catch((error) => { + addSnackbar({ + message: t('error.getUser'), + severity: 'error', + autoHideDuration: 5000 }) - setLoading(false) - } + log.error(t('error.getUser') + ' ' + error) + }) + setLoading(false) + } }, [getUser, getCourses, setCourses, isAuth]) // Card cointaining the courses with a button to the specific course diff --git a/src/pages/MainFrame/MainFrame.tsx b/src/pages/MainFrame/MainFrame.tsx index 6a12c3e5c..aa2f8fd0f 100644 --- a/src/pages/MainFrame/MainFrame.tsx +++ b/src/pages/MainFrame/MainFrame.tsx @@ -1,7 +1,15 @@ import { Outlet, useParams } from 'react-router-dom' import { Box, Divider, Grid } from '@common/components' import { useMediaQuery, useTheme } from '@common/hooks' -import { BreadcrumbsContainer, Footer, LocalNavBar, MenuBar, OpenQuestionnaire, PrivacyModal, Newsbanner } from '@components' +import { + BreadcrumbsContainer, + Footer, + LocalNavBar, + MenuBar, + OpenQuestionnaire, + PrivacyModal, + Newsbanner +} from '@components' /** * # MainFrame Page @@ -27,7 +35,7 @@ export const MainFrame = () => { <> - + {isLocalNavOpen && ( diff --git a/src/shared/translation/translationEnglish.json b/src/shared/translation/translationEnglish.json index 2f0e6c176..999225108 100644 --- a/src/shared/translation/translationEnglish.json +++ b/src/shared/translation/translationEnglish.json @@ -1134,8 +1134,6 @@ "components.TableListK.time": "Time", "components.TableListKQuestions.introduction": "Following this you will be asked questions about what learning strategies you use. You will find a list of different learning activities. Please indicate how frequently each activity occurs for you. You can rate your answers from very rarely (1) to very often (5). The questions presented are based on the LIST-K (Klingsieck, 2019), which is a shortened version of the LIST (Wild & Schiefele, 1994).", "error": "Error", - "error.getNews": "There was an Error fetching the news data.", - "error.getUniversity": "There was an Error fetching the university. Check if the user is valid.", "error.fetchCourses": "There was an Error fetching the courses data.", "error.fetchILS": "There was an Error fetching the ILS questionnaire data.", "error.fetchLearningPathElement": "There was an Error fetching the LearningPathElement data.", @@ -1147,7 +1145,9 @@ "error.getCourses": "There was an Error fetching the courses data.", "error.getLearningElementStatus": "There was an Error Learning Element Status.", "error.getLearningElementsWithStatus": "There was an Error fetching Learning Elements with Status.", + "error.getNews": "There was an Error fetching the news data.", "error.getSortedLearningPath": "There was an Error fetching and sorting the LearningPathLearningElement data.", + "error.getUniversity": "There was an Error fetching the university. Check if the user is valid.", "error.getUser": "There was an Error fetching the user data.", "error.mapNodes": "There was an Error mapping the learning path Nodes.", "error.postCalculateLearningPathILS": "There was an Error calculating the learning path based on the ILS questionnaire data.", @@ -1157,7 +1157,6 @@ "error.setLearningPathElementSpecificStatus": "There was an Error setting Learning Path Element Specific Status.", "error.setTopics": "There was an Error setting Topics.", "error.setTopicsPath": "There was an Error setting Topics Path.", - "info": "Info", "log.learningPathTopicProgressTimeout": "A timeout occured while loading the LearningPathTopicProgress hook.", "pages.1": "1", diff --git a/src/shared/translation/translationGerman.json b/src/shared/translation/translationGerman.json index a75006ab9..0ca98837b 100644 --- a/src/shared/translation/translationGerman.json +++ b/src/shared/translation/translationGerman.json @@ -1143,11 +1143,11 @@ "error.fetchRedirectMoodleLogin": "Es gab einen Fehler beim Abrufen der Moodle-Login-URL.", "error.fetchUser": "Es gab einen Fehler beim Abrufen der Nutzerdaten.", "error.getCourses": "Es gab einen Fehler beim Abrufen der Kursdaten.", - "error.getNews": "Es gab einen Fehler beim Abrufen der news.", - "error.getUniversity": "Es gab einen Fehler beim Abrufen der Universität. Prüfen Sie ob ein Benutzer vorhanden ist.", "error.getLearningElementStatus": "Es gab einen Fehler beim Abrufen des Lernelementstatus.", "error.getLearningElementsWithStatus": "Es gab einen Fehler beim Abrufen der Lernelemente (mit Status).", + "error.getNews": "Es gab einen Fehler beim Abrufen der news.", "error.getSortedLearningPath": "Es gab einen Fehler beim Abrufen und Sortieren der LearningPathLearningElement-Daten.", + "error.getUniversity": "Es gab einen Fehler beim Abrufen der Universität. Prüfen Sie ob ein Benutzer vorhanden ist.", "error.getUser": "Es gab einen Fehler beim Abrufen der Benutzerdaten.", "error.mapNodes": "Es gab einen Fehler beim Zuordnen der Lernpfad Nodes.", "error.postCalculateLearningPathILS": "Es gab einen Fehler bei der Berechnung des Lernpfades auf Basis der ILS-Fragebogendaten.", From ec2aeda7acd07f0660f26d25744f42f308eacc16 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Thu, 25 Jul 2024 11:07:08 +0200 Subject: [PATCH 31/41] added requested changes --- jest.setup.ts | 4 +- .../DefaultCollapse/DefaultCollapse.tsx | 3 + src/common/components/index.ts | 1 + src/common/hooks/UniversityCheck.tsx | 28 ++++++++++ src/common/hooks/index.ts | 1 + src/common/utils/UniversityCheck.tsx | 29 ---------- src/common/utils/index.ts | 1 - .../Newsbanner/Newsbanner.hooks.tsx | 43 ++++++-------- src/components/Newsbanner/Newsbanner.test.tsx | 23 ++++---- src/components/Newsbanner/Newsbanner.tsx | 56 +++++++------------ .../PrivacyModal/PrivacyModal.test.tsx | 10 ++-- src/components/PrivacyModal/PrivacyModal.tsx | 12 ++-- src/core/News/News.ts | 6 +- src/core/index.ts | 4 +- src/services/News/fetchNews.test.tsx | 6 +- src/services/News/fetchNews.tsx | 6 +- src/services/News/index.ts | 1 + src/services/index.ts | 2 +- .../translation/translationEnglish.json | 2 +- src/shared/translation/translationGerman.json | 4 +- src/store/Slices/NewsSlice.test.ts | 12 ++-- src/store/Slices/NewsSlice.ts | 4 +- 22 files changed, 118 insertions(+), 140 deletions(-) create mode 100644 src/common/components/DefaultCollapse/DefaultCollapse.tsx create mode 100644 src/common/hooks/UniversityCheck.tsx delete mode 100644 src/common/utils/UniversityCheck.tsx create mode 100644 src/services/News/index.ts diff --git a/jest.setup.ts b/jest.setup.ts index df982b9b5..897ff1339 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -358,7 +358,7 @@ const mockDataServices: MockDataServices = { id: 1, language_id: 'en', news_content: 'We are currently testing the site', - university: 'HS-AS' + university: 'TH-AB' }, { date: 'Thu, 13 Jul 2023 16:00:00 GMT', @@ -366,7 +366,7 @@ const mockDataServices: MockDataServices = { id: 2, language_id: 'en', news_content: 'We are currently testing the site', - university: 'HS-AS' + university: 'TH-AB' } ] }) diff --git a/src/common/components/DefaultCollapse/DefaultCollapse.tsx b/src/common/components/DefaultCollapse/DefaultCollapse.tsx new file mode 100644 index 000000000..dc875e765 --- /dev/null +++ b/src/common/components/DefaultCollapse/DefaultCollapse.tsx @@ -0,0 +1,3 @@ +import DefaultCollapse from '@mui/material/Collapse' + +export { DefaultCollapse as Collapse } \ No newline at end of file diff --git a/src/common/components/index.ts b/src/common/components/index.ts index 281707d2f..38dcd46ab 100644 --- a/src/common/components/index.ts +++ b/src/common/components/index.ts @@ -18,6 +18,7 @@ export { Stack } from './DefaultStack/DefaultStack' export { Skeleton } from './DefaultSkeleton/DefaultSkeleton' export { Backdrop } from './DefaultBackdrop/DefaultBackdrop' export { CircularProgress } from './DefaultCircularProgress/DefaultCircularProgress' +export { Collapse } from './DefaultCollapse/DefaultCollapse' export { InputAdornment } from './DefaultInputAdornment/DefaultInputAdornment' export { Paper } from './DefaultPaper/DefaultPaper' export { Fade } from './DefaultFade/DefaultFade' diff --git a/src/common/hooks/UniversityCheck.tsx b/src/common/hooks/UniversityCheck.tsx new file mode 100644 index 000000000..865e79281 --- /dev/null +++ b/src/common/hooks/UniversityCheck.tsx @@ -0,0 +1,28 @@ +import log from 'loglevel' +import { usePersistedStore } from '@store' +import { useState, useEffect, useMemo } from 'react' + +export type UniversityHookReturn = { + readonly university: string +} + +export const useUniversity = (): UniversityHookReturn => { + const [university, setUniversity] = useState('') + const getUser = usePersistedStore((state) => state.getUser) + useEffect(() => { + //fetch the university from the current user and return university + getUser().then((user)=> { + setUniversity(user.university) + }) + .catch((reason) => { + log.error(reason) + setUniversity('') + }) + },[]) + return useMemo( + () => ({ + university + }), + [university] + ) +} diff --git a/src/common/hooks/index.ts b/src/common/hooks/index.ts index 9940b5494..b4e27c100 100644 --- a/src/common/hooks/index.ts +++ b/src/common/hooks/index.ts @@ -1,3 +1,4 @@ export { useTheme } from './DefaultUseTheme/DefaultUseTheme' export { useMediaQuery } from './DefaultMediaQuery/DefaultMediaQuery' export { useLearningPathTopicProgress } from './LearningPathTopicProgress/LearningPathTopicProgress.hooks' +export * from './UniversityCheck' diff --git a/src/common/utils/UniversityCheck.tsx b/src/common/utils/UniversityCheck.tsx deleted file mode 100644 index 06f958912..000000000 --- a/src/common/utils/UniversityCheck.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import log from 'loglevel' -import { usePersistedStore } from '@store' -import { useMemo } from 'react' - -export type UniversityCheckReturn = { - readonly checkUniversity: () => Promise -} - -export const UniversityCheck = (): UniversityCheckReturn => { - const getUser = usePersistedStore((state) => state.getUser) - //fetch the university from the current user and return university - const checkUniversity = async () => { - return getUser() - .then((user) => { - return user.university - }) - .catch((reason) => { - log.error(reason) - return '' - }) - } - - return useMemo( - () => ({ - checkUniversity - }), - [checkUniversity] - ) -} diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts index 092843643..757f8b179 100644 --- a/src/common/utils/index.ts +++ b/src/common/utils/index.ts @@ -1,5 +1,4 @@ import { HaskiTheme } from './Theme/HaskiTheme' import { Theme } from './Theme/Theme' import { reportWebVitals, sendToAnalytics } from './Webvitals/Webvitals' -export * from './UniversityCheck' export { reportWebVitals, sendToAnalytics, Theme, HaskiTheme } diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index 2ee83cbcf..002b2bf9b 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -1,9 +1,9 @@ import log from 'loglevel' import { useMemo, useState, useContext } from 'react' -import { UniversityCheck as _UniversityCheck, UniversityCheck } from '@common/utils' import { SnackbarContext } from '@services' import { useStore } from '@store' import { useTranslation } from 'react-i18next' +import {useUniversity} from '@common/hooks' /** * @prop checkForNews - sets the newsItem if there is atleast one news @@ -14,8 +14,10 @@ import { useTranslation } from 'react-i18next' */ export type NewsbannerHookReturn = { - readonly checkForNews: () => Promise - readonly hasItem: () => boolean + readonly checkForNews: ()=>Promise + readonly isOpen:boolean + readonly isNewsAvailable: boolean + readonly newsText:string } /** @@ -34,28 +36,19 @@ export const useNewsbanner = (): NewsbannerHookReturn => { const { t, i18n } = useTranslation() const { addSnackbar } = useContext(SnackbarContext) const getNews = useStore((state) => state.getNews) - const { checkUniversity } = UniversityCheck() - const [newsItem, setNewsItem] = useState(false) + const { university } = useUniversity() + const [isNewsAvailable, setIsNewsAvailable] = useState(false) + const [newsText, setNewsText] = useState('') + const [ isOpen, setIsOpen]=useState(true) //** Logic **/ - const checkLanguage = () => { - return i18n.language - } - - const hasItem = () => { - return newsItem - } - //returns combined string of all the news //and checks if there are news const checkForNews = async () => { - return checkUniversity().then((university) => { - return getNews(checkLanguage(), university) - .then((news) => { - setNewsItem(news.news.length != 0) - const contentA = news.news.map(({ news_content }) => news_content).join(', ') - //console.log('news:', news, 'lang', checkLanguage(), 'university:', university) - return JSON.stringify(contentA) + return getNews(i18n.language, university) + .then((response) => { + setIsNewsAvailable(response.news.length != 0) + return setNewsText(response.news.map(({ news_content }) => news_content).join(', ')) }) .catch((error) => { addSnackbar({ @@ -63,14 +56,14 @@ export const useNewsbanner = (): NewsbannerHookReturn => { severity: 'error', autoHideDuration: 3000 }) - log.error('error.getNews', 'Error: ' + error) - return '' + log.error(t('error.getNews') + error) + return setNewsText('') }) - }) + } return useMemo( - () => ({ checkForNews, checkLanguage, hasItem, newsItem }), - [checkForNews, checkLanguage, hasItem, newsItem] + () => ({ checkForNews, isNewsAvailable, newsText, isOpen }), + [checkForNews, isNewsAvailable, newsText, isOpen] ) } diff --git a/src/components/Newsbanner/Newsbanner.test.tsx b/src/components/Newsbanner/Newsbanner.test.tsx index 0c07446fe..6437d4fa3 100644 --- a/src/components/Newsbanner/Newsbanner.test.tsx +++ b/src/components/Newsbanner/Newsbanner.test.tsx @@ -3,7 +3,7 @@ import { fireEvent, render, act, renderHook } from '@testing-library/react' import { mockServices } from 'jest.setup' import Newsbanner from './Newsbanner' import { MemoryRouter } from 'react-router-dom' -import { UniversityCheck } from '@common/utils' +import { useUniversity } from '@common/hooks' describe('Newsbanner tests', () => { beforeEach(() => { @@ -18,8 +18,8 @@ describe('Newsbanner tests', () => { date: 'Thu, 13 Jul 2023 16:00:00 GMT', expiration_date: 'Sun, 20 Apr 2025 16:00:00 GMT', id: 1, - language_id: 'en', - news_content: 'We are currently testing the site', + language_id: 'de', + news_content: 'Wir testen die Seite', university: 'TH-AB' } ] @@ -48,13 +48,14 @@ describe('Newsbanner tests', () => { ) await act(async () => { - const closeButton = getByTestId('IconButton') + expect(rerender).toContain('Wir testen die Seite') + const closeButton = getByTestId('NewsBannerCloseButton') expect(closeButton).toBeInTheDocument() }) }) test('Close the open Newsbanner', async () => { - mockServices.fetchNews = jest.fn().mockImplementation(() => + mockServices.fetchNews.mockImplementation(() => Promise.resolve({ news: [ { @@ -92,7 +93,7 @@ describe('Newsbanner tests', () => { ) await act(async () => { - const closeButton = getByTestId('IconButton') + const closeButton = getByTestId('NewsBannerCloseButton') fireEvent.click(closeButton) }) @@ -100,7 +101,7 @@ describe('Newsbanner tests', () => { }) test('Newsbanner has an error when fetching the News', () => { - mockServices.fetchNews = jest.fn().mockImplementationOnce(() => { + mockServices.fetchNews.mockImplementationOnce(() => { throw new Error('Error') }) const { container } = render() @@ -108,18 +109,18 @@ describe('Newsbanner tests', () => { }) test('Newsbanner has an error when fetching the University', async () => { - mockServices.fetchUser = jest.fn().mockImplementationOnce(() => { + mockServices.fetchUser.mockImplementationOnce(() => { throw new Error('Error') }) - const { result } = renderHook(() => UniversityCheck(), { + const { result } = renderHook(() => useUniversity(), { wrapper: ({ children }) => {children} }) - expect(await result.current.checkUniversity()).toBe('') + expect(await result.current.university).toBe('') }) test('Newsbanner doesnt open because no news', () => { - mockServices.fetchNews = jest.fn().mockImplementationOnce(() => + mockServices.fetchNews.mockImplementationOnce(() => Promise.resolve({ news: [{}] }) diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index a1b81c5d9..8e3b574e7 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -1,6 +1,6 @@ -import { Alert, Box, Collapse, IconButton } from '@mui/material' -import CloseIcon from '@mui/icons-material/Close' -import { useEffect, useState } from 'react' +import { Alert, Box, Collapse, IconButton, Typography } from '@common/components' +import { Close } from '@common/icons' +import { useEffect, memo } from 'react' import { keyframes } from '@emotion/react' import { NewsbannerHookReturn, useNewsbanner as _useNewsbanner } from './Newsbanner.hooks' @@ -18,29 +18,14 @@ export type NewsbannerProps = { */ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { - const [open, setOpen] = useState(false) - const [close, setClose] = useState(sessionStorage.getItem('newsCloseState') == 'true') - const [text, setText] = useState('') - const { checkForNews, hasItem } = useNewsbanner() + const { checkForNews, isNewsAvailable, newsText, isOpen } = useNewsbanner() - //checks if there are any news - useEffect(() => { - checkForNews().then((showNews) => { - if (hasItem()) { - setOpen(true) - } - }) - }, [hasItem]) - - //sets Text to be displayed - useEffect(() => { - checkForNews().then((showNews) => { - setText(showNews) - }) - }, [checkForNews]) + useEffect(()=>{ + checkForNews() + }), [checkForNews] //Animation logic - const text_len = text.length * 10 + const text_len = newsText.length * 10 const window_width = window.innerWidth const text_percent = text_len / window_width @@ -52,13 +37,12 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { transform: translateX(-${text_percent * 100}%) } ` - //+TODO: Option for reopening news - // Reopen new news + return ( <> - {open && !close && ( + {isNewsAvailable && isOpen && ( - + { aria-label="close" color="inherit" size="small" - data-testid="IconButton" - onClick={() => { - setClose(true) - sessionStorage.setItem('newsCloseState', 'true') - }}> - + id='newsbanner-close-icon-button' + data-testid="NewsBannerCloseButton" + > + }> - - {text} - + {newsText} + @@ -94,4 +76,4 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { ) } -export default Newsbanner +export default memo(Newsbanner) diff --git a/src/components/PrivacyModal/PrivacyModal.test.tsx b/src/components/PrivacyModal/PrivacyModal.test.tsx index cbee6d693..db73695ff 100644 --- a/src/components/PrivacyModal/PrivacyModal.test.tsx +++ b/src/components/PrivacyModal/PrivacyModal.test.tsx @@ -4,7 +4,7 @@ import { mockServices } from 'jest.setup' import * as router from 'react-router' import { MemoryRouter } from 'react-router-dom' import PrivacyModal from './PrivacyModal' -import { UniversityCheck } from '@common/utils' +import { useUniversity } from '@common/hooks' const navigate = jest.fn() @@ -127,10 +127,10 @@ describe('Test PrivacyModal', () => { }) ) - const { result } = renderHook(() => UniversityCheck(), { + const { result } = renderHook(() => useUniversity(), { wrapper: ({ children }) => {children} }) - expect(await result.current.checkUniversity()).toBe('TH-AB') + expect(await result.current.university()).toBe('TH-AB') }) test('Redirects the user to HS-KE', async () => { @@ -161,10 +161,10 @@ describe('Test PrivacyModal', () => { test('checkUniversity returns empty string when fetch fails', async () => { mockServices.fetchUser = jest.fn().mockImplementationOnce(() => Promise.reject(new Error('error'))) - const { result } = renderHook(() => UniversityCheck(), { + const { result } = renderHook(() => useUniversity(), { wrapper: ({ children }) => {children} }) - expect(await result.current.checkUniversity()).toBe('') + expect(await result.current.university()).toBe('') }) test('decline returns the user two pages prior', async () => { diff --git a/src/components/PrivacyModal/PrivacyModal.tsx b/src/components/PrivacyModal/PrivacyModal.tsx index b4c34d791..3e8f5e09e 100644 --- a/src/components/PrivacyModal/PrivacyModal.tsx +++ b/src/components/PrivacyModal/PrivacyModal.tsx @@ -13,7 +13,7 @@ import { Typography } from '@common/components' import { PrivacyModalHookReturn, usePrivacyModal as _usePrivacyModal } from './PrivacyModal.hooks' -import { UniversityCheck as _UniversityCheck, UniversityCheckReturn } from '@common/utils' +import {useUniversity} from '@common/hooks' const style = { position: 'absolute', @@ -35,7 +35,6 @@ const style = { export type PrivacyModalProps = { usePrivacyModal?: () => PrivacyModalHookReturn - UniversityCheck?: () => UniversityCheckReturn } /** @@ -52,15 +51,14 @@ export type PrivacyModalProps = { */ const PrivacyModal = ({ - usePrivacyModal = _usePrivacyModal, - UniversityCheck = _UniversityCheck + usePrivacyModal = _usePrivacyModal }: PrivacyModalProps) => { const { t } = useTranslation() const navigate = useNavigate() const [open, setOpen] = useState(true) const [checked, setChecked] = useState(false) const { privacyPolicyCookie, handleAccept } = usePrivacyModal() - const { checkUniversity } = UniversityCheck() + const { university } = useUniversity() const currentLocation = useLocation() //Disable backdropClick so the Modal only closes via the buttons @@ -138,7 +136,7 @@ const PrivacyModal = ({ aria-multiline={'true'} onClick={() => { handleModal(false) - checkUniversity().then((university) => { + if (university == 'TH-AB') { window.location.assign('https://moodle.th-ab.de/') } else if (university == 'HS-KE') { @@ -150,7 +148,7 @@ const PrivacyModal = ({ history.go(-2) } } - }) + }}> {t('appGlobal.decline')} diff --git a/src/core/News/News.ts b/src/core/News/News.ts index 61a22e1b5..015b9706a 100644 --- a/src/core/News/News.ts +++ b/src/core/News/News.ts @@ -1,6 +1,6 @@ -type NewsReturn = (languageId?: string, university?: string) => Promise +type NewsReturn = (languageId?: string, university?: string) => Promise -type NewsList = { +type NewsResponse = { news: News[] } @@ -8,4 +8,4 @@ type News = { news_content: string } export default News -export type { NewsList, NewsReturn } +export type { NewsResponse, NewsReturn } diff --git a/src/core/index.ts b/src/core/index.ts index 37a95d2bf..69555ff85 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -30,7 +30,7 @@ import LearningPathLearningElement from './LearningPathLearningElement/LearningP import LearningPathTopic from './LearningPathTopic/LearningPathTopic' import ILS from './QuestionnaireResults/ILS' import ListK from './QuestionnaireResults/ListK' -import News, { NewsList } from './News/News' +import News, { NewsResponse } from './News/News' import StudentLearningElement from './StudentLearningElement/StudentLearningElement' import Topic from './Topic/Topic' import User from './User/User' @@ -48,7 +48,7 @@ export type { LearningPathLearningElement, LearningPathElementStatus, News, - NewsList, + NewsResponse, Topic, StudentLearningElement, ILS, diff --git a/src/services/News/fetchNews.test.tsx b/src/services/News/fetchNews.test.tsx index d37cfec80..2f4664bbf 100644 --- a/src/services/News/fetchNews.test.tsx +++ b/src/services/News/fetchNews.test.tsx @@ -24,7 +24,7 @@ describe('Test the fetchNews functionalities', () => { fetch.mockResolvedValue(mockResponse) const languageId = 'en' - const university = 'HS-AS' + const university = 'TH-AB' const result = await fetchNews(languageId, university) @@ -55,7 +55,7 @@ describe('Test the fetchNews functionalities', () => { fetch.mockResolvedValue(mockResponse) const languageId = 'en' - const university = 'HS-AS' + const university = 'TH-AB' await expect(fetchNews(languageId, university)).rejects.toThrow(`${expectedMessage}`) }) @@ -71,7 +71,7 @@ describe('Test the fetchNews functionalities', () => { fetch.mockResolvedValue(mockResponse) const languageId = 'en' - const university = 'HS-AS' + const university = 'TH-AB' await expect(fetchNews(languageId, university)).rejects.toThrow('') }) diff --git a/src/services/News/fetchNews.tsx b/src/services/News/fetchNews.tsx index 818d5487c..be7310c58 100644 --- a/src/services/News/fetchNews.tsx +++ b/src/services/News/fetchNews.tsx @@ -1,13 +1,13 @@ import { getConfig } from '@shared' import { fetchData } from '../RequestResponse' -import { NewsList } from '@core' +import { NewsResponse } from '@core' /** * * @returns {@link News} object */ -export const fetchNews = async (languageId?: string, university?: string): Promise => { - return fetchData(getConfig().BACKEND + `/news?language_id=${languageId}&university=${university}`, { +export const fetchNews = async (languageId?: string, university?: string): Promise => { + return fetchData(getConfig().BACKEND + `/news?language_id=${languageId}&university=${university}`, { method: 'GET', credentials: 'include', headers: { diff --git a/src/services/News/index.ts b/src/services/News/index.ts new file mode 100644 index 000000000..f9de3cc49 --- /dev/null +++ b/src/services/News/index.ts @@ -0,0 +1 @@ +export * from './fetchNews' diff --git a/src/services/index.ts b/src/services/index.ts index 1b9de0e9b..6b5e1f3ff 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -20,5 +20,5 @@ export * from './xAPI' export { fetchILS, fetchListK, postILS, postListK } from './Questionnaire' export * from './debounce' export * from './Viewport' -export { fetchNews } from './News/fetchNews' +export { fetchNews } from './News' export { postCalculateLearningPathILS } from './LearningPath' diff --git a/src/shared/translation/translationEnglish.json b/src/shared/translation/translationEnglish.json index 77721de9c..19d061702 100644 --- a/src/shared/translation/translationEnglish.json +++ b/src/shared/translation/translationEnglish.json @@ -1147,7 +1147,7 @@ "error.getLearningElementsWithStatus": "There was an Error fetching Learning Elements with Status.", "error.getNews": "There was an Error fetching the news data.", "error.getSortedLearningPath": "There was an Error fetching and sorting the LearningPathLearningElement data.", - "error.getUniversity": "There was an Error fetching the university. Check if the user is valid.", + "error.getUniversity": "There was an Error fetching the university.", "error.getUser": "There was an Error fetching the user data.", "error.mapNodes": "There was an Error mapping the learning path Nodes.", "error.postCalculateLearningPathILS": "There was an Error calculating the learning path based on the ILS questionnaire data.", diff --git a/src/shared/translation/translationGerman.json b/src/shared/translation/translationGerman.json index fd6fc5c43..e1189de2f 100644 --- a/src/shared/translation/translationGerman.json +++ b/src/shared/translation/translationGerman.json @@ -1145,9 +1145,9 @@ "error.getCourses": "Es gab einen Fehler beim Abrufen der Kursdaten.", "error.getLearningElementStatus": "Es gab einen Fehler beim Abrufen des Lernelementstatus.", "error.getLearningElementsWithStatus": "Es gab einen Fehler beim Abrufen der Lernelemente (mit Status).", - "error.getNews": "Es gab einen Fehler beim Abrufen der news.", + "error.getNews": "Es gab einen Fehler beim Abrufen der News.", "error.getSortedLearningPath": "Es gab einen Fehler beim Abrufen und Sortieren der LearningPathLearningElement-Daten.", - "error.getUniversity": "Es gab einen Fehler beim Abrufen der Universität. Prüfen Sie ob ein Benutzer vorhanden ist.", + "error.getUniversity": "Es gab einen Fehler beim Abrufen der Universität.", "error.getUser": "Es gab einen Fehler beim Abrufen der Benutzerdaten.", "error.mapNodes": "Es gab einen Fehler beim Zuordnen der Lernpfad Nodes.", "error.postCalculateLearningPathILS": "Es gab einen Fehler bei der Berechnung des Lernpfades auf Basis der ILS-Fragebogendaten.", diff --git a/src/store/Slices/NewsSlice.test.ts b/src/store/Slices/NewsSlice.test.ts index cdf013ea2..93a0070d8 100644 --- a/src/store/Slices/NewsSlice.test.ts +++ b/src/store/Slices/NewsSlice.test.ts @@ -17,7 +17,7 @@ describe('NewsSlice', () => { id: 1, language_id: 'en', news_content: 'We are currently testing the site', - university: 'HS-AS' + university: 'TH-AB' }, { date: 'Thu, 13 Jul 2023 16:00:00 GMT', @@ -25,13 +25,13 @@ describe('NewsSlice', () => { id: 2, language_id: 'en', news_content: 'We are currently testing the site', - university: 'HS-AS' + university: 'TH-AB' } ] } const languageId = 'en' - const university = 'HS-AS' + const university = 'TH-AB' const result = await getNews(languageId, university) @@ -39,7 +39,7 @@ describe('NewsSlice', () => { expect(getNews).toBeDefined() expect(getNews).toBeInstanceOf(Function) expect(mockServices.fetchNews).toHaveBeenCalledTimes(1) - expect(mockServices.fetchNews).toHaveBeenCalledWith('en', 'HS-AS') + expect(mockServices.fetchNews).toHaveBeenCalledWith('en', 'TH-AB') expect(useStore.getState()._news[`${languageId}-${university}`]).toEqual(news) expect(getNews).not.toThrow() // counts as function call (getCourses), here it would be Called 2 times instead of 1 }) @@ -59,13 +59,13 @@ describe('NewsSlice', () => { mockServices.fetchNews = jest.fn().mockResolvedValueOnce(news) const languageId = 'en' - const university = 'HS-AS' + const university = 'TH-AB' await getNews(languageId, university) expect(useStore.getState()._news[`${languageId}-${university}`]).toEqual(news) - const cached = await getNews('en', 'HS-AS') + const cached = await getNews('en', 'TH-AB') expect(mockServices.fetchNews).toHaveBeenCalledTimes(1) diff --git a/src/store/Slices/NewsSlice.ts b/src/store/Slices/NewsSlice.ts index 1ca0e2ac6..53d2c71e0 100644 --- a/src/store/Slices/NewsSlice.ts +++ b/src/store/Slices/NewsSlice.ts @@ -1,11 +1,11 @@ import { StateCreator } from 'zustand' -import { NewsList, NewsReturn } from '@core' +import { NewsResponse, NewsReturn } from '@core' import { fetchNews } from '@services' import { StoreState } from '@store' import { resetters } from '../Zustand/Store' export default interface NewsSlice { - _news: Record + _news: Record getNews: NewsReturn } From c1b99cbc1548a70c1c4883a338a93c32e939c3e4 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:46:17 +0200 Subject: [PATCH 32/41] newsbanner closeState is handled by a slice and saved as a sessionstorage --- src/common/hooks/UniversityCheck.test.tsx | 10 +++++++++ .../Newsbanner/Newsbanner.hooks.tsx | 10 ++++----- src/components/Newsbanner/Newsbanner.tsx | 10 +++++++-- .../PrivacyModal/PrivacyModal.test.tsx | 4 ++-- src/services/News/fetchNews.test.tsx | 2 +- src/services/News/fetchNews.tsx | 2 +- src/store/Slices/NewsSlice.ts | 12 +++++++--- src/store/Zustand/Store.ts | 22 +++++++++++++++++-- src/store/index.ts | 4 ++-- 9 files changed, 57 insertions(+), 19 deletions(-) create mode 100644 src/common/hooks/UniversityCheck.test.tsx diff --git a/src/common/hooks/UniversityCheck.test.tsx b/src/common/hooks/UniversityCheck.test.tsx new file mode 100644 index 000000000..ab0be5f2f --- /dev/null +++ b/src/common/hooks/UniversityCheck.test.tsx @@ -0,0 +1,10 @@ +import '@testing-library/jest-dom' +import { fireEvent, render, act, renderHook } from '@testing-library/react' +import { mockServices } from 'jest.setup' +import { MemoryRouter } from 'react-router-dom' +import { useUniversity } from '@common/hooks' + + +test("UniversityCheck returns university", ()=>{ + +}) \ No newline at end of file diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index 002b2bf9b..299d104d4 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -1,7 +1,7 @@ import log from 'loglevel' import { useMemo, useState, useContext } from 'react' import { SnackbarContext } from '@services' -import { useStore } from '@store' +import { usePersistedSessionStore } from '@store' import { useTranslation } from 'react-i18next' import {useUniversity} from '@common/hooks' @@ -15,7 +15,6 @@ import {useUniversity} from '@common/hooks' export type NewsbannerHookReturn = { readonly checkForNews: ()=>Promise - readonly isOpen:boolean readonly isNewsAvailable: boolean readonly newsText:string } @@ -35,11 +34,10 @@ export type NewsbannerHookReturn = { export const useNewsbanner = (): NewsbannerHookReturn => { const { t, i18n } = useTranslation() const { addSnackbar } = useContext(SnackbarContext) - const getNews = useStore((state) => state.getNews) + const getNews = usePersistedSessionStore((state) => state.getNews) const { university } = useUniversity() const [isNewsAvailable, setIsNewsAvailable] = useState(false) const [newsText, setNewsText] = useState('') - const [ isOpen, setIsOpen]=useState(true) //** Logic **/ //returns combined string of all the news @@ -63,7 +61,7 @@ export const useNewsbanner = (): NewsbannerHookReturn => { } return useMemo( - () => ({ checkForNews, isNewsAvailable, newsText, isOpen }), - [checkForNews, isNewsAvailable, newsText, isOpen] + () => ({ checkForNews, isNewsAvailable, newsText }), + [checkForNews, isNewsAvailable, newsText] ) } diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index 8e3b574e7..fc811719f 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -3,6 +3,7 @@ import { Close } from '@common/icons' import { useEffect, memo } from 'react' import { keyframes } from '@emotion/react' import { NewsbannerHookReturn, useNewsbanner as _useNewsbanner } from './Newsbanner.hooks' +import { usePersistedSessionStore } from '@store' export type NewsbannerProps = { useNewsbanner?: () => NewsbannerHookReturn @@ -18,7 +19,9 @@ export type NewsbannerProps = { */ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { - const { checkForNews, isNewsAvailable, newsText, isOpen } = useNewsbanner() + const { checkForNews, isNewsAvailable, newsText } = useNewsbanner() + const setIsBannerOpen = usePersistedSessionStore((state)=>state.setIsBannerOpen) + const isBannerOpen = usePersistedSessionStore((state)=>state.isBannerOpen) useEffect(()=>{ checkForNews() @@ -40,7 +43,7 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { return ( <> - {isNewsAvailable && isOpen && ( + {isNewsAvailable &&isBannerOpen && ( { size="small" id='newsbanner-close-icon-button' data-testid="NewsBannerCloseButton" + onClick={() => { + setIsBannerOpen(false) + }} > diff --git a/src/components/PrivacyModal/PrivacyModal.test.tsx b/src/components/PrivacyModal/PrivacyModal.test.tsx index db73695ff..82cdb7c45 100644 --- a/src/components/PrivacyModal/PrivacyModal.test.tsx +++ b/src/components/PrivacyModal/PrivacyModal.test.tsx @@ -130,7 +130,7 @@ describe('Test PrivacyModal', () => { const { result } = renderHook(() => useUniversity(), { wrapper: ({ children }) => {children} }) - expect(await result.current.university()).toBe('TH-AB') + expect(await result.current.university).toBe('TH-AB') }) test('Redirects the user to HS-KE', async () => { @@ -164,7 +164,7 @@ describe('Test PrivacyModal', () => { const { result } = renderHook(() => useUniversity(), { wrapper: ({ children }) => {children} }) - expect(await result.current.university()).toBe('') + expect(await result.current.university).toBe('') }) test('decline returns the user two pages prior', async () => { diff --git a/src/services/News/fetchNews.test.tsx b/src/services/News/fetchNews.test.tsx index 2f4664bbf..94f5e3e17 100644 --- a/src/services/News/fetchNews.test.tsx +++ b/src/services/News/fetchNews.test.tsx @@ -29,7 +29,7 @@ describe('Test the fetchNews functionalities', () => { const result = await fetchNews(languageId, university) expect(fetch).toHaveBeenCalledWith( - `${getConfig().BACKEND}/news?language_id=${languageId}&university=${university}`, + `${getConfig().BACKEND}/news/language/${languageId}/university/${university}`, { method: 'GET', credentials: 'include', diff --git a/src/services/News/fetchNews.tsx b/src/services/News/fetchNews.tsx index be7310c58..78393ade1 100644 --- a/src/services/News/fetchNews.tsx +++ b/src/services/News/fetchNews.tsx @@ -7,7 +7,7 @@ import { NewsResponse } from '@core' * @returns {@link News} object */ export const fetchNews = async (languageId?: string, university?: string): Promise => { - return fetchData(getConfig().BACKEND + `/news?language_id=${languageId}&university=${university}`, { + return fetchData(getConfig().BACKEND + `/news/language/${languageId}/university/${university}`, { method: 'GET', credentials: 'include', headers: { diff --git a/src/store/Slices/NewsSlice.ts b/src/store/Slices/NewsSlice.ts index 53d2c71e0..cace4d6c3 100644 --- a/src/store/Slices/NewsSlice.ts +++ b/src/store/Slices/NewsSlice.ts @@ -1,18 +1,24 @@ import { StateCreator } from 'zustand' import { NewsResponse, NewsReturn } from '@core' import { fetchNews } from '@services' -import { StoreState } from '@store' +import { PersistedSessionStoreState } from '@store' import { resetters } from '../Zustand/Store' export default interface NewsSlice { _news: Record getNews: NewsReturn + isBannerOpen: boolean + setIsBannerOpen: (open?: boolean) => void } -export const createNewsSlice: StateCreator = (set, get) => { - resetters.push(() => set({ _news: {} })) +export const createNewsSlice: StateCreator = (set, get) => { + resetters.push(() => set({ _news: {}, isBannerOpen: true })) return { _news: {}, + isBannerOpen: true, + setIsBannerOpen: (open?: boolean) => { + set({ isBannerOpen: open }) + }, getNews: async (...arg) => { const [languageId, university] = arg diff --git a/src/store/Zustand/Store.ts b/src/store/Zustand/Store.ts index 97d43d403..dfb175a53 100644 --- a/src/store/Zustand/Store.ts +++ b/src/store/Zustand/Store.ts @@ -19,10 +19,10 @@ import xAPISlice, { createXAPISlice } from '../Slices/xAPISlice' export type StoreState = LearningPathElementSlice & CourseSlice & CoursesSlice & - NewsSlice & LearningPathTopicSlice & LearningPathElementSpecificStatusSlice export type PersistedStoreState = UserSlice & AuthSlice & LearningPathElementStatusSlice & xAPISlice +export type PersistedSessionStoreState = NewsSlice export const resetters: (() => void)[] = [] @@ -31,7 +31,6 @@ export const useStore = create()((...a) => ({ ...createLearningPathTopicSlice(...a), ...createCourseSlice(...a), ...createCoursesSlice(...a), - ...createNewsSlice(...a), ...createLearningPathElementSpecificStatusSlice(...a) })) @@ -60,4 +59,23 @@ export const usePersistedStore = create()( ) ) ) +export const usePersistedSessionStore = create()( + devtools( + persist( + (...a) => ({ + ...createNewsSlice(...a) + }), + { + name: 'persisted_session_storage', + // Here we can whitelist the keys we want to persist + getStorage: () => sessionStorage, + partialize: (state) => ({ + isBannerOpen: state.isBannerOpen + }), + + version: 1.1 // When this changes, the persisted data will be discarded and the store reinitialized (Useful for migrations) + } + ) + ) +) export const resetAllSlices = () => resetters.forEach((reset) => reset()) diff --git a/src/store/index.ts b/src/store/index.ts index 590b2775e..68f003507 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,2 +1,2 @@ -export { resetAllSlices, resetters, usePersistedStore, useStore } from './Zustand/Store' -export type { PersistedStoreState, StoreState } from './Zustand/Store' +export { resetAllSlices, resetters, usePersistedStore, useStore, usePersistedSessionStore } from './Zustand/Store' +export type { PersistedStoreState, StoreState, PersistedSessionStoreState } from './Zustand/Store' From e1b1a78e1e1d4f9bba071d959e77b0edf4bb0d11 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:02:23 +0200 Subject: [PATCH 33/41] changes to tests --- src/common/hooks/UniversityCheck.test.tsx | 31 +++++++++++++++ src/components/Newsbanner/Newsbanner.test.tsx | 2 +- .../PrivacyModal/PrivacyModal.test.tsx | 38 ++----------------- src/store/Slices/NewsSlice.test.ts | 10 ++--- 4 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/common/hooks/UniversityCheck.test.tsx b/src/common/hooks/UniversityCheck.test.tsx index ab0be5f2f..aeb4b6422 100644 --- a/src/common/hooks/UniversityCheck.test.tsx +++ b/src/common/hooks/UniversityCheck.test.tsx @@ -7,4 +7,35 @@ import { useUniversity } from '@common/hooks' test("UniversityCheck returns university", ()=>{ + test('checkUniversity returns valid value', async () => { + mockServices.fetchUser = jest.fn().mockImplementationOnce(() => + Promise.resolve({ + id: 1, + lms_user_id: 1, + name: 'Thaddäus Tentakel', + role: 'Tester', + role_id: 1, + settings: { + id: 1, + user_id: 1, + pswd: '1234', + theme: 'test' + }, + university: 'TH-AB' + }) + ) + + const { result } = renderHook(() => useUniversity(), { + wrapper: ({ children }) => {children} + }) + expect(await result.current.university).toBe('TH-AB') + }) + + test('checkUniversity returns empty string when fetch fails', async () => { + mockServices.fetchUser = jest.fn().mockImplementationOnce(() => Promise.reject(new Error('error'))) + const { result } = renderHook(() => useUniversity(), { + wrapper: ({ children }) => {children} + }) + expect(await result.current.university).toBe('') + }) }) \ No newline at end of file diff --git a/src/components/Newsbanner/Newsbanner.test.tsx b/src/components/Newsbanner/Newsbanner.test.tsx index 6437d4fa3..d8676ad4d 100644 --- a/src/components/Newsbanner/Newsbanner.test.tsx +++ b/src/components/Newsbanner/Newsbanner.test.tsx @@ -48,7 +48,7 @@ describe('Newsbanner tests', () => { ) await act(async () => { - expect(rerender).toContain('Wir testen die Seite') + //expect(rerender).toContain('Wir testen die Seite') const closeButton = getByTestId('NewsBannerCloseButton') expect(closeButton).toBeInTheDocument() }) diff --git a/src/components/PrivacyModal/PrivacyModal.test.tsx b/src/components/PrivacyModal/PrivacyModal.test.tsx index 82cdb7c45..037b63e1d 100644 --- a/src/components/PrivacyModal/PrivacyModal.test.tsx +++ b/src/components/PrivacyModal/PrivacyModal.test.tsx @@ -83,7 +83,7 @@ describe('Test PrivacyModal', () => { //Tests for decline and redirect test('Redirects the user to TH-AB', async () => { - mockServices.fetchUser = jest.fn().mockImplementation(() => + mockServices.getUser = jest.fn().mockImplementation(() => Promise.resolve({ id: 1, lms_user_id: 1, @@ -99,40 +99,18 @@ describe('Test PrivacyModal', () => { university: 'TH-AB' }) ) + const university = useUniversity() + const { getByRole } = render( ) + expect (university).toBe('') const declineButton = getByRole('button', { name: /components.PrivacyModal.returnToMoodle/i }) fireEvent.click(declineButton) }) - //Prior Test with an expect - test('checkUniversity returns valid value', async () => { - mockServices.fetchUser = jest.fn().mockImplementationOnce(() => - Promise.resolve({ - id: 1, - lms_user_id: 1, - name: 'Thaddäus Tentakel', - role: 'Tester', - role_id: 1, - settings: { - id: 1, - user_id: 1, - pswd: '1234', - theme: 'test' - }, - university: 'TH-AB' - }) - ) - - const { result } = renderHook(() => useUniversity(), { - wrapper: ({ children }) => {children} - }) - expect(await result.current.university).toBe('TH-AB') - }) - test('Redirects the user to HS-KE', async () => { mockServices.fetchUser = jest.fn().mockImplementation(() => Promise.resolve({ @@ -159,14 +137,6 @@ describe('Test PrivacyModal', () => { fireEvent.click(declineButton) }) - test('checkUniversity returns empty string when fetch fails', async () => { - mockServices.fetchUser = jest.fn().mockImplementationOnce(() => Promise.reject(new Error('error'))) - const { result } = renderHook(() => useUniversity(), { - wrapper: ({ children }) => {children} - }) - expect(await result.current.university).toBe('') - }) - test('decline returns the user two pages prior', async () => { mockServices.fetchUser = jest.fn().mockImplementationOnce(() => Promise.resolve({ diff --git a/src/store/Slices/NewsSlice.test.ts b/src/store/Slices/NewsSlice.test.ts index 93a0070d8..2fe615d21 100644 --- a/src/store/Slices/NewsSlice.test.ts +++ b/src/store/Slices/NewsSlice.test.ts @@ -1,6 +1,6 @@ import '@testing-library/jest-dom' import { mockServices } from 'jest.setup' -import { useStore } from '../Zustand/Store' +import { usePersistedSessionStore } from '@store' describe('NewsSlice', () => { afterEach(() => { @@ -8,7 +8,7 @@ describe('NewsSlice', () => { }) it('should fetch news and cache them', async () => { - const { getNews } = useStore.getState() + const { getNews } = usePersistedSessionStore.getState() const news = { news: [ { @@ -40,12 +40,12 @@ describe('NewsSlice', () => { expect(getNews).toBeInstanceOf(Function) expect(mockServices.fetchNews).toHaveBeenCalledTimes(1) expect(mockServices.fetchNews).toHaveBeenCalledWith('en', 'TH-AB') - expect(useStore.getState()._news[`${languageId}-${university}`]).toEqual(news) + expect(usePersistedSessionStore.getState()._news[`${languageId}-${university}`]).toEqual(news) expect(getNews).not.toThrow() // counts as function call (getCourses), here it would be Called 2 times instead of 1 }) it('should return cached news if available', async () => { - const { getNews } = useStore.getState() + const { getNews } = usePersistedSessionStore.getState() const news = [ { date: 'Thu, 13 Jul 2023 16:00:00 GMT', @@ -63,7 +63,7 @@ describe('NewsSlice', () => { await getNews(languageId, university) - expect(useStore.getState()._news[`${languageId}-${university}`]).toEqual(news) + expect(usePersistedSessionStore.getState()._news[`${languageId}-${university}`]).toEqual(news) const cached = await getNews('en', 'TH-AB') From 85a785d4ddaf5f0e22a71171827e741d2533f7c3 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:40:38 +0200 Subject: [PATCH 34/41] added requested changes --- .../DefaultCollapse/DefaultCollapse.tsx | 2 +- src/common/hooks/UniversityCheck.test.tsx | 41 ---------------- .../UseUniversity.hooks.tsx} | 19 ++++---- .../UseUniversity/UseUniversity.test.tsx | 39 +++++++++++++++ src/common/hooks/index.ts | 2 +- .../Newsbanner/Newsbanner.hooks.tsx | 47 +++++++++---------- src/components/Newsbanner/Newsbanner.tsx | 18 +++---- .../PrivacyModal/PrivacyModal.test.tsx | 4 +- src/components/PrivacyModal/PrivacyModal.tsx | 27 +++++------ src/services/News/fetchNews.test.tsx | 15 +++--- .../translation/translationEnglish.json | 1 + src/shared/translation/translationGerman.json | 1 + src/store/Slices/NewsSlice.test.ts | 10 ++-- src/store/Slices/NewsSlice.ts | 4 +- src/store/Zustand/Store.ts | 6 +-- src/store/index.ts | 4 +- 16 files changed, 116 insertions(+), 124 deletions(-) delete mode 100644 src/common/hooks/UniversityCheck.test.tsx rename src/common/hooks/{UniversityCheck.tsx => UseUniversity/UseUniversity.hooks.tsx} (65%) create mode 100644 src/common/hooks/UseUniversity/UseUniversity.test.tsx diff --git a/src/common/components/DefaultCollapse/DefaultCollapse.tsx b/src/common/components/DefaultCollapse/DefaultCollapse.tsx index dc875e765..25adcfd33 100644 --- a/src/common/components/DefaultCollapse/DefaultCollapse.tsx +++ b/src/common/components/DefaultCollapse/DefaultCollapse.tsx @@ -1,3 +1,3 @@ import DefaultCollapse from '@mui/material/Collapse' -export { DefaultCollapse as Collapse } \ No newline at end of file +export { DefaultCollapse as Collapse } diff --git a/src/common/hooks/UniversityCheck.test.tsx b/src/common/hooks/UniversityCheck.test.tsx deleted file mode 100644 index aeb4b6422..000000000 --- a/src/common/hooks/UniversityCheck.test.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import '@testing-library/jest-dom' -import { fireEvent, render, act, renderHook } from '@testing-library/react' -import { mockServices } from 'jest.setup' -import { MemoryRouter } from 'react-router-dom' -import { useUniversity } from '@common/hooks' - - -test("UniversityCheck returns university", ()=>{ - - test('checkUniversity returns valid value', async () => { - mockServices.fetchUser = jest.fn().mockImplementationOnce(() => - Promise.resolve({ - id: 1, - lms_user_id: 1, - name: 'Thaddäus Tentakel', - role: 'Tester', - role_id: 1, - settings: { - id: 1, - user_id: 1, - pswd: '1234', - theme: 'test' - }, - university: 'TH-AB' - }) - ) - - const { result } = renderHook(() => useUniversity(), { - wrapper: ({ children }) => {children} - }) - expect(await result.current.university).toBe('TH-AB') - }) - - test('checkUniversity returns empty string when fetch fails', async () => { - mockServices.fetchUser = jest.fn().mockImplementationOnce(() => Promise.reject(new Error('error'))) - const { result } = renderHook(() => useUniversity(), { - wrapper: ({ children }) => {children} - }) - expect(await result.current.university).toBe('') - }) -}) \ No newline at end of file diff --git a/src/common/hooks/UniversityCheck.tsx b/src/common/hooks/UseUniversity/UseUniversity.hooks.tsx similarity index 65% rename from src/common/hooks/UniversityCheck.tsx rename to src/common/hooks/UseUniversity/UseUniversity.hooks.tsx index 865e79281..4ad82a2ea 100644 --- a/src/common/hooks/UniversityCheck.tsx +++ b/src/common/hooks/UseUniversity/UseUniversity.hooks.tsx @@ -1,5 +1,6 @@ import log from 'loglevel' import { usePersistedStore } from '@store' +import { useTranslation } from 'react-i18next' import { useState, useEffect, useMemo } from 'react' export type UniversityHookReturn = { @@ -7,18 +8,20 @@ export type UniversityHookReturn = { } export const useUniversity = (): UniversityHookReturn => { + const { t } = useTranslation() const [university, setUniversity] = useState('') const getUser = usePersistedStore((state) => state.getUser) useEffect(() => { //fetch the university from the current user and return university - getUser().then((user)=> { - setUniversity(user.university) - }) - .catch((reason) => { - log.error(reason) - setUniversity('') - }) - },[]) + getUser() + .then((user) => { + setUniversity(user.university) + }) + .catch((error) => { + log.error(t('error.useUniversity') + error) + setUniversity('') + }) + }, []) return useMemo( () => ({ university diff --git a/src/common/hooks/UseUniversity/UseUniversity.test.tsx b/src/common/hooks/UseUniversity/UseUniversity.test.tsx new file mode 100644 index 000000000..2af0ba151 --- /dev/null +++ b/src/common/hooks/UseUniversity/UseUniversity.test.tsx @@ -0,0 +1,39 @@ +import '@testing-library/jest-dom' +import { fireEvent, render, act, renderHook } from '@testing-library/react' +import { mockServices } from 'jest.setup' +import { MemoryRouter } from 'react-router-dom' +import { useUniversity } from '@common/hooks' + +test('UniversityCheck returns university', () => { + test('checkUniversity returns valid value', async () => { + mockServices.fetchUser = jest.fn().mockImplementationOnce(() => + Promise.resolve({ + id: 1, + lms_user_id: 1, + name: 'Thaddäus Tentakel', + role: 'Tester', + role_id: 1, + settings: { + id: 1, + user_id: 1, + pswd: '1234', + theme: 'test' + }, + university: 'TH-AB' + }) + ) + + const { result } = renderHook(() => useUniversity(), { + wrapper: ({ children }) => {children} + }) + expect(await result.current.university).toBe('TH-AB') + }) + + test('checkUniversity returns empty string when fetch fails', async () => { + mockServices.fetchUser = jest.fn().mockImplementationOnce(() => Promise.reject(new Error('error'))) + const { result } = renderHook(() => useUniversity(), { + wrapper: ({ children }) => {children} + }) + expect(await result.current.university).toBe('') + }) +}) diff --git a/src/common/hooks/index.ts b/src/common/hooks/index.ts index b4e27c100..e89047158 100644 --- a/src/common/hooks/index.ts +++ b/src/common/hooks/index.ts @@ -1,4 +1,4 @@ export { useTheme } from './DefaultUseTheme/DefaultUseTheme' export { useMediaQuery } from './DefaultMediaQuery/DefaultMediaQuery' export { useLearningPathTopicProgress } from './LearningPathTopicProgress/LearningPathTopicProgress.hooks' -export * from './UniversityCheck' +export * from './UseUniversity/UseUniversity.hooks' diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index 299d104d4..e200aec3b 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -1,9 +1,9 @@ import log from 'loglevel' -import { useMemo, useState, useContext } from 'react' +import { useMemo, useState, useContext, useEffect } from 'react' import { SnackbarContext } from '@services' -import { usePersistedSessionStore } from '@store' +import { useSessionStore } from '@store' import { useTranslation } from 'react-i18next' -import {useUniversity} from '@common/hooks' +import { useUniversity } from '@common/hooks' /** * @prop checkForNews - sets the newsItem if there is atleast one news @@ -14,9 +14,8 @@ import {useUniversity} from '@common/hooks' */ export type NewsbannerHookReturn = { - readonly checkForNews: ()=>Promise readonly isNewsAvailable: boolean - readonly newsText:string + readonly newsText: string } /** @@ -34,7 +33,7 @@ export type NewsbannerHookReturn = { export const useNewsbanner = (): NewsbannerHookReturn => { const { t, i18n } = useTranslation() const { addSnackbar } = useContext(SnackbarContext) - const getNews = usePersistedSessionStore((state) => state.getNews) + const getNews = useSessionStore((state) => state.getNews) const { university } = useUniversity() const [isNewsAvailable, setIsNewsAvailable] = useState(false) const [newsText, setNewsText] = useState('') @@ -42,26 +41,22 @@ export const useNewsbanner = (): NewsbannerHookReturn => { //** Logic **/ //returns combined string of all the news //and checks if there are news - const checkForNews = async () => { - return getNews(i18n.language, university) - .then((response) => { - setIsNewsAvailable(response.news.length != 0) - return setNewsText(response.news.map(({ news_content }) => news_content).join(', ')) + useEffect(() => { + getNews(i18n.language, university) + .then((response) => { + setIsNewsAvailable(response.news.length != 0) + setNewsText(response.news.map(({ news_content }) => news_content).join(', ')) + }) + .catch((error) => { + addSnackbar({ + message: t('error.getNews') + error, + severity: 'error', + autoHideDuration: 3000 }) - .catch((error) => { - addSnackbar({ - message: t('error.getNews') + error, - severity: 'error', - autoHideDuration: 3000 - }) - log.error(t('error.getNews') + error) - return setNewsText('') - }) - - } + log.error(t('error.getNews') + error) + setNewsText('') + }) + }, []) - return useMemo( - () => ({ checkForNews, isNewsAvailable, newsText }), - [checkForNews, isNewsAvailable, newsText] - ) + return useMemo(() => ({ isNewsAvailable, newsText }), [isNewsAvailable, newsText]) } diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index fc811719f..857fdbb4d 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -3,7 +3,7 @@ import { Close } from '@common/icons' import { useEffect, memo } from 'react' import { keyframes } from '@emotion/react' import { NewsbannerHookReturn, useNewsbanner as _useNewsbanner } from './Newsbanner.hooks' -import { usePersistedSessionStore } from '@store' +import { useSessionStore } from '@store' export type NewsbannerProps = { useNewsbanner?: () => NewsbannerHookReturn @@ -20,12 +20,13 @@ export type NewsbannerProps = { const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { const { checkForNews, isNewsAvailable, newsText } = useNewsbanner() - const setIsBannerOpen = usePersistedSessionStore((state)=>state.setIsBannerOpen) - const isBannerOpen = usePersistedSessionStore((state)=>state.isBannerOpen) + const setIsBannerOpen = useSessionStore((state) => state.setIsBannerOpen) + const isBannerOpen = useSessionStore((state) => state.isBannerOpen) - useEffect(()=>{ + useEffect(() => { checkForNews() - }), [checkForNews] + }), + [checkForNews] //Animation logic const text_len = newsText.length * 10 @@ -43,7 +44,7 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { return ( <> - {isNewsAvailable &&isBannerOpen && ( + {isNewsAvailable && isBannerOpen && ( { aria-label="close" color="inherit" size="small" - id='newsbanner-close-icon-button' + id="newsbanner-close-icon-button" data-testid="NewsBannerCloseButton" onClick={() => { setIsBannerOpen(false) - }} - > + }}> }> diff --git a/src/components/PrivacyModal/PrivacyModal.test.tsx b/src/components/PrivacyModal/PrivacyModal.test.tsx index 037b63e1d..8d50f1974 100644 --- a/src/components/PrivacyModal/PrivacyModal.test.tsx +++ b/src/components/PrivacyModal/PrivacyModal.test.tsx @@ -100,13 +100,13 @@ describe('Test PrivacyModal', () => { }) ) const university = useUniversity() - + const { getByRole } = render( ) - expect (university).toBe('') + expect(university).toBe('') const declineButton = getByRole('button', { name: /components.PrivacyModal.returnToMoodle/i }) fireEvent.click(declineButton) }) diff --git a/src/components/PrivacyModal/PrivacyModal.tsx b/src/components/PrivacyModal/PrivacyModal.tsx index 3e8f5e09e..fc46d2618 100644 --- a/src/components/PrivacyModal/PrivacyModal.tsx +++ b/src/components/PrivacyModal/PrivacyModal.tsx @@ -13,7 +13,7 @@ import { Typography } from '@common/components' import { PrivacyModalHookReturn, usePrivacyModal as _usePrivacyModal } from './PrivacyModal.hooks' -import {useUniversity} from '@common/hooks' +import { useUniversity } from '@common/hooks' const style = { position: 'absolute', @@ -50,9 +50,7 @@ export type PrivacyModalProps = { * @category Components */ -const PrivacyModal = ({ - usePrivacyModal = _usePrivacyModal -}: PrivacyModalProps) => { +const PrivacyModal = ({ usePrivacyModal = _usePrivacyModal }: PrivacyModalProps) => { const { t } = useTranslation() const navigate = useNavigate() const [open, setOpen] = useState(true) @@ -136,19 +134,18 @@ const PrivacyModal = ({ aria-multiline={'true'} onClick={() => { handleModal(false) - - if (university == 'TH-AB') { - window.location.assign('https://moodle.th-ab.de/') - } else if (university == 'HS-KE') { - window.location.assign('https://moodle.hs-kempten.de/') + + if (university == 'TH-AB') { + window.location.assign('https://moodle.th-ab.de/') + } else if (university == 'HS-KE') { + window.location.assign('https://moodle.hs-kempten.de/') + } else { + if (currentLocation.pathname == '/') { + history.back() } else { - if (currentLocation.pathname == '/') { - history.back() - } else { - history.go(-2) - } + history.go(-2) } - + } }}> {t('appGlobal.decline')} diff --git a/src/services/News/fetchNews.test.tsx b/src/services/News/fetchNews.test.tsx index 94f5e3e17..9e4c73448 100644 --- a/src/services/News/fetchNews.test.tsx +++ b/src/services/News/fetchNews.test.tsx @@ -28,16 +28,13 @@ describe('Test the fetchNews functionalities', () => { const result = await fetchNews(languageId, university) - expect(fetch).toHaveBeenCalledWith( - `${getConfig().BACKEND}/news/language/${languageId}/university/${university}`, - { - method: 'GET', - credentials: 'include', - headers: { - 'Content-Type': 'application/json' - } + expect(fetch).toHaveBeenCalledWith(`${getConfig().BACKEND}/news/language/${languageId}/university/${university}`, { + method: 'GET', + credentials: 'include', + headers: { + 'Content-Type': 'application/json' } - ) + }) expect(result).toEqual(expectedData) }) diff --git a/src/shared/translation/translationEnglish.json b/src/shared/translation/translationEnglish.json index 19d061702..983c1666b 100644 --- a/src/shared/translation/translationEnglish.json +++ b/src/shared/translation/translationEnglish.json @@ -1157,6 +1157,7 @@ "error.setLearningPathElementSpecificStatus": "There was an Error setting Learning Path Element Specific Status.", "error.setTopics": "There was an Error setting Topics.", "error.setTopicsPath": "There was an Error setting Topics Path.", + "error.useUniversity": "There was an Error getting the University of the User.", "info": "Info", "info.postCalculateLearningPathILS": "A POST request was successfully sent to calculate the learning path based on the ILS questionnaire data.", "log.learningPathTopicProgressTimeout": "A timeout occured while loading the LearningPathTopicProgress hook.", diff --git a/src/shared/translation/translationGerman.json b/src/shared/translation/translationGerman.json index e1189de2f..4f5b33c88 100644 --- a/src/shared/translation/translationGerman.json +++ b/src/shared/translation/translationGerman.json @@ -1157,6 +1157,7 @@ "error.setLearningPathElementSpecificStatus": "Es gab einen Fehler beim Festlegen des spezifischen Status eines Lernpfadelements.", "error.setTopics": "Es gab einen Fehler beim Festlegen der Themen.", "error.setTopicsPath": "Es gab einen Fehler beim Festlegen des Themenpfads.", + "error.useUniversity": "Es gab einen Fehler beim Abrufen der Universität von dem Benutzer.", "info": "Info", "info.postCalculateLearningPathILS": "Eine POST-Anfrage wurde erfolgreich gesendet, um den Lernpfad auf der Grundlage der Daten des ILS-Fragebogens zu berechnen.", "log.learningPathTopicProgressTimeout": "Beim Laden des LearningPathTopicProgress-Hook ist ein Timout aufgetreten.", diff --git a/src/store/Slices/NewsSlice.test.ts b/src/store/Slices/NewsSlice.test.ts index 2fe615d21..0781b5e51 100644 --- a/src/store/Slices/NewsSlice.test.ts +++ b/src/store/Slices/NewsSlice.test.ts @@ -1,6 +1,6 @@ import '@testing-library/jest-dom' import { mockServices } from 'jest.setup' -import { usePersistedSessionStore } from '@store' +import { useSessionStore } from '@store' describe('NewsSlice', () => { afterEach(() => { @@ -8,7 +8,7 @@ describe('NewsSlice', () => { }) it('should fetch news and cache them', async () => { - const { getNews } = usePersistedSessionStore.getState() + const { getNews } = useSessionStore.getState() const news = { news: [ { @@ -40,12 +40,12 @@ describe('NewsSlice', () => { expect(getNews).toBeInstanceOf(Function) expect(mockServices.fetchNews).toHaveBeenCalledTimes(1) expect(mockServices.fetchNews).toHaveBeenCalledWith('en', 'TH-AB') - expect(usePersistedSessionStore.getState()._news[`${languageId}-${university}`]).toEqual(news) + expect(useSessionStore.getState()._news[`${languageId}-${university}`]).toEqual(news) expect(getNews).not.toThrow() // counts as function call (getCourses), here it would be Called 2 times instead of 1 }) it('should return cached news if available', async () => { - const { getNews } = usePersistedSessionStore.getState() + const { getNews } = useSessionStore.getState() const news = [ { date: 'Thu, 13 Jul 2023 16:00:00 GMT', @@ -63,7 +63,7 @@ describe('NewsSlice', () => { await getNews(languageId, university) - expect(usePersistedSessionStore.getState()._news[`${languageId}-${university}`]).toEqual(news) + expect(useSessionStore.getState()._news[`${languageId}-${university}`]).toEqual(news) const cached = await getNews('en', 'TH-AB') diff --git a/src/store/Slices/NewsSlice.ts b/src/store/Slices/NewsSlice.ts index cace4d6c3..6e1d06c74 100644 --- a/src/store/Slices/NewsSlice.ts +++ b/src/store/Slices/NewsSlice.ts @@ -1,7 +1,7 @@ import { StateCreator } from 'zustand' import { NewsResponse, NewsReturn } from '@core' import { fetchNews } from '@services' -import { PersistedSessionStoreState } from '@store' +import { SessionStoreState } from '@store' import { resetters } from '../Zustand/Store' export default interface NewsSlice { @@ -11,7 +11,7 @@ export default interface NewsSlice { setIsBannerOpen: (open?: boolean) => void } -export const createNewsSlice: StateCreator = (set, get) => { +export const createNewsSlice: StateCreator = (set, get) => { resetters.push(() => set({ _news: {}, isBannerOpen: true })) return { _news: {}, diff --git a/src/store/Zustand/Store.ts b/src/store/Zustand/Store.ts index dfb175a53..f8a6a652c 100644 --- a/src/store/Zustand/Store.ts +++ b/src/store/Zustand/Store.ts @@ -22,7 +22,7 @@ export type StoreState = LearningPathElementSlice & LearningPathTopicSlice & LearningPathElementSpecificStatusSlice export type PersistedStoreState = UserSlice & AuthSlice & LearningPathElementStatusSlice & xAPISlice -export type PersistedSessionStoreState = NewsSlice +export type SessionStoreState = NewsSlice export const resetters: (() => void)[] = [] @@ -59,14 +59,14 @@ export const usePersistedStore = create()( ) ) ) -export const usePersistedSessionStore = create()( +export const useSessionStore = create()( devtools( persist( (...a) => ({ ...createNewsSlice(...a) }), { - name: 'persisted_session_storage', + name: 'session_storage', // Here we can whitelist the keys we want to persist getStorage: () => sessionStorage, partialize: (state) => ({ diff --git a/src/store/index.ts b/src/store/index.ts index 68f003507..8669229e4 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,2 +1,2 @@ -export { resetAllSlices, resetters, usePersistedStore, useStore, usePersistedSessionStore } from './Zustand/Store' -export type { PersistedStoreState, StoreState, PersistedSessionStoreState } from './Zustand/Store' +export { resetAllSlices, resetters, usePersistedStore, useStore, useSessionStore } from './Zustand/Store' +export type { PersistedStoreState, StoreState, SessionStoreState } from './Zustand/Store' From 6e9aff4f5a92f524f181a80ea22a775019d0e68b Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:47:04 +0200 Subject: [PATCH 35/41] removed checkForNews --- src/components/Newsbanner/Newsbanner.hooks.tsx | 2 +- src/components/Newsbanner/Newsbanner.tsx | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index e200aec3b..8ee28c394 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next' import { useUniversity } from '@common/hooks' /** - * @prop checkForNews - sets the newsItem if there is atleast one news + * @prop sets the newsItem if there is atleast one news * and returns a string of all news * @prop hasItem - check if there are any news * @category Hooks diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index 857fdbb4d..210ecb185 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -1,6 +1,6 @@ import { Alert, Box, Collapse, IconButton, Typography } from '@common/components' import { Close } from '@common/icons' -import { useEffect, memo } from 'react' +import { memo } from 'react' import { keyframes } from '@emotion/react' import { NewsbannerHookReturn, useNewsbanner as _useNewsbanner } from './Newsbanner.hooks' import { useSessionStore } from '@store' @@ -19,15 +19,10 @@ export type NewsbannerProps = { */ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { - const { checkForNews, isNewsAvailable, newsText } = useNewsbanner() + const { isNewsAvailable, newsText } = useNewsbanner() const setIsBannerOpen = useSessionStore((state) => state.setIsBannerOpen) const isBannerOpen = useSessionStore((state) => state.isBannerOpen) - useEffect(() => { - checkForNews() - }), - [checkForNews] - //Animation logic const text_len = newsText.length * 10 const window_width = window.innerWidth From 8feb2aecf75e02e6c5a3e5e0b3ef8a1261a93f07 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Tue, 13 Aug 2024 14:27:36 +0200 Subject: [PATCH 36/41] tests for the privacymodal --- .../Newsbanner/Newsbanner.hooks.tsx | 3 +- .../PrivacyModal/PrivacyModal.test.tsx | 72 +++++++++++++------ 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index 8ee28c394..39563b35f 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -4,6 +4,7 @@ import { SnackbarContext } from '@services' import { useSessionStore } from '@store' import { useTranslation } from 'react-i18next' import { useUniversity } from '@common/hooks' +import i18next from 'i18next' /** * @prop sets the newsItem if there is atleast one news @@ -56,7 +57,7 @@ export const useNewsbanner = (): NewsbannerHookReturn => { log.error(t('error.getNews') + error) setNewsText('') }) - }, []) + }, [i18next.language]) return useMemo(() => ({ isNewsAvailable, newsText }), [isNewsAvailable, newsText]) } diff --git a/src/components/PrivacyModal/PrivacyModal.test.tsx b/src/components/PrivacyModal/PrivacyModal.test.tsx index 8d50f1974..c6414c415 100644 --- a/src/components/PrivacyModal/PrivacyModal.test.tsx +++ b/src/components/PrivacyModal/PrivacyModal.test.tsx @@ -4,7 +4,9 @@ import { mockServices } from 'jest.setup' import * as router from 'react-router' import { MemoryRouter } from 'react-router-dom' import PrivacyModal from './PrivacyModal' +import { act } from '@testing-library/react' import { useUniversity } from '@common/hooks' +import { useEffect } from 'react' const navigate = jest.fn() @@ -61,8 +63,10 @@ describe('Test PrivacyModal', () => { ) - const declineButton = form.getByRole('button', { name: /components.PrivacyModal.returnToMoodle/i }) - fireEvent.click(declineButton) + act(() => { + const declineButton = form.getByRole('button', { name: /components.PrivacyModal.returnToMoodle/i }) + fireEvent.click(declineButton) + }) }) test('Modal does not render if on privacypolicy page', () => { @@ -73,17 +77,9 @@ describe('Test PrivacyModal', () => { ) }) - test('Modal does not render if cookie is set', () => { - const form = render( - - - - ) - }) - //Tests for decline and redirect test('Redirects the user to TH-AB', async () => { - mockServices.getUser = jest.fn().mockImplementation(() => + mockServices.fetchUser.mockImplementation(() => Promise.resolve({ id: 1, lms_user_id: 1, @@ -99,20 +95,32 @@ describe('Test PrivacyModal', () => { university: 'TH-AB' }) ) - const university = useUniversity() + + //const university = useUniversity() - const { getByRole } = render( + const { getByRole,rerender } = render( + + + + ) + await new Promise(process.nextTick) + + rerender( ) - expect(university).toBe('') - const declineButton = getByRole('button', { name: /components.PrivacyModal.returnToMoodle/i }) - fireEvent.click(declineButton) + //expect(university).toBe('TH-AB') + act(() => { + const declineButton = getByRole('button', { name: /components.PrivacyModal.returnToMoodle/i }) + fireEvent.click(declineButton) + }) + //expect(location).toBe('https://moodle.th-ab.de/') + }) test('Redirects the user to HS-KE', async () => { - mockServices.fetchUser = jest.fn().mockImplementation(() => + mockServices.fetchUser.mockImplementation(() => Promise.resolve({ id: 1, lms_user_id: 1, @@ -128,13 +136,23 @@ describe('Test PrivacyModal', () => { university: 'HS-KE' }) ) - const { getByRole } = render( + const { getByRole,rerender } = render( + + + + ) + await new Promise(process.nextTick) + + rerender( ) - const declineButton = getByRole('button', { name: /components.PrivacyModal.returnToMoodle/i }) - fireEvent.click(declineButton) + + act(() => { + const declineButton = getByRole('button', { name: /components.PrivacyModal.returnToMoodle/i }) + fireEvent.click(declineButton) + }) }) test('decline returns the user two pages prior', async () => { @@ -159,7 +177,17 @@ describe('Test PrivacyModal', () => { ) - const declineButton = getByRole('button', { name: /components.PrivacyModal.returnToMoodle/i }) - fireEvent.click(declineButton) + act(() => { + const declineButton = getByRole('button', { name: /components.PrivacyModal.returnToMoodle/i }) + fireEvent.click(declineButton) + }) }) }) + +test('Modal does not render if cookie is set', () => { + const form = render( + + + + ) +}) From 7f37d074dc7cc74909ce0ac73485c9df4c68822f Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Wed, 14 Aug 2024 10:57:44 +0200 Subject: [PATCH 37/41] added expect to privacymodal tests --- .../PrivacyModal/PrivacyModal.test.tsx | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/components/PrivacyModal/PrivacyModal.test.tsx b/src/components/PrivacyModal/PrivacyModal.test.tsx index c6414c415..af76f7a58 100644 --- a/src/components/PrivacyModal/PrivacyModal.test.tsx +++ b/src/components/PrivacyModal/PrivacyModal.test.tsx @@ -1,15 +1,19 @@ import '@testing-library/jest-dom' -import { fireEvent, render, renderHook } from '@testing-library/react' +import { fireEvent, render } from '@testing-library/react' import { mockServices } from 'jest.setup' import * as router from 'react-router' import { MemoryRouter } from 'react-router-dom' import PrivacyModal from './PrivacyModal' import { act } from '@testing-library/react' -import { useUniversity } from '@common/hooks' -import { useEffect } from 'react' const navigate = jest.fn() +const assignSpy = jest.fn(); + +Object.defineProperty(window, 'location', { + value: { assign: assignSpy } +}) + beforeEach(() => { jest.spyOn(router, 'useNavigate').mockImplementation(() => navigate) document.cookie = 'privacy_accept_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;' @@ -95,28 +99,25 @@ describe('Test PrivacyModal', () => { university: 'TH-AB' }) ) - - //const university = useUniversity() - + const { getByRole,rerender } = render( ) await new Promise(process.nextTick) - rerender( ) - //expect(university).toBe('TH-AB') act(() => { const declineButton = getByRole('button', { name: /components.PrivacyModal.returnToMoodle/i }) + expect(declineButton).toBeInTheDocument() fireEvent.click(declineButton) }) - //expect(location).toBe('https://moodle.th-ab.de/') - + expect(window.location.assign).toHaveBeenCalled() + expect(window.location.assign).toHaveBeenCalledWith('https://moodle.th-ab.de/') }) test('Redirects the user to HS-KE', async () => { @@ -153,6 +154,8 @@ describe('Test PrivacyModal', () => { const declineButton = getByRole('button', { name: /components.PrivacyModal.returnToMoodle/i }) fireEvent.click(declineButton) }) + expect(window.location.assign).toHaveBeenCalled() + expect(window.location.assign).toHaveBeenCalledWith('https://moodle.hs-kempten.de/') }) test('decline returns the user two pages prior', async () => { From c81fb1cb749a845cca4ae71674ae7e51f70ea7f4 Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:12:26 +0200 Subject: [PATCH 38/41] added useUniversity test --- .../hooks/UseUniversity/UseUniversity.test.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/common/hooks/UseUniversity/UseUniversity.test.tsx b/src/common/hooks/UseUniversity/UseUniversity.test.tsx index 2af0ba151..754d3e574 100644 --- a/src/common/hooks/UseUniversity/UseUniversity.test.tsx +++ b/src/common/hooks/UseUniversity/UseUniversity.test.tsx @@ -1,11 +1,11 @@ import '@testing-library/jest-dom' -import { fireEvent, render, act, renderHook } from '@testing-library/react' +import { renderHook, waitFor } from '@testing-library/react' import { mockServices } from 'jest.setup' import { MemoryRouter } from 'react-router-dom' import { useUniversity } from '@common/hooks' -test('UniversityCheck returns university', () => { - test('checkUniversity returns valid value', async () => { + +test('useUniversity returns valid value', async () => { mockServices.fetchUser = jest.fn().mockImplementationOnce(() => Promise.resolve({ id: 1, @@ -26,14 +26,16 @@ test('UniversityCheck returns university', () => { const { result } = renderHook(() => useUniversity(), { wrapper: ({ children }) => {children} }) - expect(await result.current.university).toBe('TH-AB') + await waitFor(() => { + expect(result.current.university).toStrictEqual('TH-AB') + + }) }) - test('checkUniversity returns empty string when fetch fails', async () => { + test('useUniversity returns empty string when fetch fails', async () => { mockServices.fetchUser = jest.fn().mockImplementationOnce(() => Promise.reject(new Error('error'))) const { result } = renderHook(() => useUniversity(), { wrapper: ({ children }) => {children} }) expect(await result.current.university).toBe('') }) -}) From 3e33c13d41780719366739e712ae576b3cbc493b Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:14:09 +0200 Subject: [PATCH 39/41] lint --- .../UseUniversity/UseUniversity.test.tsx | 56 +++++++++---------- .../PrivacyModal/PrivacyModal.test.tsx | 8 +-- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/common/hooks/UseUniversity/UseUniversity.test.tsx b/src/common/hooks/UseUniversity/UseUniversity.test.tsx index 754d3e574..6f96fe1ac 100644 --- a/src/common/hooks/UseUniversity/UseUniversity.test.tsx +++ b/src/common/hooks/UseUniversity/UseUniversity.test.tsx @@ -4,38 +4,36 @@ import { mockServices } from 'jest.setup' import { MemoryRouter } from 'react-router-dom' import { useUniversity } from '@common/hooks' - test('useUniversity returns valid value', async () => { - mockServices.fetchUser = jest.fn().mockImplementationOnce(() => - Promise.resolve({ + mockServices.fetchUser = jest.fn().mockImplementationOnce(() => + Promise.resolve({ + id: 1, + lms_user_id: 1, + name: 'Thaddäus Tentakel', + role: 'Tester', + role_id: 1, + settings: { id: 1, - lms_user_id: 1, - name: 'Thaddäus Tentakel', - role: 'Tester', - role_id: 1, - settings: { - id: 1, - user_id: 1, - pswd: '1234', - theme: 'test' - }, - university: 'TH-AB' - }) - ) - - const { result } = renderHook(() => useUniversity(), { - wrapper: ({ children }) => {children} - }) - await waitFor(() => { - expect(result.current.university).toStrictEqual('TH-AB') - + user_id: 1, + pswd: '1234', + theme: 'test' + }, + university: 'TH-AB' }) + ) + + const { result } = renderHook(() => useUniversity(), { + wrapper: ({ children }) => {children} + }) + await waitFor(() => { + expect(result.current.university).toStrictEqual('TH-AB') }) +}) - test('useUniversity returns empty string when fetch fails', async () => { - mockServices.fetchUser = jest.fn().mockImplementationOnce(() => Promise.reject(new Error('error'))) - const { result } = renderHook(() => useUniversity(), { - wrapper: ({ children }) => {children} - }) - expect(await result.current.university).toBe('') +test('useUniversity returns empty string when fetch fails', async () => { + mockServices.fetchUser = jest.fn().mockImplementationOnce(() => Promise.reject(new Error('error'))) + const { result } = renderHook(() => useUniversity(), { + wrapper: ({ children }) => {children} }) + expect(await result.current.university).toBe('') +}) diff --git a/src/components/PrivacyModal/PrivacyModal.test.tsx b/src/components/PrivacyModal/PrivacyModal.test.tsx index af76f7a58..ead7c9ee9 100644 --- a/src/components/PrivacyModal/PrivacyModal.test.tsx +++ b/src/components/PrivacyModal/PrivacyModal.test.tsx @@ -8,7 +8,7 @@ import { act } from '@testing-library/react' const navigate = jest.fn() -const assignSpy = jest.fn(); +const assignSpy = jest.fn() Object.defineProperty(window, 'location', { value: { assign: assignSpy } @@ -99,8 +99,8 @@ describe('Test PrivacyModal', () => { university: 'TH-AB' }) ) - - const { getByRole,rerender } = render( + + const { getByRole, rerender } = render( @@ -137,7 +137,7 @@ describe('Test PrivacyModal', () => { university: 'HS-KE' }) ) - const { getByRole,rerender } = render( + const { getByRole, rerender } = render( From b19976d3755787805eca9412bc6247808646514a Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Mon, 9 Sep 2024 13:05:58 +0200 Subject: [PATCH 40/41] added changes to translation --- .../University.hooks.tsx} | 2 +- .../University.test.tsx} | 0 src/common/hooks/index.ts | 2 +- src/components/Newsbanner/Newsbanner.hooks.tsx | 4 ++-- src/components/Newsbanner/Newsbanner.tsx | 10 +++++----- src/components/PrivacyModal/PrivacyModal.test.tsx | 7 ++----- src/shared/translation/translationEnglish.json | 1 - src/shared/translation/translationGerman.json | 1 - 8 files changed, 11 insertions(+), 16 deletions(-) rename src/common/hooks/{UseUniversity/UseUniversity.hooks.tsx => University/University.hooks.tsx} (93%) rename src/common/hooks/{UseUniversity/UseUniversity.test.tsx => University/University.test.tsx} (100%) diff --git a/src/common/hooks/UseUniversity/UseUniversity.hooks.tsx b/src/common/hooks/University/University.hooks.tsx similarity index 93% rename from src/common/hooks/UseUniversity/UseUniversity.hooks.tsx rename to src/common/hooks/University/University.hooks.tsx index 4ad82a2ea..36abb1daa 100644 --- a/src/common/hooks/UseUniversity/UseUniversity.hooks.tsx +++ b/src/common/hooks/University/University.hooks.tsx @@ -18,7 +18,7 @@ export const useUniversity = (): UniversityHookReturn => { setUniversity(user.university) }) .catch((error) => { - log.error(t('error.useUniversity') + error) + t('error.getUser') + error setUniversity('') }) }, []) diff --git a/src/common/hooks/UseUniversity/UseUniversity.test.tsx b/src/common/hooks/University/University.test.tsx similarity index 100% rename from src/common/hooks/UseUniversity/UseUniversity.test.tsx rename to src/common/hooks/University/University.test.tsx diff --git a/src/common/hooks/index.ts b/src/common/hooks/index.ts index e89047158..a85f2eccc 100644 --- a/src/common/hooks/index.ts +++ b/src/common/hooks/index.ts @@ -1,4 +1,4 @@ export { useTheme } from './DefaultUseTheme/DefaultUseTheme' export { useMediaQuery } from './DefaultMediaQuery/DefaultMediaQuery' export { useLearningPathTopicProgress } from './LearningPathTopicProgress/LearningPathTopicProgress.hooks' -export * from './UseUniversity/UseUniversity.hooks' +export * from './University/University.hooks' diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index 39563b35f..00d241db9 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -50,11 +50,11 @@ export const useNewsbanner = (): NewsbannerHookReturn => { }) .catch((error) => { addSnackbar({ - message: t('error.getNews') + error, + message: t('error.getNews'), severity: 'error', autoHideDuration: 3000 }) - log.error(t('error.getNews') + error) + t('error.getNews') + error setNewsText('') }) }, [i18next.language]) diff --git a/src/components/Newsbanner/Newsbanner.tsx b/src/components/Newsbanner/Newsbanner.tsx index 210ecb185..55e53101b 100644 --- a/src/components/Newsbanner/Newsbanner.tsx +++ b/src/components/Newsbanner/Newsbanner.tsx @@ -24,16 +24,16 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { const isBannerOpen = useSessionStore((state) => state.isBannerOpen) //Animation logic - const text_len = newsText.length * 10 - const window_width = window.innerWidth - const text_percent = text_len / window_width + const textLength = newsText.length * 10 + const windowWidth = window.innerWidth + const textPercent = textLength / windowWidth const scrolling = keyframes` from { transform: translateX(100%) }, to { - transform: translateX(-${text_percent * 100}%) + transform: translateX(-${textPercent * 100}%) } ` @@ -66,7 +66,7 @@ const Newsbanner = ({ useNewsbanner = _useNewsbanner }: NewsbannerProps) => { sx={{ animation: `${scrolling} 30s linear infinite`, transform: `translateX(100%)`, - width: window_width + width: windowWidth }}> {newsText} diff --git a/src/components/PrivacyModal/PrivacyModal.test.tsx b/src/components/PrivacyModal/PrivacyModal.test.tsx index ead7c9ee9..ed98bdbb2 100644 --- a/src/components/PrivacyModal/PrivacyModal.test.tsx +++ b/src/components/PrivacyModal/PrivacyModal.test.tsx @@ -1,17 +1,14 @@ import '@testing-library/jest-dom' -import { fireEvent, render } from '@testing-library/react' +import { fireEvent, render, act } from '@testing-library/react' import { mockServices } from 'jest.setup' import * as router from 'react-router' import { MemoryRouter } from 'react-router-dom' import PrivacyModal from './PrivacyModal' -import { act } from '@testing-library/react' const navigate = jest.fn() -const assignSpy = jest.fn() - Object.defineProperty(window, 'location', { - value: { assign: assignSpy } + value: { assign: jest.fn() } }) beforeEach(() => { diff --git a/src/shared/translation/translationEnglish.json b/src/shared/translation/translationEnglish.json index 983c1666b..f0e927597 100644 --- a/src/shared/translation/translationEnglish.json +++ b/src/shared/translation/translationEnglish.json @@ -1147,7 +1147,6 @@ "error.getLearningElementsWithStatus": "There was an Error fetching Learning Elements with Status.", "error.getNews": "There was an Error fetching the news data.", "error.getSortedLearningPath": "There was an Error fetching and sorting the LearningPathLearningElement data.", - "error.getUniversity": "There was an Error fetching the university.", "error.getUser": "There was an Error fetching the user data.", "error.mapNodes": "There was an Error mapping the learning path Nodes.", "error.postCalculateLearningPathILS": "There was an Error calculating the learning path based on the ILS questionnaire data.", diff --git a/src/shared/translation/translationGerman.json b/src/shared/translation/translationGerman.json index 4f5b33c88..2c374783b 100644 --- a/src/shared/translation/translationGerman.json +++ b/src/shared/translation/translationGerman.json @@ -1147,7 +1147,6 @@ "error.getLearningElementsWithStatus": "Es gab einen Fehler beim Abrufen der Lernelemente (mit Status).", "error.getNews": "Es gab einen Fehler beim Abrufen der News.", "error.getSortedLearningPath": "Es gab einen Fehler beim Abrufen und Sortieren der LearningPathLearningElement-Daten.", - "error.getUniversity": "Es gab einen Fehler beim Abrufen der Universität.", "error.getUser": "Es gab einen Fehler beim Abrufen der Benutzerdaten.", "error.mapNodes": "Es gab einen Fehler beim Zuordnen der Lernpfad Nodes.", "error.postCalculateLearningPathILS": "Es gab einen Fehler bei der Berechnung des Lernpfades auf Basis der ILS-Fragebogendaten.", From 61f795e941ac036032c2d09fe0cc4e220e4c482d Mon Sep 17 00:00:00 2001 From: Gesine Wagner <80248709+Platura@users.noreply.github.com> Date: Mon, 9 Sep 2024 13:18:33 +0200 Subject: [PATCH 41/41] changed log.error --- src/common/hooks/University/University.hooks.tsx | 2 +- src/components/Newsbanner/Newsbanner.hooks.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/hooks/University/University.hooks.tsx b/src/common/hooks/University/University.hooks.tsx index 36abb1daa..06b363d8e 100644 --- a/src/common/hooks/University/University.hooks.tsx +++ b/src/common/hooks/University/University.hooks.tsx @@ -18,7 +18,7 @@ export const useUniversity = (): UniversityHookReturn => { setUniversity(user.university) }) .catch((error) => { - t('error.getUser') + error + log.error(t('error.getUser') + ' ' + error) setUniversity('') }) }, []) diff --git a/src/components/Newsbanner/Newsbanner.hooks.tsx b/src/components/Newsbanner/Newsbanner.hooks.tsx index 00d241db9..62d01edd9 100644 --- a/src/components/Newsbanner/Newsbanner.hooks.tsx +++ b/src/components/Newsbanner/Newsbanner.hooks.tsx @@ -54,7 +54,7 @@ export const useNewsbanner = (): NewsbannerHookReturn => { severity: 'error', autoHideDuration: 3000 }) - t('error.getNews') + error + log.error(t('error.getNews') + ' ' + error) setNewsText('') }) }, [i18next.language])