import { zodResolver } from "@hookform/resolvers/zod"; import { useSession } from "next-auth/react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useState, useEffect } from "react"; import { useForm } from "react-hook-form"; import { Toaster } from "sonner"; import { z } from "zod"; import AppNotInstalledMessage from "@calcom/app-store/_components/AppNotInstalledMessage"; import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc"; import { Button } from "@calcom/ui/components/button"; import { Switch } from "@calcom/ui/components/form"; import { Icon } from "@calcom/ui/components/icon"; import { showToast } from "@calcom/ui/components/toast"; import KeyField from "../../components/KeyInput"; import { hitpayCredentialKeysSchema } from "../../lib/hitpayCredentialKeysSchema"; export type IHitPaySetupProps = z.infer; export default function HitPaySetup(props: IHitPaySetupProps) { const params = useCompatSearchParams(); if (params?.get("callback") === "true") { return ; } return ; } function HitPaySetupCallback() { const [error, setError] = useState(null); const searchParams = useCompatSearchParams(); useEffect(() => { if (!searchParams) { return; } if (!window.opener) { setError("Something went wrong. Opener not available. Please contact support@getalby.com"); return; } const code = searchParams?.get("code"); const error = searchParams?.get("error"); if (!code) { setError("declined"); } if (error) { setError(error); return; } window.opener.postMessage({ type: "hitpay:oauth:success", payload: { code }, }); window.close(); }, [searchParams]); return (
{error &&

Authorization failed: {error}

} {!error &&

Connecting...

}
); } function HitPaySetupPage(props: IHitPaySetupProps) { const [loading, setLoading] = useState(false); const [updatable, setUpdatable] = useState(false); const [isSandbox, SetIsSandbox] = useState(props.isSandbox || false); const [keyData, setKeyData] = useState< | { apiKey: string; saltKey: string; } | undefined >(); const session = useSession(); const router = useRouter(); const { t } = useLocale(); const settingsSchema = z.object({ apiKey: z .string() .trim() .min(64) .max(128, { message: t("max_limit_allowed_hint", { limit: 128 }), }), saltKey: z .string() .trim() .min(64) .max(128, { message: t("max_limit_allowed_hint", { limit: 128 }), }), }); const integrations = trpc.viewer.apps.integrations.useQuery({ variant: "payment", appId: "hitpay" }); const [HitPayPaymentAppCredentials] = integrations.data?.items || []; const [credentialId] = HitPayPaymentAppCredentials?.userCredentialIds || [-1]; const showContent = !!integrations.data && integrations.isSuccess && !!credentialId; const saveKeysMutation = trpc.viewer.apps.updateAppCredentials.useMutation({ onSuccess: () => { showToast(t("keys_have_been_saved"), "success"); router.push("/event-types"); }, onError: (error) => { showToast(error.message, "error"); }, }); const deleteMutation = trpc.viewer.credentials.delete.useMutation({ onSuccess: () => { router.push("/apps/hitpay"); }, onError: () => { showToast(t("error_removing_app"), "error"); }, }); const { register, handleSubmit, formState: { errors }, watch, reset, } = useForm>({ reValidateMode: "onChange", resolver: zodResolver(settingsSchema), }); useEffect(() => { const keyObj = isSandbox ? props.sandbox : props.prod; const _keyData = { apiKey: keyObj?.apiKey || "", saltKey: keyObj?.saltKey || "", }; reset(_keyData); setKeyData(_keyData); }, [isSandbox]); useEffect(() => { const subscription = watch((value) => { const { apiKey, saltKey } = value; if (apiKey && saltKey && (keyData?.apiKey !== apiKey || keyData?.saltKey !== saltKey)) { setUpdatable(true); } else { setUpdatable(false); } }); return () => subscription.unsubscribe(); }, [watch, keyData]); const onSubmit = handleSubmit(async (data) => { if (loading) return; setLoading(true); try { const keyParams = { isSandbox, prod: isSandbox ? props.prod : data, sandbox: isSandbox ? data : props.sandbox, }; saveKeysMutation.mutate({ credentialId, key: hitpayCredentialKeysSchema.parse(keyParams), }); } catch (error: unknown) { let message = ""; if (error instanceof Error) { message = error.message; } showToast(message, "error"); } finally { setLoading(false); } }); const onCancel = () => { deleteMutation.mutate({ id: credentialId }); }; const hitpayIcon = ( <> HitPay Icon ); if (session.status === "loading") return <>; if (integrations.isPending) { return
; } return ( <>
{showContent ? (
Create or connect to an existing HitPay account to receive payments for your paid bookings.

Account Information

SetIsSandbox(value as boolean)} checked={isSandbox} label="Sandbox" />
{errors.apiKey && (

{errors.apiKey?.message}

)}
{errors.saltKey && (

{errors.saltKey?.message}

)}
{!props.prod && !props.sandbox ? (
) : (
)}
) : ( )}
); }