fix: stripe connect atom for teams (#17294)
* add teamId * add team app credentials method * add handler to get all user admin teams * update stripe logic to handle teams * enable teamId for stripe connect * update stripe module * implement PR feedback * update stripe module * add method to get credential by team id * handle check for teamId * abstract team and individual stripe connection checks into two separate parts * hide badge for platform user * update typing * add logic to handle team stripe integration * bump platform libraries * bump platform libraries --------- Co-authored-by: Morgan Vernay <morgan@cal.com> Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
This commit is contained in:
co-authored by
Morgan Vernay
Morgan
parent
aaa5531a3a
commit
c3f03c8000
@@ -28,7 +28,7 @@
|
||||
"dependencies": {
|
||||
"@calcom/platform-constants": "*",
|
||||
"@calcom/platform-enums": "*",
|
||||
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.54",
|
||||
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.56",
|
||||
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2",
|
||||
"@calcom/platform-types": "*",
|
||||
"@calcom/platform-utils": "*",
|
||||
|
||||
@@ -21,4 +21,15 @@ export class AppsRepository {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async createTeamAppCredential(type: string, key: Prisma.InputJsonValue, teamId: number, appId: string) {
|
||||
return this.dbWrite.prisma.credential.create({
|
||||
data: {
|
||||
type: type,
|
||||
key: key,
|
||||
teamId: teamId,
|
||||
appId: appId,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,10 @@ export class CredentialsRepository {
|
||||
return this.dbWrite.prisma.credential.findFirst({ where: { type, userId } });
|
||||
}
|
||||
|
||||
getByTypeAndTeamId(type: string, teamId: number) {
|
||||
return this.dbWrite.prisma.credential.findFirst({ where: { type, teamId } });
|
||||
}
|
||||
|
||||
getAllUserCredentialsByTypeAndId(type: string, userId: number) {
|
||||
return this.dbRead.prisma.credential.findMany({ where: { type, userId } });
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
Req,
|
||||
BadRequestException,
|
||||
Headers,
|
||||
Param,
|
||||
} from "@nestjs/common";
|
||||
import { ApiTags as DocsTags, ApiOperation } from "@nestjs/swagger";
|
||||
import { plainToClass } from "class-transformer";
|
||||
@@ -46,7 +47,8 @@ export class StripeController {
|
||||
@Headers("Authorization") authorization: string,
|
||||
@GetUser() user: UserWithProfile,
|
||||
@Query("redir") redir?: string | null,
|
||||
@Query("errorRedir") errorRedir?: string | null
|
||||
@Query("errorRedir") errorRedir?: string | null,
|
||||
@Query("teamId") teamId?: string | null
|
||||
): Promise<StripConnectOutputResponseDto> {
|
||||
const origin = req.headers.origin;
|
||||
const accessToken = authorization.replace("Bearer ", "");
|
||||
@@ -56,6 +58,7 @@ export class StripeController {
|
||||
fromApp: false,
|
||||
returnTo: !!redir ? redir : origin,
|
||||
accessToken,
|
||||
teamId: Number(teamId) ?? null,
|
||||
};
|
||||
|
||||
const stripeRedirectUrl = await this.stripeService.getStripeRedirectUrl(
|
||||
@@ -99,6 +102,16 @@ export class StripeController {
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: "Check stripe connection" })
|
||||
async check(@GetUser() user: UserWithProfile): Promise<StripCredentialsCheckOutputResponseDto> {
|
||||
return await this.stripeService.checkIfStripeAccountConnected(user.id);
|
||||
return await this.stripeService.checkIfIndividualStripeAccountConnected(user.id);
|
||||
}
|
||||
|
||||
@Get("/check/:teamId")
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: "Check team stripe connection" })
|
||||
async checkTeamStripeConnection(
|
||||
@Param("teamId") teamId: string
|
||||
): Promise<StripCredentialsCheckOutputResponseDto> {
|
||||
return await this.stripeService.checkIfTeamStripeAccountConnected(Number(teamId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { AppsRepository } from "@/modules/apps/apps.repository";
|
||||
import { CredentialsRepository } from "@/modules/credentials/credentials.repository";
|
||||
import { MembershipsRepository } from "@/modules/memberships/memberships.repository";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { StripeController } from "@/modules/stripe/controllers/stripe.controller";
|
||||
import { StripeService } from "@/modules/stripe/stripe.service";
|
||||
@@ -10,7 +11,7 @@ import { ConfigModule } from "@nestjs/config";
|
||||
@Module({
|
||||
imports: [ConfigModule, PrismaModule],
|
||||
exports: [StripeService],
|
||||
providers: [StripeService, AppsRepository, CredentialsRepository, TokensRepository],
|
||||
providers: [StripeService, AppsRepository, CredentialsRepository, TokensRepository, MembershipsRepository],
|
||||
controllers: [StripeController],
|
||||
})
|
||||
export class StripeModule {}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { AppConfig } from "@/config/type";
|
||||
import { AppsRepository } from "@/modules/apps/apps.repository";
|
||||
import { CredentialsRepository } from "@/modules/credentials/credentials.repository";
|
||||
import { MembershipsRepository } from "@/modules/memberships/memberships.repository";
|
||||
import { getReturnToValueFromQueryState } from "@/modules/stripe/utils/getReturnToValueFromQueryState";
|
||||
import { stripeInstance } from "@/modules/stripe/utils/newStripeInstance";
|
||||
import { StripeData } from "@/modules/stripe/utils/stripeDataSchemas";
|
||||
import { TokensRepository } from "@/modules/tokens/tokens.repository";
|
||||
import { Injectable, NotFoundException, BadRequestException, UnauthorizedException } from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import type { Prisma } from "@prisma/client";
|
||||
import type { Prisma, Credential } from "@prisma/client";
|
||||
import Stripe from "stripe";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -17,6 +18,14 @@ import { stripeKeysResponseSchema } from "./utils/stripeDataSchemas";
|
||||
|
||||
import stringify = require("qs-stringify");
|
||||
|
||||
type IntegrationOAuthCallbackState = {
|
||||
accessToken: string;
|
||||
returnTo: string;
|
||||
onErrorReturnTo: string;
|
||||
fromApp: boolean;
|
||||
teamId?: number | null;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class StripeService {
|
||||
public stripe: Stripe;
|
||||
@@ -27,7 +36,8 @@ export class StripeService {
|
||||
private readonly config: ConfigService,
|
||||
private readonly appsRepository: AppsRepository,
|
||||
private readonly credentialRepository: CredentialsRepository,
|
||||
private readonly tokensRepository: TokensRepository
|
||||
private readonly tokensRepository: TokensRepository,
|
||||
private readonly membershipRepository: MembershipsRepository
|
||||
) {
|
||||
this.stripe = new Stripe(configService.get("stripe.apiKey", { infer: true }) ?? "", {
|
||||
apiVersion: "2020-08-27",
|
||||
@@ -76,6 +86,7 @@ export class StripeService {
|
||||
|
||||
async saveStripeAccount(state: string, code: string, accessToken: string): Promise<{ url: string }> {
|
||||
const userId = await this.tokensRepository.getAccessTokenOwnerId(accessToken);
|
||||
const oAuthCallbackState: IntegrationOAuthCallbackState = JSON.parse(state);
|
||||
|
||||
if (!userId) {
|
||||
throw new UnauthorizedException("Invalid Access token.");
|
||||
@@ -92,6 +103,19 @@ export class StripeService {
|
||||
data["default_currency"] = account.default_currency;
|
||||
}
|
||||
|
||||
if (oAuthCallbackState.teamId) {
|
||||
await this.checkIfUserHasAdminAccessToTeam(oAuthCallbackState.teamId, userId);
|
||||
|
||||
await this.appsRepository.createTeamAppCredential(
|
||||
"stripe_payment",
|
||||
data as unknown as Prisma.InputJsonObject,
|
||||
oAuthCallbackState.teamId,
|
||||
"stripe"
|
||||
);
|
||||
|
||||
return { url: getReturnToValueFromQueryState(state) };
|
||||
}
|
||||
|
||||
await this.appsRepository.createAppCredential(
|
||||
"stripe_payment",
|
||||
data as unknown as Prisma.InputJsonObject,
|
||||
@@ -102,18 +126,39 @@ export class StripeService {
|
||||
return { url: getReturnToValueFromQueryState(state) };
|
||||
}
|
||||
|
||||
async checkIfStripeAccountConnected(userId: number): Promise<{ status: typeof SUCCESS_STATUS }> {
|
||||
async checkIfIndividualStripeAccountConnected(userId: number): Promise<{ status: typeof SUCCESS_STATUS }> {
|
||||
const stripeCredentials = await this.credentialRepository.getByTypeAndUserId("stripe_payment", userId);
|
||||
|
||||
if (!stripeCredentials) {
|
||||
return await this.validateStripeCredentials(stripeCredentials);
|
||||
}
|
||||
|
||||
async checkIfTeamStripeAccountConnected(teamId: number): Promise<{ status: typeof SUCCESS_STATUS }> {
|
||||
const stripeCredentials = await this.credentialRepository.getByTypeAndTeamId("stripe_payment", teamId);
|
||||
|
||||
return await this.validateStripeCredentials(stripeCredentials);
|
||||
}
|
||||
|
||||
async checkIfUserHasAdminAccessToTeam(teamId: number, userId: number) {
|
||||
const teamMembership = await this.membershipRepository.findMembershipByTeamId(teamId, userId);
|
||||
const hasAdminAccessToTeam = teamMembership?.role === "ADMIN" || teamMembership?.role === "OWNER";
|
||||
|
||||
if (!hasAdminAccessToTeam) {
|
||||
throw new BadRequestException("You must be team owner or admin to do this");
|
||||
}
|
||||
}
|
||||
|
||||
async validateStripeCredentials(
|
||||
credentials?: Credential | null
|
||||
): Promise<{ status: typeof SUCCESS_STATUS }> {
|
||||
if (!credentials) {
|
||||
throw new NotFoundException("Credentials for stripe not found.");
|
||||
}
|
||||
|
||||
if (stripeCredentials.invalid) {
|
||||
if (credentials.invalid) {
|
||||
throw new BadRequestException("Invalid stripe credentials.");
|
||||
}
|
||||
|
||||
const stripeKey = JSON.stringify(stripeCredentials.key);
|
||||
const stripeKey = JSON.stringify(credentials.key);
|
||||
const stripeKeyObject = JSON.parse(stripeKey);
|
||||
|
||||
const stripeAccount = await stripeInstance.accounts.retrieve(stripeKeyObject?.stripe_user_id);
|
||||
|
||||
@@ -81,7 +81,7 @@ export default function AppCard({
|
||||
</p>
|
||||
</div>
|
||||
<div className="ml-auto flex items-center space-x-2">
|
||||
{app.credentialOwner && (
|
||||
{app.credentialOwner && !isPlatform && (
|
||||
<div className="ml-auto">
|
||||
<Badge variant="gray">
|
||||
<div className="flex items-center">
|
||||
|
||||
@@ -6,12 +6,13 @@ import type { IconName } from "@calcom/ui";
|
||||
import type { ButtonColor } from "@calcom/ui";
|
||||
|
||||
import type { OnCheckErrorType, UseCheckProps } from "../../hooks/connect/useCheck";
|
||||
import { useCheck } from "../../hooks/stripe/useCheck";
|
||||
import { useTeamCheck, useCheck } from "../../hooks/stripe/useCheck";
|
||||
import { useConnect } from "../../hooks/stripe/useConnect";
|
||||
import { AtomsWrapper } from "../../src/components/atoms-wrapper";
|
||||
import { cn } from "../../src/lib/utils";
|
||||
|
||||
type StripeConnectProps = {
|
||||
teamId?: number | null;
|
||||
icon?: IconName;
|
||||
color?: ButtonColor;
|
||||
isClickable?: boolean;
|
||||
@@ -27,6 +28,7 @@ type StripeConnectProps = {
|
||||
};
|
||||
|
||||
export const StripeConnect: FC<Partial<StripeConnectProps>> = ({
|
||||
teamId,
|
||||
icon,
|
||||
color,
|
||||
isClickable,
|
||||
@@ -41,17 +43,25 @@ export const StripeConnect: FC<Partial<StripeConnectProps>> = ({
|
||||
onCheckSuccess,
|
||||
}) => {
|
||||
const { t } = useLocale();
|
||||
const { connect } = useConnect(redir, errorRedir);
|
||||
let displayedLabel = label || t("stripe_connect_atom_label");
|
||||
|
||||
const { connect } = useConnect(redir, errorRedir, teamId);
|
||||
const { allowConnect, checked } = useCheck({
|
||||
onCheckError,
|
||||
onCheckSuccess,
|
||||
initialData,
|
||||
});
|
||||
const { allowConnect: allowConnectTeam, checked: checkedTeam } = useTeamCheck({
|
||||
teamId,
|
||||
onCheckError,
|
||||
onCheckSuccess,
|
||||
initialData,
|
||||
});
|
||||
|
||||
let displayedLabel = label || t("stripe_connect_atom_label");
|
||||
const isChecking = teamId ? !checkedTeam : !checked;
|
||||
const isAllowConnect = teamId ? allowConnectTeam : allowConnect;
|
||||
|
||||
const isChecking = !checked;
|
||||
const isDisabled = isChecking || !allowConnect;
|
||||
const isDisabled = isChecking || !isAllowConnect;
|
||||
|
||||
if (isChecking) {
|
||||
displayedLabel = loadingLabel || t("stripe_connect_atom_loading_label");
|
||||
|
||||
@@ -1,22 +1,34 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import type { CredentialDataWithTeamName, LocationOption } from "@calcom/app-store/utils";
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import type { App, CredentialDataWithTeamName, LocationOption } from "@calcom/platform-libraries-1.2.3";
|
||||
import type { ApiResponse } from "@calcom/platform-types";
|
||||
import type { App } from "@calcom/types/App";
|
||||
|
||||
import { useAtomsContext } from "../../hooks/useAtomsContext";
|
||||
import http from "../../lib/http";
|
||||
|
||||
type UserTeams =
|
||||
| []
|
||||
| {
|
||||
teamId: number;
|
||||
name: string;
|
||||
logoUrl: string | null;
|
||||
credentialId: number;
|
||||
isAdmin: boolean;
|
||||
}[];
|
||||
|
||||
type EnabledAppType = App & {
|
||||
credential: CredentialDataWithTeamName;
|
||||
credentials: CredentialDataWithTeamName[];
|
||||
userCredentialIds: number[];
|
||||
locationOption: LocationOption | null;
|
||||
teams: UserTeams;
|
||||
};
|
||||
|
||||
export const QUERY_KEY = "use-event-app-integration";
|
||||
export const useAtomsEventTypeById = (appSlug: string | null) => {
|
||||
const pathname = `/atoms/event-types-app/${appSlug}`;
|
||||
export const useAtomsEventTypeById = (appSlug: string | null, teamId: number | null) => {
|
||||
const pathname = `/atoms/event-types-app/${appSlug}${teamId ? `?teamId=${teamId}` : ""}`;
|
||||
const { isInit, accessToken } = useAtomsContext();
|
||||
|
||||
return useQuery({
|
||||
|
||||
@@ -9,12 +9,19 @@ import useAppsData from "@calcom/lib/hooks/useAppsData";
|
||||
import { EmptyScreen } from "@calcom/ui";
|
||||
|
||||
import { StripeConnect } from "../../connect/stripe/StripeConnect";
|
||||
import { useCheck } from "../../hooks/stripe/useCheck";
|
||||
import { useCheck, useTeamCheck } from "../../hooks/stripe/useCheck";
|
||||
import { useAtomsEventTypeById } from "../hooks/useAtomEventTypeAppIntegration";
|
||||
|
||||
const EventPaymentsTabPlatformWrapper = ({ eventType }: { eventType: EventTypeSetupProps["eventType"] }) => {
|
||||
const { allowConnect, checked } = useCheck({});
|
||||
const isStripeConnected = !checked || !allowConnect;
|
||||
const { allowConnect: allowConnectTeam, checked: checkedTeam } = useTeamCheck({ teamId: eventType.teamId });
|
||||
|
||||
const isAllowConnect = eventType.teamId ? allowConnectTeam : allowConnect;
|
||||
const isChecking = eventType.teamId ? !checkedTeam : !checked;
|
||||
|
||||
const isStripeConnected = isChecking || !isAllowConnect;
|
||||
|
||||
if (isChecking) return <div>Checking...</div>;
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -25,6 +32,7 @@ const EventPaymentsTabPlatformWrapper = ({ eventType }: { eventType: EventTypeSe
|
||||
description="You need to connect Stripe to use this feature. Pleae click on the button below to connect."
|
||||
buttonRaw={
|
||||
<StripeConnect
|
||||
teamId={eventType.teamId}
|
||||
label="Connect to Stripe"
|
||||
loadingLabel="Connect to Stripe"
|
||||
alreadyConnectedLabel="Connect to Stripe"
|
||||
@@ -43,8 +51,7 @@ const EventPaymentsTabPlatformWrapper = ({ eventType }: { eventType: EventTypeSe
|
||||
|
||||
const StripeAppCard = ({ eventType }: { eventType: EventTypeSetupProps["eventType"] }) => {
|
||||
const { getAppDataGetter, getAppDataSetter, eventTypeFormMetadata } = useAppsData();
|
||||
const { data: stripeData, isLoading } = useAtomsEventTypeById("stripe");
|
||||
|
||||
const { data: stripeData, isLoading } = useAtomsEventTypeById("stripe", eventType.teamId);
|
||||
const transformedAppData = {
|
||||
...stripeData?.app,
|
||||
logo: `https://app.cal.com${stripeData?.app.logo}`,
|
||||
@@ -52,21 +59,50 @@ const StripeAppCard = ({ eventType }: { eventType: EventTypeSetupProps["eventTyp
|
||||
|
||||
if (isLoading || !stripeData) return null;
|
||||
|
||||
return (
|
||||
<div>
|
||||
if (!!transformedAppData.teams && transformedAppData.teams.length > 0) {
|
||||
const eventTypeAssociatedTeam = transformedAppData.teams.find((team) => team.teamId === eventType.teamId);
|
||||
|
||||
if (!eventTypeAssociatedTeam) return null;
|
||||
|
||||
return (
|
||||
<EventTypeAppCard
|
||||
getAppData={getAppDataGetter(transformedAppData.slug as EventTypeAppsList)}
|
||||
setAppData={getAppDataSetter(
|
||||
transformedAppData.slug as EventTypeAppsList,
|
||||
transformedAppData.categories as string[],
|
||||
transformedAppData.userCredentialIds && (transformedAppData.userCredentialIds[0] as number)
|
||||
eventTypeAssociatedTeam.credentialId
|
||||
)}
|
||||
key={transformedAppData.slug}
|
||||
app={transformedAppData as EventTypeApp}
|
||||
key={(transformedAppData.slug ?? stripeData.app.slug) + eventTypeAssociatedTeam.credentialId}
|
||||
app={
|
||||
{
|
||||
...transformedAppData,
|
||||
credentialOwner: {
|
||||
name: eventTypeAssociatedTeam.name,
|
||||
avatar: eventTypeAssociatedTeam.logoUrl,
|
||||
teamId: eventTypeAssociatedTeam.teamId,
|
||||
credentialId: eventTypeAssociatedTeam.credentialId,
|
||||
},
|
||||
} as unknown as EventTypeApp
|
||||
}
|
||||
eventType={eventType as unknown as EventTypeForAppCard}
|
||||
eventTypeFormMetadata={eventTypeFormMetadata}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EventTypeAppCard
|
||||
getAppData={getAppDataGetter(transformedAppData.slug as EventTypeAppsList)}
|
||||
setAppData={getAppDataSetter(
|
||||
transformedAppData.slug as EventTypeAppsList,
|
||||
transformedAppData.categories as string[],
|
||||
transformedAppData.userCredentialIds && (transformedAppData.userCredentialIds[0] as number)
|
||||
)}
|
||||
key={transformedAppData.slug}
|
||||
app={transformedAppData as unknown as EventTypeApp}
|
||||
eventType={eventType as unknown as EventTypeForAppCard}
|
||||
eventTypeFormMetadata={eventTypeFormMetadata}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ export interface UseCheckProps {
|
||||
};
|
||||
}
|
||||
const stripeQueryKey = ["get-stripe-check"];
|
||||
const stripeTeamQueryKey = ["get-stripe-team-check"];
|
||||
|
||||
export type OnCheckErrorType = (err: ApiErrorResponse) => void;
|
||||
export const getQueryKey = (calendar: (typeof CALENDARS)[number]) => [`get-${calendar}-check`];
|
||||
|
||||
@@ -28,7 +30,6 @@ export const useCheck = ({ onCheckError, initialData, onCheckSuccess }: UseCheck
|
||||
|
||||
const { data: check, refetch } = useQuery({
|
||||
queryKey: stripeQueryKey,
|
||||
staleTime: 6000,
|
||||
enabled: isInit && !!accessToken,
|
||||
queryFn: () => {
|
||||
return http
|
||||
@@ -60,3 +61,46 @@ export const useCheck = ({ onCheckError, initialData, onCheckSuccess }: UseCheck
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const useTeamCheck = ({
|
||||
teamId,
|
||||
onCheckError,
|
||||
initialData,
|
||||
onCheckSuccess,
|
||||
}: UseCheckProps & { teamId?: number | null }) => {
|
||||
const { isInit, accessToken } = useAtomsContext();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { data: check, refetch } = useQuery({
|
||||
queryKey: stripeTeamQueryKey,
|
||||
enabled: isInit && !!accessToken && !!teamId,
|
||||
queryFn: () => {
|
||||
return http
|
||||
?.get<ApiResponse<{ checked: boolean; allowConnect: boolean }>>(`/stripe/check/${teamId}`)
|
||||
.then(({ data: responseBody }) => {
|
||||
if (responseBody.status === SUCCESS_STATUS) {
|
||||
onCheckSuccess?.();
|
||||
return { status: SUCCESS_STATUS, data: { allowConnect: false, checked: true } };
|
||||
}
|
||||
onCheckError?.(responseBody);
|
||||
return { status: ERROR_STATUS, data: { allowConnect: true, checked: true } };
|
||||
})
|
||||
.catch((err) => {
|
||||
onCheckError?.(err);
|
||||
return { status: ERROR_STATUS, data: { allowConnect: true, checked: true } };
|
||||
});
|
||||
},
|
||||
initialData,
|
||||
});
|
||||
return {
|
||||
allowConnect: check?.data?.allowConnect ?? false,
|
||||
checked: check?.data?.checked ?? false,
|
||||
refetch: () => {
|
||||
queryClient.setQueryData(stripeQueryKey, {
|
||||
status: SUCCESS_STATUS,
|
||||
data: { allowConnect: false, checked: false },
|
||||
});
|
||||
refetch();
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { ApiResponse } from "@calcom/platform-types";
|
||||
|
||||
import http from "../../lib/http";
|
||||
|
||||
export const useGetRedirectUrl = (redir?: string, errorRedir?: string) => {
|
||||
export const useGetRedirectUrl = (redir?: string, errorRedir?: string, teamId?: number | null) => {
|
||||
const authUrl = useQuery({
|
||||
queryKey: ["get-stripe-connect-redirect-uri"],
|
||||
staleTime: Infinity,
|
||||
@@ -15,7 +15,7 @@ export const useGetRedirectUrl = (redir?: string, errorRedir?: string) => {
|
||||
?.get<ApiResponse<{ authUrl: string }>>(
|
||||
`/stripe/connect${redir ? `?redir=${encodeURIComponent(redir)}` : "?redir="}${
|
||||
errorRedir ? `&errorRedir=${encodeURIComponent(errorRedir)}` : ""
|
||||
}`
|
||||
}${teamId ? `&teamId=${teamId}` : ""}`
|
||||
)
|
||||
.then(({ data: responseBody }) => {
|
||||
if (responseBody.status === SUCCESS_STATUS) {
|
||||
@@ -30,8 +30,8 @@ export const useGetRedirectUrl = (redir?: string, errorRedir?: string) => {
|
||||
return authUrl;
|
||||
};
|
||||
|
||||
export const useConnect = (redir?: string, errorRedir?: string) => {
|
||||
const { refetch } = useGetRedirectUrl(redir, errorRedir);
|
||||
export const useConnect = (redir?: string, errorRedir?: string, teamId?: number | null) => {
|
||||
const { refetch } = useGetRedirectUrl(redir, errorRedir, teamId);
|
||||
|
||||
const connect = async () => {
|
||||
const redirectUri = await refetch();
|
||||
|
||||
Reference in New Issue
Block a user