@indietabletop/appkit 6.1.6 → 7.0.0-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AppConfig/AppConfig.d.ts +29 -0
- package/dist/AuthCard/AuthCard.d.ts +10 -0
- package/dist/AuthCard/AuthCard.stories.d.ts +34 -0
- package/dist/AuthCard/style.css.d.ts +23 -0
- package/dist/DialogTrigger/index.d.ts +13 -0
- package/dist/DocumentTitle/DocumentTitle.d.ts +3 -0
- package/dist/EnumMapper.d.ts +25 -0
- package/dist/ExternalLink.d.ts +3 -0
- package/dist/FullscreenDismissBlocker.d.ts +5 -0
- package/{lib/HistoryState.ts → dist/HistoryState.d.ts} +2 -5
- package/dist/IndieTabletopClubLogo.d.ts +7 -0
- package/dist/IndieTabletopClubSymbol.d.ts +7 -0
- package/dist/InfoPage/index.d.ts +8 -0
- package/dist/InfoPage/pages.d.ts +2 -0
- package/dist/InfoPage/style.css.d.ts +5 -0
- package/dist/Letterhead/index.d.ts +19 -0
- package/dist/Letterhead/stories.d.ts +13 -0
- package/dist/Letterhead/style.css.d.ts +46 -0
- package/dist/LetterheadForm/LetterheadReadonlyTextField.stories.d.ts +17 -0
- package/dist/LetterheadForm/LetterheadSubmitError.stories.d.ts +11 -0
- package/dist/LetterheadForm/LetterheadTextField.stories.d.ts +336 -0
- package/dist/LetterheadForm/index.d.ts +44 -0
- package/dist/LetterheadForm/style.css.d.ts +8 -0
- package/dist/LoadingIndicator.d.ts +3 -0
- package/dist/MiddotSeparated/MiddotSeparated.d.ts +8 -0
- package/dist/MiddotSeparated/MiddotSeparated.stories.d.ts +586 -0
- package/dist/MiddotSeparated/style.css.d.ts +1 -0
- package/dist/ModalDialog/index.d.ts +12 -0
- package/dist/ModalDialog/style.css.d.ts +58 -0
- package/dist/ModernIDB/Cursor.d.ts +56 -0
- package/dist/ModernIDB/ModernIDB.d.ts +66 -0
- package/dist/ModernIDB/ModernIDBError.d.ts +3 -0
- package/dist/ModernIDB/ObjectStore.d.ts +112 -0
- package/dist/ModernIDB/ObjectStoreIndex.d.ts +53 -0
- package/dist/ModernIDB/Transaction.d.ts +16 -0
- package/dist/ModernIDB/VersionChangeManager.d.ts +30 -0
- package/dist/ModernIDB/bindings/factory.d.ts +12 -0
- package/dist/ModernIDB/bindings/index.d.ts +2 -0
- package/{lib/ModernIDB/bindings/types.ts → dist/ModernIDB/bindings/types.d.ts} +13 -32
- package/dist/ModernIDB/bindings/utils.d.ts +2 -0
- package/dist/ModernIDB/index.d.ts +10 -0
- package/dist/ModernIDB/types.d.ts +88 -0
- package/dist/ModernIDB/utils.d.ts +4 -0
- package/dist/QRCode/QRCode.d.ts +7 -0
- package/dist/QRCode/QRCode.stories.d.ts +33 -0
- package/dist/QRCode/style.css.d.ts +4 -0
- package/dist/ReleaseInfo/index.d.ts +5 -0
- package/dist/RulesetResolver.d.ts +87 -0
- package/dist/SafariCheck/SafariCheck.d.ts +23 -0
- package/dist/SafariCheck/SafariCheck.stories.d.ts +73 -0
- package/dist/SafariCheck/style.css.d.ts +17 -0
- package/dist/ServiceWorkerHandler.d.ts +11 -0
- package/dist/ShareButton/ShareButton.d.ts +57 -0
- package/dist/ShareButton/ShareButton.stories.d.ts +1577 -0
- package/dist/ShareButton/test.css.d.ts +1 -0
- package/dist/SubscribeCard/LetterheadInfoCard.d.ts +2 -0
- package/dist/SubscribeCard/SubscribeByEmailCard.d.ts +24 -0
- package/dist/SubscribeCard/SubscribeByEmailCard.stories.d.ts +10 -0
- package/dist/SubscribeCard/SubscribeByPledgeCard.d.ts +36 -0
- package/dist/SubscribeCard/SubscribeByPledgeCard.stories.d.ts +65 -0
- package/dist/SubscribeCard/style.css.d.ts +4 -0
- package/dist/account/AccountIssueView.d.ts +3 -0
- package/dist/account/AlreadyLoggedInView.d.ts +5 -0
- package/dist/account/CurrentUserFetcher.d.ts +20 -0
- package/dist/account/CurrentUserFetcher.stories.d.ts +136 -0
- package/dist/account/FailureFallbackView.d.ts +1 -0
- package/dist/account/JoinCard.d.ts +14 -0
- package/dist/account/JoinCard.stories.d.ts +143 -0
- package/dist/account/LoadingView.d.ts +1 -0
- package/dist/account/LoginCard.d.ts +39 -0
- package/dist/account/LoginCard.stories.d.ts +217 -0
- package/dist/account/LoginView.d.ts +10 -0
- package/dist/account/NoConnectionView.d.ts +4 -0
- package/dist/account/PasswordResetCard.d.ts +15 -0
- package/dist/account/PasswordResetCard.stories.d.ts +128 -0
- package/dist/account/UserMismatchView.d.ts +6 -0
- package/dist/account/VerifyPage.d.ts +13 -0
- package/dist/account/style.css.d.ts +10 -0
- package/{lib/account/types.ts → dist/account/types.d.ts} +3 -6
- package/dist/account/useFetchCurrentUser.d.ts +28 -0
- package/dist/account/useRedirectPath.d.ts +6 -0
- package/dist/animations.css.d.ts +3 -0
- package/dist/append-copy-to-text.d.ts +10 -0
- package/dist/append-copy-to-text.test.d.ts +1 -0
- package/dist/appkit.css +1 -0
- package/dist/appkit.js +10692 -0
- package/dist/async-op.d.ts +101 -0
- package/dist/atomic.css.d.ts +6 -0
- package/{lib/caught-value.ts → dist/caught-value.d.ts} +1 -11
- package/{lib/class-names.ts → dist/class-names.d.ts} +6 -17
- package/dist/client.d.ts +424 -0
- package/dist/common.css.d.ts +5 -0
- package/dist/copyrightRange.d.ts +1 -0
- package/dist/copyrightRange.test.d.ts +1 -0
- package/dist/createSafeStorage.d.ts +34 -0
- package/dist/failureMessages.d.ts +20 -0
- package/dist/failureMessages.test.d.ts +1 -0
- package/dist/form/FormSubmitButton.d.ts +17 -0
- package/dist/form/SubmitErrorAlert.d.ts +5 -0
- package/dist/form/style.css.d.ts +3 -0
- package/dist/globals.css.d.ts +0 -0
- package/dist/groupBy.d.ts +1 -0
- package/dist/groupBy.test.d.ts +1 -0
- package/dist/hrefs.d.ts +32 -0
- package/dist/hrefs.test.d.ts +1 -0
- package/dist/idToDate.d.ts +5 -0
- package/dist/idToDate.test.d.ts +1 -0
- package/dist/ids.d.ts +1 -0
- package/dist/ids.test.d.ts +1 -0
- package/dist/index.d.ts +64 -0
- package/dist/internal.css.d.ts +2 -0
- package/dist/mailto.d.ts +8 -0
- package/dist/mailto.test.d.ts +1 -0
- package/dist/media.d.ts +39 -0
- package/dist/random.d.ts +3 -0
- package/dist/result/swr.d.ts +4 -0
- package/{lib/sleep.ts → dist/sleep.d.ts} +1 -3
- package/dist/store/index.d.ts +237 -0
- package/dist/store/store.d.ts +144 -0
- package/dist/store/types.d.ts +49 -0
- package/dist/store/utils.d.ts +10 -0
- package/dist/storybook/decorators.d.ts +3 -0
- package/dist/structs.d.ts +1 -0
- package/{lib/typeguards.ts → dist/typeguards.d.ts} +1 -3
- package/dist/typeguards.test.d.ts +1 -0
- package/{lib/types.ts → dist/types.d.ts} +12 -23
- package/dist/unique.d.ts +10 -0
- package/dist/unique.test.d.ts +1 -0
- package/dist/use-async-op.d.ts +6 -0
- package/dist/use-document-background-color.d.ts +4 -0
- package/dist/use-form.d.ts +29 -0
- package/dist/use-is-installed.d.ts +8 -0
- package/dist/use-media-query.d.ts +1 -0
- package/dist/use-reverting-state.d.ts +5 -0
- package/dist/use-scroll-restoration.d.ts +25 -0
- package/dist/useEnsureValue.d.ts +6 -0
- package/dist/useInvokeClient.d.ts +25 -0
- package/dist/useIsVisible.d.ts +4 -0
- package/dist/utm.d.ts +58 -0
- package/dist/utm.test.d.ts +1 -0
- package/dist/validations.d.ts +3 -0
- package/dist/vars.css.d.ts +10 -0
- package/package.json +12 -5
- package/lib/AppConfig/AppConfig.tsx +0 -61
- package/lib/AuthCard/AuthCard.stories.ts +0 -34
- package/lib/AuthCard/AuthCard.tsx +0 -64
- package/lib/AuthCard/style.css.ts +0 -49
- package/lib/DialogTrigger/index.tsx +0 -36
- package/lib/DocumentTitle/DocumentTitle.tsx +0 -10
- package/lib/EnumMapper.ts +0 -50
- package/lib/ExternalLink.tsx +0 -10
- package/lib/FullscreenDismissBlocker.tsx +0 -23
- package/lib/IndieTabletopClubLogo.tsx +0 -44
- package/lib/IndieTabletopClubSymbol.tsx +0 -37
- package/lib/InfoPage/index.tsx +0 -46
- package/lib/InfoPage/pages.tsx +0 -36
- package/lib/InfoPage/style.css.ts +0 -36
- package/lib/Letterhead/index.tsx +0 -85
- package/lib/Letterhead/stories.tsx +0 -41
- package/lib/Letterhead/style.css.ts +0 -152
- package/lib/LetterheadForm/LetterheadReadonlyTextField.stories.tsx +0 -17
- package/lib/LetterheadForm/LetterheadSubmitError.stories.tsx +0 -19
- package/lib/LetterheadForm/LetterheadTextField.stories.tsx +0 -19
- package/lib/LetterheadForm/index.tsx +0 -137
- package/lib/LetterheadForm/style.css.ts +0 -89
- package/lib/LoadingIndicator.tsx +0 -40
- package/lib/MiddotSeparated/MiddotSeparated.stories.ts +0 -26
- package/lib/MiddotSeparated/MiddotSeparated.tsx +0 -26
- package/lib/MiddotSeparated/style.css.ts +0 -10
- package/lib/ModalDialog/index.tsx +0 -28
- package/lib/ModalDialog/style.css.ts +0 -88
- package/lib/ModernIDB/Cursor.ts +0 -91
- package/lib/ModernIDB/ModernIDB.ts +0 -337
- package/lib/ModernIDB/ModernIDBError.ts +0 -9
- package/lib/ModernIDB/ObjectStore.ts +0 -195
- package/lib/ModernIDB/ObjectStoreIndex.ts +0 -102
- package/lib/ModernIDB/README.md +0 -9
- package/lib/ModernIDB/Transaction.ts +0 -40
- package/lib/ModernIDB/VersionChangeManager.ts +0 -57
- package/lib/ModernIDB/bindings/factory.tsx +0 -165
- package/lib/ModernIDB/bindings/index.ts +0 -2
- package/lib/ModernIDB/bindings/utils.tsx +0 -32
- package/lib/ModernIDB/index.ts +0 -10
- package/lib/ModernIDB/types.ts +0 -120
- package/lib/ModernIDB/utils.ts +0 -51
- package/lib/QRCode/QRCode.stories.tsx +0 -41
- package/lib/QRCode/QRCode.tsx +0 -54
- package/lib/QRCode/style.css.ts +0 -23
- package/lib/ReleaseInfo/index.tsx +0 -29
- package/lib/RulesetResolver.ts +0 -214
- package/lib/SafariCheck/SafariCheck.stories.tsx +0 -99
- package/lib/SafariCheck/SafariCheck.tsx +0 -273
- package/lib/SafariCheck/addToDock.svg +0 -13
- package/lib/SafariCheck/addToHomeScreen.svg +0 -12
- package/lib/SafariCheck/safari.svg +0 -32
- package/lib/SafariCheck/shareIcon.svg +0 -11
- package/lib/SafariCheck/style.css.ts +0 -106
- package/lib/ServiceWorkerHandler.tsx +0 -53
- package/lib/ShareButton/ShareButton.stories.tsx +0 -58
- package/lib/ShareButton/ShareButton.tsx +0 -153
- package/lib/ShareButton/test.css.ts +0 -3
- package/lib/SubscribeCard/LetterheadInfoCard.tsx +0 -23
- package/lib/SubscribeCard/SubscribeByEmailCard.stories.tsx +0 -69
- package/lib/SubscribeCard/SubscribeByEmailCard.tsx +0 -183
- package/lib/SubscribeCard/SubscribeByPledgeCard.stories.tsx +0 -133
- package/lib/SubscribeCard/SubscribeByPledgeCard.tsx +0 -127
- package/lib/SubscribeCard/style.css.ts +0 -14
- package/lib/account/AccountIssueView.tsx +0 -44
- package/lib/account/AlreadyLoggedInView.tsx +0 -47
- package/lib/account/CurrentUserFetcher.stories.tsx +0 -292
- package/lib/account/CurrentUserFetcher.tsx +0 -118
- package/lib/account/FailureFallbackView.tsx +0 -36
- package/lib/account/JoinCard.stories.tsx +0 -257
- package/lib/account/JoinCard.tsx +0 -301
- package/lib/account/LoadingView.tsx +0 -14
- package/lib/account/LoginCard.stories.tsx +0 -288
- package/lib/account/LoginCard.tsx +0 -100
- package/lib/account/LoginView.tsx +0 -151
- package/lib/account/NoConnectionView.tsx +0 -34
- package/lib/account/PasswordResetCard.stories.tsx +0 -242
- package/lib/account/PasswordResetCard.tsx +0 -296
- package/lib/account/UserMismatchView.tsx +0 -62
- package/lib/account/VerifyPage.tsx +0 -195
- package/lib/account/style.css.ts +0 -57
- package/lib/account/useFetchCurrentUser.tsx +0 -63
- package/lib/account/useRedirectPath.ts +0 -21
- package/lib/animations.css.ts +0 -17
- package/lib/append-copy-to-text.ts +0 -35
- package/lib/async-op.ts +0 -286
- package/lib/atomic.css.ts +0 -11
- package/lib/client.ts +0 -662
- package/lib/common.css.ts +0 -48
- package/lib/copyrightRange.ts +0 -10
- package/lib/createSafeStorage.ts +0 -91
- package/lib/failureMessages.ts +0 -108
- package/lib/form/FormSubmitButton.tsx +0 -58
- package/lib/form/SubmitErrorAlert.tsx +0 -21
- package/lib/form/style.css.ts +0 -9
- package/lib/globals.css.ts +0 -62
- package/lib/groupBy.ts +0 -25
- package/lib/hrefs.ts +0 -48
- package/lib/idToDate.ts +0 -8
- package/lib/ids.ts +0 -6
- package/lib/index.ts +0 -71
- package/lib/internal.css.ts +0 -10
- package/lib/mailto.ts +0 -40
- package/lib/media.ts +0 -50
- package/lib/random.ts +0 -19
- package/lib/result/swr.ts +0 -18
- package/lib/store/index.tsx +0 -241
- package/lib/store/store.ts +0 -479
- package/lib/store/types.ts +0 -45
- package/lib/store/utils.ts +0 -54
- package/lib/storybook/decorators.tsx +0 -10
- package/lib/structs.ts +0 -3
- package/lib/unique.ts +0 -24
- package/lib/use-async-op.ts +0 -16
- package/lib/use-document-background-color.ts +0 -16
- package/lib/use-form.ts +0 -78
- package/lib/use-is-installed.ts +0 -17
- package/lib/use-media-query.ts +0 -21
- package/lib/use-reverting-state.ts +0 -32
- package/lib/use-scroll-restoration.ts +0 -99
- package/lib/useEnsureValue.ts +0 -31
- package/lib/useInvokeClient.ts +0 -54
- package/lib/useIsVisible.ts +0 -27
- package/lib/utm.ts +0 -92
- package/lib/validations.ts +0 -25
- package/lib/vars.css.ts +0 -13
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { useState, type ReactNode } from "react";
|
|
2
|
-
import { ModalDialog } from "../ModalDialog/index.tsx";
|
|
3
|
-
import { useCurrentUser } from "../store/index.tsx";
|
|
4
|
-
import { AccountIssueView } from "./AccountIssueView.tsx";
|
|
5
|
-
import { LoginView } from "./LoginView.tsx";
|
|
6
|
-
import { useFetchCurrentUser } from "./useFetchCurrentUser.tsx";
|
|
7
|
-
import { UserMismatchView } from "./UserMismatchView.tsx";
|
|
8
|
-
import { VerifyAccountView } from "./VerifyPage.tsx";
|
|
9
|
-
|
|
10
|
-
type CurrentUserFetcherProps = {
|
|
11
|
-
children: ReactNode;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Fetches fresh current user data if a local user exists in the app store.
|
|
16
|
-
*
|
|
17
|
-
* This component uses the Indie Tabletop Client under the hood, so if new
|
|
18
|
-
* data is successfully fetched, the onCurrentUser callback will be invoked,
|
|
19
|
-
* and it is up to the configuration of the client to store the data.
|
|
20
|
-
*
|
|
21
|
-
* Importantly, this component also handles the various user account issues
|
|
22
|
-
* that we could run into: expired session, user mismatch and account deletion.
|
|
23
|
-
*
|
|
24
|
-
* All other errors are ignored. This allows users to use the app in offline
|
|
25
|
-
* mode, and doesn't interrupt their session if some unexpected error happens,
|
|
26
|
-
* which they cannot do anything about anyways.
|
|
27
|
-
*/
|
|
28
|
-
export function CurrentUserFetcher(props: CurrentUserFetcherProps) {
|
|
29
|
-
const { children } = props;
|
|
30
|
-
const localUser = useCurrentUser();
|
|
31
|
-
const [isOpen, setOpen] = useState(true);
|
|
32
|
-
|
|
33
|
-
const { result, reload } = useFetchCurrentUser({
|
|
34
|
-
// We only want to fetch the current user if they exist in the store, i.e.
|
|
35
|
-
// they have logged into the app previously.
|
|
36
|
-
performFetch: !!localUser,
|
|
37
|
-
|
|
38
|
-
// If we are performing a fetch, we want to make sure that it is up to date
|
|
39
|
-
// every time the user focuses the window.
|
|
40
|
-
revalidateOnFocus: true,
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
if (result.isFailure && result.failure.type === "API_ERROR") {
|
|
44
|
-
// The user's session has expired. They should be prompted to
|
|
45
|
-
// re-authenticate, as any syncing attemps will fail.
|
|
46
|
-
if (result.failure.code === 401) {
|
|
47
|
-
return (
|
|
48
|
-
<>
|
|
49
|
-
<ModalDialog size="large" open>
|
|
50
|
-
<LoginView
|
|
51
|
-
currentUser={localUser}
|
|
52
|
-
onLogin={() => reload()}
|
|
53
|
-
description={undefined}
|
|
54
|
-
reload={reload}
|
|
55
|
-
/>
|
|
56
|
-
</ModalDialog>
|
|
57
|
-
{children}
|
|
58
|
-
</>
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (result.failure.code === 404) {
|
|
63
|
-
// The user account is not found. The user might have been deleted.
|
|
64
|
-
// The user should be notified and instructed to log out, as many
|
|
65
|
-
// interactions acrosss the app will be broken.
|
|
66
|
-
return (
|
|
67
|
-
<>
|
|
68
|
-
<ModalDialog size="large" open>
|
|
69
|
-
<AccountIssueView reload={reload} />
|
|
70
|
-
</ModalDialog>
|
|
71
|
-
|
|
72
|
-
{children}
|
|
73
|
-
</>
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (localUser && result.isSuccess) {
|
|
79
|
-
const serverUser = result.value;
|
|
80
|
-
|
|
81
|
-
// The cookie (server) user and the user in local storage are a different
|
|
82
|
-
// user. The current user needs to decide which account to use.
|
|
83
|
-
if (serverUser.id !== localUser.id) {
|
|
84
|
-
return (
|
|
85
|
-
<>
|
|
86
|
-
<ModalDialog size="large" open>
|
|
87
|
-
<UserMismatchView
|
|
88
|
-
serverUser={result.value}
|
|
89
|
-
localUser={localUser}
|
|
90
|
-
reload={reload}
|
|
91
|
-
/>
|
|
92
|
-
</ModalDialog>
|
|
93
|
-
|
|
94
|
-
{children}
|
|
95
|
-
</>
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (!serverUser.isVerified) {
|
|
100
|
-
return (
|
|
101
|
-
<>
|
|
102
|
-
<ModalDialog size="large" open={isOpen}>
|
|
103
|
-
<VerifyAccountView
|
|
104
|
-
currentUser={serverUser}
|
|
105
|
-
onClose={() => setOpen(false)}
|
|
106
|
-
reload={reload}
|
|
107
|
-
/>
|
|
108
|
-
</ModalDialog>
|
|
109
|
-
|
|
110
|
-
{children}
|
|
111
|
-
</>
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// In all other cases we simply render the children
|
|
117
|
-
return <>{children}</>;
|
|
118
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { Button } from "@ariakit/react";
|
|
2
|
-
import { cx } from "../class-names.ts";
|
|
3
|
-
import { interactiveText } from "../common.css.ts";
|
|
4
|
-
import {
|
|
5
|
-
Letterhead,
|
|
6
|
-
LetterheadHeading,
|
|
7
|
-
LetterheadParagraph,
|
|
8
|
-
} from "../Letterhead/index.tsx";
|
|
9
|
-
|
|
10
|
-
export function FailureFallbackView() {
|
|
11
|
-
return (
|
|
12
|
-
<Letterhead>
|
|
13
|
-
<LetterheadHeading>Something went wrong</LetterheadHeading>
|
|
14
|
-
|
|
15
|
-
<LetterheadParagraph>
|
|
16
|
-
{"This is probably an issue on our side. Sorry about that!"}
|
|
17
|
-
</LetterheadParagraph>
|
|
18
|
-
|
|
19
|
-
<LetterheadParagraph>
|
|
20
|
-
{"You can try "}
|
|
21
|
-
<Button
|
|
22
|
-
{...cx(interactiveText)}
|
|
23
|
-
onClick={() => window.location.reload()}
|
|
24
|
-
>
|
|
25
|
-
reloading the app
|
|
26
|
-
</Button>
|
|
27
|
-
{". "}
|
|
28
|
-
{"If the issue persists, please get in touch at "}
|
|
29
|
-
<a {...cx(interactiveText)} href="mailto:support@indietabletop.club">
|
|
30
|
-
support@indietabletop.club
|
|
31
|
-
</a>
|
|
32
|
-
{"."}
|
|
33
|
-
</LetterheadParagraph>
|
|
34
|
-
</Letterhead>
|
|
35
|
-
);
|
|
36
|
-
}
|
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
import { http, HttpResponse } from "msw";
|
|
2
|
-
import preview from "../../.storybook/preview.tsx";
|
|
3
|
-
import { sleep } from "../sleep.ts";
|
|
4
|
-
import type { CurrentUser, SessionInfo } from "../types.ts";
|
|
5
|
-
import { JoinCard } from "./JoinCard.tsx";
|
|
6
|
-
|
|
7
|
-
function createMocks(options?: { responseSpeed?: number }) {
|
|
8
|
-
const simulateNetwork = () => sleep(options?.responseSpeed ?? 2000);
|
|
9
|
-
|
|
10
|
-
const john: CurrentUser = {
|
|
11
|
-
id: "john",
|
|
12
|
-
email: "john@example.com",
|
|
13
|
-
isVerified: true,
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const sessionInfo: SessionInfo = {
|
|
17
|
-
createdTs: 123,
|
|
18
|
-
expiresTs: 123,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
data: { john },
|
|
23
|
-
handlers: {
|
|
24
|
-
refreshTokens: {
|
|
25
|
-
failed: () => {
|
|
26
|
-
return http.post(
|
|
27
|
-
"http://mock.api/v1/sessions/access-tokens",
|
|
28
|
-
async () => {
|
|
29
|
-
await simulateNetwork();
|
|
30
|
-
return HttpResponse.text("Refresh token expired or missing", {
|
|
31
|
-
status: 401,
|
|
32
|
-
});
|
|
33
|
-
},
|
|
34
|
-
);
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
|
|
38
|
-
getCurrentUser: {
|
|
39
|
-
success: (currentUser: CurrentUser) => {
|
|
40
|
-
return http.get("http://mock.api/v1/users/me", async () => {
|
|
41
|
-
await simulateNetwork();
|
|
42
|
-
return HttpResponse.json(currentUser);
|
|
43
|
-
});
|
|
44
|
-
},
|
|
45
|
-
|
|
46
|
-
noConnection: () => {
|
|
47
|
-
return http.get("http://mock.api/v1/users/me", async () => {
|
|
48
|
-
return HttpResponse.error();
|
|
49
|
-
});
|
|
50
|
-
},
|
|
51
|
-
|
|
52
|
-
unknownFailure: () => {
|
|
53
|
-
return http.get("http://mock.api/v1/users/me", async () => {
|
|
54
|
-
await simulateNetwork();
|
|
55
|
-
return HttpResponse.text("Internal server error", { status: 500 });
|
|
56
|
-
});
|
|
57
|
-
},
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Auth cookies no longer valid to make this request.
|
|
61
|
-
*/
|
|
62
|
-
notAuthenticated: () => {
|
|
63
|
-
return http.get("http://mock.api/v1/users/me", async () => {
|
|
64
|
-
await simulateNetwork();
|
|
65
|
-
return HttpResponse.text("Not authenticated", { status: 401 });
|
|
66
|
-
});
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
join: {
|
|
71
|
-
success(currentUser: CurrentUser) {
|
|
72
|
-
return http.post("http://mock.api/v1/users", async () => {
|
|
73
|
-
await simulateNetwork();
|
|
74
|
-
|
|
75
|
-
return HttpResponse.json({
|
|
76
|
-
currentUser,
|
|
77
|
-
sessionInfo,
|
|
78
|
-
tokenId: "1",
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
emailTaken() {
|
|
84
|
-
return http.post("http://mock.api/v1/users", async () => {
|
|
85
|
-
await simulateNetwork();
|
|
86
|
-
|
|
87
|
-
return HttpResponse.text("Duplicate unique key", { status: 409 });
|
|
88
|
-
});
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
unknownFailure() {
|
|
92
|
-
return http.post("http://mock.api/v1/users", async () => {
|
|
93
|
-
await simulateNetwork();
|
|
94
|
-
return HttpResponse.text("Internal server error", {
|
|
95
|
-
status: 500,
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
verify: {
|
|
101
|
-
success() {
|
|
102
|
-
return http.put(
|
|
103
|
-
"http://mock.api/v1/user-verification-tokens/:id",
|
|
104
|
-
async () => {
|
|
105
|
-
await simulateNetwork();
|
|
106
|
-
return HttpResponse.json({ message: "OK" });
|
|
107
|
-
},
|
|
108
|
-
);
|
|
109
|
-
},
|
|
110
|
-
notFoundOrExpired() {
|
|
111
|
-
return http.put(
|
|
112
|
-
"http://mock.api/v1/user-verification-tokens/:id",
|
|
113
|
-
async () => {
|
|
114
|
-
await simulateNetwork();
|
|
115
|
-
return HttpResponse.text("Not found", { status: 404 });
|
|
116
|
-
},
|
|
117
|
-
);
|
|
118
|
-
},
|
|
119
|
-
unknownFailure() {
|
|
120
|
-
return http.put(
|
|
121
|
-
"http://mock.api/v1/user-verification-tokens/:id",
|
|
122
|
-
async () => {
|
|
123
|
-
await simulateNetwork();
|
|
124
|
-
return HttpResponse.text("Internal server error", {
|
|
125
|
-
status: 500,
|
|
126
|
-
});
|
|
127
|
-
},
|
|
128
|
-
);
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const { data, handlers } = createMocks({ responseSpeed: 700 });
|
|
136
|
-
|
|
137
|
-
const meta = preview.meta({
|
|
138
|
-
title: "Account/Join Card",
|
|
139
|
-
component: JoinCard,
|
|
140
|
-
tags: ["autodocs"],
|
|
141
|
-
args: {
|
|
142
|
-
defaultValues: {},
|
|
143
|
-
},
|
|
144
|
-
parameters: {
|
|
145
|
-
msw: {
|
|
146
|
-
handlers: {
|
|
147
|
-
refresh: handlers.refreshTokens.failed(),
|
|
148
|
-
currentUser: handlers.getCurrentUser.notAuthenticated(),
|
|
149
|
-
join: handlers.join.success(data.john),
|
|
150
|
-
verify: handlers.verify.success(),
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* The default case in which all steps of the flow succeed.
|
|
158
|
-
*/
|
|
159
|
-
export const Success = meta.story({});
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* In this case, the initial step fails because the email address is associated
|
|
163
|
-
* with an existing user.
|
|
164
|
-
*/
|
|
165
|
-
export const EmailTakenOnJoin = meta.story({
|
|
166
|
-
parameters: {
|
|
167
|
-
msw: {
|
|
168
|
-
handlers: {
|
|
169
|
-
join: handlers.join.emailTaken(),
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
},
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* In this case, the initial step fails for a reason that doesn't have any
|
|
177
|
-
* special handling in this location. E.g. network error, server error, etc.
|
|
178
|
-
*/
|
|
179
|
-
export const UnknownFailureOnJoin = meta.story({
|
|
180
|
-
parameters: {
|
|
181
|
-
msw: {
|
|
182
|
-
handlers: {
|
|
183
|
-
join: handlers.join.unknownFailure(),
|
|
184
|
-
},
|
|
185
|
-
},
|
|
186
|
-
},
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* In this case, the verify step fails because the token has expired,
|
|
191
|
-
* or is incorrect.
|
|
192
|
-
*/
|
|
193
|
-
export const NotFoundOrExpiredOnVerify = meta.story({
|
|
194
|
-
parameters: {
|
|
195
|
-
msw: {
|
|
196
|
-
handlers: {
|
|
197
|
-
verify: handlers.verify.notFoundOrExpired(),
|
|
198
|
-
},
|
|
199
|
-
},
|
|
200
|
-
},
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* In this case, the verify step fails for a reason that doesn't have any
|
|
205
|
-
* special handling in this location. E.g. network error, server error, etc.
|
|
206
|
-
*/
|
|
207
|
-
export const UnknownFailureOnVerify = meta.story({
|
|
208
|
-
parameters: {
|
|
209
|
-
msw: {
|
|
210
|
-
handlers: {
|
|
211
|
-
verify: handlers.verify.unknownFailure(),
|
|
212
|
-
},
|
|
213
|
-
},
|
|
214
|
-
},
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* The proactive user-session check returns a user account.
|
|
219
|
-
*
|
|
220
|
-
* The user can continue to use the app, or log out.
|
|
221
|
-
*/
|
|
222
|
-
export const AlreadyLoggedIn = meta.story({
|
|
223
|
-
parameters: {
|
|
224
|
-
msw: {
|
|
225
|
-
handlers: {
|
|
226
|
-
currentUser: handlers.getCurrentUser.success(data.john),
|
|
227
|
-
},
|
|
228
|
-
},
|
|
229
|
-
},
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* The proactive user session check has failed due to connection issues.
|
|
234
|
-
*/
|
|
235
|
-
export const NoConnection = meta.story({
|
|
236
|
-
parameters: {
|
|
237
|
-
msw: {
|
|
238
|
-
handlers: {
|
|
239
|
-
currentUser: handlers.getCurrentUser.noConnection(),
|
|
240
|
-
},
|
|
241
|
-
},
|
|
242
|
-
},
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* The proactive user session check has failed due to an error that doesn't
|
|
247
|
-
* carry any special meaning.
|
|
248
|
-
*/
|
|
249
|
-
export const UnknownFailure = meta.story({
|
|
250
|
-
parameters: {
|
|
251
|
-
msw: {
|
|
252
|
-
handlers: {
|
|
253
|
-
currentUser: handlers.getCurrentUser.unknownFailure(),
|
|
254
|
-
},
|
|
255
|
-
},
|
|
256
|
-
},
|
|
257
|
-
});
|
package/lib/account/JoinCard.tsx
DELETED
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
import { Form, useStoreState } from "@ariakit/react";
|
|
2
|
-
import { type Dispatch, type SetStateAction, useState } from "react";
|
|
3
|
-
import { Link } from "wouter";
|
|
4
|
-
import { useAppConfig, useClient } from "../AppConfig/AppConfig.tsx";
|
|
5
|
-
import { cx } from "../class-names.ts";
|
|
6
|
-
import { interactiveText } from "../common.css.ts";
|
|
7
|
-
import { getSubmitFailureMessage } from "../failureMessages.ts";
|
|
8
|
-
import {
|
|
9
|
-
Letterhead,
|
|
10
|
-
LetterheadHeading,
|
|
11
|
-
LetterheadParagraph,
|
|
12
|
-
LetterheadSubmitButton,
|
|
13
|
-
} from "../Letterhead/index.tsx";
|
|
14
|
-
import { button } from "../Letterhead/style.css.ts";
|
|
15
|
-
import {
|
|
16
|
-
InputsStack,
|
|
17
|
-
LetterheadCheckboxField,
|
|
18
|
-
LetterheadFormActions,
|
|
19
|
-
LetterheadHeader,
|
|
20
|
-
LetterheadSubmitError,
|
|
21
|
-
LetterheadTextField,
|
|
22
|
-
} from "../LetterheadForm/index.tsx";
|
|
23
|
-
import { useForm } from "../use-form.ts";
|
|
24
|
-
import { validEmail, validPassword } from "../validations.ts";
|
|
25
|
-
import { AlreadyLoggedInView } from "./AlreadyLoggedInView.tsx";
|
|
26
|
-
import { FailureFallbackView } from "./FailureFallbackView.tsx";
|
|
27
|
-
import { LoadingView } from "./LoadingView.tsx";
|
|
28
|
-
import { NoConnectionView } from "./NoConnectionView.tsx";
|
|
29
|
-
import type { DefaultFormValues } from "./types.ts";
|
|
30
|
-
import { useFetchCurrentUser } from "./useFetchCurrentUser.tsx";
|
|
31
|
-
import { useRedirectPath } from "./useRedirectPath.ts";
|
|
32
|
-
|
|
33
|
-
type SetStep = Dispatch<SetStateAction<JoinStep>>;
|
|
34
|
-
|
|
35
|
-
type InitialStepProps = {
|
|
36
|
-
setStep: SetStep;
|
|
37
|
-
defaultValues?: DefaultFormValues;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
function InitialStep(props: InitialStepProps) {
|
|
41
|
-
const { client, placeholders, hrefs } = useAppConfig();
|
|
42
|
-
const { defaultValues, setStep } = props;
|
|
43
|
-
|
|
44
|
-
const { form, submitName } = useForm({
|
|
45
|
-
defaultValues: {
|
|
46
|
-
email: defaultValues?.email ?? "",
|
|
47
|
-
password: "",
|
|
48
|
-
acceptedTos: false,
|
|
49
|
-
subscribedToNewsletter: false,
|
|
50
|
-
},
|
|
51
|
-
validate: {
|
|
52
|
-
email: validEmail,
|
|
53
|
-
password: validPassword,
|
|
54
|
-
},
|
|
55
|
-
async onSubmit({ values }) {
|
|
56
|
-
const op = await client.join(values);
|
|
57
|
-
|
|
58
|
-
return op.mapFailure((failure) => {
|
|
59
|
-
return getSubmitFailureMessage(failure, {
|
|
60
|
-
409: "🙀 This email address is already in use. Please choose a different one, or log in.",
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
},
|
|
64
|
-
onSuccess(response, form) {
|
|
65
|
-
setStep({
|
|
66
|
-
type: "SUBMIT_CODE",
|
|
67
|
-
tokenId: response.tokenId,
|
|
68
|
-
email: form.values.email,
|
|
69
|
-
});
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
const emailValue = useStoreState(form, (s) => s.values.email);
|
|
74
|
-
|
|
75
|
-
return (
|
|
76
|
-
<Letterhead>
|
|
77
|
-
<LetterheadHeader>
|
|
78
|
-
<LetterheadHeading>Join Indie Tabletop Club</LetterheadHeading>
|
|
79
|
-
<LetterheadParagraph>
|
|
80
|
-
Enter your email and choose a strong password. We will send you a
|
|
81
|
-
one-time code to verify your account.
|
|
82
|
-
</LetterheadParagraph>
|
|
83
|
-
</LetterheadHeader>
|
|
84
|
-
|
|
85
|
-
<Form store={form} resetOnSubmit={false}>
|
|
86
|
-
<InputsStack>
|
|
87
|
-
<LetterheadTextField
|
|
88
|
-
name={form.names.email}
|
|
89
|
-
label="Email"
|
|
90
|
-
type="email"
|
|
91
|
-
placeholder={placeholders.email}
|
|
92
|
-
autoComplete="username"
|
|
93
|
-
required
|
|
94
|
-
/>
|
|
95
|
-
|
|
96
|
-
<LetterheadTextField
|
|
97
|
-
name={form.names.password}
|
|
98
|
-
label="Password"
|
|
99
|
-
type="password"
|
|
100
|
-
placeholder="Choose a strong password"
|
|
101
|
-
hint="Must be at least 8 characters"
|
|
102
|
-
autoComplete="new-password"
|
|
103
|
-
required
|
|
104
|
-
/>
|
|
105
|
-
|
|
106
|
-
<LetterheadCheckboxField
|
|
107
|
-
name={form.names.subscribedToNewsletter}
|
|
108
|
-
label={
|
|
109
|
-
<>
|
|
110
|
-
Subscribe to <em>The Changelog</em>, an at-most-once-a-month
|
|
111
|
-
newsletter about updates and new releases. You can unsubscribe
|
|
112
|
-
any time with one click.
|
|
113
|
-
</>
|
|
114
|
-
}
|
|
115
|
-
/>
|
|
116
|
-
|
|
117
|
-
<LetterheadCheckboxField
|
|
118
|
-
name={form.names.acceptedTos}
|
|
119
|
-
required
|
|
120
|
-
label={
|
|
121
|
-
<>
|
|
122
|
-
I accept the{" "}
|
|
123
|
-
<a
|
|
124
|
-
target="_blank"
|
|
125
|
-
rel="noreferrer noopener"
|
|
126
|
-
href={hrefs.terms({ content: "join" })}
|
|
127
|
-
className={interactiveText}
|
|
128
|
-
>
|
|
129
|
-
Terms of Service
|
|
130
|
-
</a>
|
|
131
|
-
.
|
|
132
|
-
</>
|
|
133
|
-
}
|
|
134
|
-
/>
|
|
135
|
-
</InputsStack>
|
|
136
|
-
|
|
137
|
-
<LetterheadFormActions>
|
|
138
|
-
<LetterheadSubmitError name={submitName} />
|
|
139
|
-
<LetterheadSubmitButton>Join</LetterheadSubmitButton>
|
|
140
|
-
|
|
141
|
-
<LetterheadParagraph align="start">
|
|
142
|
-
{"Have an existing account? "}
|
|
143
|
-
<Link
|
|
144
|
-
{...cx(interactiveText)}
|
|
145
|
-
href={hrefs.login()}
|
|
146
|
-
state={{ emailValue }}
|
|
147
|
-
>
|
|
148
|
-
Log in
|
|
149
|
-
</Link>
|
|
150
|
-
{"."}
|
|
151
|
-
</LetterheadParagraph>
|
|
152
|
-
</LetterheadFormActions>
|
|
153
|
-
</Form>
|
|
154
|
-
</Letterhead>
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
type SubmitCodeStepProps = {
|
|
159
|
-
tokenId: string;
|
|
160
|
-
setStep: SetStep;
|
|
161
|
-
email: string;
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
function SubmitCodeStep(props: SubmitCodeStepProps) {
|
|
165
|
-
const { tokenId, email, setStep } = props;
|
|
166
|
-
const client = useClient();
|
|
167
|
-
|
|
168
|
-
const { form, submitName } = useForm({
|
|
169
|
-
defaultValues: {
|
|
170
|
-
code: "",
|
|
171
|
-
},
|
|
172
|
-
async onSubmit({ values }) {
|
|
173
|
-
const op = await client.verifyUser({ ...values, tokenId });
|
|
174
|
-
|
|
175
|
-
return op.mapFailure((failure) => {
|
|
176
|
-
return getSubmitFailureMessage(failure, {
|
|
177
|
-
404: "🚫 This code is incorrect or expired. Please try again.",
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
},
|
|
181
|
-
onSuccess() {
|
|
182
|
-
setStep({ type: "SUCCESS" });
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
return (
|
|
187
|
-
<Form store={form} resetOnSubmit={false}>
|
|
188
|
-
<Letterhead>
|
|
189
|
-
<LetterheadHeader>
|
|
190
|
-
<LetterheadHeading>Verify account</LetterheadHeading>
|
|
191
|
-
<LetterheadParagraph>
|
|
192
|
-
We've sent a one-time code to <em>{email}</em>. Please, enter the
|
|
193
|
-
code in the field below to verify your account.
|
|
194
|
-
</LetterheadParagraph>
|
|
195
|
-
</LetterheadHeader>
|
|
196
|
-
|
|
197
|
-
<LetterheadTextField
|
|
198
|
-
name={form.names.code}
|
|
199
|
-
label="Code"
|
|
200
|
-
placeholder="E.g. 123123"
|
|
201
|
-
autoComplete="one-time-code"
|
|
202
|
-
required
|
|
203
|
-
/>
|
|
204
|
-
|
|
205
|
-
<LetterheadFormActions>
|
|
206
|
-
<LetterheadSubmitError name={submitName} />
|
|
207
|
-
<LetterheadSubmitButton>Verify</LetterheadSubmitButton>
|
|
208
|
-
</LetterheadFormActions>
|
|
209
|
-
</Letterhead>
|
|
210
|
-
</Form>
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
function SuccessStep() {
|
|
215
|
-
const { hrefs } = useAppConfig();
|
|
216
|
-
const redirectPath = useRedirectPath();
|
|
217
|
-
|
|
218
|
-
return (
|
|
219
|
-
<Letterhead>
|
|
220
|
-
<LetterheadHeader>
|
|
221
|
-
<LetterheadHeading>Success!</LetterheadHeading>
|
|
222
|
-
<LetterheadParagraph>
|
|
223
|
-
Your Indie Tabletop Club account has been verified, yay!
|
|
224
|
-
</LetterheadParagraph>
|
|
225
|
-
</LetterheadHeader>
|
|
226
|
-
|
|
227
|
-
<Link href={redirectPath ?? hrefs.dashboard()} {...cx(button())}>
|
|
228
|
-
{redirectPath ? "Continue" : "Go to dashboard"}
|
|
229
|
-
</Link>
|
|
230
|
-
</Letterhead>
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
type JoinStep =
|
|
235
|
-
| { type: "INITIAL" }
|
|
236
|
-
| { type: "SUBMIT_CODE"; tokenId: string; email: string }
|
|
237
|
-
| { type: "SUCCESS" };
|
|
238
|
-
|
|
239
|
-
type JoinFlowProps = {
|
|
240
|
-
defaultValues?: DefaultFormValues;
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
function JoinFlow(props: JoinFlowProps) {
|
|
244
|
-
const [step, setStep] = useState<JoinStep>({ type: "INITIAL" });
|
|
245
|
-
|
|
246
|
-
switch (step.type) {
|
|
247
|
-
case "INITIAL": {
|
|
248
|
-
return <InitialStep {...props} setStep={setStep} />;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
case "SUBMIT_CODE": {
|
|
252
|
-
return <SubmitCodeStep {...step} setStep={setStep} />;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
case "SUCCESS": {
|
|
256
|
-
return <SuccessStep />;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
export type JoinCardProps = {
|
|
262
|
-
defaultValues?: DefaultFormValues;
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Allows the user to join Indie Tabletop Club.
|
|
267
|
-
*
|
|
268
|
-
* Will automatically use the `redirectTo` query param value as the redirect
|
|
269
|
-
* location once the user creates and verifies their account.
|
|
270
|
-
*
|
|
271
|
-
* Otherwise a success screen will be shown and the user will be directed to
|
|
272
|
-
* the dashboard.
|
|
273
|
-
*/
|
|
274
|
-
export function JoinCard(props: JoinCardProps) {
|
|
275
|
-
const { result, latestAttemptTs, reload } = useFetchCurrentUser();
|
|
276
|
-
|
|
277
|
-
return result.unpack(
|
|
278
|
-
(currentUser) => {
|
|
279
|
-
return <AlreadyLoggedInView currentUser={currentUser} reload={reload} />;
|
|
280
|
-
},
|
|
281
|
-
(failure) => {
|
|
282
|
-
if (failure.type === "API_ERROR" && failure.code === 401) {
|
|
283
|
-
return <JoinFlow {...props} />;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
if (failure.type === "NETWORK_ERROR") {
|
|
287
|
-
return (
|
|
288
|
-
<NoConnectionView
|
|
289
|
-
latestAttemptTs={latestAttemptTs}
|
|
290
|
-
onRetry={() => reload()}
|
|
291
|
-
/>
|
|
292
|
-
);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
return <FailureFallbackView />;
|
|
296
|
-
},
|
|
297
|
-
() => {
|
|
298
|
-
return <LoadingView />;
|
|
299
|
-
},
|
|
300
|
-
);
|
|
301
|
-
}
|