Skip to content

Commit

Permalink
fix: Invite link fix (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
adityachoudhari26 authored Aug 30, 2024
1 parent f3e1205 commit 13a9d80
Show file tree
Hide file tree
Showing 8 changed files with 2,584 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import type { User, WorkspaceMember } from "@ctrlplane/db/schema";
import type { ColumnDef, ColumnFiltersState } from "@tanstack/react-table";
import { useEffect, useState } from "react";
import { useState } from "react";
import {
flexRender,
getCoreRowModel,
Expand All @@ -11,6 +11,7 @@ import {
} from "@tanstack/react-table";
import { capitalCase } from "change-case";
import { TbCheck, TbChevronDown, TbCopy, TbDots } from "react-icons/tb";
import { v4 } from "uuid";

import { Avatar, AvatarFallback, AvatarImage } from "@ctrlplane/ui/avatar";
import { Button } from "@ctrlplane/ui/button";
Expand Down Expand Up @@ -41,32 +42,34 @@ interface Member {

const InviteLinkSection: React.FC<{
sessionMember?: Member;
}> = ({ sessionMember }) => {
const inviteLink = api.invite.workspace.link.byWorkspaceMemberId.useQuery(
sessionMember?.workspace_member.id ?? "",
{ enabled: sessionMember != null },
);
const { mutateAsync } = api.invite.workspace.link.create.useMutation();
workspaceSlug: string;
inviteLink?: string;
}> = ({ sessionMember, workspaceSlug, inviteLink }) => {
const workspace = api.workspace.bySlug.useQuery(workspaceSlug);
const utils = api.useUtils();
const { mutateAsync } = api.invite.workspace.link.create.useMutation({
onSuccess: () =>
utils.invite.workspace.link.byWorkspaceMemberId.invalidate(),
});
const [clickedCopy, setClickedCopy] = useState(false);

useEffect(() => {
if (inviteLink.isSuccess && inviteLink.data == null)
mutateAsync(sessionMember?.workspace_member.id ?? "").then(() =>
utils.invite.workspace.link.byWorkspaceMemberId.invalidate(
sessionMember?.workspace_member.id ?? "",
),
);
}, [mutateAsync, inviteLink, sessionMember?.workspace_member.id, utils]);

const link = `${env.NEXT_PUBLIC_BASE_URL}/join/${inviteLink.data?.token ?? ""}`;
const [token] = useState(inviteLink ?? v4());
const link = `${env.NEXT_PUBLIC_BASE_URL}/join/${token}`;

const handleCopyClick = () =>
const handleCopyClick = () => {
navigator.clipboard.writeText(link).then(() => {
setClickedCopy(true);
setTimeout(() => setClickedCopy(false), 1000);
});

if (inviteLink == null && workspace.data != null && sessionMember != null)
mutateAsync({
workspaceId: workspace.data.id,
workspaceMemberId: sessionMember.workspace_member.id,
token,
});
};

return (
<div className="space-y-4">
<div>
Expand All @@ -91,6 +94,10 @@ const AddMembersDialog: React.FC<{
sessionMember?: Member;
}> = ({ sessionMember, workspaceSlug }) => {
const [inviteMode, setInviteMode] = useState<"email" | "link">("email");
const inviteLink = api.invite.workspace.link.byWorkspaceMemberId.useQuery(
sessionMember?.workspace_member.id ?? "",
{ enabled: sessionMember != null },
);

return (
<Dialog>
Expand All @@ -103,7 +110,11 @@ const AddMembersDialog: React.FC<{
</DialogHeader>

{inviteMode === "link" ? (
<InviteLinkSection sessionMember={sessionMember} />
<InviteLinkSection
sessionMember={sessionMember}
workspaceSlug={workspaceSlug}
inviteLink={inviteLink.data?.token}
/>
) : (
<div>email</div>
)}
Expand Down
1 change: 1 addition & 0 deletions packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@t3-oss/env-core": "^0.10.1",
"@trpc/server": "11.0.0-rc.364",
"bullmq": "^5.12.10",
"date-fns": "^3.6.0",
"google-auth-library": "^9.13.0",
"googleapis": "^140.0.1",
"ioredis": "^5.4.1",
Expand Down
33 changes: 24 additions & 9 deletions packages/api/src/router/invite.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { addWeeks } from "date-fns";
import { z } from "zod";

import { eq, takeFirst, takeFirstOrNull } from "@ctrlplane/db";
import { and, eq, gte, takeFirst, takeFirstOrNull } from "@ctrlplane/db";
import {
workspace,
workspaceInviteLink,
Expand All @@ -17,23 +18,37 @@ const workspaceRouter = createTRPCRouter({
return ctx.db
.select()
.from(workspaceInviteLink)
.where(eq(workspaceInviteLink.workspaceMemberId, input))
.where(
and(
eq(workspaceInviteLink.workspaceMemberId, input),
gte(workspaceInviteLink.expiresAt, new Date()),
),
)
.then(takeFirstOrNull);
}),
create: protectedProcedure
.meta({
access: ({ ctx, input }) => ctx.accessQuery().workspace.id(input),
access: ({ ctx, input }) =>
ctx.accessQuery().workspace.id(input.workspaceId),
})
.input(z.string())
.mutation(async ({ ctx, input }) => {
return ctx.db
.input(
z.object({
workspaceId: z.string().uuid(),
workspaceMemberId: z.string().uuid(),
token: z.string().uuid(),
}),
)
.mutation(async ({ ctx, input }) =>
ctx.db
.insert(workspaceInviteLink)
.values({
workspaceMemberId: input,
workspaceMemberId: input.workspaceMemberId,
expiresAt: addWeeks(new Date(), 1),
token: input.token,
})
.returning()
.then(takeFirst);
}),
.then(takeFirst),
),
}),

fromInviteToken: publicProcedure
Expand Down
1 change: 1 addition & 0 deletions packages/db/drizzle/0003_cloudy_jamie_braddock.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE "workspace_invite_link" ADD COLUMN "expires_at" timestamp NOT NULL;
Loading

0 comments on commit 13a9d80

Please sign in to comment.