import { auth, Client, webln } from "@getalby/sdk"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useState, useCallback, useEffect } from "react"; import { Toaster } from "sonner"; 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 { showToast } from "@calcom/ui/components/toast"; import { Badge } from "@calcom/ui/components/badge"; import { Button } from "@calcom/ui/components/button"; import { Icon } from "@calcom/ui/components/icon"; import { albyCredentialKeysSchema } from "../../lib/albyCredentialKeysSchema"; export interface IAlbySetupProps { email: string | null; lightningAddress: string | null; clientId: string; clientSecret: string; } export default function AlbySetup(props: IAlbySetupProps) { const params = useCompatSearchParams(); if (params?.get("callback") === "true") { return ; } return ; } function AlbySetupCallback() { 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); alert(error); return; } window.opener.postMessage({ type: "alby:oauth:success", payload: { code }, }); window.close(); }, [searchParams]); return ( {error && Authorization failed: {error}} {!error && Connecting...} ); } function AlbySetupPage(props: IAlbySetupProps) { const router = useRouter(); const { t } = useLocale(); const integrations = trpc.viewer.apps.integrations.useQuery({ variant: "payment", appId: "alby" }); const [albyPaymentAppCredentials] = integrations.data?.items || []; const [credentialId] = albyPaymentAppCredentials?.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 connectWithAlby = useCallback(async () => { const authClient = new auth.OAuth2User({ client_id: props.clientId, client_secret: props.clientSecret, callback: `${process.env.NEXT_PUBLIC_WEBAPP_URL}/apps/alby/setup?callback=true`, scopes: ["invoices:read", "account:read"], user_agent: "cal.com", }); const weblnOAuthProvider = new webln.OauthWeblnProvider({ auth: authClient, }); await weblnOAuthProvider.enable(); const client = new Client(authClient); const accountInfo = await client.accountInformation({}); // TODO: add a way to delete the endpoint when the app is uninstalled const webhookEndpoint = await client.createWebhookEndpoint({ filter_types: ["invoice.incoming.settled"], url: `${process.env.NEXT_PUBLIC_WEBAPP_URL}/api/integrations/alby/webhook`, description: "Cal.com", }); saveKeysMutation.mutate({ credentialId, key: albyCredentialKeysSchema.parse({ account_id: accountInfo.identifier, account_email: accountInfo.email, account_lightning_address: accountInfo.lightning_address, webhook_endpoint_id: webhookEndpoint.id, webhook_endpoint_secret: webhookEndpoint.endpoint_secret, }), }); }, [credentialId, props.clientId, props.clientSecret, saveKeysMutation]); if (integrations.isPending) { return ; } const albyIcon = ( <> > ); return ( {showContent ? ( {!props.lightningAddress ? ( <> Create or connect to an existing Alby account to receive lightning payments for your paid bookings. {albyIcon} Connect with Alby > ) : ( <> {albyIcon} Alby Connected! Email: {props.email} Lightning Address: {props.lightningAddress} > )} {/* TODO: remove when invoices are generated using user identifier */} Your Alby lightning address will be used to generate invoices. If you update your lightning address, please disconnect and setup the Alby app again. Go to App Store Listing ) : ( )} ); }
Authorization failed: {error}
Connecting...
Create or connect to an existing Alby account to receive lightning payments for your paid bookings.
Alby Connected!