Files
calendar/packages/features/ee/organizations/hooks/useWelcomeModal.ts
T
sean-brydonandGitHub 79bcd6dc30 feat: welcome to organizations modal after creation (#24823)
## What does this PR do?

Adds a welcome modal for new organizations that appears after organization creation. The modal showcases key features of the Organizations plan and provides a better onboarding experience.

## Visual Demo (For contributors especially)

#### Image Demo:

![CleanShot 2025-10-31 at 12.19.17.gif](https://app.graphite.dev/user-attachments/assets/4f8c3286-9400-40e6-aeb4-8a012f604c64.gif)

## Mandatory Tasks (DO NOT REMOVE)

- [x] I have self-reviewed the code.
- [x] I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. N/A
- [x] I confirm automated tests are in place that prove my fix is effective or that my feature works.

## How should this be tested?

1. Create a new organization through either:
   - The onboarding flow
   - The settings/organizations/new page
   - The organization creation form

2. After successful creation and redirect, verify the welcome modal appears showing organization features.

3. Verify the modal can be closed by:
   - Clicking the "Continue" button
   - Clicking outside the modal
   - Pressing ESC key

4. Verify the modal doesn't reappear after being closed (query param and session storage should be cleared).

## Checklist

- I have read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md)
- My code follows the style guidelines of this project
- I have commented my code, particularly in hard-to-understand areas
- I have checked if my changes generate no new warnings
2025-11-03 11:11:16 +00:00

52 lines
1.3 KiB
TypeScript

import { parseAsBoolean, useQueryState } from "nuqs";
import { useEffect, useState } from "react";
const STORAGE_KEY = "showNewOrgModal";
export function useWelcomeModal() {
const [newOrganizationModal, setNewOrganizationModal] = useQueryState(
"newOrganizationModal",
parseAsBoolean.withDefault(false)
);
const [isOpen, setIsOpen] = useState(false);
useEffect(() => {
// Check query param first
if (newOrganizationModal) {
setIsOpen(true);
return;
}
// Check sessionStorage as fallback (for cases where we redirect through personal onboarding)
if (typeof window !== "undefined" && sessionStorage.getItem(STORAGE_KEY) === "true") {
setIsOpen(true);
}
}, [newOrganizationModal]);
const closeModal = () => {
setIsOpen(false);
// Remove the query param from URL
setNewOrganizationModal(null);
// Also clear sessionStorage
if (typeof window !== "undefined") {
sessionStorage.removeItem(STORAGE_KEY);
}
};
return {
isOpen,
closeModal,
};
}
/**
* Helper function to set the flag that triggers the welcome modal.
* Use this before redirecting to ensure the modal shows after navigation.
*/
export function setShowNewOrgModalFlag() {
if (typeof window !== "undefined") {
sessionStorage.setItem(STORAGE_KEY, "true");
}
}