mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-19 07:17:00 +08:00
feat: support sign-in with subscription coupon (#5768)
This commit is contained in:
@@ -23,6 +23,7 @@ import type { AuthPanelProps } from './index';
|
||||
import * as style from './style.css';
|
||||
import { INTERNAL_BETA_URL, useAuth } from './use-auth';
|
||||
import { Captcha, useCaptcha } from './use-captcha';
|
||||
import { useSubscriptionSearch } from './use-subscription';
|
||||
|
||||
function validateEmail(email: string) {
|
||||
return emailRegex.test(email);
|
||||
@@ -37,6 +38,7 @@ export const SignIn: FC<AuthPanelProps> = ({
|
||||
const t = useAFFiNEI18N();
|
||||
const loginStatus = useCurrentLoginStatus();
|
||||
const [verifyToken, challenge] = useCaptcha();
|
||||
const subscriptionData = useSubscriptionSearch();
|
||||
|
||||
const {
|
||||
isMutating: isSigningIn,
|
||||
@@ -83,7 +85,8 @@ export const SignIn: FC<AuthPanelProps> = ({
|
||||
if (verifyToken) {
|
||||
if (user) {
|
||||
// provider password sign-in if user has by default
|
||||
if (user.hasPassword) {
|
||||
// If with payment, onl support email sign in to avoid redirect to affine app
|
||||
if (user.hasPassword && !subscriptionData) {
|
||||
setAuthState('signInWithPassword');
|
||||
} else {
|
||||
const res = await signIn(email, verifyToken, challenge);
|
||||
@@ -103,6 +106,7 @@ export const SignIn: FC<AuthPanelProps> = ({
|
||||
}
|
||||
}
|
||||
}, [
|
||||
subscriptionData,
|
||||
challenge,
|
||||
email,
|
||||
setAuthEmail,
|
||||
|
||||
@@ -3,10 +3,10 @@ import { Button } from '@affine/component/ui/button';
|
||||
import { Loading } from '@affine/component/ui/loading';
|
||||
import { AffineShapeIcon } from '@affine/core/components/page-list';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import type { SubscriptionRecurring } from '@affine/graphql';
|
||||
import type { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql';
|
||||
import {
|
||||
changePasswordMutation,
|
||||
checkoutMutation,
|
||||
createCheckoutSessionMutation,
|
||||
subscriptionQuery,
|
||||
} from '@affine/graphql';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
@@ -30,18 +30,25 @@ const usePaymentRedirect = () => {
|
||||
}
|
||||
|
||||
const recurring = searchData.recurring as SubscriptionRecurring;
|
||||
const plan = searchData.plan as SubscriptionPlan;
|
||||
const coupon = searchData.coupon;
|
||||
const idempotencyKey = useMemo(() => nanoid(), []);
|
||||
const { trigger: checkoutSubscription } = useMutation({
|
||||
mutation: checkoutMutation,
|
||||
mutation: createCheckoutSessionMutation,
|
||||
});
|
||||
|
||||
return useAsyncCallback(async () => {
|
||||
const { checkout } = await checkoutSubscription({
|
||||
recurring,
|
||||
idempotencyKey,
|
||||
const { createCheckoutSession: checkoutUrl } = await checkoutSubscription({
|
||||
input: {
|
||||
recurring,
|
||||
plan,
|
||||
coupon,
|
||||
idempotencyKey,
|
||||
successCallbackLink: null,
|
||||
},
|
||||
});
|
||||
window.open(checkout, '_self', 'norefferer');
|
||||
}, [recurring, idempotencyKey, checkoutSubscription]);
|
||||
window.open(checkoutUrl, '_self', 'norefferer');
|
||||
}, [recurring, plan, coupon, idempotencyKey, checkoutSubscription]);
|
||||
};
|
||||
|
||||
const CenterLoading = () => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useSearchParams } from 'react-router-dom';
|
||||
enum SubscriptionKey {
|
||||
Recurring = 'subscription_recurring',
|
||||
Plan = 'subscription_plan',
|
||||
Coupon = 'coupon',
|
||||
SignUp = 'sign_up', // A new user with subscription journey: signup > set password > pay in stripe > go to app
|
||||
Token = 'token', // When signup, there should have a token to set password
|
||||
}
|
||||
@@ -22,11 +23,13 @@ export function useSubscriptionSearch() {
|
||||
|
||||
const recurring = searchParams.get(SubscriptionKey.Recurring);
|
||||
const plan = searchParams.get(SubscriptionKey.Plan);
|
||||
const coupon = searchParams.get(SubscriptionKey.Coupon);
|
||||
const withSignUp = searchParams.get(SubscriptionKey.SignUp) === '1';
|
||||
const passwordToken = searchParams.get(SubscriptionKey.Token);
|
||||
return {
|
||||
recurring,
|
||||
plan,
|
||||
coupon,
|
||||
withSignUp,
|
||||
passwordToken,
|
||||
getRedirectUrl(signUp?: boolean) {
|
||||
@@ -35,6 +38,10 @@ export function useSubscriptionSearch() {
|
||||
[SubscriptionKey.Plan, plan ?? ''],
|
||||
]);
|
||||
|
||||
if (coupon) {
|
||||
paymentParams.set(SubscriptionKey.Coupon, coupon);
|
||||
}
|
||||
|
||||
if (signUp) {
|
||||
paymentParams.set(SubscriptionKey.SignUp, '1');
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import type {
|
||||
SubscriptionMutator,
|
||||
} from '@affine/core/hooks/use-subscription';
|
||||
import {
|
||||
checkoutMutation,
|
||||
createCheckoutSessionMutation,
|
||||
SubscriptionPlan,
|
||||
SubscriptionRecurring,
|
||||
SubscriptionStatus,
|
||||
@@ -359,7 +359,7 @@ const Upgrade = ({
|
||||
}) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const { isMutating, trigger } = useMutation({
|
||||
mutation: checkoutMutation,
|
||||
mutation: createCheckoutSessionMutation,
|
||||
});
|
||||
|
||||
const newTabRef = useRef<Window | null>(null);
|
||||
@@ -383,13 +383,21 @@ const Upgrade = ({
|
||||
newTabRef.current.focus();
|
||||
} else {
|
||||
await trigger(
|
||||
{ recurring, idempotencyKey },
|
||||
{
|
||||
input: {
|
||||
recurring,
|
||||
idempotencyKey,
|
||||
plan: SubscriptionPlan.Pro, // Only support prod plan now.
|
||||
coupon: null,
|
||||
successCallbackLink: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
onSuccess: data => {
|
||||
// FIXME: safari prevents from opening new tab by window api
|
||||
// TODO(@xp): what if electron?
|
||||
const newTab = window.open(
|
||||
data.checkout,
|
||||
data.createCheckoutSession,
|
||||
'_blank',
|
||||
'noopener noreferrer'
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user