feat: improve team settings loading

This commit is contained in:
Marc Seitz
2025-10-10 12:33:36 +02:00
parent 9ef10648ab
commit 1c54548fdc
5 changed files with 119 additions and 12 deletions

View File

@@ -25,6 +25,7 @@ import {
} from "@/lib/folders/create-folder";
import { usePlan } from "@/lib/swr/use-billing";
import useLimits from "@/lib/swr/use-limits";
import { useTeamSettings } from "@/lib/swr/use-team-settings";
import { CustomUser } from "@/lib/types";
import { cn } from "@/lib/utils";
import { getSupportedContentType } from "@/lib/utils/get-content-type";
@@ -103,6 +104,11 @@ export default function UploadZone({
? limits?.documents - limits?.usage?.documents
: 0;
// Fetch team settings with proper revalidation - ensures settings stay fresh across tabs
const { settings: teamSettings } = useTeamSettings(teamInfo?.currentTeam?.id);
const replicateDataroomFolders =
teamSettings?.replicateDataroomFolders ?? true;
// Track if we've created the dataroom folder in "All Documents" for non-replication mode
// Using promise-lock pattern to prevent race conditions during concurrent folder creation
const dataroomFolderPathRef = useRef<string | null>(null);
@@ -113,7 +119,7 @@ export default function UploadZone({
useEffect(() => {
dataroomFolderPathRef.current = null;
dataroomFolderCreationPromiseRef.current = null;
}, [teamInfo?.currentTeam?.replicateDataroomFolders]);
}, [replicateDataroomFolders, dataroomId]);
const fileSizeLimits = useMemo(
() =>
@@ -618,10 +624,6 @@ export default function UploadZone({
isFirstLevelFolder,
});
// Get team's replication setting, default to true if not set
const replicateDataroomFolders =
teamInfo.currentTeam?.replicateDataroomFolders ?? true;
// If replication is disabled, ensure the dataroom folder exists in "All Documents"
// Uses promise-lock pattern to prevent race conditions
if (!replicateDataroomFolders && dataroomName) {
@@ -730,9 +732,6 @@ export default function UploadZone({
: entry.fullPath;
// Determine where to upload in "All Documents"
const replicateDataroomFolders =
teamInfo.currentTeam?.replicateDataroomFolders ?? true;
if (!replicateDataroomFolders && dataroomId && dataroomName) {
// If replication is disabled, ensure the dataroom folder exists and use it
// This await is safe because getOrCreateDataroomFolder uses a promise-lock

View File

@@ -36,6 +36,7 @@ export const TeamProvider = ({ children }: TeamContextProps): JSX.Element => {
const { teams, loading } = useTeams();
const [currentTeam, setCurrentTeamState] = useState<Team | null>(null);
// Effect to set initial currentTeam on mount
useEffect(() => {
if (!teams || teams.length === 0 || currentTeam) return;

View File

@@ -0,0 +1,31 @@
import useSWR from "swr";
import { fetcher } from "@/lib/utils";
interface TeamSettings {
replicateDataroomFolders: boolean;
enableExcelAdvancedMode: boolean;
}
/**
* Hook to fetch fresh team settings with proper revalidation.
* Useful when you need to ensure settings are up-to-date across tabs.
*/
export function useTeamSettings(teamId: string | undefined | null) {
const { data, error, isValidating } = useSWR<TeamSettings>(
teamId ? `/api/teams/${teamId}/settings` : null,
fetcher,
{
revalidateOnFocus: true,
revalidateOnReconnect: true,
dedupingInterval: 5000, // Short deduping for settings
},
);
return {
settings: data,
isLoading: !data && !error,
isError: error,
isValidating,
};
}

View File

@@ -0,0 +1,64 @@
import { NextApiRequest, NextApiResponse } from "next";
import { getServerSession } from "next-auth/next";
import { errorhandler } from "@/lib/errorHandler";
import prisma from "@/lib/prisma";
import { CustomUser } from "@/lib/types";
import { authOptions } from "../../auth/[...nextauth]";
export default async function handle(
req: NextApiRequest,
res: NextApiResponse,
) {
if (req.method === "GET") {
// GET /api/teams/:teamId/settings
const session = await getServerSession(req, res, authOptions);
if (!session) {
return res.status(401).end("Unauthorized");
}
const { teamId } = req.query as { teamId: string };
const userId = (session.user as CustomUser).id;
try {
// Verify user has access to the team
const teamAccess = await prisma.userTeam.findUnique({
where: {
userId_teamId: {
userId: userId,
teamId: teamId,
},
},
select: { teamId: true },
});
if (!teamAccess) {
return res.status(401).end("Unauthorized");
}
// Fetch only the settings fields
const teamSettings = await prisma.team.findUnique({
where: {
id: teamId,
},
select: {
replicateDataroomFolders: true,
enableExcelAdvancedMode: true,
},
});
if (!teamSettings) {
return res.status(404).json({ error: "Team not found" });
}
return res.status(200).json(teamSettings);
} catch (error) {
errorhandler(error, res);
}
} else {
res.setHeader("Allow", ["GET"]);
return res.status(405).end(`Method ${req.method} Not Allowed`);
}
}

View File

@@ -7,6 +7,7 @@ import { mutate } from "swr";
import { useAnalytics } from "@/lib/analytics";
import { usePlan } from "@/lib/swr/use-billing";
import { useTeamSettings } from "@/lib/swr/use-team-settings";
import { validateContent } from "@/lib/utils/sanitize-html";
import { UpgradePlanModal } from "@/components/billing/upgrade-plan-modal";
@@ -26,6 +27,9 @@ export default function General() {
const [planModalTrigger, setPlanModalTrigger] = useState<string>("");
const [planModalOpen, setPlanModalOpen] = useState<boolean>(false);
// Fetch fresh team settings with proper revalidation
const { settings: teamSettings } = useTeamSettings(teamId);
const showUpgradeModal = (plan: PlanEnum, trigger: string) => {
setSelectedPlan(plan);
setPlanModalTrigger(trigger);
@@ -62,7 +66,11 @@ export default function General() {
const { error } = await res.json();
throw new Error(error.message);
}
await Promise.all([mutate(`/api/teams/${teamId}`), mutate(`/api/teams`)]);
await Promise.all([
mutate(`/api/teams/${teamId}`),
mutate(`/api/teams`),
mutate(`/api/teams/${teamId}/settings`),
]);
return res.json();
});
@@ -97,7 +105,11 @@ export default function General() {
const { error } = await res.json();
throw new Error(error.message);
}
await Promise.all([mutate(`/api/teams/${teamId}`), mutate(`/api/teams`)]);
await Promise.all([
mutate(`/api/teams/${teamId}`),
mutate(`/api/teams`),
mutate(`/api/teams/${teamId}/settings`),
]);
return res.json();
});
@@ -188,7 +200,7 @@ export default function General() {
placeholder: "Enable advanced mode for Excel files",
}}
defaultValue={String(
teamInfo?.currentTeam?.enableExcelAdvancedMode ?? false,
teamSettings?.enableExcelAdvancedMode ?? false,
)}
helpText="When enabled, newly uploaded Excel files will be viewed using the Microsoft Office viewer for better formatting and compatibility."
handleSubmit={handleExcelAdvancedModeChange}
@@ -204,7 +216,7 @@ export default function General() {
placeholder: "Replicate folder structure in All Documents",
}}
defaultValue={String(
teamInfo?.currentTeam?.replicateDataroomFolders ?? true,
teamSettings?.replicateDataroomFolders ?? true,
)}
helpText="When enabled, folders uploaded to datarooms will be created in 'All Documents' with the same structure. When disabled, all documents will be placed in a single folder named after the dataroom in 'All Documents'."
handleSubmit={handleReplicateFoldersChange}