refactoring and more work with clerk

This commit is contained in:
Carl-Gerhard Lindesvärd
2024-02-07 23:28:55 +01:00
parent a9cbff2306
commit 86d2d0750f
61 changed files with 703 additions and 727 deletions

View File

@@ -1,5 +1,5 @@
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
import { db } from '@/server/db';
import { db, getId } from '@/server/db';
import { PrismaError } from 'prisma-error-enum';
import { z } from 'zod';
@@ -61,12 +61,15 @@ export const dashboardRouter = createTRPCRouter({
z.object({
name: z.string(),
projectId: z.string(),
organizationSlug: z.string(),
})
)
.mutation(async ({ input: { projectId, name } }) => {
.mutation(async ({ input: { organizationSlug, projectId, name } }) => {
return db.dashboard.create({
data: {
id: await getId('dashboard', name),
project_id: projectId,
organization_slug: organizationSlug,
name,
},
});

View File

@@ -1,8 +1,6 @@
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
import {
getCurrentOrganization,
getOrganizationBySlug,
} from '@/server/services/organization.service';
import { getOrganizationBySlug } from '@/server/services/organization.service';
import { zInviteUser } from '@/utils/validation';
import { clerkClient } from '@clerk/nextjs';
import { z } from 'zod';
@@ -10,7 +8,7 @@ export const organizationRouter = createTRPCRouter({
list: protectedProcedure.query(() => {
return clerkClient.organizations.getOrganizationList();
}),
first: protectedProcedure.query(() => getCurrentOrganization()),
// first: protectedProcedure.query(() => getCurrentOrganization()),
get: protectedProcedure
.input(
z.object({
@@ -32,4 +30,20 @@ export const organizationRouter = createTRPCRouter({
name: input.name,
});
}),
inviteUser: protectedProcedure
.input(zInviteUser)
.mutation(async ({ input, ctx }) => {
const organization = await getOrganizationBySlug(input.organizationSlug);
if (!organization) {
throw new Error('Organization not found');
}
return clerkClient.organizations.createOrganizationInvitation({
organizationId: organization.id,
emailAddress: input.email,
role: input.role,
inviterUserId: ctx.session.userId,
});
}),
});

View File

@@ -28,19 +28,4 @@ export const userRouter = createTRPCRouter({
})
.then(transformUser);
}),
invite: protectedProcedure
.input(
z.object({
email: z.string().email(),
organizationId: z.string(),
})
)
.mutation(async ({ input, ctx }) => {
await db.invite.create({
data: {
organization_id: input.organizationId,
email: input.email,
},
});
}),
});

View File

@@ -4,10 +4,7 @@ import { db } from '@mixan/db';
export { db } from '@mixan/db';
export async function getId(
tableName: 'project' | 'organization' | 'dashboard',
name: string
) {
export async function getId(tableName: 'project' | 'dashboard', name: string) {
const newId = slug(name);
if (!db[tableName]) {
throw new Error('Table does not exists');

View File

@@ -0,0 +1,25 @@
import { notFound } from 'next/navigation';
import { getOrganizationBySlug } from './services/organization.service';
import { getProjectById } from './services/project.service';
export async function getExists(organizationSlug: string, projectId?: string) {
const promises: Promise<any>[] = [getOrganizationBySlug(organizationSlug)];
if (projectId) {
promises.push(getProjectById(projectId));
}
const results = await Promise.all(promises);
if (results.some((res) => !res)) {
return notFound();
}
return {
organization: results[0] as Awaited<
ReturnType<typeof getOrganizationBySlug>
>,
project: results[1] as Awaited<ReturnType<typeof getProjectById>>,
};
}

View File

@@ -1,20 +1,40 @@
import { unstable_cache } from 'next/cache';
import { db } from '../db';
export type IServiceRecentDashboards = Awaited<
ReturnType<typeof getRecentDashboardsByUserId>
>;
export type IServiceDashboard = Awaited<ReturnType<typeof getDashboardById>>;
export type IServiceDashboardWithProject = Awaited<
export type IServiceDashboards = Awaited<
ReturnType<typeof getDashboardsByProjectId>
>[number];
>;
export function getDashboardById(id: string) {
return db.dashboard.findUniqueOrThrow({
export async function getDashboardById(id: string) {
const dashboard = await db.dashboard.findUnique({
where: {
id,
},
include: {
project: true,
},
});
if (!dashboard) {
return null;
}
return dashboard;
}
export async function getDashboardsByOrganization(organizationSlug: string) {
return db.dashboard.findMany({
where: {
organization_slug: organizationSlug,
},
include: {
project: true,
},
orderBy: {
reports: {
_count: 'desc',
},
},
});
}
@@ -28,59 +48,3 @@ export function getDashboardsByProjectId(projectId: string) {
},
});
}
export async function getRecentDashboardsByUserId(userId: string) {
const tag = `recentDashboards_${userId}`;
return unstable_cache(
async (userId: string) => {
return db.recentDashboards.findMany({
where: {
user_id: userId,
},
orderBy: {
createdAt: 'desc',
},
include: {
project: true,
dashboard: true,
},
take: 5,
});
},
tag.split('_'),
{
revalidate: 3600,
tags: [tag],
}
)(userId);
}
export async function createRecentDashboard({
organizationId,
projectId,
dashboardId,
userId,
}: {
organizationId: string;
projectId: string;
dashboardId: string;
userId: string;
}) {
await db.recentDashboards.deleteMany({
where: {
user_id: userId,
project_id: projectId,
dashboard_id: dashboardId,
organization_slug: organizationId,
},
});
return db.recentDashboards.create({
data: {
user_id: userId,
organization_slug: organizationId,
project_id: projectId,
dashboard_id: dashboardId,
},
});
}

View File

@@ -1,12 +1,17 @@
import { auth, clerkClient } from '@clerk/nextjs';
import type { Organization } from '@clerk/nextjs/dist/types/server';
import type {
Organization,
OrganizationInvitation,
} from '@clerk/nextjs/dist/types/server';
import { db } from '../db';
export type IServiceOrganization = Awaited<
ReturnType<typeof getOrganizations>
ReturnType<typeof getCurrentOrganizations>
>[number];
export type IServiceInvites = Awaited<ReturnType<typeof getInvites>>;
function transformOrganization(org: Organization) {
return {
id: org.id,
@@ -15,28 +20,19 @@ function transformOrganization(org: Organization) {
};
}
export async function getOrganizations() {
const orgs = await clerkClient.organizations.getOrganizationList();
return orgs.map(transformOrganization);
}
export async function getCurrentOrganization() {
export async function getCurrentOrganizations() {
const session = auth();
if (!session?.orgSlug) {
return null;
}
const organization = await clerkClient.organizations.getOrganization({
slug: session.orgSlug,
const organizations = await clerkClient.users.getOrganizationMembershipList({
userId: session.userId!,
});
return transformOrganization(organization);
return organizations.map((item) => transformOrganization(item.organization));
}
export function getOrganizationBySlug(slug: string) {
return clerkClient.organizations
.getOrganization({ slug })
.then(transformOrganization);
.then(transformOrganization)
.catch(() => null);
}
export async function getOrganizationByProjectId(projectId: string) {
@@ -50,3 +46,22 @@ export async function getOrganizationByProjectId(projectId: string) {
slug: project.organization_slug,
});
}
export function transformInvite(invite: OrganizationInvitation) {
return {
id: invite.id,
email: invite.emailAddress,
role: invite.role,
status: invite.status,
createdAt: invite.createdAt,
updatedAt: invite.updatedAt,
};
}
export async function getInvites(organizationId: string) {
return await clerkClient.organizations
.getOrganizationInvitationList({
organizationId,
})
.then((invites) => invites.map(transformInvite));
}

View File

@@ -1,7 +1,4 @@
import { unstable_cache } from 'next/cache';
import { db } from '../db';
import { getCurrentOrganization } from './organization.service';
export type IServiceProject = Awaited<ReturnType<typeof getProjectById>>;
@@ -13,12 +10,10 @@ export function getProjectById(id: string) {
});
}
export async function getCurrentProjects() {
const organization = await getCurrentOrganization();
if (!organization?.slug) return [];
export async function getCurrentProjects(organizationSlug: string) {
return await db.project.findMany({
where: {
organization_slug: organization.slug,
organization_slug: organizationSlug,
},
});
}

View File

@@ -70,12 +70,16 @@ export function getReportsByDashboardId(dashboardId: string) {
.then((reports) => reports.map(transformReport));
}
export function getReportById(id: string) {
return db.report
.findUniqueOrThrow({
where: {
id,
},
})
.then(transformReport);
export async function getReportById(id: string) {
const report = await db.report.findUnique({
where: {
id,
},
});
if (!report) {
return null;
}
return transformReport(report);
}