+
{name}
@@ -87,6 +99,7 @@ export const SquadList = ({
data-testid="squad-action"
buttonVariants={[ButtonVariant.Secondary, ButtonVariant.Float]}
/>
+ {canShare && }
{children}
);
diff --git a/packages/shared/src/components/cards/squad/UnfeaturedSquadGrid.spec.tsx b/packages/shared/src/components/cards/squad/UnfeaturedSquadGrid.spec.tsx
index e92e18a2af0..99996778efe 100644
--- a/packages/shared/src/components/cards/squad/UnfeaturedSquadGrid.spec.tsx
+++ b/packages/shared/src/components/cards/squad/UnfeaturedSquadGrid.spec.tsx
@@ -1,6 +1,7 @@
import type { RenderResult } from '@testing-library/react';
import { render, screen, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import { GrowthBook } from '@growthbook/growthbook-react';
import React from 'react';
import nock from 'nock';
import { AuthContextProvider } from '../../../contexts/AuthContext';
@@ -20,6 +21,11 @@ import {
CONTENT_PREFERENCE_STATUS_QUERY,
ContentPreferenceType,
} from '../../../graphql/contentPreference';
+import { TestBootProvider } from '../../../../__tests__/helpers/boot';
+import {
+ featureSharingVisibility,
+ featureShareSquadDirectory,
+} from '../../../lib/featureManagement';
const squads = [generateTestSquad()];
const members = generateMembersList();
@@ -141,3 +147,61 @@ it('should render the component with a join squad button', async () => {
await waitFor(() => expect(queryCalled).toBeTruthy());
});
});
+
+describe('squad directory share', () => {
+ const mockContentPreference = () =>
+ mockGraphQL({
+ request: {
+ query: CONTENT_PREFERENCE_STATUS_QUERY,
+ variables: {
+ id: admin.source.id,
+ entity: ContentPreferenceType.Source,
+ },
+ },
+ result: { data: { contentPreferenceStatus: null } },
+ });
+
+ const renderWithSharing = (enabled: boolean): RenderResult => {
+ const gb = new GrowthBook();
+ gb.setFeatures({
+ [featureSharingVisibility.id]: { defaultValue: enabled },
+ [featureShareSquadDirectory.id]: { defaultValue: enabled },
+ });
+
+ return render(
+
+
+ ,
+ );
+ };
+
+ it('flag off: keeps the join button alone in the header row', async () => {
+ mockContentPreference();
+ renderWithSharing(false);
+
+ const button = await screen.findByTestId('squad-action');
+ expect(screen.queryByLabelText('Share Squad')).not.toBeInTheDocument();
+ // No wrapper is added: the button stays a direct child of the original
+ // header row, with the exact original class list.
+ expect(button.parentElement!.className).toBe(
+ 'mb-3 flex items-center justify-between',
+ );
+ });
+
+ it('flag on: renders the copy-link control next to the join button', async () => {
+ mockContentPreference();
+ renderWithSharing(true);
+
+ const button = await screen.findByTestId('squad-action');
+ expect(screen.getByLabelText('Share Squad')).toBeInTheDocument();
+ const wrapper = button.parentElement!;
+ expect(wrapper.className).toBe('z-0 flex flex-row items-center gap-2');
+ expect(wrapper.parentElement!.className).toBe(
+ 'mb-3 flex items-center justify-between',
+ );
+ });
+});
diff --git a/packages/shared/src/components/cards/squad/UnfeaturedSquadGrid.tsx b/packages/shared/src/components/cards/squad/UnfeaturedSquadGrid.tsx
index ef4f41d2b9d..2c65f469b9e 100644
--- a/packages/shared/src/components/cards/squad/UnfeaturedSquadGrid.tsx
+++ b/packages/shared/src/components/cards/squad/UnfeaturedSquadGrid.tsx
@@ -15,12 +15,27 @@ import { Origin } from '../../../lib/log';
import { SquadActionButton } from '../../squads/SquadActionButton';
import { ButtonVariant } from '../../buttons/common';
import { Image, ImageType } from '../../image/Image';
+import { useSquadDirectoryShareEnabled } from '../../../hooks/squads/useSquadDirectoryShareEnabled';
+import { SquadDirectoryShareButton } from './SquadDirectoryShareButton';
export const UnfeaturedSquadGrid = ({
source,
className,
}: UnFeaturedSquadCardProps): ReactElement => {
const title = source.name;
+ const canShare = useSquadDirectoryShareEnabled();
+
+ // Flag-off must keep the exact original DOM (Join alone in the header row);
+ // the share control and its wrapper only exist when the sharing flags are on.
+ const joinButton = (
+
+ );
return (
@@ -36,13 +51,14 @@ export const UnfeaturedSquadGrid = ({
className="size-16 rounded-full"
type={ImageType.Squad}
/>
-
+ {canShare ? (
+
+ {joinButton}
+
+
+ ) : (
+ joinButton
+ )}