diff --git a/src/assets/icons/lernfair/ico-settings.svg b/src/assets/icons/lernfair/ico-settings.svg deleted file mode 100644 index 62a2e22ca..000000000 --- a/src/assets/icons/lernfair/ico-settings.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/components/Popover.tsx b/src/components/Popover.tsx index 11459c561..397902c68 100644 --- a/src/components/Popover.tsx +++ b/src/components/Popover.tsx @@ -8,6 +8,10 @@ const PopoverTrigger = PopoverPrimitive.Trigger; const PopoverAnchor = PopoverPrimitive.Anchor; +const PopoverArrow = PopoverPrimitive.Arrow; + +const PopoverClose = PopoverPrimitive.Close; + const PopoverContent = React.forwardRef, React.ComponentPropsWithoutRef>( ({ className, align = 'center', sideOffset = 4, ...props }, ref) => ( @@ -25,4 +29,4 @@ const PopoverContent = React.forwardRef void; -}; +} -const MessageBox: FC = ({ userNotification, isStandalone, isRead, updateLastTimeChecked }) => { +const MessageBox = ({ userNotification, isStandalone, isRead, updateLastTimeChecked }: MessageBoxProps) => { const [leavePageModalOpen, setLeavePageModalOpen] = useState(false); const [achievementModalForId, setAchievementModalForId] = useState(null); const [notificationModalOpen, setNotificationModalOpen] = useState(false); const navigate = useNavigate(); - const isMobile = useBreakpointValue({ - base: true, - lg: false, - }); if (!userNotification || !userNotification.message || !isMessageValid(userNotification.message)) return null; const { sentAt } = userNotification || { sentAt: '' }; const { headline, body, type, navigateTo, modalText } = userNotification.message; - const boxProps = { - mb: 2, - height: '100%', - fullWidth: 320, - width: 270, - borderRadius: 10, - maxHeight: 500, - }; - - const vStackProps = { - mt: 2, - maxW: 200, - }; const navigateToLink = () => { if (modalText) { @@ -70,18 +54,21 @@ const MessageBox: FC = ({ userNotification, isStandalone, isRead, updateL const navigateExternal = () => (navigateTo ? window.open(navigateTo, '_blank') : null); const Icon = getIconForMessageType(type); - - const LinkedBox: FC = ({ children, ...boxProps }) => { - const Component = () => {children}; + const LinkedBox = ({ children, ...rest }: React.HTMLAttributes) => { + const Component = () => {children}; if (typeof navigateTo === 'string') { return ( <> - + - - - setLeavePageModalOpen(false)} navigateTo={navigateExternal} /> - + + {achievementModalForId !== null && ( setAchievementModalForId(null)} /> )} @@ -90,17 +77,16 @@ const MessageBox: FC = ({ userNotification, isStandalone, isRead, updateL } else if (modalText) { return ( <> - + - - - setNotificationModalOpen(false)} - modalText={modalText} - headline={headline} - /> - + + > ); } @@ -109,38 +95,46 @@ const MessageBox: FC = ({ userNotification, isStandalone, isRead, updateL return ( - - - - - - - - - {headline} - - - - + + + + + + + + + {headline} + + + {headline} + + + + + + + + {body} + + + {body} - - - - - + + + + {!isStandalone && ( - + - + )} - + ); }; diff --git a/src/components/notifications/NotificationAlert.tsx b/src/components/notifications/NotificationAlert.tsx index a049b586c..8dcf7933b 100644 --- a/src/components/notifications/NotificationAlert.tsx +++ b/src/components/notifications/NotificationAlert.tsx @@ -1,13 +1,13 @@ -import { Popover } from 'native-base'; -import { MutableRefObject, useContext, useEffect, useState } from 'react'; +import { useContext, useEffect, useState } from 'react'; import { useLastTimeCheckedNotifications } from '../../hooks/useLastTimeCheckedNotifications'; import { useConcreteNotifications } from '../../hooks/useConcreteNotifications'; import NotificationPanel from './NotificationPanel'; import { NotificationsContext } from '../../context/NotificationsProvider'; import { getNewNotifications } from '../../helper/notification-helper'; import { Button } from '../Button'; -import { IconBell } from '@tabler/icons-react'; +import { IconBell, IconX } from '@tabler/icons-react'; import { Badge } from '../Badge'; +import { Popover, PopoverArrow, PopoverClose, PopoverContent, PopoverTrigger } from '../Popover'; const NotificationAlert: React.FC = () => { const [count, setCount] = useState(0); @@ -33,40 +33,44 @@ const NotificationAlert: React.FC = () => { setCount(unreadNotifications.length); }, [lastTimeCheckedNotifications, userNotifications]); - const handleTrigger = ({ onPress, ref }: { onPress: () => void; ref: MutableRefObject }): React.ReactElement => { - return ( - - {!!count && ( - - {count} - - )} - - - - - ); - }; - - const onOpen = () => { - refetch(); - setIsOpen(true); - }; - - const onClose = () => { - updateLastTimeChecked(); - setIsOpen(false); + const handleOnOpenChange = (value: boolean) => { + setIsOpen(value); + if (value) { + refetch(); + } else { + updateLastTimeChecked(); + } }; return ( <> - handleTrigger(triggerprops)} onClose={onClose} onOpen={onOpen}> - updateLastTimeChecked()} - /> + + + + {!!count && ( + + {count} + + )} + + + + + + + + + + + + + updateLastTimeChecked()} + /> + > ); diff --git a/src/components/notifications/NotificationModal.tsx b/src/components/notifications/NotificationModal.tsx index a478915fe..1a4b3c7a9 100644 --- a/src/components/notifications/NotificationModal.tsx +++ b/src/components/notifications/NotificationModal.tsx @@ -1,52 +1,35 @@ -import { Box, CloseIcon, Heading, Modal, Pressable, useTheme, Row, Button, Text } from 'native-base'; import { useTranslation } from 'react-i18next'; import { getIconForNotificationPreferenceModal } from '../../helper/notification-helper'; +import { Button } from '../Button'; +import { BaseModalProps, Modal, ModalFooter, ModalHeader, ModalTitle } from '../Modal'; +import { Typography } from '../Typography'; -type Props = { +interface NotificationModalProps extends BaseModalProps { messageType: string; headline?: string; modalText: string; - onClose: () => any; -}; -const AppointmentCancelledModal: React.FC = ({ messageType, onClose, headline, modalText }) => { +} +const NotificationModal = ({ isOpen, onOpenChange, messageType, headline, modalText }: NotificationModalProps) => { const { t } = useTranslation(); - const { space } = useTheme(); const Icon = getIconForNotificationPreferenceModal(messageType); return ( - <> - - - - - - - - - - - - {headline && ( - - {headline} - - )} - - {modalText} - - - - - - {t('notification.controlPanel.closeButton')} - - - - - - > + + + {headline} + + + + {modalText} + + + onOpenChange(false)}> + {t('notification.controlPanel.closeButton')} + + + ); }; -export default AppointmentCancelledModal; +export default NotificationModal; diff --git a/src/components/notifications/NotificationPanel.tsx b/src/components/notifications/NotificationPanel.tsx index 15ed1831f..95e442b6e 100644 --- a/src/components/notifications/NotificationPanel.tsx +++ b/src/components/notifications/NotificationPanel.tsx @@ -1,9 +1,8 @@ -import { Box, Popover, Spinner, useBreakpointValue } from 'native-base'; import { useEffect, useState } from 'react'; -import SettingsIcon from '../../assets/icons/lernfair/ico-settings.svg'; import { getAllNewUserNotificationsButMinimumFiveNotifications } from '../../helper/notification-helper'; import { AllNotifications, NewNotifications, NoNotifications } from './PanelContent'; import { Concrete_Notification } from '../../gql/graphql'; +import CenterLoadingSpinner from '../CenterLoadingSpinner'; type Props = { userNotifications: Concrete_Notification[]; @@ -16,21 +15,6 @@ const NotificationPanel: React.FC = ({ userNotifications, lastTimeChecked const [shouldShowAll, setShouldShowAll] = useState(false); const [notificationsToShow, setNotificationsToShow] = useState([]); - const panelMarginLeft = useBreakpointValue({ - base: 3, - lg: 0, - }); - - const panelMarginRight = useBreakpointValue({ - base: 0, - lg: 10, - }); - - const panelPropsAllDevices = { - maxH: 420, - minW: 320, - }; - const handleClick = () => { setShouldShowAll(!shouldShowAll); }; @@ -44,29 +28,23 @@ const NotificationPanel: React.FC = ({ userNotifications, lastTimeChecked } }, [userNotifications, lastTimeCheckedNotifications, shouldShowAll]); + const hasNotifications = userNotifications.length && notificationsToShow.length; return ( - - - - - - - {loading && } - - {!shouldShowAll && notificationsToShow.length !== 0 && ( - updateLastTimeChecked()} - /> - )} - {shouldShowAll && } - {!notificationsToShow.length && } - - - - + + + {loading && } + {!shouldShowAll && notificationsToShow.length !== 0 && ( + updateLastTimeChecked()} + /> + )} + {shouldShowAll && } + {!loading && !hasNotifications && } + + ); }; diff --git a/src/components/notifications/PanelContent.tsx b/src/components/notifications/PanelContent.tsx index 49aae401d..0e1fe610f 100644 --- a/src/components/notifications/PanelContent.tsx +++ b/src/components/notifications/PanelContent.tsx @@ -1,8 +1,9 @@ -import { Box, Button, ScrollView, Text } from 'native-base'; import { useTranslation } from 'react-i18next'; import { isNewNotification } from '../../helper/notification-helper'; import MessageBox from './MessageBox'; import { Concrete_Notification } from '../../gql/graphql'; +import { Button } from '../Button'; +import { Typography } from '../Typography'; type NewProps = { notificationsToShow: Concrete_Notification[]; @@ -16,23 +17,19 @@ const NewNotifications: React.FC = ({ notificationsToShow, lastTimeChe return ( <> - - - {notificationsToShow.map( - (notification) => - notification.message && ( - updateLastTimeChecked()} - /> - ) - )} - - - - {t('notification.panel.button.text')} + {notificationsToShow.map( + (notification) => + notification.message && ( + updateLastTimeChecked()} + /> + ) + )} + + {t('notification.panel.button.text')} > ); @@ -46,18 +43,12 @@ type AllProps = { const AllNotifications: React.FC = ({ userNotifications, lastTimeChecked }) => { return ( <> - - {userNotifications.map( - (notification: Concrete_Notification) => - notification.message && ( - - ) - )} - + {userNotifications.map( + (notification: Concrete_Notification) => + notification.message && ( + + ) + )} > ); }; @@ -65,9 +56,9 @@ const AllNotifications: React.FC = ({ userNotifications, lastTimeCheck const NoNotifications = () => { const { t } = useTranslation(); return ( - - {t('notification.panel.noNotifications')} - + + {t('notification.panel.noNotifications')} + ); }; diff --git a/src/components/notifications/TimeIndicator.tsx b/src/components/notifications/TimeIndicator.tsx index d03f3371a..8d9b35061 100644 --- a/src/components/notifications/TimeIndicator.tsx +++ b/src/components/notifications/TimeIndicator.tsx @@ -1,31 +1,28 @@ import { useState } from 'react'; -import { Box, Text } from 'native-base'; import useInterval from '../../hooks/useInterval'; import { useTranslation } from 'react-i18next'; import { getTimeText } from '../../helper/notification-helper'; +import { Typography } from '../Typography'; type TimeIndicatorProps = { sentAt: string; }; -const TimeIndicator: React.FC = ({ sentAt }) => { +const TimeIndicator = ({ sentAt }: TimeIndicatorProps) => { const { t } = useTranslation(); const [toggleRerender, setToggleRerender] = useState(false); const time = getTimeText(sentAt); - const boxPropsAllDevices = { - maxW: 80, - pr: 3, - }; - useInterval(() => { setToggleRerender(!toggleRerender); }, 60_000); return ( - - {typeof time === 'string' ? {time} : {t(time.text, time?.options)}} - + + + {typeof time === 'string' ? time : t(time.text, time?.options)} + + ); }; diff --git a/src/helper/notification-helper.ts b/src/helper/notification-helper.ts index c1eea6bdd..7a6dfd0e3 100644 --- a/src/helper/notification-helper.ts +++ b/src/helper/notification-helper.ts @@ -8,12 +8,12 @@ import { NotificationCategories, systemNotificationCategories, } from './notification-preferences'; -import { FC } from 'react'; +import { FC, HTMLAttributes } from 'react'; import { NotificationPreferences } from '../types/lernfair/NotificationPreferences'; import { Concrete_Notification, NotificationMessage } from '../gql/graphql'; const getIconForMessageType = (messageType: string): FC => (messageIcons.hasOwnProperty(messageType) ? messageIcons[messageType] : () => null); -const getIconForNotificationPreferenceModal = (messageType: string): FC => { +const getIconForNotificationPreferenceModal = (messageType: string): FC> => { return modalIcons.hasOwnProperty(messageType) ? modalIcons[messageType] : () => null; }; diff --git a/src/modals/LeavePageModal.tsx b/src/modals/LeavePageModal.tsx index 1d327b0d0..b598cb467 100644 --- a/src/modals/LeavePageModal.tsx +++ b/src/modals/LeavePageModal.tsx @@ -1,57 +1,37 @@ -import { Box, CloseIcon, Heading, Modal, Pressable, useTheme, Row, Button, Text } from 'native-base'; +import { Button } from '@/components/Button'; +import { BaseModalProps, Modal, ModalFooter, ModalHeader, ModalTitle } from '@/components/Modal'; +import { Typography } from '@/components/Typography'; import { useTranslation } from 'react-i18next'; import { getIconForNotificationPreferenceModal } from '../helper/notification-helper'; -type Props = { +interface LeavePageModalProps extends BaseModalProps { url: string; messageType: string; - onClose: () => any; navigateTo: () => void | Window | null; -}; -const LeavePageModal: React.FC = ({ url, messageType, onClose, navigateTo }) => { +} +const LeavePageModal = ({ isOpen, onOpenChange, url, messageType, navigateTo }: LeavePageModalProps) => { const { t } = useTranslation(); - const { space } = useTheme(); - const Icon = getIconForNotificationPreferenceModal(messageType); return ( - <> - - - - - - - - - - - - - {t('notification.panel.leavePageModal.text')} - - - {t('notification.panel.leavePageModal.description')} - - - {url} - - - - - - {t('notification.panel.leavePageModal.button')} - - - - - {t('notification.controlPanel.closeButton')} - - - - - - > + + + {t('notification.panel.leavePageModal.text')} + + + + {t('notification.panel.leavePageModal.description')} + {url} + + + onOpenChange(false)}> + {t('notification.controlPanel.closeButton')} + + + {t('notification.panel.leavePageModal.button')} + + + ); };