Skip to content

Commit

Permalink
New GQL client (Banking) (#670)
Browse files Browse the repository at this point in the history
* useQuery clean up part 1

* Migrate out of Suspense

* Use new GQL client

* Updates

* Update

* Rebase

* Update to beta

* Upgrade to beta 2

* Update

* Update
  • Loading branch information
bloodyowl authored Apr 8, 2024
1 parent b613cf8 commit 71477a9
Show file tree
Hide file tree
Showing 61 changed files with 4,696 additions and 4,679 deletions.
8 changes: 2 additions & 6 deletions clients/banking/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,16 @@
"clean": "tsc --clean"
},
"dependencies": {
"@0no-co/graphql.web": "1.0.6",
"@formatjs/intl": "2.10.1",
"@juggle/resize-observer": "3.4.0",
"@sentry/react": "7.109.0",
"@swan-io/boxed": "2.1.1",
"@swan-io/chicane": "2.0.0",
"@swan-io/graphql-client": "0.1.0-beta4",
"@swan-io/lake": "7.3.3",
"@swan-io/request": "1.0.4",
"@swan-io/shared-business": "7.3.3",
"@swan-io/use-form": "2.0.0",
"@urql/devtools": "2.0.3",
"@urql/exchange-graphcache": "7.0.0",
"core-js": "3.36.1",
"dayjs": "1.11.10",
"iban": "0.0.14",
Expand All @@ -35,9 +33,7 @@
"react-ux-form": "1.5.0",
"rifm": "0.12.1",
"tggl-client": "1.13.2",
"ts-pattern": "5.1.0",
"urql": "4.0.7",
"wonka": "6.3.4"
"ts-pattern": "5.1.0"
},
"devDependencies": {
"@types/iban": "0.0.35",
Expand Down
112 changes: 69 additions & 43 deletions clients/banking/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import { AsyncData } from "@swan-io/boxed";
import { ClientContext, useQuery } from "@swan-io/graphql-client";
import { ErrorBoundary } from "@swan-io/lake/src/components/ErrorBoundary";
import { LoadingView } from "@swan-io/lake/src/components/LoadingView";
import { ToastStack } from "@swan-io/lake/src/components/ToastStack";
import { colors } from "@swan-io/lake/src/constants/design";
import { isNotNullishOrEmpty } from "@swan-io/lake/src/utils/nullish";
import { Suspense } from "react";
import { StyleSheet } from "react-native";
import { P, match } from "ts-pattern";
import { Provider as ClientProvider } from "urql";
import { AccountArea } from "./components/AccountArea";
import { AccountMembershipArea } from "./components/AccountMembershipArea";
import { ErrorView } from "./components/ErrorView";
import { ProjectRootRedirect } from "./components/ProjectRootRedirect";
import { Redirect } from "./components/Redirect";
import { AuthStatusDocument } from "./graphql/partner";
import { NotFoundPage } from "./pages/NotFoundPage";
import { PopupCallbackPage } from "./pages/PopupCallbackPage";
import { ProjectLoginPage } from "./pages/ProjectLoginPage";
import { partnerClient, unauthenticatedClient } from "./utils/gql";
import { logFrontendError } from "./utils/logger";
import { projectConfiguration } from "./utils/projectId";
import { Router } from "./utils/routes";
import { isUnauthorizedError, partnerClient } from "./utils/urql";

const styles = StyleSheet.create({
base: {
Expand All @@ -25,51 +26,76 @@ const styles = StyleSheet.create({
},
});

const AppContainer = () => {
const route = Router.useRoute(["ProjectLogin", "ProjectRootRedirect", "AccountArea"]);
const [authStatus] = useQuery(AuthStatusDocument, {});

const loginInfo = authStatus
.mapOk(data => data.user?.id != null)
.map(result => ({ isLoggedIn: result.getWithDefault(false) }));

return match(loginInfo)
.with(AsyncData.P.NotAsked, AsyncData.P.Loading, () => null)
.with(AsyncData.P.Done(P.select()), ({ isLoggedIn }) => {
return match(route)
.with({ name: "ProjectLogin" }, ({ params: { sessionExpired } }) =>
projectConfiguration.match({
None: () => <ErrorView />,
Some: ({ projectId }) =>
isLoggedIn ? (
// Skip login and redirect to the root URL
<Redirect to={Router.ProjectRootRedirect()} />
) : (
<ClientContext.Provider value={unauthenticatedClient}>
<ProjectLoginPage
projectId={projectId}
sessionExpired={isNotNullishOrEmpty(sessionExpired)}
/>
</ClientContext.Provider>
),
}),
)
.with({ name: "AccountArea" }, { name: "ProjectRootRedirect" }, route =>
isLoggedIn ? (
match(route)
.with({ name: "AccountArea" }, ({ params: { accountMembershipId } }) => (
<AccountMembershipArea accountMembershipId={accountMembershipId} />
))
.with({ name: "ProjectRootRedirect" }, ({ params: { to, source } }) => (
<ProjectRootRedirect to={to} source={source} />
))
.with(P.nullish, () => <NotFoundPage />)
.exhaustive()
) : (
<Redirect to={Router.ProjectLogin()} />
),
)
.with(P.nullish, () => <NotFoundPage style={styles.base} />)
.exhaustive();
})
.exhaustive();
};

export const App = () => {
const route = Router.useRoute([
"PopupCallback",
"ProjectLogin",
"ProjectRootRedirect",
"AccountArea",
]);
const route = Router.useRoute(["PopupCallback"]);

return (
<ErrorBoundary
key={route?.name}
onError={error => logFrontendError(error)}
fallback={({ error }) =>
isUnauthorizedError(error) ? <></> : <ErrorView error={error} style={styles.base} />
}
fallback={() => <ErrorView style={styles.base} />}
>
<ClientProvider value={partnerClient}>
<Suspense fallback={<LoadingView color={colors.gray[400]} style={styles.base} />}>
{match(route)
.with({ name: "PopupCallback" }, () => <PopupCallbackPage />)
.with({ name: "ProjectLogin" }, ({ params: { sessionExpired } }) =>
projectConfiguration.match({
None: () => <ErrorView />,
Some: ({ projectId }) => (
<ProjectLoginPage
projectId={projectId}
sessionExpired={isNotNullishOrEmpty(sessionExpired)}
/>
),
}),
)
.with({ name: "AccountArea" }, { name: "ProjectRootRedirect" }, route =>
match(route)
.with({ name: "AccountArea" }, ({ params: { accountMembershipId } }) => (
<AccountArea accountMembershipId={accountMembershipId} />
))
.with({ name: "ProjectRootRedirect" }, ({ params: { to, source } }) => (
<ProjectRootRedirect to={to} source={source} />
))
.exhaustive(),
)
.with(P.nullish, () => <NotFoundPage style={styles.base} />)
.exhaustive()}
</Suspense>
</ClientProvider>
{match(route)
// The callback page is agnostic as to the current authentication,
// meaning we don't check if the user is logged in when on this path
.with({ name: "PopupCallback" }, () => <PopupCallbackPage />)
.otherwise(() => (
// The auth check requires a GraphQL client
<ClientContext.Provider value={partnerClient}>
<AppContainer />
<ToastStack />
</ClientContext.Provider>
))}

<ToastStack />
</ErrorBoundary>
Expand Down
Loading

0 comments on commit 71477a9

Please sign in to comment.