62df0f0445
Fixes: #8487 #5027 1. Summary The purpose of these changes is to elevate the dev/user experience when the initial config load call fails for whatever reason by displaying a fallback component. 2. Solution I ended up making more changes than I initially planned. I had to update the order of the contexts a bit because `GenericErrorFallback` is dependent on `AppThemeProvider` for styling and `AppThemeProvider` is dependent on `ObjectMetadataItemsProvider` for [`useObjectMetadataItem`](https://github.com/khuddite/twenty/blob/ae2f193d68c6168e4c8323297d58f6dbc1de9fdf/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts#L22) hook (`AppThemeProvider` -> `useColorScheme` -> `useUpdateOneRecord` -> `useObjectMetadataItem`). I had to create a wrapper component for `AppThemeProvider` and stylize it in a way that it looks responsive on both mobile and desktop devices. Finally, I had to introduce the `isErrored` flag to differentiate the loading and error states. There are some improvements we can make later - - Display a loading state for the initial config load - Implement a refetch logic for the initial config loading failure 3. Recording https://github.com/user-attachments/assets/c2f43573-8006-4118-8e18-8576099d78fd https://github.com/user-attachments/assets/9c5853d3-539b-4880-aa38-c416c3e13594 --------- Co-authored-by: Félix Malfait <felix@twenty.com>
65 lines
1.9 KiB
TypeScript
65 lines
1.9 KiB
TypeScript
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
|
import { PageContainer } from '@/ui/layout/page/components/PageContainer';
|
|
import { PageHeader } from '@/ui/layout/page/components/PageHeader';
|
|
import { useEffect, useState } from 'react';
|
|
import { FallbackProps } from 'react-error-boundary';
|
|
import { useLocation } from 'react-router-dom';
|
|
import {
|
|
AnimatedPlaceholder,
|
|
AnimatedPlaceholderEmptyContainer,
|
|
AnimatedPlaceholderEmptySubTitle,
|
|
AnimatedPlaceholderEmptyTextContainer,
|
|
AnimatedPlaceholderEmptyTitle,
|
|
Button,
|
|
IconRefresh,
|
|
} from 'twenty-ui';
|
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
|
|
|
type GenericErrorFallbackProps = FallbackProps & {
|
|
title?: string;
|
|
hidePageHeader?: boolean;
|
|
};
|
|
|
|
export const GenericErrorFallback = ({
|
|
error,
|
|
resetErrorBoundary,
|
|
title = 'Sorry, something went wrong',
|
|
hidePageHeader = false,
|
|
}: GenericErrorFallbackProps) => {
|
|
const location = useLocation();
|
|
|
|
const [previousLocation] = useState(location);
|
|
|
|
useEffect(() => {
|
|
if (!isDeeplyEqual(previousLocation, location)) {
|
|
resetErrorBoundary();
|
|
}
|
|
}, [previousLocation, location, resetErrorBoundary]);
|
|
|
|
return (
|
|
<PageContainer>
|
|
{!hidePageHeader && <PageHeader />}
|
|
|
|
<PageBody>
|
|
<AnimatedPlaceholderEmptyContainer>
|
|
<AnimatedPlaceholder type="errorIndex" />
|
|
<AnimatedPlaceholderEmptyTextContainer>
|
|
<AnimatedPlaceholderEmptyTitle>
|
|
{title}
|
|
</AnimatedPlaceholderEmptyTitle>
|
|
<AnimatedPlaceholderEmptySubTitle>
|
|
{error.message}
|
|
</AnimatedPlaceholderEmptySubTitle>
|
|
</AnimatedPlaceholderEmptyTextContainer>
|
|
<Button
|
|
Icon={IconRefresh}
|
|
title="Reload"
|
|
variant={'secondary'}
|
|
onClick={resetErrorBoundary}
|
|
/>
|
|
</AnimatedPlaceholderEmptyContainer>
|
|
</PageBody>
|
|
</PageContainer>
|
|
);
|
|
};
|