personal web client for Bluesky
typescript
solidjs
bluesky
atcute
1import { Match, Switch } from 'solid-js';
2
3import type { AppBskyActorDefs } from '@atcute/bluesky';
4import { ClientResponseError } from '@atcute/client';
5import { TokenRefreshError } from '@atcute/oauth-browser-client';
6import { useQueryClient } from '@mary/solid-query';
7
8import { formatQueryError } from '~/api/utils/error';
9
10import { openModal } from '~/globals/modals';
11
12import { useSession } from '~/lib/states/session';
13
14import Button from '~/components/button';
15import SignInDialogLazy from '~/components/main/sign-in-dialog-lazy';
16
17export interface ErrorViewProps {
18 error: unknown;
19 onRetry?: () => void;
20}
21
22const ErrorView = (props: ErrorViewProps) => {
23 const queryClient = useQueryClient();
24
25 const { currentAccount } = useSession();
26
27 return (
28 <div class="p-4">
29 <div class="mb-4 text-sm">
30 <p class="font-bold">Something went wrong</p>
31 <p class="text-pretty text-contrast-muted">{formatQueryError(props.error)}</p>
32 </div>
33
34 <div class="flex flex-wrap gap-4">
35 <Switch>
36 <Match when={isInvalidTokenError(props.error)}>
37 <Button
38 onClick={() => {
39 type Profile = AppBskyActorDefs.ProfileViewDetailed;
40
41 const did = currentAccount!.did;
42 const profile = queryClient.getQueryData<Profile>(['profile', currentAccount!.did]);
43
44 openModal(() => <SignInDialogLazy relogin={/* @once */ { did, handle: profile?.handle }} />);
45 }}
46 variant="primary"
47 >
48 Sign in again
49 </Button>
50
51 <Button onClick={props.onRetry}>Try again</Button>
52 </Match>
53
54 <Match when>
55 <Button onClick={props.onRetry} variant="primary">
56 Try again
57 </Button>
58 </Match>
59 </Switch>
60 </div>
61 </div>
62 );
63};
64
65export default ErrorView;
66
67const isInvalidTokenError = (err: unknown): boolean => {
68 return (
69 err instanceof TokenRefreshError || (err instanceof ClientResponseError && err.error === 'invalid_token')
70 );
71};