-
Notifications
You must be signed in to change notification settings - Fork 5
✨ app: add card limit kyc flow #903
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,6 +33,8 @@ import PortfolioSummary from "./PortfolioSummary"; | |
| import SpendingLimitSheet from "./SpendingLimitSheet"; | ||
| import VisaSignatureBanner from "./VisaSignatureBanner"; | ||
| import VisaSignatureModal from "./VisaSignatureSheet"; | ||
| import { newMessage } from "../../utils/intercom"; | ||
| import { startCardLimitKYC } from "../../utils/persona"; | ||
| import queryClient from "../../utils/queryClient"; | ||
| import reportError from "../../utils/reportError"; | ||
| import { cardModeMutationOptions } from "../../utils/server"; | ||
|
|
@@ -55,7 +57,7 @@ import SafeView from "../shared/SafeView"; | |
| import View from "../shared/View"; | ||
|
|
||
| import type { ActivityItem } from "../../utils/queryClient"; | ||
| import type { CardDetails, KYCStatus } from "../../utils/server"; | ||
| import type { CardActivity, CardDetails, KYCStatus } from "../../utils/server"; | ||
| import type { Credential } from "@exactly/common/validation"; | ||
|
|
||
| const HEALTH_FACTOR_THRESHOLD = (WAD * 11n) / 10n; | ||
|
|
@@ -134,6 +136,20 @@ export default function Home() { | |
| kycStatus && "code" in kycStatus && (kycStatus.code === "ok" || kycStatus.code === "legacy kyc"), | ||
| ); | ||
| const { data: card } = useQuery<CardDetails>({ queryKey: ["card", "details"], enabled: !!account && !!bytecode }); | ||
| const { data: cardActivity } = useQuery<CardActivity[]>({ queryKey: ["activity", "card"] }); | ||
| const { data: cardLimitStatus } = useQuery<KYCStatus>({ queryKey: ["kyc", "cardLimit"], enabled: !!card }); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The new home alert also depends on Useful? React with 👍 / 👎. |
||
| const cardLimitProcessing = cardLimitStatus?.code === "processing"; | ||
| const cardLimitApproved = cardLimitStatus?.code === "ok"; | ||
| const spendingLimitReached = useMemo(() => { | ||
| if (!card?.limit.amount || !cardActivity) return false; | ||
| const limit = card.limit.amount / 100; | ||
|
Comment on lines
+144
to
+145
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This new threshold calculation depends on Useful? React with 👍 / 👎. |
||
| const totalSpent = cardActivity.reduce((sum, item) => { | ||
| if (item.type !== "panda") return sum; | ||
| const elapsed = (Date.now() - new Date(item.timestamp).getTime()) / 1000; | ||
| return elapsed <= 604_800 ? sum + item.usdAmount : sum; | ||
| }, 0); | ||
| return totalSpent / limit >= 0.9; | ||
| }, [card?.limit.amount, cardActivity]); | ||
| const { data: spotlightShown } = useQuery<boolean>({ queryKey: ["settings", "installments-spotlight"] }); | ||
| const toast = useToastController(); | ||
| const { mutate: mutateMode } = useMutation({ | ||
|
|
@@ -210,6 +226,32 @@ export default function Home() { | |
| <View flex={1} gap="$s5" paddingBottom="$s5"> | ||
| <YStack backgroundColor="$backgroundSoft" padding="$s4" gap="$s4"> | ||
| {markets && healthFactor(markets) < HEALTH_FACTOR_THRESHOLD && <LiquidationAlert />} | ||
| {spendingLimitReached && !cardLimitProcessing && ( | ||
| <InfoAlert | ||
| variant="warning" | ||
| title={t("You've reached 90% of your weekly card spending limit.")} | ||
| actionText={t("Increase spending limit")} | ||
| onPress={() => { | ||
| if (cardLimitApproved) newMessage(t("I want to increase my spending limit")).catch(reportError); | ||
| else | ||
| startCardLimitKYC() | ||
| .then((result) => { | ||
| if (result.status === "error") | ||
| toast.show(t("Something went wrong. Please try again."), { | ||
| native: true, | ||
| burntOptions: { haptic: "error", preset: "error" }, | ||
| }); | ||
| }) | ||
| .catch((error: unknown) => { | ||
| reportError(error); | ||
| toast.show(t("Something went wrong. Please try again."), { | ||
| native: true, | ||
| burntOptions: { haptic: "error", preset: "error" }, | ||
| }); | ||
| }); | ||
|
franm91 marked this conversation as resolved.
|
||
| }} | ||
| /> | ||
| )} | ||
| {(showKYCMigration || showPluginOutdated) && ( | ||
| <InfoAlert | ||
| title={t( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the home card-limit alert depends on this new
cardActivityquery, pull-to-refresh still only invalidates['activity']withexact: trueinrefresh(), so['activity', 'card']is never refetched from the home screen. After a recent card purchase or refund, users can refresh Home and continue seeing a stale 90% warning state until another remount/refocus or the Card screen refreshes that query; include this query in the refresh path or avoid the exact invalidation.Useful? React with 👍 / 👎.