Add general error message for wardrobe crashes
Boom, pulled some stuff out into util! Now we also have error boundaries in both panels of the wardrobe page. You can test this one by visiting `/outfits/new?send-test-error-for-sentry`, just like on the home page! Util component for fake errors owo
This commit is contained in:
parent
6dc6ad2578
commit
65af7ef64c
6 changed files with 139 additions and 106 deletions
|
@ -29,6 +29,7 @@ import {
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
Heading1,
|
Heading1,
|
||||||
Heading2,
|
Heading2,
|
||||||
|
TestErrorSender,
|
||||||
useCommonStyles,
|
useCommonStyles,
|
||||||
useLocalStorage,
|
useLocalStorage,
|
||||||
usePageTitle,
|
usePageTitle,
|
||||||
|
@ -51,12 +52,6 @@ function HomePage() {
|
||||||
|
|
||||||
const [previewState, setPreviewState] = React.useState(null);
|
const [previewState, setPreviewState] = React.useState(null);
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (window.location.href.includes("send-test-error-for-sentry")) {
|
|
||||||
throw new Error("Test error for Sentry");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex direction="column" align="center" textAlign="center" marginTop="8">
|
<Flex direction="column" align="center" textAlign="center" marginTop="8">
|
||||||
<Box
|
<Box
|
||||||
|
@ -103,6 +98,7 @@ function HomePage() {
|
||||||
<WIPCallout details="We started building this last year, but, well… what a year 😅 Anyway, this will eventually become the main site, at impress.openneo.net!">
|
<WIPCallout details="We started building this last year, but, well… what a year 😅 Anyway, this will eventually become the main site, at impress.openneo.net!">
|
||||||
Maybe we'll rename it to Impress 2021… or maybe not! 🤔
|
Maybe we'll rename it to Impress 2021… or maybe not! 🤔
|
||||||
</WIPCallout>
|
</WIPCallout>
|
||||||
|
<TestErrorSender />
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Box, Flex, Grid, Link } from "@chakra-ui/react";
|
import { Box } from "@chakra-ui/react";
|
||||||
import { loadable } from "./util";
|
import { loadable } from "./util";
|
||||||
import * as Sentry from "@sentry/react";
|
import * as Sentry from "@sentry/react";
|
||||||
import { WarningIcon } from "@chakra-ui/icons";
|
|
||||||
|
|
||||||
import ErrorGrundoImg from "./images/error-grundo.png";
|
import { MajorErrorMessage } from "./util";
|
||||||
import ErrorGrundoImg2x from "./images/error-grundo@2x.png";
|
|
||||||
|
|
||||||
const GlobalHeader = loadable(() => import("./GlobalHeader"));
|
const GlobalHeader = loadable(() => import("./GlobalHeader"));
|
||||||
const GlobalFooter = loadable(() => import("./GlobalFooter"));
|
const GlobalFooter = loadable(() => import("./GlobalFooter"));
|
||||||
|
@ -41,49 +39,4 @@ function PageLayout({ children }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MajorErrorMessage({ error }) {
|
|
||||||
return (
|
|
||||||
<Flex justify="center" marginTop="8">
|
|
||||||
<Grid
|
|
||||||
templateAreas='"icon title" "icon description" "icon details"'
|
|
||||||
templateColumns="auto 1fr"
|
|
||||||
maxWidth="500px"
|
|
||||||
columnGap="4"
|
|
||||||
>
|
|
||||||
<Box gridArea="icon" marginTop="2">
|
|
||||||
<Box
|
|
||||||
as="img"
|
|
||||||
src={ErrorGrundoImg}
|
|
||||||
srcSet={`${ErrorGrundoImg} 1x, ${ErrorGrundoImg2x} 2x`}
|
|
||||||
borderRadius="full"
|
|
||||||
boxShadow="md"
|
|
||||||
width="100px"
|
|
||||||
height="100px"
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Box gridArea="title" fontSize="lg" marginBottom="1">
|
|
||||||
Ah dang, I broke it 😖
|
|
||||||
</Box>
|
|
||||||
<Box gridArea="description" marginBottom="2">
|
|
||||||
There was an error displaying this page. I'll get info about it
|
|
||||||
automatically, but you can tell me more at{" "}
|
|
||||||
<Link href="mailto:matchu@openneo.net" color="green.400">
|
|
||||||
matchu@openneo.net
|
|
||||||
</Link>
|
|
||||||
!
|
|
||||||
</Box>
|
|
||||||
<Box gridArea="details" fontSize="xs" opacity="0.8">
|
|
||||||
<WarningIcon
|
|
||||||
marginRight="1.5"
|
|
||||||
marginTop="-2px"
|
|
||||||
aria-label="Error message"
|
|
||||||
/>
|
|
||||||
"{error.message}"
|
|
||||||
</Box>
|
|
||||||
</Grid>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PageLayout;
|
export default PageLayout;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Box, Flex } from "@chakra-ui/react";
|
import { Box, Flex } from "@chakra-ui/react";
|
||||||
|
import * as Sentry from "@sentry/react";
|
||||||
|
|
||||||
import ItemsPanel from "./ItemsPanel";
|
import ItemsPanel from "./ItemsPanel";
|
||||||
import SearchToolbar, {
|
import SearchToolbar, {
|
||||||
|
@ -7,6 +8,7 @@ import SearchToolbar, {
|
||||||
searchQueryIsEmpty,
|
searchQueryIsEmpty,
|
||||||
} from "./SearchToolbar";
|
} from "./SearchToolbar";
|
||||||
import SearchPanel from "./SearchPanel";
|
import SearchPanel from "./SearchPanel";
|
||||||
|
import { MajorErrorMessage, TestErrorSender } from "../util";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ItemsAndSearchPanels manages the shared layout and state for:
|
* ItemsAndSearchPanels manages the shared layout and state for:
|
||||||
|
@ -21,13 +23,20 @@ import SearchPanel from "./SearchPanel";
|
||||||
* performing some wiring to help them interact with each other via simple
|
* performing some wiring to help them interact with each other via simple
|
||||||
* state and refs.
|
* state and refs.
|
||||||
*/
|
*/
|
||||||
function ItemsAndSearchPanels({ loading, outfitState, outfitSaving, dispatchToOutfit }) {
|
function ItemsAndSearchPanels({
|
||||||
|
loading,
|
||||||
|
outfitState,
|
||||||
|
outfitSaving,
|
||||||
|
dispatchToOutfit,
|
||||||
|
}) {
|
||||||
const [searchQuery, setSearchQuery] = React.useState(emptySearchQuery);
|
const [searchQuery, setSearchQuery] = React.useState(emptySearchQuery);
|
||||||
const scrollContainerRef = React.useRef();
|
const scrollContainerRef = React.useRef();
|
||||||
const searchQueryRef = React.useRef();
|
const searchQueryRef = React.useRef();
|
||||||
const firstSearchResultRef = React.useRef();
|
const firstSearchResultRef = React.useRef();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<Sentry.ErrorBoundary fallback={MajorErrorMessage}>
|
||||||
|
<TestErrorSender />
|
||||||
<Flex direction="column" height="100%">
|
<Flex direction="column" height="100%">
|
||||||
<Box px="5" py="3" boxShadow="sm">
|
<Box px="5" py="3" boxShadow="sm">
|
||||||
<SearchToolbar
|
<SearchToolbar
|
||||||
|
@ -75,6 +84,7 @@ function ItemsAndSearchPanels({ loading, outfitState, outfitSaving, dispatchToOu
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
</Sentry.ErrorBoundary>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,12 @@ function WardrobePageLayout({ previewAndControls, itemsAndSearch }) {
|
||||||
height="100%"
|
height="100%"
|
||||||
width="100%"
|
width="100%"
|
||||||
>
|
>
|
||||||
<Box gridArea="previewAndControls" bg="gray.900" position="relative">
|
<Box
|
||||||
|
gridArea="previewAndControls"
|
||||||
|
bg="gray.900"
|
||||||
|
color="gray.50"
|
||||||
|
position="relative"
|
||||||
|
>
|
||||||
{previewAndControls}
|
{previewAndControls}
|
||||||
</Box>
|
</Box>
|
||||||
<Box gridArea="itemsAndSearch" bg={itemsAndSearchBackground}>
|
<Box gridArea="itemsAndSearch" bg={itemsAndSearchBackground}>
|
||||||
|
|
|
@ -2,13 +2,14 @@ import React from "react";
|
||||||
import { Box, DarkMode } from "@chakra-ui/react";
|
import { Box, DarkMode } from "@chakra-ui/react";
|
||||||
import gql from "graphql-tag";
|
import gql from "graphql-tag";
|
||||||
import { useQuery } from "@apollo/client";
|
import { useQuery } from "@apollo/client";
|
||||||
|
import * as Sentry from "@sentry/react";
|
||||||
|
|
||||||
import OutfitThumbnail, {
|
import OutfitThumbnail, {
|
||||||
outfitThumbnailFragment,
|
outfitThumbnailFragment,
|
||||||
getOutfitThumbnailRenderSize,
|
getOutfitThumbnailRenderSize,
|
||||||
} from "../components/OutfitThumbnail";
|
} from "../components/OutfitThumbnail";
|
||||||
import { useOutfitPreview } from "../components/OutfitPreview";
|
import { useOutfitPreview } from "../components/OutfitPreview";
|
||||||
import { loadable } from "../util";
|
import { loadable, MajorErrorMessage, TestErrorSender } from "../util";
|
||||||
|
|
||||||
const OutfitControls = loadable(() => import("./OutfitControls"));
|
const OutfitControls = loadable(() => import("./OutfitControls"));
|
||||||
|
|
||||||
|
@ -34,7 +35,8 @@ function WardrobePreviewAndControls({
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Sentry.ErrorBoundary fallback={MajorErrorMessage}>
|
||||||
|
<TestErrorSender />
|
||||||
<Box position="absolute" top="0" bottom="0" left="0" right="0">
|
<Box position="absolute" top="0" bottom="0" left="0" right="0">
|
||||||
<DarkMode>{preview}</DarkMode>
|
<DarkMode>{preview}</DarkMode>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -46,7 +48,7 @@ function WardrobePreviewAndControls({
|
||||||
appearance={appearance}
|
appearance={appearance}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</Sentry.ErrorBoundary>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,19 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Box, Heading, useColorModeValue } from "@chakra-ui/react";
|
import {
|
||||||
|
Box,
|
||||||
|
Flex,
|
||||||
|
Grid,
|
||||||
|
Heading,
|
||||||
|
Link,
|
||||||
|
useColorModeValue,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
import loadableLibrary from "@loadable/component";
|
import loadableLibrary from "@loadable/component";
|
||||||
import * as Sentry from "@sentry/react";
|
import * as Sentry from "@sentry/react";
|
||||||
|
|
||||||
|
import ErrorGrundoImg from "./images/error-grundo.png";
|
||||||
|
import ErrorGrundoImg2x from "./images/error-grundo@2x.png";
|
||||||
|
import { WarningIcon } from "@chakra-ui/icons";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delay hides its content at first, then shows it after the given delay.
|
* Delay hides its content at first, then shows it after the given delay.
|
||||||
*
|
*
|
||||||
|
@ -375,3 +386,59 @@ export function logAndCapture(e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
Sentry.captureException(e);
|
Sentry.captureException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function MajorErrorMessage({ error }) {
|
||||||
|
return (
|
||||||
|
<Flex justify="center" marginTop="8">
|
||||||
|
<Grid
|
||||||
|
templateAreas='"icon title" "icon description" "icon details"'
|
||||||
|
templateColumns="auto 1fr"
|
||||||
|
maxWidth="500px"
|
||||||
|
marginX="8"
|
||||||
|
columnGap="4"
|
||||||
|
>
|
||||||
|
<Box gridArea="icon" marginTop="2">
|
||||||
|
<Box
|
||||||
|
as="img"
|
||||||
|
src={ErrorGrundoImg}
|
||||||
|
srcSet={`${ErrorGrundoImg} 1x, ${ErrorGrundoImg2x} 2x`}
|
||||||
|
borderRadius="full"
|
||||||
|
boxShadow="md"
|
||||||
|
width="100px"
|
||||||
|
height="100px"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box gridArea="title" fontSize="lg" marginBottom="1">
|
||||||
|
Ah dang, I broke it 😖
|
||||||
|
</Box>
|
||||||
|
<Box gridArea="description" marginBottom="2">
|
||||||
|
There was an error displaying this page. I'll get info about it
|
||||||
|
automatically, but you can tell me more at{" "}
|
||||||
|
<Link href="mailto:matchu@openneo.net" color="green.400">
|
||||||
|
matchu@openneo.net
|
||||||
|
</Link>
|
||||||
|
!
|
||||||
|
</Box>
|
||||||
|
<Box gridArea="details" fontSize="xs" opacity="0.8">
|
||||||
|
<WarningIcon
|
||||||
|
marginRight="1.5"
|
||||||
|
marginTop="-2px"
|
||||||
|
aria-label="Error message"
|
||||||
|
/>
|
||||||
|
"{error.message}"
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TestErrorSender() {
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (window.location.href.includes("send-test-error-for-sentry")) {
|
||||||
|
throw new Error("Test error for Sentry");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue