diff --git a/apps/teams-test-app/src/App.css b/apps/teams-test-app/src/App.css index 76b873fae0..7b61b5be4d 100644 --- a/apps/teams-test-app/src/App.css +++ b/apps/teams-test-app/src/App.css @@ -16,3 +16,31 @@ .App-container { display: grid; } + +/* ============================================================== + * Grouped Mode - Button, Section Button, and Section Content Styles + * ============================================================== */ + +/* Style for individual section buttons */ +.section-button-in-grouped-mode { + background-color: #0f6cbd; /* Blue background for buttons */ + color: white; /* White text */ + border: none; /* Remove default border */ + border-radius: 4px; /* Rounded corners */ + padding: 8px 15px; /* Padding inside the button */ + cursor: pointer; /* Pointer cursor on hover */ + font-size: 14px; /* Font size of the button text */ +} + +/* Style for section button hover effect */ +.section-button-in-grouped-mode:hover { + background-color: #0056b3; /* Darker blue on hover */ +} + +/* Style for the section content */ +.section-content-in-grouped-mode { + margin-top: 2px; /* Space above each section's content */ + border: 1px solid #ddd; /* Light grey border around the section */ + padding: 4px; /* Padding inside the section */ + border-radius: 4px; /* Rounded corners */ +} diff --git a/apps/teams-test-app/src/pages/TestApp.tsx b/apps/teams-test-app/src/pages/TestApp.tsx index b7f4355b73..d4531e3fa8 100644 --- a/apps/teams-test-app/src/pages/TestApp.tsx +++ b/apps/teams-test-app/src/pages/TestApp.tsx @@ -1,5 +1,5 @@ import { IAppWindow } from '@microsoft/teams-js'; -import React from 'react'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; import AppAPIs from '../components/AppAPIs'; import AppEntityAPIs from '../components/AppEntityAPIs'; @@ -69,15 +69,128 @@ import VisualMediaAPIs from '../components/VisualMediaAPIs'; import WebStorageAPIs from '../components/WebStorageAPIs'; export const appInitializationTestQueryParameter = 'appInitializationTest'; +export const groupedModeQueryParameter = 'groupedMode'; // Define query parameter name for grouped mode export const TestApp: React.FC = () => { - const dialogWindowRef = React.useRef(null); - const [iframeUrl, setIframeUrl] = React.useState(null); + const dialogWindowRef = useRef(null); + const [iframeUrl, setIframeUrl] = useState(null); + const [groupedMode, setGroupedMode] = useState(false); // Toggle between default and grouped mode + const [visibleSections, setVisibleSections] = useState([]); // Track multiple open sections + const [hideButtons, setHideButtons] = useState(false); // New state to hide buttons const loadCurrentUrl = (): void => { setIframeUrl(new URL(window.location.href + `?${appInitializationTestQueryParameter}=true`)); }; + // Function to toggle the visibility of a specific section + const toggleSection = (sectionName: string): void => { + setVisibleSections( + (prev) => + prev.includes(sectionName) + ? prev.filter((section) => section !== sectionName) // Hide section if already open + : [...prev, sectionName], // Show section if not open + ); + }; + + // List of sections dynamically created from React elements + const sections = useMemo( + () => [ + { name: 'AppAPIs', component: }, + { name: 'AppInitializationAPIs', component: }, + { name: 'AppInstallDialogAPIs', component: }, + { name: 'AuthenticationAPIs', component: }, + { name: 'AppEntityAPIs', component: }, + { name: 'BarCodeAPIs', component: }, + { name: 'CalendarAPIs', component: }, + { name: 'CallAPIs', component: }, + { name: 'ChatAPIs', component: }, + { name: 'ClipboardAPIs', component: }, + { name: 'CookieAccessComponent', component: }, + { name: 'CopilotAPIs', component: }, + { name: 'CustomAPIs', component: }, + { name: 'DialogAPIs', component: }, + { name: 'DialogCardAPIs', component: }, + { name: 'DialogCardBotAPIs', component: }, + { name: 'DialogUpdateAPIs', component: }, + { name: 'DialogUrlAPIs', component: }, + { name: 'DialogUrlBotAPIs', component: }, + { + name: 'DialogUrlParentCommunicationAPIs', + component: , + }, + { name: 'ExternalAppAuthenticationAPIs', component: }, + { name: 'ExternalAppAuthenticationForCEAAPIs', component: }, + { name: 'ExternalAppCardActionsAPIs', component: }, + { name: 'ExternalAppCardActionsForCEAAPIs', component: }, + { name: 'ExternalAppCommandsAPIs', component: }, + { name: 'FilesAPIs', component: }, + { name: 'FullTrustAPIs', component: }, + { name: 'GeoLocationAPIs', component: }, + { name: 'HostEntityTabAPIs', component: }, + { name: 'Links', component: }, + { name: 'LocationAPIs', component: }, + { name: 'LogAPIs', component: }, + { name: 'MailAPIs', component: }, + { name: 'MarketplaceAPIs', component: }, + { name: 'MediaAPIs', component: }, + { name: 'MeetingAPIs', component: }, + { name: 'MeetingRoomAPIs', component: }, + { name: 'MenusAPIs', component: }, + { name: 'MessageChannelAPIs', component: }, + { name: 'MonetizationAPIs', component: }, + { name: 'NestedAppAuthAPIs', component: }, + { name: 'NotificationAPIs', component: }, + { name: 'OtherAppStateChangedAPIs', component: }, + { name: 'PagesAPIs', component: }, + { name: 'PagesAppButtonAPIs', component: }, + { name: 'PagesBackStackAPIs', component: }, + { name: 'PagesConfigAPIs', component: }, + { name: 'PagesCurrentAppAPIs', component: }, + { name: 'PagesTabsAPIs', component: }, + { name: 'PeopleAPIs', component: }, + { name: 'PrivateAPIs', component: }, + { name: 'ProfileAPIs', component: }, + { name: 'RemoteCameraAPIs', component: }, + { name: 'SearchAPIs', component: }, + { name: 'SecondaryBrowserAPIs', component: }, + { name: 'SharingAPIs', component: }, + { name: 'WebStorageAPIs', component: }, + { name: 'StageViewAPIs', component: }, + { name: 'StageViewSelfAPIs', component: }, + { name: 'TeamsCoreAPIs', component: }, + { name: 'TeamsAPIs', component: }, + { name: 'ThirdPartyCloudStorageAPIs', component: }, + { name: 'VideoAPIs', component: }, + { name: 'VideoExAPIs', component: }, + { name: 'VisualMediaAPIs', component: }, + ], + [], + ); + + // Check URL for groupedMode parameter on component mount + useEffect(() => { + const params = new URLSearchParams(window.location.search); + const groupedModeParam = params.get(groupedModeQueryParameter); + + if (groupedModeParam) { + setGroupedMode(true); // Automatically switch to grouped mode + + // Split the parameter by comma to support multiple sections + const sectionsToOpen = groupedModeParam.split(','); + + // Find matching sections + const matchingSections = sections + .filter((section) => sectionsToOpen.some((param) => param.toLowerCase() === section.name.toLowerCase())) + .map((section) => section.name); + + // If matching sections found, open them + if (matchingSections.length > 0) { + setVisibleSections(matchingSections); + setHideButtons(true); // Hide buttons if sections are specified in query + } + } + }, [sections]); // Include sections in the dependency array + return ( <> + + {/* Toggle between default and grouped mode */} + +
{iframeUrl !== null && (
@@ -94,71 +213,41 @@ export const TestApp: React.FC = () => {