Skip to content
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

fix(billing): check for email verified to add funds #535

Merged
merged 3 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class CheckoutController {
const { currentUser } = this.authService;
const redirectUrl = this.billingConfig.STRIPE_CHECKOUT_REDIRECT_URL;

if (!currentUser?.userId) {
if (!currentUser?.userId || !currentUser?.emailVerified) {
return c.redirect(`${redirectUrl}?unauthorized=true`);
}

Expand Down
45 changes: 27 additions & 18 deletions apps/deploy-web/src/components/get-started/GetStartedStepper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { browserEnvConfig } from "@src/config/browser-env.config";
import { useChainParam } from "@src/context/ChainParamProvider";
import { useWallet } from "@src/context/WalletProvider";
import { useCustomUser } from "@src/hooks/useCustomUser";
import { useIsEmailVerified } from "@src/hooks/useRequiredEmailVerified";
import { useWalletBalance } from "@src/hooks/useWalletBalance";
import walletStore from "@src/store/walletStore";
import { RouteStep } from "@src/types/route-steps.type";
Expand All @@ -26,6 +27,7 @@ import { uaktToAKT } from "@src/utils/priceUtils";
import { UrlService } from "@src/utils/urlUtils";
import LiquidityModal from "../liquidity-modal";
import { ExternalLink } from "../shared/ExternalLink";
import { VerifyEmail } from "../shared/VerifyEmail";
import { ConnectWalletButton } from "../wallet/ConnectWalletButton";
import { QontoConnector, QontoStepIcon } from "./Stepper";

Expand All @@ -38,6 +40,7 @@ export const GetStartedStepper: React.FunctionComponent = () => {
const usdcBalance = walletBalance ? udenomToDenom(walletBalance.balanceUUSDC) : 0;
const [isSignedInWithTrial] = useAtom(walletStore.isSignedInWithTrial);
const { user } = useCustomUser();
const isEmailVerified = useIsEmailVerified();

useEffect(() => {
const getStartedStep = localStorage.getItem("getStartedStep");
Expand Down Expand Up @@ -104,27 +107,33 @@ export const GetStartedStepper: React.FunctionComponent = () => {

<div className="my-4 flex items-center space-x-4">
{isManagedWallet && (
<TopUpAmountPicker popoverClassName="absolute md:min-w-max" mdMode="hover">
<LoginRequiredLink
className={cn("hover:no-underline", buttonVariants({ variant: "outline", className: "mr-2 border-primary" }))}
href="/api/proxy/v1/checkout"
message="Sign In or Sign Up to add funds to your balance"
>
<HandCard className="text-xs text-accent-foreground" />
<span className="m-2 whitespace-nowrap text-accent-foreground">Add Funds</span>
</LoginRequiredLink>
</TopUpAmountPicker>
)}
<Button variant="default" onClick={handleNext}>
Next
</Button>
{!isManagedWallet && (
<Link className={cn(buttonVariants({ variant: "text" }))} href={UrlService.getStartedWallet()}>
Learn how
</Link>
<div className="flex flex-col items-start space-y-2">
<VerifyEmail />

<TopUpAmountPicker popoverClassName="absolute md:min-w-max" mdMode="hover">
<LoginRequiredLink
className={cn("hover:no-underline", buttonVariants({ variant: "outline", className: "mr-2 border-primary" }))}
href="/api/proxy/v1/checkout"
message="Sign In or Sign Up to add funds to your balance"
disabled={!isEmailVerified}
>
<HandCard className="text-xs text-accent-foreground" />
<span className="m-2 whitespace-nowrap text-accent-foreground">Add Funds</span>
</LoginRequiredLink>
</TopUpAmountPicker>
</div>
)}
</div>

<Button variant="default" onClick={handleNext}>
Next
</Button>
{!isManagedWallet && (
<Link className={cn(buttonVariants({ variant: "text" }))} href={UrlService.getStartedWallet()}>
Learn how
</Link>
)}

{isWalletConnected && isTrialing && (
<div className="my-4 flex items-center space-x-2">
<Check className="text-green-600" />
Expand Down
27 changes: 17 additions & 10 deletions apps/deploy-web/src/components/home/YourAccount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { UAKT_DENOM } from "@src/config/denom.config";
import { usePricing } from "@src/context/PricingProvider";
import { useWallet } from "@src/context/WalletProvider";
import { useUsdcDenom } from "@src/hooks/useDenom";
import { useIsEmailVerified } from "@src/hooks/useRequiredEmailVerified";
import useTailwind from "@src/hooks/useTailwind";
import { WalletBalance } from "@src/hooks/useWalletBalance";
import sdlStore from "@src/store/sdlStore";
Expand All @@ -30,6 +31,7 @@ import { ConnectWallet } from "../shared/ConnectWallet";
import { LeaseSpecDetail } from "../shared/LeaseSpecDetail";
import { PriceValue } from "../shared/PriceValue";
import { StatusPill } from "../shared/StatusPill";
import { VerifyEmail } from "../shared/VerifyEmail";

type Props = {
isLoadingBalances: boolean;
Expand All @@ -56,6 +58,7 @@ export const YourAccount: React.FunctionComponent<Props> = ({ isLoadingBalances,
const _storage = bytesToShrink(totalStorage);
const [, setDeploySdl] = useAtom(sdlStore.deploySdl);
const { price, isLoaded } = usePricing();
const isEmailVerified = useIsEmailVerified();

const colors = {
balance_akt: customColors.akashRed,
Expand Down Expand Up @@ -230,16 +233,20 @@ export const YourAccount: React.FunctionComponent<Props> = ({ isLoadingBalances,
</Link>
)}
{isManagedWallet && (
<TopUpAmountPicker className="mt-4 inline-flex flex-col" mdMode="hover">
<LoginRequiredLink
className={cn(buttonVariants({ variant: "default" }))}
href="/api/proxy/v1/checkout"
message="Sign In or Sign Up to add funds to your balance"
>
Add Funds
<HandCard className="ml-4 rotate-45 text-sm" />
</LoginRequiredLink>
</TopUpAmountPicker>
<>
<VerifyEmail className="mt-4" />
<TopUpAmountPicker className="mt-4 inline-flex flex-col" mdMode="hover">
<LoginRequiredLink
className={cn(buttonVariants({ variant: "default" }))}
href="/api/proxy/v1/checkout"
message="Sign In or Sign Up to add funds to your balance"
disabled={!isEmailVerified}
>
Add Funds
<HandCard className="ml-4 rotate-45 text-sm" />
</LoginRequiredLink>
</TopUpAmountPicker>
</>
)}
</div>

Expand Down
20 changes: 20 additions & 0 deletions apps/deploy-web/src/components/shared/VerifyEmail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Alert, AlertDescription } from "@akashnetwork/ui/components";
import { cn } from "@akashnetwork/ui/utils";
import { WarningCircle } from "iconoir-react";

import { useIsEmailVerified } from "@src/hooks/useRequiredEmailVerified";

export const VerifyEmail = ({ className }: { className?: string }) => {
const isEmailVerified = useIsEmailVerified();

if (isEmailVerified) return null;

return (
<Alert variant="warning" className={className}>
<AlertDescription className="flex items-center space-x-2">
<WarningCircle className="text-lg" />
<span>Verify your email to add funds to your balance.</span>
</AlertDescription>
</Alert>
);
};
10 changes: 9 additions & 1 deletion apps/deploy-web/src/components/user/LoginRequiredLink.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from "react";
import { Button } from "@akashnetwork/ui/components";
import Link, { LinkProps } from "next/link";

import { useLoginRequiredEventHandler } from "@src/hooks/useLoginRequiredEventHandler";
Expand All @@ -9,8 +10,15 @@ export const LoginRequiredLink: FCWithChildren<
LinkProps & {
children?: React.ReactNode;
message: string;
disabled?: boolean;
} & React.RefAttributes<HTMLAnchorElement>
> = ({ message, ...props }) => {
const whenLoggedIn = useLoginRequiredEventHandler();
return <Link {...props} onClick={whenLoggedIn(props.onClick || (() => {}), message)} />;
return props.disabled ? (
<Button className={props.className} disabled>
{props.children}
</Button>
) : (
<Link {...props} onClick={whenLoggedIn(props.onClick || (() => {}), message)} />
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ import { TopUpAmountPicker } from "@src/components/top-up-amount-picker/TopUpAmo
import { useWallet } from "@src/context/WalletProvider";
import { useLoginRequiredEventHandler } from "@src/hooks/useLoginRequiredEventHandler";
import { useManagedEscrowFaqModal } from "@src/hooks/useManagedEscrowFaqModal";
import { useIsEmailVerified } from "@src/hooks/useRequiredEmailVerified";
import { WalletBalance } from "@src/hooks/useWalletBalance";
import { LinkTo } from "../shared/LinkTo";
import { VerifyEmail } from "../shared/VerifyEmail";

interface ManagedWalletPopupProps extends React.PropsWithChildren {
walletBalance: WalletBalance;
}

export const ManagedWalletPopup: React.FC<ManagedWalletPopupProps> = ({ walletBalance }) => {
const isEmailVerified = useIsEmailVerified();
const { switchWalletType, isManaged, isTrialing } = useWallet();
const whenLoggedIn = useLoginRequiredEventHandler();
const { showManagedEscrowFaqModal } = useManagedEscrowFaqModal();
Expand Down Expand Up @@ -71,8 +74,10 @@ export const ManagedWalletPopup: React.FC<ManagedWalletPopupProps> = ({ walletBa
)}

<div className="flex flex-col items-center justify-end space-y-2 pt-2">
<VerifyEmail />

<TopUpAmountPicker mdMode="click" className="w-full">
<Button onClick={whenLoggedIn(goToCheckout, "Sign In or Sign Up to add funds")} variant="outline" className="w-full space-x-2">
<Button onClick={whenLoggedIn(goToCheckout, "Sign In or Sign Up to add funds")} variant="outline" className="w-full space-x-2" disabled={!isEmailVerified}>
<HandCard />
<span>Add Funds</span>
</Button>
Expand Down
5 changes: 4 additions & 1 deletion apps/deploy-web/src/hooks/useHasCreditCardBanner.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useEffect, useMemo, useState } from "react";
import { useAtom } from "jotai";

import { browserEnvConfig } from "@src/config/browser-env.config";
import { useWallet } from "@src/context/WalletProvider";
import walletStore from "@src/store/walletStore";
import { useUser } from "./useUser";

const withBilling = browserEnvConfig.NEXT_PUBLIC_BILLING_ENABLED;
Expand All @@ -11,8 +13,9 @@ export function useHasCreditCardBanner() {
const [isBannerVisible, setIsBannerVisible] = useState(false);
const [isInitialized, setIsInitialized] = useState(false);
const { hasManagedWallet, isWalletLoading } = useWallet();
const [isSignedInWithTrial] = useAtom(walletStore.isSignedInWithTrial);
const shouldShowBanner = useMemo(
() => isInitialized && withBilling && !hasManagedWallet && !isWalletLoading,
() => isInitialized && withBilling && !hasManagedWallet && !isWalletLoading && !isSignedInWithTrial,
[isInitialized, hasManagedWallet, isWalletLoading]
);

Expand Down
6 changes: 6 additions & 0 deletions apps/deploy-web/src/hooks/useRequiredEmailVerified.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { useCustomUser } from "./useCustomUser";

export const useIsEmailVerified = () => {
const { user } = useCustomUser();
return !user || !!user?.emailVerified;
};
4 changes: 0 additions & 4 deletions apps/deploy-web/src/pages/api/auth/[...auth0].ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export default handleAuth({
refetch: true,
afterRefetch: async (req, res, session) => {
try {
// TODO: Fix for console
const user_metadata = session.user["https://console.akash.network/user_metadata"];
const headers = new AxiosHeaders({
Authorization: `Bearer ${session.accessToken}`
Expand All @@ -45,9 +44,6 @@ export default handleAuth({
}
);

// session.user["user_metadata"] = { ...session.user["https://console.akash.network/user_metadata"] };
// delete session.user["https://console.akash.network/user_metadata"];

session.user = { ...session.user, ...userSettings.data };
} catch (err) {
console.error(err);
Expand Down
Loading