diff --git a/src/vertex/app/changelog.md b/src/vertex/app/changelog.md index f334890af6..1161573fa0 100644 --- a/src/vertex/app/changelog.md +++ b/src/vertex/app/changelog.md @@ -3,6 +3,31 @@ > **Note**: This changelog consolidates all recent improvements, features, and fixes to the AirQo Vertex frontend. --- + +## Version 1.23.57 +**Released:** June 02, 2026 + +### Organization Picker Banner Migration + +Replaced the `ReusableToast` error call in `OrganizationPicker` with the centralized `useBannerWithDelay` hook. The shimmer progress bar dispatch (`setOrganizationSwitching`) was also moved to just before navigation fires so it only appears when the switch is actually proceeding — errors that occur before navigation never trigger the shimmer. + +
+Changes (2) + +- **Error Feedback**: Replaced `ReusableToast` with `showBannerWithDelay` (`scoped: false`) for org switch failures. Using the delayed variant ensures the banner is not cleared by `ReusableDialog`'s `hideBanner` cleanup effect that fires when the modal closes. +- **Shimmer Timing Fix**: Moved `setOrganizationSwitching({ isSwitching: true })` inside the try block just before navigation so the progress bar only appears when switching is guaranteed to proceed. The catch block no longer needs to reset it. + +
+ +
+Files Updated (1) + +- `src/vertex/components/features/org-picker/organization-picker.tsx` [MODIFIED] + +
+ +--- + ## Version 1.23.56 **Released:** May 29, 2026 diff --git a/src/vertex/components/features/org-picker/organization-picker.tsx b/src/vertex/components/features/org-picker/organization-picker.tsx index 3aeed274b2..3d4f88bd8d 100644 --- a/src/vertex/components/features/org-picker/organization-picker.tsx +++ b/src/vertex/components/features/org-picker/organization-picker.tsx @@ -17,7 +17,7 @@ import { UserContext } from "@/core/redux/slices/userSlice"; import { AqGrid01 } from "@airqo/icons-react"; import { Skeleton } from "@/components/ui/skeleton"; import { useRouter, usePathname } from "next/navigation"; -import ReusableToast from "@/components/shared/toast/ReusableToast"; +import { useBannerWithDelay } from "@/core/hooks/useBannerWithDelay"; const formatTitle = (title: string) => { if (!title) return ""; @@ -32,6 +32,7 @@ const OrganizationPicker: React.FC = () => { const userGroups = useAppSelector((state) => state.user.userGroups); const [isModalOpen, setIsModalOpen] = useState(false); const { isLoading } = useUserContext(); + const { showBannerWithDelay } = useBannerWithDelay(); const { isSwitching } = useAppSelector((state) => state.user.organizationSwitching); const pathname = usePathname(); const lastPathname = useRef(pathname); @@ -53,25 +54,16 @@ const OrganizationPicker: React.FC = () => { }, [userGroups]); const handleOrganizationChange = async (group: Group) => { - // 1. Instant UI Feedback setIsModalOpen(false); - // Clear any stale forbidden state from previous context before switching. dispatch(clearForbiddenState()); - // 2. Start Background Transition - dispatch(setOrganizationSwitching({ - isSwitching: true, - switchingTo: group.grp_title - })); - const newContext: UserContext = group.grp_title.toLowerCase() === "airqo" ? "personal" : "external-org"; try { - // 3. Optimized Background Cleanup (Non-blocking) - // We don't await these to prevent UI blocking + // Optimized Background Cleanup (Non-blocking) const orgScopedQueryKeys = [ ["devices"], ["myDevices"], @@ -93,21 +85,24 @@ const OrganizationPicker: React.FC = () => { queryClient.removeQueries({ queryKey }); }); - // 4. Update Redux State + // Start shimmer just before navigation fires + dispatch(setOrganizationSwitching({ isSwitching: true, switchingTo: group.grp_title })); + dispatch(setActiveGroup(group)); dispatch(setUserContext(newContext)); - // 5. Trigger Navigation if (pathname === "/home") { - // If already on home, we must clear immediately as pathname won't change dispatch(setOrganizationSwitching({ isSwitching: false, switchingTo: "" })); router.refresh(); } else { router.push("/home"); } } catch { - ReusableToast({ message: "Failed to switch organization", type: "ERROR" }); - dispatch(setOrganizationSwitching({ isSwitching: false, switchingTo: "" })); + showBannerWithDelay({ + severity: 'error', + message: 'Failed to switch organization. Please try again.', + scoped: false, + }); } };