diff --git a/src/app/(payment)/layout.tsx b/src/app/(payment)/layout.tsx deleted file mode 100644 index 765d7fa..0000000 --- a/src/app/(payment)/layout.tsx +++ /dev/null @@ -1,11 +0,0 @@ -export default function PaymentLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( -
- {children} -
- ); -} diff --git a/src/app/(payment)/payment/failed/page.tsx b/src/app/(payment)/payment/failed/page.tsx deleted file mode 100644 index 9f0f25b..0000000 --- a/src/app/(payment)/payment/failed/page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -// import { getTranslations } from "next-intl/server"; - -import AnimatedInfoScreen from "@/components/widgets/AnimatedInfoScreen/AnimatedInfoScreen"; -import LottieAnimation from "@/components/widgets/LottieAnimation/LottieAnimation"; -import { ROUTES } from "@/shared/constants/client-routes"; -import { ELottieKeys } from "@/shared/constants/lottie"; - -export default async function PaymentFailed() { - // const t = await getTranslations("Payment.Error"); - - return ( - - } - // title={t("title")} - title="Payment failed" - animationTime={0} - animationTexts={[]} - buttonText="Try again" - nextRoute={ROUTES.home()} - /> - ); -} diff --git a/src/app/(payment)/payment/route.ts b/src/app/(payment)/payment/route.ts deleted file mode 100644 index 69ae3d2..0000000 --- a/src/app/(payment)/payment/route.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; - -import { createPaymentCheckout } from "@/entities/payment/api"; -import { ROUTES } from "@/shared/constants/client-routes"; - -export async function GET(req: NextRequest) { - const productId = req.nextUrl.searchParams.get("productId"); - const placementId = req.nextUrl.searchParams.get("placementId"); - const paywallId = req.nextUrl.searchParams.get("paywallId"); - const fbPixels = req.nextUrl.searchParams.get("fb_pixels"); - const productPrice = req.nextUrl.searchParams.get("price"); - const currency = req.nextUrl.searchParams.get("currency"); - - console.log("PRODUCT ID:", productId); - const data = await createPaymentCheckout({ - productId: productId || "", - placementId: placementId || "", - paywallId: paywallId || "", - }); - console.log("DATA:", data); - - let redirectUrl: URL = new URL(data?.paymentUrl || "", req.nextUrl.origin); - if (!redirectUrl) { - redirectUrl = new URL(`${ROUTES.paymentFailed()}`, origin); - } - if (fbPixels) redirectUrl.searchParams.set("fb_pixels", fbPixels); - if (productPrice) redirectUrl.searchParams.set("price", productPrice); - if (currency) redirectUrl.searchParams.set("currency", currency); - - return NextResponse.redirect(redirectUrl, { status: 307 }); -} diff --git a/src/app/(payment)/payment/success/Button.tsx b/src/app/(payment)/payment/success/Button.tsx deleted file mode 100644 index 0f775c5..0000000 --- a/src/app/(payment)/payment/success/Button.tsx +++ /dev/null @@ -1,31 +0,0 @@ -"use client"; - -import { ActionButton } from "@/components/ui/ActionButton/ActionButton"; -// import { useRouter } from "next/navigation"; -// import { useTranslations } from "next-intl"; - -import Typography from "@/components/ui/Typography/Typography"; -// import { ROUTES } from "@/shared/constants/client-routes"; - -// import styles from "./Button.module.scss"; - -export default function PaymentSuccessButton() { - // const t = useTranslations("Payment.Success"); - // const router = useRouter(); - - const handleNext = () => { - // router.push(ROUTES.additionalPurchases()); - }; - - return ( - - - {/* {t("button")} */} - Done - - - ); -} diff --git a/src/app/(payment)/payment/success/page.tsx b/src/app/(payment)/payment/success/page.tsx deleted file mode 100644 index 089c7a8..0000000 --- a/src/app/(payment)/payment/success/page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -// import { getTranslations } from "next-intl/server"; - -import AnimatedInfoScreen from "@/components/widgets/AnimatedInfoScreen/AnimatedInfoScreen"; -import LottieAnimation from "@/components/widgets/LottieAnimation/LottieAnimation"; - -import PaymentSuccessButton from "./Button"; -import { ELottieKeys } from "@/shared/constants/lottie"; - -export default async function PaymentSuccess() { - // const t = await getTranslations("Payment.Success"); - - return ( - <> - - } - // title={t("title")} - title="Payment successful" - /> - - - ); -} diff --git a/src/components/funnel/templates/TrialPaymentTemplate/TrialPaymentTemplate.tsx b/src/components/funnel/templates/TrialPaymentTemplate/TrialPaymentTemplate.tsx index 057884f..b3564ae 100644 --- a/src/components/funnel/templates/TrialPaymentTemplate/TrialPaymentTemplate.tsx +++ b/src/components/funnel/templates/TrialPaymentTemplate/TrialPaymentTemplate.tsx @@ -37,8 +37,39 @@ import { usePaymentPlacement } from "@/hooks/payment/usePaymentPlacement"; import { Spinner } from "@/components/ui/spinner"; import { Currency } from "@/shared/types"; import { getFormattedPrice } from "@/shared/utils/price"; -import { useRouter } from "next/navigation"; -import { ROUTES } from "@/shared/constants/client-routes"; +import { useClientToken } from "@/hooks/auth/useClientToken"; + +function getTrackingCookiesForRedirect() { + const cookieObj = Object.fromEntries( + document.cookie.split("; ").map((c) => c.split("=")) + ); + + const result = Object.entries(cookieObj).filter(([key]) => { + return ( + [ + "_fbc", + "_fbp", + "_ym_uid", + "_ym_d", + "_ym_isad", + "_ym_visorc", + "yandexuid", + "ymex", + ].includes(key) || + key.startsWith("_ga") || + key.startsWith("_gid") + ); + }); + + const queryString = result + .map( + ([key, value]) => + `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}` + ) + .join("&"); + + return queryString; +} interface TrialPaymentTemplateProps { funnel: FunnelDefinition; @@ -58,7 +89,7 @@ export function TrialPaymentTemplate({ screenProgress, defaultTexts, }: TrialPaymentTemplateProps) { - const router = useRouter(); + const token = useClientToken(); // TODO: выбрать корректный paymentId для этого экрана (ключ из backend), временно "main" const paymentId = "main"; @@ -76,17 +107,15 @@ export function TrialPaymentTemplate({ const billingPeriod = placement?.billingPeriod; const billingInterval = placement?.billingInterval || 1; const currency = placement?.currency || Currency.USD; - - console.log({ placement }); + const paymentUrl = placement?.paymentUrl || ""; const handlePayClick = () => { - router.push( - ROUTES.payment({ - productId, - placementId, - paywallId, - }) - ); + const redirectUrl = `${paymentUrl}?paywallId=${paywallId}&placementId=${placementId}&productId=${productId}&jwtToken=${token}&price=${( + (trialPrice || 100) / 100 + ).toFixed(2)}¤cy=${currency}&${getTrackingCookiesForRedirect()}`; + console.log("redirectUrl", redirectUrl); + + // return window.location.replace(redirectUrl); }; const paymentSectionRef = useRef(null); @@ -215,7 +244,7 @@ export function TrialPaymentTemplate({ } ); - if (isLoading || !placement) { + if (isLoading || !placement || !token) { return (
@@ -239,7 +268,7 @@ export function TrialPaymentTemplate({ {/* Header block */} {screen.headerBlock && (
) => { + if (disabled) return; + const targetEl = e.target as HTMLElement | null; + const isCheckboxTarget = targetEl?.closest('[data-slot="checkbox"]'); + if (isCheckboxTarget) { + return; + } + e.preventDefault(); + props.onClick?.(e); + }} asChild > diff --git a/src/components/widgets/BottomActionButton/BottomActionButton.tsx b/src/components/widgets/BottomActionButton/BottomActionButton.tsx index 4c46854..2be9245 100644 --- a/src/components/widgets/BottomActionButton/BottomActionButton.tsx +++ b/src/components/widgets/BottomActionButton/BottomActionButton.tsx @@ -76,7 +76,7 @@ const BottomActionButton = forwardRef(
=> { maxAge: 60 * 60 * 24 * 365, }); }; + +export const getAuthTokenFromCookie = async (): Promise => { + const cookieStore = await cookies(); + return cookieStore.get("accessToken")?.value; +}; diff --git a/src/hooks/auth/useClientToken.ts b/src/hooks/auth/useClientToken.ts new file mode 100644 index 0000000..19533c0 --- /dev/null +++ b/src/hooks/auth/useClientToken.ts @@ -0,0 +1,17 @@ +"use client"; + +import { getAuthTokenFromCookie } from "@/entities/user/serverActions"; +import { useEffect, useMemo, useState } from "react"; + +export const useClientToken = () => { + const [token, setToken] = useState(undefined); + + useEffect(() => { + (async () => { + const token = await getAuthTokenFromCookie(); + setToken(token); + })(); + }, []); + + return useMemo(() => token, [token]); +}; diff --git a/src/shared/api/httpClient.ts b/src/shared/api/httpClient.ts index d0f3482..c8d0859 100644 --- a/src/shared/api/httpClient.ts +++ b/src/shared/api/httpClient.ts @@ -100,8 +100,10 @@ class HttpClient { accessToken = await getServerAccessToken(); } else { try { - const { getClientAccessToken } = await import("../auth/token"); - accessToken = getClientAccessToken(); + const { getAuthTokenFromCookie } = await import( + "@/entities/user/serverActions" + ); + accessToken = await getAuthTokenFromCookie(); } catch { // ignore }