diff --git a/src/components/App.tsx b/src/components/App.tsx index dfd0db8eb..215de0b13 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -4,6 +4,8 @@ import { Route, Routes } from 'react-router-dom'; import { saveUrlForRedirection } from '@graasp/sdk'; import { CustomInitialLoader, withAuthorization } from '@graasp/ui'; +import * as Sentry from '@sentry/react'; + import { DOMAIN } from '@/config/env'; import { SIGN_IN_PATH } from '@/config/externalPaths'; @@ -19,6 +21,7 @@ import { buildItemPath, } from '../config/paths'; import { hooks } from '../config/queryClient'; +import FallbackComponent from './Fallback'; import RecycleBinScreen from './RecycleBinScreen'; import SharedItems from './SharedItems'; import { useCurrentUserContext } from './context/CurrentUserContext'; @@ -73,24 +76,29 @@ const App = (): JSX.Element => { ); return ( - - } /> - } /> - } - /> - } - /> - } /> - } /> - } /> - } /> - } /> - } /> - + }> + + } /> + } /> + } + /> + } + /> + } /> + } + /> + } /> + } /> + } /> + } /> + + ); }; diff --git a/src/components/Fallback.tsx b/src/components/Fallback.tsx new file mode 100644 index 000000000..5f03eb287 --- /dev/null +++ b/src/components/Fallback.tsx @@ -0,0 +1,52 @@ +import { useNavigate } from 'react-router'; + +import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline'; +import { Box, Button, Stack, Typography } from '@mui/material'; + +import { useBuilderTranslation } from '@/config/i18n'; +import { HOME_PATH } from '@/config/paths'; + +import { BUILDER } from '../langs/constants'; + +const FallbackComponent = (): JSX.Element => { + const navigate = useNavigate(); + const { t: translateBuilder } = useBuilderTranslation(); + + return ( + + + + {translateBuilder(BUILDER.FALLBACK_TITLE)} + + {translateBuilder(BUILDER.FALLBACK_TEXT)} + + + + + ); +}; + +export default FallbackComponent; diff --git a/src/components/Root.tsx b/src/components/Root.tsx index 0448a8a97..e77c2ab98 100644 --- a/src/components/Root.tsx +++ b/src/components/Root.tsx @@ -37,7 +37,7 @@ const Root = (): JSX.Element => ( - {import.meta.env.DEV && } + {import.meta.env.DEV && } ); diff --git a/src/components/main/MainMenu.tsx b/src/components/main/MainMenu.tsx index 51c1870df..2c41a1fe3 100644 --- a/src/components/main/MainMenu.tsx +++ b/src/components/main/MainMenu.tsx @@ -1,17 +1,28 @@ import { useLocation, useNavigate } from 'react-router'; +import { BugReport } from '@mui/icons-material'; import AutoStoriesIcon from '@mui/icons-material/AutoStories'; import DeleteIcon from '@mui/icons-material/Delete'; import FolderIcon from '@mui/icons-material/Folder'; import FolderSharedIcon from '@mui/icons-material/FolderShared'; import Star from '@mui/icons-material/Star'; -import { styled, useTheme } from '@mui/material'; +import { + ListItem, + ListItemButton, + ListItemText, + Stack, + styled, + useTheme, +} from '@mui/material'; import ListItemIcon from '@mui/material/ListItemIcon'; +import { DEFAULT_LANG } from '@graasp/sdk'; import { MainMenu as GraaspMainMenu, LibraryIcon, MenuItem } from '@graasp/ui'; +import { captureMessage, showReportDialog } from '@sentry/react'; + import { TUTORIALS_LINK } from '../../config/constants'; -import { useBuilderTranslation } from '../../config/i18n'; +import i18n, { useBuilderTranslation } from '../../config/i18n'; import { FAVORITE_ITEMS_PATH, HOME_PATH, @@ -22,20 +33,6 @@ import { import { BUILDER } from '../../langs/constants'; import { useCurrentUserContext } from '../context/CurrentUserContext'; -const StyledLink = styled('a')(({ theme }) => ({ - position: 'absolute', - bottom: 0, - width: '100%', - display: 'flex', - alignItems: 'center', - padding: theme.spacing(2), - boxSizing: 'border-box', - color: 'grey', - textDecoration: 'none', - '&:hover': { - color: theme.palette.primary.main, - }, -})); const StyledMenuItem = styled(MenuItem)(({ theme }) => ({ '&:hover': { color: theme.palette.primary.main, @@ -55,13 +52,38 @@ const MainMenu = (): JSX.Element => { navigate(path); }; - const resourcesLink = ( - - - - - {translateBuilder('Tutorials')} - + const openBugReport = () => { + const eventId = captureMessage( + `Graasp Builder | User Feedback ${Date.now()}`, + ); + // this will be reported in sentry user feedback issues + showReportDialog({ + eventId, + title: translateBuilder(BUILDER.REPORT_A_BUG), + lang: i18n.language || DEFAULT_LANG, + }); + }; + + const reportBugLink = ( + + + + + + {translateBuilder(BUILDER.REPORT_A_BUG)} + + + ); + + const resourceLinks = ( + + + + + + {translateBuilder('Tutorials')} + + ); const renderAuthenticatedMemberMenuItems = () => { @@ -76,7 +98,7 @@ const MainMenu = (): JSX.Element => { } return ( - <> +
goTo(HOME_PATH)} selected={pathname === HOME_PATH} @@ -113,14 +135,19 @@ const MainMenu = (): JSX.Element => { text={translateBuilder(BUILDER.RECYCLE_BIN_TITLE)} icon={} /> - +
); }; return ( - {renderAuthenticatedMemberMenuItems()} - {resourcesLink} + + {renderAuthenticatedMemberMenuItems()} +
+ {reportBugLink} + {resourceLinks} +
+
); }; diff --git a/src/langs/ar.json b/src/langs/ar.json index 23997b5c9..d9a634be1 100644 --- a/src/langs/ar.json +++ b/src/langs/ar.json @@ -242,6 +242,10 @@ "USER_SWITCH_SIGN_OUT_BUTTON": "خروج", "USER_SWITCH_SIGNED_OUT_TOOLTIP": "أنت غير مسجل الدخول.", "USER_SWITCH_SWITCH_USER_TEXT": "تسجيل الدخول بحساب آخر", + "FALLBACK_TITLE": "عفواً", + "FALLBACK_TEXT": "حدث خطأ غير متوقع، يرحى المحاولة لاحقاً", + "FALLBACK_BACK_TO_HOME": "الرجوع إلى الصفحة الرئيسية", + "REPORT_A_BUG": "الإبلاغ عن مشكلة", "DELETE_MEMBERSHIP": "حذف العضوية", "DELETE_MEMBERSHIP_MODAL_CONFIRM_BUTTON": "تأكيد", "DELETE_OWN_MEMBERSHIP_MESSAGE": "هل أنت متأكد من إلغاء عضويتك على هذا العنصر؟", diff --git a/src/langs/constants.ts b/src/langs/constants.ts index 7b106297f..10121de21 100644 --- a/src/langs/constants.ts +++ b/src/langs/constants.ts @@ -307,6 +307,10 @@ export const BUILDER = { STATUS_TOOLTIP_IS_COLLAPSIBLE: 'STATUS_TOOLTIP_IS_COLLAPSIBLE', STATUS_TOOLTIP_SHOW_CHATBOX: 'STATUS_TOOLTIP_SHOW_CHATBOX', SETTINGS_FILE_SETTINGS_TITLE: 'SETTINGS_FILE_SETTINGS_TITLE', + FALLBACK_TITLE: 'FALLBACK_TITLE', + FALLBACK_TEXT: 'FALLBACK_TEXT', + FALLBACK_BACK_TO_HOME: 'FALLBACK_BACK_TO_HOME', + REPORT_A_BUG: 'REPORT_A_BUG', DELETE_MEMBERSHIP: 'DELETE_MEMBERSHIP', DELETE_MEMBERSHIP_MODAL_CONFIRM_BUTTON: 'DELETE_MEMBERSHIP_MODAL_CONFIRM_BUTTON', diff --git a/src/langs/en.json b/src/langs/en.json index e284ad05c..cbb391b63 100644 --- a/src/langs/en.json +++ b/src/langs/en.json @@ -249,6 +249,10 @@ "STATUS_TOOLTIP_IS_COLLAPSIBLE": "Collapsible", "STATUS_TOOLTIP_SHOW_CHATBOX": "Chatbox visible", "SETTINGS_FILE_SETTINGS_TITLE": "File Settings", + "FALLBACK_TITLE": "Oops!", + "FALLBACK_TEXT": "Sorry, something went wrong. Try again later.", + "FALLBACK_BACK_TO_HOME": "Back to homepage", + "REPORT_A_BUG": "Report a Bug", "DELETE_MEMBERSHIP": "Delete Membership", "DELETE_MEMBERSHIP_MODAL_CONFIRM_BUTTON": "Confirm", "DELETE_OWN_MEMBERSHIP_MESSAGE": "Are you sure you want to delete your own permission on this item? You will loose access to this item, this action can not be undone.", diff --git a/src/langs/fr.json b/src/langs/fr.json index 8dd10cdd1..d1f67e2e7 100644 --- a/src/langs/fr.json +++ b/src/langs/fr.json @@ -248,6 +248,10 @@ "STATUS_TOOLTIP_IS_COLLAPSIBLE": "Minifié", "STATUS_TOOLTIP_SHOW_CHATBOX": "Chatbox visible", "SETTINGS_FILE_SETTINGS_TITLE": "Paramètres du fichier", + "FALLBACK_TITLE": "Oops!", + "FALLBACK_TEXT": "Désolé, une erreur inattendue est survenue. Veuillez réessayer plus tard.", + "FALLBACK_BACK_TO_HOME": "Retour à la page d'accueil", + "REPORT_A_BUG": "Signaler un problème", "DELETE_MEMBERSHIP": "Supprimer l'autorisation", "DELETE_MEMBERSHIP_MODAL_CONFIRM_BUTTON": "Confirmer", "DELETE_OWN_MEMBERSHIP_MESSAGE": "Êtes-vous sûr de vouloir supprimer votre propre autorisation sur cet élément ? Vous perdrez l'accès à cet élément, cette action est irréversible.",