mirror of
https://github.com/mfts/papermark.git
synced 2025-12-20 01:03:24 +08:00
feat: improve team settings loading
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
31
lib/swr/use-team-settings.ts
Normal file
31
lib/swr/use-team-settings.ts
Normal 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,
|
||||
};
|
||||
}
|
||||
64
pages/api/teams/[teamId]/settings.ts
Normal file
64
pages/api/teams/[teamId]/settings.ts
Normal 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`);
|
||||
}
|
||||
}
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user