fix: preserve frontend medication deep links
This commit is contained in:
@@ -257,8 +257,10 @@ export function MedicationsPage() {
|
||||
useUnsavedChangesWarning(formChanged);
|
||||
|
||||
// View mode: grid (default) or form (edit/new)
|
||||
// If navigating in with editMedId, suppress rendering until the edit form is ready
|
||||
const [pendingEditTransition, setPendingEditTransition] = useState(() => searchParams.has("editMedId"));
|
||||
// If navigating in with a medication deep-link, suppress rendering until the target form is ready
|
||||
const [pendingEditTransition, setPendingEditTransition] = useState(
|
||||
() => searchParams.has("editMedId") || searchParams.has("viewMedId")
|
||||
);
|
||||
const [viewMode, setViewMode] = useState<"grid" | "form">(pendingEditTransition ? "form" : "grid");
|
||||
const [lightboxImage, setLightboxImage] = useState<{ src: string; alt: string } | null>(null);
|
||||
const [activeTab, setActiveTab] = useState<"general" | "stock" | "prescription" | "schedule">("general");
|
||||
@@ -269,9 +271,23 @@ export function MedicationsPage() {
|
||||
useEffect(() => {
|
||||
showEditModalRef.current = showEditModal;
|
||||
}, [showEditModal]);
|
||||
const processedEditMedIdRef = useRef<string | null>(null);
|
||||
const processedMedicationLinkRef = useRef<string | null>(null);
|
||||
const hasDesktopFormHistoryState = useRef(false);
|
||||
|
||||
const getMedicationLinkState = useCallback((params: URLSearchParams) => {
|
||||
const viewMedId = params.get("viewMedId");
|
||||
if (viewMedId) {
|
||||
return { mode: "view" as const, linkedMedId: viewMedId };
|
||||
}
|
||||
|
||||
const editMedId = params.get("editMedId");
|
||||
if (editMedId) {
|
||||
return { mode: "edit" as const, linkedMedId: editMedId };
|
||||
}
|
||||
|
||||
return { mode: null, linkedMedId: null };
|
||||
}, []);
|
||||
|
||||
// Sync formChanged state to the global context for navigation blocking
|
||||
const { setHasUnsavedChanges } = useUnsavedChanges();
|
||||
useEffect(() => {
|
||||
@@ -819,12 +835,13 @@ export function MedicationsPage() {
|
||||
[t]
|
||||
);
|
||||
|
||||
const clearEditMedIdParam = useCallback(() => {
|
||||
const clearMedicationLinkParams = useCallback(() => {
|
||||
setSearchParams(
|
||||
(prevParams) => {
|
||||
if (!prevParams.has("editMedId")) return prevParams;
|
||||
if (!prevParams.has("editMedId") && !prevParams.has("viewMedId")) return prevParams;
|
||||
const nextParams = new URLSearchParams(prevParams);
|
||||
nextParams.delete("editMedId");
|
||||
nextParams.delete("viewMedId");
|
||||
return nextParams;
|
||||
},
|
||||
{ replace: true }
|
||||
@@ -848,7 +865,7 @@ export function MedicationsPage() {
|
||||
setShowUnsavedConfirm(true);
|
||||
return;
|
||||
}
|
||||
clearEditMedIdParam();
|
||||
clearMedicationLinkParams();
|
||||
// Mark as confirmed to avoid double confirmation in popstate handler
|
||||
closeConfirmedRef.current = true;
|
||||
window.history.back();
|
||||
@@ -1159,7 +1176,7 @@ export function MedicationsPage() {
|
||||
if (shouldCloseMobileModal) {
|
||||
// Treat post-save close as confirmed so popstate does not trigger unsaved guards.
|
||||
closeConfirmedRef.current = true;
|
||||
clearEditMedIdParam();
|
||||
clearMedicationLinkParams();
|
||||
setShowEditModal(false);
|
||||
setReadOnlyView(false);
|
||||
setActiveTab("general");
|
||||
@@ -1188,7 +1205,8 @@ export function MedicationsPage() {
|
||||
// Handle browser back button for modals and unsaved changes
|
||||
useEffect(() => {
|
||||
const handlePopState = () => {
|
||||
const currentEditMedId = new URLSearchParams(window.location.search).get("editMedId");
|
||||
const currentParams = new URLSearchParams(window.location.search);
|
||||
const { mode: currentLinkMode, linkedMedId: currentMedicationLinkId } = getMedicationLinkState(currentParams);
|
||||
|
||||
// Obsolete confirmation is open — dismiss it and stay where we are
|
||||
if (showObsoleteConfirm) {
|
||||
@@ -1207,10 +1225,10 @@ export function MedicationsPage() {
|
||||
// If close was already confirmed programmatically, allow navigation
|
||||
if (closeConfirmedRef.current) {
|
||||
closeConfirmedRef.current = false;
|
||||
if (currentEditMedId) {
|
||||
if (currentMedicationLinkId && currentLinkMode) {
|
||||
// Prevent URL popstate from immediately reopening mobile edit for the same id.
|
||||
processedEditMedIdRef.current = currentEditMedId;
|
||||
clearEditMedIdParam();
|
||||
processedMedicationLinkRef.current = `${currentLinkMode}:${currentMedicationLinkId}`;
|
||||
clearMedicationLinkParams();
|
||||
}
|
||||
if (showEditModal) {
|
||||
setShowEditModal(false);
|
||||
@@ -1231,11 +1249,11 @@ export function MedicationsPage() {
|
||||
setShowUnsavedConfirm(true);
|
||||
return;
|
||||
}
|
||||
if (currentEditMedId) {
|
||||
if (currentMedicationLinkId && currentLinkMode) {
|
||||
// Mark as handled before URL cleanup to avoid same-tick re-open races.
|
||||
processedEditMedIdRef.current = currentEditMedId;
|
||||
processedMedicationLinkRef.current = `${currentLinkMode}:${currentMedicationLinkId}`;
|
||||
}
|
||||
clearEditMedIdParam();
|
||||
clearMedicationLinkParams();
|
||||
setShowEditModal(false);
|
||||
resetForm();
|
||||
resetMedicationEnrichment();
|
||||
@@ -1271,7 +1289,16 @@ export function MedicationsPage() {
|
||||
};
|
||||
window.addEventListener("popstate", handlePopState);
|
||||
return () => window.removeEventListener("popstate", handlePopState);
|
||||
}, [showObsoleteConfirm, showDeleteConfirm, showEditModal, viewMode, formChanged, resetForm, clearEditMedIdParam]);
|
||||
}, [
|
||||
showObsoleteConfirm,
|
||||
showDeleteConfirm,
|
||||
showEditModal,
|
||||
viewMode,
|
||||
formChanged,
|
||||
resetForm,
|
||||
clearMedicationLinkParams,
|
||||
getMedicationLinkState,
|
||||
]);
|
||||
|
||||
// Close modal on Escape key
|
||||
useEffect(() => {
|
||||
@@ -1389,22 +1416,23 @@ export function MedicationsPage() {
|
||||
}, [activeMeds, editingId]);
|
||||
|
||||
useEffect(() => {
|
||||
const editMedId = searchParams.get("editMedId");
|
||||
if (!editMedId) {
|
||||
processedEditMedIdRef.current = null;
|
||||
const { mode: linkMode, linkedMedId } = getMedicationLinkState(searchParams);
|
||||
if (!linkedMedId || !linkMode) {
|
||||
processedMedicationLinkRef.current = null;
|
||||
return;
|
||||
}
|
||||
if (processedEditMedIdRef.current === editMedId) return;
|
||||
const parsedMedId = Number.parseInt(editMedId, 10);
|
||||
const linkKey = `${linkMode}:${linkedMedId}`;
|
||||
if (processedMedicationLinkRef.current === linkKey) return;
|
||||
const parsedMedId = Number.parseInt(linkedMedId, 10);
|
||||
if (Number.isNaN(parsedMedId)) return;
|
||||
const medicationToEdit =
|
||||
meds.find((med) => med.id === parsedMedId) ?? allMeds.find((med) => med.id === parsedMedId);
|
||||
if (!medicationToEdit) return;
|
||||
|
||||
processedEditMedIdRef.current = editMedId;
|
||||
processedMedicationLinkRef.current = linkKey;
|
||||
|
||||
setShowNameValidation(false);
|
||||
setReadOnlyView(false);
|
||||
setReadOnlyView(linkMode === "view");
|
||||
setActiveTab("general");
|
||||
resetMedicationEnrichment(medicationToEdit.name || medicationToEdit.genericName || "");
|
||||
startEdit(medicationToEdit, openEditModal);
|
||||
@@ -1415,8 +1443,9 @@ export function MedicationsPage() {
|
||||
|
||||
const nextParams = new URLSearchParams(searchParams);
|
||||
nextParams.delete("editMedId");
|
||||
nextParams.delete("viewMedId");
|
||||
setSearchParams(nextParams, { replace: true });
|
||||
}, [allMeds, meds, openEditModal, searchParams, setSearchParams, startEdit]);
|
||||
}, [allMeds, getMedicationLinkState, meds, openEditModal, searchParams, setSearchParams, startEdit]);
|
||||
|
||||
const selectedMedication = useMemo(() => {
|
||||
if (!editingId) return null;
|
||||
|
||||
Reference in New Issue
Block a user