Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: logic for archiving dataroom #1051

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions components/datarooms/empty-archived-dataroom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ServerIcon } from "lucide-react";

export function EmptyArchivedDataroom() {
return (
<div className="text-center">
<ServerIcon
className="mx-auto h-12 w-12 text-muted-foreground"
strokeWidth={1}
/>
<h3 className="mt-2 text-sm font-medium text-foreground">
No archived datarooms here
</h3>
<p className="mt-1 text-sm text-muted-foreground">
Get started by creating a new dataroom.
</p>
</div>
);
}
68 changes: 68 additions & 0 deletions components/datarooms/settings/archive-dataroom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Button } from "@/components/ui/button";
import {
Card,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";

import useArchiveDataroom from "@/lib/swr/use-archive-dataroom";

export default function ArchiveDataroom({
dataroomId,
teamId,
}: {
dataroomId: string;
teamId?: string;
}) {
const { isArchived, toggleArchive, isLoading, isUpdating } =
useArchiveDataroom(dataroomId, teamId);

return (
<div className="rounded-lg">
<Card className="bg-transparent">
<CardHeader>
<CardTitle>
{isLoading ? (
<Skeleton className="h-8 w-1/3" />
) : isArchived ? (
"Unarchive Dataroom"
) : (
"Archive Dataroom"
)}
</CardTitle>
<CardDescription>
{isLoading ? (
<Skeleton className="h-4 w-2/3" />
) : isArchived ? (
"Unarchive this dataroom and re-enable all its links."
) : (
"Archive this dataroom and disable all its links."
)}
</CardDescription>
</CardHeader>
<CardFooter className="flex items-center justify-end rounded-b-lg border-t px-6 py-3">
{isLoading ? (
<Skeleton className="h-9 w-32" />
) : (
<Button
variant={isArchived ? "default" : "destructive"}
onClick={toggleArchive}
disabled={isUpdating}
>
{isUpdating
? isArchived
? "Unarchiving..."
: "Archiving..."
: isArchived
? "Unarchive Dataroom"
: "Archive Dataroom"}
</Button>
)}
</CardFooter>
</Card>
</div>
);
}
6 changes: 4 additions & 2 deletions components/layouts/trial-banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ function TrialBannerComponent({
<div className="flex flex-col space-y-2">
<div className="text-sm font-bold">
Data Room trial:{" "}
{datarooms && daysLeft(new Date(datarooms[0].createdAt), 7)} days
left
{datarooms &&
datarooms.length > 0 &&
daysLeft(new Date(datarooms[0].createdAt), 7)}{" "}
days left
</div>

<div className="text-sm">
Expand Down
1 change: 1 addition & 0 deletions lib/api/links/link-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export async function fetchDataroomLinkData({
id: true,
name: true,
teamId: true,
isArchived: true,
documents: {
where:
groupPermissions.length > 0 || groupId
Expand Down
65 changes: 65 additions & 0 deletions lib/swr/use-archive-dataroom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { useState } from "react";

import { toast } from "sonner";
import useSWR, { useSWRConfig } from "swr";

import { fetcher } from "@/lib/utils";

export default function useArchiveDataroom(
dataroomId: string,
teamId?: string,
) {
const { mutate } = useSWRConfig();
const { data, isLoading, error } = useSWR<{ isArchived: boolean }>(
teamId && dataroomId
? `/api/teams/${teamId}/datarooms/${dataroomId}/archive`
: null,
fetcher,
);

const [isUpdating, setIsUpdating] = useState(false);

const toggleArchive = async () => {
if (!teamId) return;

setIsUpdating(true);
try {
const response = await fetch(
`/api/teams/${teamId}/datarooms/${dataroomId}/archive`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
},
);

if (!response.ok) {
return toast.error("Failed to archive/unarchive dataroom.");
} else {
toast.success(
data?.isArchived
? "Dataroom unarchived successfully!"
: "Dataroom archived successfully!",
);
}

mutate(`/api/teams/${teamId}/datarooms`);
mutate(`/api/teams/${teamId}/datarooms/archived`);
mutate(`/api/teams/${teamId}/datarooms/${dataroomId}/archive`);
} catch (error) {
console.error(error);
toast.error("Failed to archive/unarchive dataroom.");
} finally {
setIsUpdating(false);
}
};

return {
isArchived: data?.isArchived ?? false,
toggleArchive,
error,
isLoading,
isUpdating,
};
}
32 changes: 32 additions & 0 deletions lib/swr/use-archived-datarooms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useTeam } from "@/context/team-context";
import { Dataroom } from "@prisma/client";
import useSWR from "swr";

import { fetcher } from "@/lib/utils";

export type DataroomWithCount = Dataroom & {
_count: {
documents: number;
views: number;
};
};

export default function useArchivedDatarooms() {
const teamInfo = useTeam();

const { data: archivedDatarooms, error } = useSWR<DataroomWithCount[]>(
teamInfo?.currentTeam?.id &&
`/api/teams/${teamInfo?.currentTeam?.id}/datarooms/archived`,
fetcher,
{
revalidateOnFocus: false,
dedupingInterval: 30000,
},
);

return {
archivedDatarooms,
loading: !archivedDatarooms && !error,
error,
};
}
12 changes: 11 additions & 1 deletion pages/api/links/[id]/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ export default async function handle(
data: true,
},
},
dataroom: {
select: {
isArchived: true,
},
},
enableAgreement: true,
agreement: true,
showBanner: true,
Expand Down Expand Up @@ -96,7 +101,12 @@ export default async function handle(
...linkData,
};

return res.status(200).json({ linkType, link: returnLink, brand });
return res.status(200).json({
linkType,
link: returnLink,
brand,
dataroomIsArchived: link.dataroom?.isArchived || false,
});
} catch (error) {
return res.status(500).json({
message: "Internal Server Error",
Expand Down
120 changes: 120 additions & 0 deletions pages/api/teams/[teamId]/datarooms/[id]/archive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { NextApiRequest, NextApiResponse } from "next";

import { authOptions } from "@/pages/api/auth/[...nextauth]";
import { getServerSession } from "next-auth/next";

import prisma from "@/lib/prisma";
import { CustomUser } from "@/lib/types";

export default async function handle(
req: NextApiRequest,
res: NextApiResponse,
) {
if (req.method === "GET") {
// GET /api/teams/:teamId/datarooms/:id/archive
const session = await getServerSession(req, res, authOptions);
if (!session) {
res.status(401).end("Unauthorized");
return;
}

const { teamId, id: dataroomId } = req.query as {
teamId: string;
id: string;
};
const userId = (session.user as CustomUser).id;

try {
const team = await prisma.team.findUnique({
where: {
id: teamId,
users: {
some: {
userId: userId,
},
},
},
});

if (!team) {
return res.status(401).end("Unauthorized");
}

const dataroom = await prisma.dataroom.findUnique({
where: {
id: dataroomId,
teamId: teamId,
},
select: { isArchived: true },
});

if (!dataroom) {
return res.status(404).json({ message: "Dataroom not found" });
}

res.status(200).json({ isArchived: dataroom.isArchived });
} catch (error) {
console.error("Request error", error);
res.status(500).json({ message: "Error fetching dataroom archive status" });
}
} else if (req.method === "POST") {
// POST /api/teams/:teamId/datarooms/:id/archive
const session = await getServerSession(req, res, authOptions);
if (!session) {
res.status(401).end("Unauthorized");
return;
}

const { teamId, id: dataroomId } = req.query as {
teamId: string;
id: string;
};
const userId = (session.user as CustomUser).id;

try {
const team = await prisma.team.findUnique({
where: {
id: teamId,
users: {
some: {
userId: userId,
},
},
},
});

if (!team) {
return res.status(401).end("Unauthorized");
}

const dataroom = await prisma.dataroom.findUnique({
where: {
id: dataroomId,
teamId: teamId,
},
select: { id: true, isArchived: true },
});

if (!dataroom) {
return res.status(404).json({ message: "Dataroom not found" });
}

// Toggle the archive status
const updatedDataroom = await prisma.dataroom.update({
where: { id: dataroomId },
data: {
isArchived: !dataroom.isArchived,
},
});

res.status(200).json({ isArchived: updatedDataroom.isArchived });
} catch (error) {
console.error("Request error", error);
res.status(500).json({ message: "Error updating dataroom archive status" });
}
} else {
// We only allow GET and POST requests
res.setHeader("Allow", ["GET", "POST"]);
return res.status(405).end(`Method ${req.method} Not Allowed`);
}
}
Loading
Loading