Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/vertex/app/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

<details>
<summary><strong>Changes (2)</strong></summary>

- **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.

</details>

<details>
<summary><strong>Files Updated (1)</strong></summary>

- `src/vertex/components/features/org-picker/organization-picker.tsx` [MODIFIED]

</details>

---

## Version 1.23.56
**Released:** May 29, 2026

Expand Down
27 changes: 11 additions & 16 deletions src/vertex/components/features/org-picker/organization-picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 "";
Expand All @@ -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);
Expand All @@ -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"],
Expand All @@ -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 {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this success banner for Switched to ..., it is not necessary @BwanikaRobert

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Codebmk Actually in the production even the error banner won't be shown because all the switching happens at the client side.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kindly remove it still @BwanikaRobert. Thanks.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The success banner has been removed. We only have the error banner left.

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,
});
}
};

Expand Down
Loading