Files
twenty/packages/twenty-front/src/modules/error-handler/components/GenericErrorFallback.tsx
Khuddite 62df0f0445 Display a generic fallback component when initial config load fails (#8588)
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`](ae2f193d68/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>
2024-11-22 09:45:23 +01:00

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>
);
};