mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-03 05:10:16 +03:00
Signing UI edge-case cleanup (#6849)
This commit is contained in:
@@ -130,7 +130,12 @@ const ShareManagementModal: React.FC<ShareManagementModalProps> = ({
|
|||||||
}, [config?.frontendUrl]);
|
}, [config?.frontendUrl]);
|
||||||
|
|
||||||
const loadShareLinks = useCallback(async () => {
|
const loadShareLinks = useCallback(async () => {
|
||||||
if (!file.remoteStorageId) return;
|
if (!file.remoteStorageId) {
|
||||||
|
// No remote file yet — clear any leftover state from a previously opened file.
|
||||||
|
setShareLinks([]);
|
||||||
|
setSharedUsers([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setErrorMessage(null);
|
setErrorMessage(null);
|
||||||
try {
|
try {
|
||||||
@@ -161,6 +166,10 @@ const ShareManagementModal: React.FC<ShareManagementModalProps> = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (opened) {
|
if (opened) {
|
||||||
|
// Clear the previous file's data before loading so a stale list is never
|
||||||
|
// shown (and never targeted by a Remove click) while the new file resolves.
|
||||||
|
setShareLinks([]);
|
||||||
|
setSharedUsers([]);
|
||||||
loadShareLinks();
|
loadShareLinks();
|
||||||
setActivityMap({});
|
setActivityMap({});
|
||||||
setShareRole("editor");
|
setShareRole("editor");
|
||||||
|
|||||||
@@ -331,6 +331,12 @@ export const SignaturePreviewLayer = memo(function SignaturePreviewLayer({
|
|||||||
newY = startTop + (startHeight - newHeight);
|
newY = startTop + (startHeight - newHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep the box on-page (mirrors the placement clamp).
|
||||||
|
newWidth = Math.min(newWidth, 1);
|
||||||
|
newHeight = Math.min(newHeight, 1);
|
||||||
|
newX = Math.max(0, Math.min(newX, 1 - newWidth));
|
||||||
|
newY = Math.max(0, Math.min(newY, 1 - newHeight));
|
||||||
|
|
||||||
onChange(
|
onChange(
|
||||||
previews.map((p) =>
|
previews.map((p) =>
|
||||||
p.id === preview.id
|
p.id === preview.id
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import apiClient from "@app/services/apiClient";
|
import apiClient from "@app/services/apiClient";
|
||||||
import { alert } from "@app/components/toast";
|
import { alert } from "@app/components/toast";
|
||||||
@@ -103,6 +103,10 @@ export function useSigningSessionController(enabled: boolean) {
|
|||||||
const [requestData, setRequestData] = useState<SigningRequestData | null>(
|
const [requestData, setRequestData] = useState<SigningRequestData | null>(
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
|
// The session currently shown in the detail view. A refresh checks this at
|
||||||
|
// resolve time so a request dispatched before navigation is discarded rather
|
||||||
|
// than painting its data onto whatever is now on screen.
|
||||||
|
const openDetailSessionIdRef = useRef<string | null>(null);
|
||||||
|
|
||||||
// Leaving the tool (panel unmounts) must not leave the signing document and
|
// Leaving the tool (panel unmounts) must not leave the signing document and
|
||||||
// overlays lingering on the shared viewer.
|
// overlays lingering on the shared viewer.
|
||||||
@@ -111,6 +115,7 @@ export function useSigningSessionController(enabled: boolean) {
|
|||||||
}, [setOverlay]);
|
}, [setOverlay]);
|
||||||
|
|
||||||
const backToList = useCallback(() => {
|
const backToList = useCallback(() => {
|
||||||
|
openDetailSessionIdRef.current = null;
|
||||||
setOverlay(null);
|
setOverlay(null);
|
||||||
setDetailData(null);
|
setDetailData(null);
|
||||||
setRequestData(null);
|
setRequestData(null);
|
||||||
@@ -203,6 +208,9 @@ export function useSigningSessionController(enabled: boolean) {
|
|||||||
);
|
);
|
||||||
const session = response.data;
|
const session = response.data;
|
||||||
markSessionSeen(session.sessionId, countSignedParticipants(session));
|
markSessionSeen(session.sessionId, countSignedParticipants(session));
|
||||||
|
// Discard a refresh that resolves after the user navigated away, so we
|
||||||
|
// never paint this session's data onto another document.
|
||||||
|
if (openDetailSessionIdRef.current !== session.sessionId) return;
|
||||||
setDetailData((prev) => (prev ? { ...prev, session } : prev));
|
setDetailData((prev) => (prev ? { ...prev, session } : prev));
|
||||||
// Keep the read-only overlay in sync as participants sign.
|
// Keep the read-only overlay in sync as participants sign.
|
||||||
setOverlay((prev) =>
|
setOverlay((prev) =>
|
||||||
@@ -275,6 +283,8 @@ export function useSigningSessionController(enabled: boolean) {
|
|||||||
detailResponse.data.myStatus === "NOTIFIED" ||
|
detailResponse.data.myStatus === "NOTIFIED" ||
|
||||||
detailResponse.data.myStatus === "VIEWED";
|
detailResponse.data.myStatus === "VIEWED";
|
||||||
|
|
||||||
|
// Leaving the detail view: stop any in-flight detail refresh from applying.
|
||||||
|
openDetailSessionIdRef.current = null;
|
||||||
// Seed the viewer with the document immediately; the request panel enriches
|
// Seed the viewer with the document immediately; the request panel enriches
|
||||||
// the overlay with interactive placement props once it mounts.
|
// the overlay with interactive placement props once it mounts.
|
||||||
setOverlay({ file: pdfFile });
|
setOverlay({ file: pdfFile });
|
||||||
@@ -353,6 +363,7 @@ export function useSigningSessionController(enabled: boolean) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openDetailSessionIdRef.current = session.sessionId;
|
||||||
setOverlay({
|
setOverlay({
|
||||||
file: pdfFile,
|
file: pdfFile,
|
||||||
signaturePreviews: computeWetSignaturePreviews(detailResponse.data),
|
signaturePreviews: computeWetSignaturePreviews(detailResponse.data),
|
||||||
|
|||||||
Reference in New Issue
Block a user