From b060494a78662fd6036449be78ec18dd4dc7e29e Mon Sep 17 00:00:00 2001 From: deibyrayo Date: Thu, 4 Dec 2025 12:33:19 -0500 Subject: [PATCH] Fix: Handle undefined window.openai in local development - Add null checks for window.openai.setWidgetState in useWidgetState hook - Enable local development by showing product details inline when window.openai is unavailable - Fixes crash that prevented local development with 'Cannot read properties of undefined' error Before this change, running the project locally would crash because the code assumed window.openai (part of the ChatGPT Apps SDK) would always be available. Now the code gracefully handles both environments: - In ChatGPT: Uses window.openai.requestModal() to open modals - In local dev: Shows product details inline in the main view This allows developers to run and test the UI components locally without errors. --- src/pizzaz-shop/index.tsx | 42 ++++++++++++++++++++------------------- src/use-widget-state.ts | 4 ++-- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/pizzaz-shop/index.tsx b/src/pizzaz-shop/index.tsx index 3fcc4cc..11cc8e9 100644 --- a/src/pizzaz-shop/index.tsx +++ b/src/pizzaz-shop/index.tsx @@ -58,12 +58,12 @@ const FILTERS: Array<{ label: string; tag?: string; }> = [ - { id: "all", label: "All" }, - { id: "vegetarian", label: "Vegetarian", tag: "vegetarian" }, - { id: "vegan", label: "Vegan", tag: "vegan" }, - { id: "size", label: "Size", tag: "size" }, - { id: "spicy", label: "Spicy", tag: "spicy" }, -]; + { id: "all", label: "All" }, + { id: "vegetarian", label: "Vegetarian", tag: "vegetarian" }, + { id: "vegan", label: "Vegan", tag: "vegan" }, + { id: "size", label: "Size", tag: "size" }, + { id: "spicy", label: "Spicy", tag: "spicy" }, + ]; const INITIAL_CART_ITEMS: CartItem[] = [ { @@ -604,12 +604,12 @@ function App() { const modalParams = viewParams && typeof viewParams === "object" ? (viewParams as { - state?: unknown; - cartItems?: unknown; - subtotal?: unknown; - total?: unknown; - totalItems?: unknown; - }) + state?: unknown; + cartItems?: unknown; + subtotal?: unknown; + total?: unknown; + totalItems?: unknown; + }) : null; const modalState = @@ -619,7 +619,9 @@ function App() { const isCartModalView = isModalView && modalState === "cart"; const shouldShowCheckoutOnly = - isCheckoutRoute || (isModalView && !isCartModalView); + isCheckoutRoute || + (isModalView && !isCartModalView) || + (selectedCartItemId != null && typeof window.openai === "undefined"); const wasModalViewRef = useRef(isModalView); useEffect(() => { @@ -730,11 +732,11 @@ function App() { anchorRect == null ? undefined : { - top: anchorRect.top, - left: anchorRect.left, - width: anchorRect.width, - height: anchorRect.height, - }; + top: anchorRect.top, + left: anchorRect.left, + width: anchorRect.width, + height: anchorRect.height, + }; void (async () => { try { @@ -886,8 +888,8 @@ function App() { const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => { - requestAnimationFrame(updateItemColumnPlacement); - }) + requestAnimationFrame(updateItemColumnPlacement); + }) : null; observer?.observe(node); diff --git a/src/use-widget-state.ts b/src/use-widget-state.ts index 9ef4afa..2ee2bff 100644 --- a/src/use-widget-state.ts +++ b/src/use-widget-state.ts @@ -32,14 +32,14 @@ export function useWidgetState( _setWidgetState((prevState) => { const newState = typeof state === "function" ? state(prevState) : state; - if (newState != null) { + if (newState != null && window.openai?.setWidgetState) { window.openai.setWidgetState(newState); } return newState; }); }, - [window.openai.setWidgetState] + [window.openai?.setWidgetState] ); return [widgetState, setWidgetState] as const;