feat(subscriptions): added polar as payment provider for subscriptions

* feature(dashboard): add polar / subscription

* wip(payments): manage subscription

* wip(payments): add free product, faq and some other improvements

* fix(root): change node to bundler in tsconfig

* wip(payments): display current subscription

* feat(dashboard): schedule project for deletion

* wip(payments): support custom products/subscriptions

* wip(payments): fix polar scripts

* wip(payments): add json package to dockerfiles
This commit is contained in:
Carl-Gerhard Lindesvärd
2025-02-26 11:24:00 +01:00
committed by GitHub
parent 86bf9dd064
commit 168ebc3430
105 changed files with 3395 additions and 463 deletions

View File

@@ -2,16 +2,17 @@ import crypto from 'node:crypto';
import type { z } from 'zod';
import { stripTrailingSlash } from '@openpanel/common';
import type { ProjectType } from '@openpanel/db';
import { db, getId, getOrganizationBySlug, getUserById } from '@openpanel/db';
import type { IServiceUser, ProjectType } from '@openpanel/db';
import { zOnboardingProject } from '@openpanel/validation';
import { hashPassword } from '@openpanel/common/server';
import { addDays } from 'date-fns';
import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc';
async function createOrGetOrganization(
input: z.infer<typeof zOnboardingProject>,
userId: string,
user: IServiceUser,
) {
if (input.organizationId) {
return await getOrganizationBySlug(input.organizationId);
@@ -22,7 +23,9 @@ async function createOrGetOrganization(
data: {
id: await getId('organization', input.organization),
name: input.organization,
createdByUserId: userId,
createdByUserId: user.id,
subscriptionEndsAt: addDays(new Date(), 30),
subscriptionStatus: 'trialing',
},
});
}
@@ -72,10 +75,8 @@ export const onboardingRouter = createTRPCRouter({
if (input.app) types.push('app');
if (input.backend) types.push('backend');
const [organization, user] = await Promise.all([
createOrGetOrganization(input, ctx.session.userId),
getUserById(ctx.session.userId),
]);
const user = await getUserById(ctx.session.userId);
const organization = await createOrGetOrganization(input, user);
if (!organization?.id) {
throw new Error('Organization slug is missing');