Files
zooqueenandHanzo Dev dff97c65fb sqlite: name the enum columns by their type instead of restating them
The last of it, all one shape: sqlite has no enum, so those columns read back
as `string`, while hand-written prop and payload types restated the literals.
Each now names the type the shim already exports — DownloadType, ViewType —
so the column and the code that consumes it stay in step.

`linkType` reaches an outgoing webhook, whose contract is a zod enum and
should stay strict, so the assertion happens where the payload is built and
LINK_TYPES lives with the schema that defines it.

DocumentPage.embeddedLinks is the last postgres String[] that became Json;
duplicating a document read it back out and wrote it straight into the copy.

99 errors -> 0. Verified from a clean `prisma generate`.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-09 12:01:34 -07:00

99 lines
2.7 KiB
TypeScript

import ErrorPage from "next/error";
import { DownloadCloudIcon } from "lucide-react";
import BarChartComponent from "@/components/charts/bar-chart";
import { useVisitorStats } from "@/lib/swr/use-stats";
import StatsChartSkeleton from "../documents/stats-chart-skeleton";
import { DownloadType } from "@prisma/client";
export default function VisitorChart({
documentId,
viewId,
totalPages = 0,
versionNumber,
downloadType,
downloadMetadata,
}: {
documentId: string;
viewId: string;
totalPages?: number;
versionNumber?: number;
downloadType?: DownloadType | null;
downloadMetadata?: {
folderName?: string;
folderPath?: string;
dataroomName?: string;
documentCount?: number;
documents?: {
id: string;
name: string;
}[];
} | null;
}) {
const { stats, error } = useVisitorStats(viewId);
if (error && error.status === 404) {
return <ErrorPage statusCode={404} />;
}
if (!stats?.duration.data) {
return <StatsChartSkeleton />;
}
// Check if this is a download-only view (no pages viewed)
const hasViewData = stats.duration.data.some(
(item) => item.sum_duration > 0,
);
// If no view data and it's a download (any type), show a message instead of the graph
if (!hasViewData && downloadType) {
let downloadMessage = "";
if (downloadType === "FOLDER" && downloadMetadata?.folderName) {
downloadMessage = `Downloaded without viewing via dataroom folder "${downloadMetadata.folderName}"`;
} else if (downloadType === "BULK" && downloadMetadata?.dataroomName) {
downloadMessage = `Downloaded without viewing via bulk download from "${downloadMetadata.dataroomName}" dataroom`;
} else if (downloadType === "BULK") {
downloadMessage = "Downloaded without viewing via bulk dataroom download";
} else if (downloadType === "SINGLE") {
downloadMessage = "Downloaded without viewing";
}
return (
<div className="rounded-bl-lg border-b border-l p-4">
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<DownloadCloudIcon className="h-4 w-4" />
<span>{downloadMessage}</span>
</div>
</div>
);
}
let durationData = Array.from({ length: totalPages }, (_, i) => ({
pageNumber: (i + 1).toString(),
sum_duration: 0,
}));
const swrData = stats?.duration;
durationData = durationData.map((item) => {
const swrItem = swrData.data.find(
(data) => data.pageNumber === item.pageNumber,
);
return swrItem ? swrItem : item;
});
return (
<div className="rounded-bl-lg border-b border-l pb-0.5 pl-0.5 md:pb-1 md:pl-1">
<BarChartComponent
data={durationData}
isSum={true}
versionNumber={versionNumber}
/>
</div>
);
}