feat: add stripe feed integration

This commit is contained in:
moonrailgun 2024-10-26 00:55:51 +08:00
parent 59d32e0119
commit 09d0f02d84
2 changed files with 132 additions and 0 deletions

View File

@ -4,6 +4,7 @@ import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
import { CodeBlock } from '../CodeBlock'; import { CodeBlock } from '../CodeBlock';
import { useTranslation } from '@i18next-toolkit/react'; import { useTranslation } from '@i18next-toolkit/react';
import { SiSentry } from 'react-icons/si'; import { SiSentry } from 'react-icons/si';
import { FaStripe } from 'react-icons/fa6';
export const FeedIntegration: React.FC<{ export const FeedIntegration: React.FC<{
feedId: string; feedId: string;
@ -57,6 +58,22 @@ export const FeedIntegration: React.FC<{
} }
/> />
<FeedIntegrationItem
icon={<FaStripe size={32} />}
label="Stripe"
content={
<div>
<div className="text-lg font-bold">{t('Receive Webhooks')}</div>
<div>{t('Add sentry webhook with url')}:</div>
<CodeBlock
code={`${window.location.origin}/open/feed/${props.feedId}/stripe`}
/>
</div>
}
/>
<div onClick={() => window.open('/feed/playground', '_blank')}> <div onClick={() => window.open('/feed/playground', '_blank')}>
<FeedIntegrationItemTrigger <FeedIntegrationItemTrigger
icon={<LuTestTube2 size={32} />} icon={<LuTestTube2 size={32} />}

View File

@ -184,6 +184,121 @@ export const feedIntegrationRouter = router({
logUnknownIntegration('github', input); 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'; return 'Not supported yet';
}), }),
tencentCloudAlarm: publicProcedure tencentCloudAlarm: publicProcedure