feat: re-render bookings page after feature opt-in without full refresh (#27873)
* feat: re-render bookings page after feature opt-in without full refresh Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: make onOptInSuccess a required prop Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -6,8 +6,8 @@ import FeatureOptInBannerWrapper from "~/feature-opt-in/components/FeatureOptInB
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import classNames from "@calcom/ui/classNames";
|
||||
import dynamic from "next/dynamic";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useMemo } from "react";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { useFeatureOptInBanner } from "../../feature-opt-in/hooks/useFeatureOptInBanner";
|
||||
import { BookingListContainer } from "../components/BookingListContainer";
|
||||
import { useActiveFiltersValidator } from "../hooks/useActiveFiltersValidator";
|
||||
@@ -78,7 +78,11 @@ export default function Bookings(props: BookingsProps) {
|
||||
|
||||
function BookingsContent({ status, permissions, bookingsV3Enabled, bookingAuditEnabled }: BookingsProps) {
|
||||
const [view] = useBookingsView({ bookingsV3Enabled });
|
||||
const optInBanner = useFeatureOptInBanner("bookings-v3");
|
||||
const router = useRouter();
|
||||
const handleOptInSuccess = useCallback(() => {
|
||||
router.refresh();
|
||||
}, [router]);
|
||||
const optInBanner = useFeatureOptInBanner("bookings-v3", { onOptInSuccess: handleOptInSuccess });
|
||||
|
||||
return (
|
||||
<div className={classNames(view === "calendar" && "-mb-8")}>
|
||||
|
||||
@@ -75,7 +75,9 @@ describe("useFeatureOptInBanner", () => {
|
||||
it("shows banner for normal users when eligible", () => {
|
||||
mockUseSession.mockReturnValue({ data: { user: {} } });
|
||||
|
||||
const { result } = renderHook(() => useFeatureOptInBanner("bookings-v3"));
|
||||
const { result } = renderHook(() =>
|
||||
useFeatureOptInBanner("bookings-v3", { onOptInSuccess: vi.fn() })
|
||||
);
|
||||
|
||||
expect(result.current.shouldShow).toBe(true);
|
||||
});
|
||||
@@ -85,8 +87,23 @@ describe("useFeatureOptInBanner", () => {
|
||||
data: { user: { impersonatedBy: { id: 999, email: "admin@cal.com" } } },
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useFeatureOptInBanner("bookings-v3"));
|
||||
const { result } = renderHook(() =>
|
||||
useFeatureOptInBanner("bookings-v3", { onOptInSuccess: vi.fn() })
|
||||
);
|
||||
|
||||
expect(result.current.shouldShow).toBe(true);
|
||||
});
|
||||
|
||||
it("calls onOptInSuccess callback when markOptedIn is invoked", () => {
|
||||
mockUseSession.mockReturnValue({ data: { user: {} } });
|
||||
const onOptInSuccess = vi.fn();
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useFeatureOptInBanner("bookings-v3", { onOptInSuccess })
|
||||
);
|
||||
|
||||
result.current.markOptedIn();
|
||||
|
||||
expect(onOptInSuccess).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -58,7 +58,14 @@ function isFeatureOptedIn(featureId: string): boolean {
|
||||
return getFeatureOptInTimestamp(featureId) !== null;
|
||||
}
|
||||
|
||||
function useFeatureOptInBanner(featureId: string): UseFeatureOptInBannerResult {
|
||||
type UseFeatureOptInBannerOptions = {
|
||||
onOptInSuccess: () => void;
|
||||
};
|
||||
|
||||
function useFeatureOptInBanner(
|
||||
featureId: string,
|
||||
options: UseFeatureOptInBannerOptions
|
||||
): UseFeatureOptInBannerResult {
|
||||
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
||||
const [isDismissed, setIsDismissed] = useState(() => isFeatureDismissed(featureId));
|
||||
const [isOptedIn, setIsOptedIn] = useState(() => isFeatureOptedIn(featureId));
|
||||
@@ -135,7 +142,8 @@ function useFeatureOptInBanner(featureId: string): UseFeatureOptInBannerResult {
|
||||
const markOptedIn = useCallback(() => {
|
||||
setFeatureOptedIn(featureId);
|
||||
setIsOptedIn(true);
|
||||
}, [featureId]);
|
||||
options.onOptInSuccess();
|
||||
}, [featureId, options.onOptInSuccess]);
|
||||
|
||||
const openDialog = useCallback(() => {
|
||||
posthog.capture("feature_opt_in_banner_try_it_clicked", {
|
||||
|
||||
Reference in New Issue
Block a user