feat(frontend): dynamic search terms (#11156)

## Changes 🏗️

<img width="800" height="664" alt="Screenshot 2025-10-14 at 14 09 54"
src="https://github.com/user-attachments/assets/73f6277a-6bef-40f9-b208-31aba0cfc69f"
/>

<img width="600" height="773" alt="Screenshot 2025-10-14 at 14 10 05"
src="https://github.com/user-attachments/assets/c88cb22f-1597-4216-9688-09c19030df89"
/>

Allow to manage on the fly which search terms appear on the Marketplace
page via Launch Darkly dashboard. There is a new flag configured there:
`marketplace-search-terms`:
- **enabled** → `["Foo", "Bar"]` → the terms that will appear
- **disabled** → `[ "Marketing", "SEO", "Content Creation",
"Automation", "Fun"]` → the default ones show

### Small fix

Fix the following browser console warning about `onLoadingComplete`
being deprecated...
<img width="600" height="231" alt="Screenshot 2025-10-14 at 13 55 45"
src="https://github.com/user-attachments/assets/1b26e228-0902-4554-9f8c-4839f8d4ed83"
/>


## Checklist 📋

### For code changes:
- [x] I have clearly listed my changes in the PR description
- [x] I have made a test plan
- [x] I have tested my changes according to the test plan:
- [x] Ran the flag locally and verified it shows the terms set on Launch
Darkly

### For configuration changes:

Launch Darkly new flag needs to be configured on all environments.
This commit is contained in:
Ubbe
2025-10-14 09:43:56 +04:00
committed by GitHub
parent 9c8652b273
commit 5f2d4643f8
5 changed files with 18 additions and 9 deletions

View File

@@ -5,7 +5,7 @@ import { SearchBar } from "../SearchBar/SearchBar";
import { useHeroSection } from "./useHeroSection";
export const HeroSection = () => {
const { onFilterChange } = useHeroSection();
const { onFilterChange, searchTerms } = useHeroSection();
return (
<div className="mb-2 mt-8 flex flex-col items-center justify-center px-4 sm:mb-4 sm:mt-12 sm:px-6 md:mb-6 md:mt-16 lg:my-24 lg:px-8 xl:my-16">
<div className="w-full max-w-3xl lg:max-w-4xl xl:max-w-5xl">
@@ -35,13 +35,7 @@ export const HeroSection = () => {
<div>
<div className="flex justify-center">
<FilterChips
badges={[
"Marketing",
"SEO",
"Content Creation",
"Automation",
"Fun",
]}
badges={searchTerms}
onFilterChange={onFilterChange}
multiSelect={false}
/>

View File

@@ -0,0 +1,7 @@
export const DEFAULT_SEARCH_TERMS = [
"Marketing",
"SEO",
"Content Creation",
"Automation",
"Fun",
];

View File

@@ -1,10 +1,13 @@
import { useOnboarding } from "@/providers/onboarding/onboarding-provider";
import { Flag, useGetFlag } from "@/services/feature-flags/use-get-flag";
import { useRouter } from "next/navigation";
import { useEffect } from "react";
import { DEFAULT_SEARCH_TERMS } from "./helpers";
export const useHeroSection = () => {
const router = useRouter();
const { completeStep } = useOnboarding();
const searchTerms = useGetFlag(Flag.MARKETPLACE_SEARCH_TERMS);
// Mark marketplace visit task as completed
useEffect(() => {
@@ -18,5 +21,6 @@ export const useHeroSection = () => {
return {
onFilterChange,
searchTerms: searchTerms || DEFAULT_SEARCH_TERMS,
};
};

View File

@@ -156,7 +156,7 @@ export function AvatarImage({
sizes={sizes}
priority={priority}
unoptimized={unoptimized}
onLoadingComplete={handleLoadingComplete}
onLoad={handleLoadingComplete}
onError={handleErrorNext as ImageProps["onError"]}
/>
);

View File

@@ -1,5 +1,6 @@
"use client";
import { DEFAULT_SEARCH_TERMS } from "@/app/(platform)/marketplace/components/HeroSection/helpers";
import { BehaveAs, getBehaveAs } from "@/lib/utils";
import { useFlags } from "launchdarkly-react-client-sdk";
@@ -13,6 +14,7 @@ export enum Flag {
BUILDER_VIEW_SWITCH = "builder-view-switch",
SHARE_EXECUTION_RESULTS = "share-execution-results",
AGENT_FAVORITING = "agent-favoriting",
MARKETPLACE_SEARCH_TERMS = "marketplace-search-terms",
}
export type FlagValues = {
@@ -25,6 +27,7 @@ export type FlagValues = {
[Flag.BUILDER_VIEW_SWITCH]: boolean;
[Flag.SHARE_EXECUTION_RESULTS]: boolean;
[Flag.AGENT_FAVORITING]: boolean;
[Flag.MARKETPLACE_SEARCH_TERMS]: string[];
};
const isPwMockEnabled = process.env.NEXT_PUBLIC_PW_TEST === "true";
@@ -39,6 +42,7 @@ const mockFlags = {
[Flag.BUILDER_VIEW_SWITCH]: false,
[Flag.SHARE_EXECUTION_RESULTS]: false,
[Flag.AGENT_FAVORITING]: false,
[Flag.MARKETPLACE_SEARCH_TERMS]: DEFAULT_SEARCH_TERMS,
};
export function useGetFlag<T extends Flag>(flag: T): FlagValues[T] | null {