diff --git a/src/client/components/feed/FeedIntegration.tsx b/src/client/components/feed/FeedIntegration.tsx index 879e1e7..5b9199e 100644 --- a/src/client/components/feed/FeedIntegration.tsx +++ b/src/client/components/feed/FeedIntegration.tsx @@ -4,6 +4,7 @@ import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'; import { CodeBlock } from '../CodeBlock'; import { useTranslation } from '@i18next-toolkit/react'; import { SiSentry } from 'react-icons/si'; +import { FaStripe } from 'react-icons/fa6'; export const FeedIntegration: React.FC<{ feedId: string; @@ -57,6 +58,22 @@ export const FeedIntegration: React.FC<{ } /> + } + label="Stripe" + content={ +
+
{t('Receive Webhooks')}
+ +
{t('Add sentry webhook with url')}:
+ + +
+ } + /> +
window.open('/feed/playground', '_blank')}> } diff --git a/src/server/trpc/routers/feed/integration.ts b/src/server/trpc/routers/feed/integration.ts index fbf441a..90f8514 100644 --- a/src/server/trpc/routers/feed/integration.ts +++ b/src/server/trpc/routers/feed/integration.ts @@ -184,6 +184,121 @@ export const feedIntegrationRouter = router({ logUnknownIntegration('github', input); + return 'Not supported yet'; + }), + stripe: publicProcedure + .meta( + buildFeedPublicOpenapi({ + method: 'POST', + path: '/{channelId}/stripe', + summary: 'integrate with stripe webhook', + }) + ) + .input( + z + .object({ + channelId: z.string(), + }) + .passthrough() + ) + .output(z.string()) + .mutation(async ({ input, ctx }) => { + console.log(input); + const { channelId, ...data } = input; + const type = data.type; + + const workspaceId = await prisma.feedChannel + .findFirst({ + where: { + id: channelId, + }, + select: { + workspaceId: true, + }, + }) + .then((res) => res?.workspaceId); + + if (!workspaceId) { + throw new Error('Not found Workspace'); + } + + if (type === 'payment_intent.succeeded') { + const amount = get(data, 'data.object.amount_received'); + const currency = String( + get(data, 'data.object.currency') + ).toUpperCase(); + const eventId = String(get(data, 'data.id')).toUpperCase(); + + await createFeedEvent(workspaceId, { + channelId: channelId, + eventName: type, + eventContent: `You receive a payment of ${currency} **${amount}**`, + tags: [], + source: 'stripe', + senderId: eventId, + important: true, + payload: data, + }); + return 'ok'; + } + + if (type === 'payment_intent.canceled') { + const amount = get(data, 'data.object.amount'); + const currency = String( + get(data, 'data.object.currency') + ).toUpperCase(); + const eventId = String(get(data, 'data.id')).toUpperCase(); + + await createFeedEvent(workspaceId, { + channelId: channelId, + eventName: type, + eventContent: `A payment has been canceled of ${currency} **${amount}**`, + tags: [], + source: 'stripe', + senderId: eventId, + important: false, + payload: data, + }); + return 'ok'; + } + + if (type === 'customer.subscription.created') { + const eventId = String(get(data, 'data.id')).toUpperCase(); + const planName = get(data, 'data.object.plan.nickname'); + + await createFeedEvent(workspaceId, { + channelId: channelId, + eventName: type, + eventContent: `A customer has been subscribed service: **${planName}**`, + tags: [], + source: 'stripe', + senderId: eventId, + important: true, + payload: data, + }); + return 'ok'; + } + + if (type === 'customer.subscription.deleted') { + const eventId = String(get(data, 'data.id')).toUpperCase(); + const planName = get(data, 'data.object.plan.nickname'); + + await createFeedEvent(workspaceId, { + channelId: channelId, + eventName: type, + eventContent: `A customer cancel subscription service: ${planName}`, + tags: [], + source: 'stripe', + senderId: eventId, + important: true, + payload: data, + }); + + return 'ok'; + } + + logUnknownIntegration('stripe', input); + return 'Not supported yet'; }), tencentCloudAlarm: publicProcedure