From e71fd44d89602cd989a943cddba6fcf74ab4b22c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=B4mulo=20Penido?= <romulo.penido@gmail.com>
Date: Mon, 21 Oct 2024 15:42:46 -0300
Subject: [PATCH] refactor: add onComponentSelected callback function

---
 src/library-authoring/common/context.tsx       |  6 ++++++
 .../component-info/ComponentInfo.tsx           | 12 +++++-------
 .../component-picker/ComponentPicker.tsx       | 18 ++++++++++++++++--
 .../components/ComponentCard.tsx               |  7 ++-----
 4 files changed, 29 insertions(+), 14 deletions(-)

diff --git a/src/library-authoring/common/context.tsx b/src/library-authoring/common/context.tsx
index cc085ef77c..1a5927b2d1 100644
--- a/src/library-authoring/common/context.tsx
+++ b/src/library-authoring/common/context.tsx
@@ -26,6 +26,7 @@ export interface LibraryContextData {
   setCollectionId: (collectionId?: string) => void;
   // Whether we're in "component picker" mode
   componentPickerMode: boolean;
+  onComponentSelected?: (usageKey: string, category: string) => void;
   // Sidebar stuff - only one sidebar is active at any given time:
   sidebarBodyComponent: SidebarBodyComponentId | null;
   closeLibrarySidebar: () => void;
@@ -69,6 +70,8 @@ interface LibraryProviderProps {
   /** The component picker mode is a special mode where the user is selecting a component to add to a Unit (or another
    *  XBlock) */
   componentPickerMode?: boolean;
+  /** Function to call when a component is selected */
+  onComponentSelected?: (usageKey: string, category: string) => void;
   /** Only used for testing */
   initialSidebarComponentUsageKey?: string;
   /** Only used for testing */
@@ -83,6 +86,7 @@ export const LibraryProvider = ({
   libraryId,
   collectionId: collectionIdProp,
   componentPickerMode = false,
+  onComponentSelected,
   initialSidebarComponentUsageKey,
   initialSidebarCollectionId,
 }: LibraryProviderProps) => {
@@ -140,6 +144,7 @@ export const LibraryProvider = ({
     readOnly,
     isLoadingLibraryData,
     componentPickerMode,
+    onComponentSelected,
     sidebarBodyComponent,
     closeLibrarySidebar,
     openAddContentSidebar,
@@ -165,6 +170,7 @@ export const LibraryProvider = ({
     readOnly,
     isLoadingLibraryData,
     componentPickerMode,
+    onComponentSelected,
     sidebarBodyComponent,
     closeLibrarySidebar,
     openAddContentSidebar,
diff --git a/src/library-authoring/component-info/ComponentInfo.tsx b/src/library-authoring/component-info/ComponentInfo.tsx
index 4cbb35598f..bd3d5e16ee 100644
--- a/src/library-authoring/component-info/ComponentInfo.tsx
+++ b/src/library-authoring/component-info/ComponentInfo.tsx
@@ -5,6 +5,7 @@ import {
   Tabs,
   Stack,
 } from '@openedx/paragon';
+import { useCallback } from 'react';
 
 import { useLibraryContext } from '../common/context';
 import { ComponentMenu } from '../components';
@@ -23,6 +24,7 @@ const ComponentInfo = () => {
     readOnly,
     openComponentEditor,
     componentPickerMode,
+    onComponentSelected,
   } = useLibraryContext();
 
   // istanbul ignore if: this should never happen
@@ -32,13 +34,9 @@ const ComponentInfo = () => {
 
   const canEdit = canEditComponent(usageKey);
 
-  const handleAddComponentToCourse = () => {
-    window.parent.postMessage({
-      usageKey,
-      type: 'pickerComponentSelected',
-      category: getBlockType(usageKey),
-    }, '*');
-  };
+  const handleAddComponentToCourse = useCallback(() => {
+    onComponentSelected?.(usageKey, getBlockType(usageKey));
+  }, [usageKey]);
 
   return (
     <Stack>
diff --git a/src/library-authoring/component-picker/ComponentPicker.tsx b/src/library-authoring/component-picker/ComponentPicker.tsx
index 372506d4cd..c6ae860abb 100644
--- a/src/library-authoring/component-picker/ComponentPicker.tsx
+++ b/src/library-authoring/component-picker/ComponentPicker.tsx
@@ -19,8 +19,22 @@ const InnerComponentPicker: React.FC<LibraryComponentPickerProps> = ({ returnToL
   return <LibraryAuthoringPage returnToLibrarySelection={returnToLibrarySelection} />;
 };
 
+const defaultComponentSelectedCallback = (usageKey: string, category: string) => {
+  window.parent.postMessage({
+    usageKey,
+    type: 'pickerComponentSelected',
+    category,
+  }, '*');
+};
+
+interface ComponentPickerProps {
+  onComponentSelected: (usageKey: string, category: string) => void;
+}
+
 // eslint-disable-next-line import/prefer-default-export
-export const ComponentPicker = () => {
+export const ComponentPicker: React.FC<ComponentPickerProps> = ({
+  onComponentSelected = defaultComponentSelectedCallback,
+}) => {
   const [currentStep, setCurrentStep] = useState('select-library');
   const [selectedLibrary, setSelectedLibrary] = useState('');
 
@@ -43,7 +57,7 @@ export const ComponentPicker = () => {
       </Stepper.Step>
 
       <Stepper.Step eventKey="pick-components" title="Pick some components">
-        <LibraryProvider libraryId={selectedLibrary} componentPickerMode>
+        <LibraryProvider libraryId={selectedLibrary} componentPickerMode onComponentSelected={onComponentSelected}>
           <InnerComponentPicker returnToLibrarySelection={returnToLibrarySelection} />
         </LibraryProvider>
       </Stepper.Step>
diff --git a/src/library-authoring/components/ComponentCard.tsx b/src/library-authoring/components/ComponentCard.tsx
index 5dd56381a4..4be3619526 100644
--- a/src/library-authoring/components/ComponentCard.tsx
+++ b/src/library-authoring/components/ComponentCard.tsx
@@ -93,6 +93,7 @@ const ComponentCard = ({ contentHit }: ComponentCardProps) => {
   const {
     openComponentInfoSidebar,
     componentPickerMode,
+    onComponentSelected,
   } = useLibraryContext();
 
   const {
@@ -109,11 +110,7 @@ const ComponentCard = ({ contentHit }: ComponentCardProps) => {
   const displayName = formatted?.displayName ?? '';
 
   const handleAddComponentToCourse = () => {
-    window.parent.postMessage({
-      usageKey,
-      type: 'pickerComponentSelected',
-      category: blockType,
-    }, '*');
+    onComponentSelected?.(usageKey, blockType);
   };
 
   return (