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 (
- <>
+
);
};
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.",