mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-20 00:08:02 +01:00
feat: A/B test search feedback variants (#6085)
Search was not getting any feedback. We introduced 3 different variants to compare conversion rate. ![image](https://github.com/Unleash/unleash/assets/964450/9c4fbcd6-c6d9-4570-9a08-9321087f609a) ![image](https://github.com/Unleash/unleash/assets/964450/6d643d48-1dcb-4a67-9951-7f0c6865f31d) ![image](https://github.com/Unleash/unleash/assets/964450/423dbd54-5dd1-409c-9cd5-295edb9453d9)
This commit is contained in:
parent
79e86e1aca
commit
bb02ffd8c4
@ -1,6 +1,7 @@
|
|||||||
import { useCallback, useEffect, useMemo, useState, VFC } from 'react';
|
import { useCallback, useEffect, useMemo, useState, VFC } from 'react';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
|
Button,
|
||||||
IconButton,
|
IconButton,
|
||||||
Link,
|
Link,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
@ -69,7 +70,7 @@ const feedbackCategory = 'search';
|
|||||||
|
|
||||||
export const FeatureToggleListTable: VFC = () => {
|
export const FeatureToggleListTable: VFC = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { openFeedback } = useFeedback(feedbackCategory, 'automatic');
|
const featureSearchFeedback = useUiFlag('featureSearchFeedback');
|
||||||
const { trackEvent } = usePlausibleTracker();
|
const { trackEvent } = usePlausibleTracker();
|
||||||
const { environments } = useEnvironments();
|
const { environments } = useEnvironments();
|
||||||
const enabledEnvironments = environments
|
const enabledEnvironments = environments
|
||||||
@ -81,7 +82,17 @@ export const FeatureToggleListTable: VFC = () => {
|
|||||||
|
|
||||||
const { setToastApiError } = useToast();
|
const { setToastApiError } = useToast();
|
||||||
const { uiConfig } = useUiConfig();
|
const { uiConfig } = useUiConfig();
|
||||||
const featureSearchFeedback = useUiFlag('featureSearchFeedback');
|
|
||||||
|
const variant =
|
||||||
|
featureSearchFeedback !== false
|
||||||
|
? featureSearchFeedback?.name ?? ''
|
||||||
|
: '';
|
||||||
|
|
||||||
|
const { openFeedback } = useFeedback(
|
||||||
|
feedbackCategory,
|
||||||
|
'automatic',
|
||||||
|
variant,
|
||||||
|
);
|
||||||
|
|
||||||
const stateConfig = {
|
const stateConfig = {
|
||||||
offset: withDefault(NumberParam, 0),
|
offset: withDefault(NumberParam, 0),
|
||||||
@ -352,19 +363,64 @@ export const FeatureToggleListTable: VFC = () => {
|
|||||||
<FeatureToggleListActions
|
<FeatureToggleListActions
|
||||||
onExportClick={() => setShowExportDialog(true)}
|
onExportClick={() => setShowExportDialog(true)}
|
||||||
/>
|
/>
|
||||||
<ConditionallyRender
|
{featureSearchFeedback !== false &&
|
||||||
condition={featureSearchFeedback}
|
featureSearchFeedback?.enabled && (
|
||||||
show={
|
<>
|
||||||
<Tooltip title='Provide feedback' arrow>
|
<ConditionallyRender
|
||||||
<IconButton
|
condition={
|
||||||
onClick={createFeedbackContext}
|
variant === 'withoutText'
|
||||||
size='large'
|
}
|
||||||
>
|
show={
|
||||||
<ReviewsOutlined />
|
<Tooltip
|
||||||
</IconButton>
|
title='Provide feedback'
|
||||||
</Tooltip>
|
arrow
|
||||||
}
|
>
|
||||||
/>
|
<IconButton
|
||||||
|
onClick={
|
||||||
|
createFeedbackContext
|
||||||
|
}
|
||||||
|
size='large'
|
||||||
|
>
|
||||||
|
<ReviewsOutlined />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={variant === 'withText'}
|
||||||
|
show={
|
||||||
|
<Button
|
||||||
|
startIcon={
|
||||||
|
<ReviewsOutlined />
|
||||||
|
}
|
||||||
|
onClick={
|
||||||
|
createFeedbackContext
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Provide feedback
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>{' '}
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={
|
||||||
|
variant === 'withTextOutlined'
|
||||||
|
}
|
||||||
|
show={
|
||||||
|
<Button
|
||||||
|
startIcon={
|
||||||
|
<ReviewsOutlined />
|
||||||
|
}
|
||||||
|
onClick={
|
||||||
|
createFeedbackContext
|
||||||
|
}
|
||||||
|
variant='outlined'
|
||||||
|
>
|
||||||
|
Provide feedback
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -4,7 +4,11 @@ import { IFeedbackCategory } from 'hooks/useSubmittedFeedback';
|
|||||||
export type FeedbackMode = 'automatic' | 'manual';
|
export type FeedbackMode = 'automatic' | 'manual';
|
||||||
export interface IFeedbackContext {
|
export interface IFeedbackContext {
|
||||||
feedbackData: FeedbackData | undefined;
|
feedbackData: FeedbackData | undefined;
|
||||||
openFeedback: (data: FeedbackData, mode: FeedbackMode) => void;
|
openFeedback: (
|
||||||
|
data: FeedbackData,
|
||||||
|
mode: FeedbackMode,
|
||||||
|
variant?: string,
|
||||||
|
) => void;
|
||||||
closeFeedback: () => void;
|
closeFeedback: () => void;
|
||||||
showFeedback: boolean;
|
showFeedback: boolean;
|
||||||
setShowFeedback: (visible: boolean) => void;
|
setShowFeedback: (visible: boolean) => void;
|
||||||
|
@ -13,7 +13,11 @@ export const FeedbackProvider: FC = ({ children }) => {
|
|||||||
const [feedbackMode, setFeedbackMode] = useState<
|
const [feedbackMode, setFeedbackMode] = useState<
|
||||||
FeedbackMode | undefined
|
FeedbackMode | undefined
|
||||||
>();
|
>();
|
||||||
const openFeedback = (data: FeedbackData, mode: FeedbackMode) => {
|
const openFeedback = (
|
||||||
|
data: FeedbackData,
|
||||||
|
mode: FeedbackMode,
|
||||||
|
variant: string = '',
|
||||||
|
) => {
|
||||||
setFeedbackData(data);
|
setFeedbackData(data);
|
||||||
setShowFeedback(true);
|
setShowFeedback(true);
|
||||||
setFeedbackMode(mode);
|
setFeedbackMode(mode);
|
||||||
@ -22,6 +26,7 @@ export const FeedbackProvider: FC = ({ children }) => {
|
|||||||
props: {
|
props: {
|
||||||
eventType: `feedback opened - ${data.category}`,
|
eventType: `feedback opened - ${data.category}`,
|
||||||
category: data.category,
|
category: data.category,
|
||||||
|
variant: variant,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -30,6 +30,7 @@ export const useFeedbackContext = (): IFeedbackContext => {
|
|||||||
export const useFeedback = (
|
export const useFeedback = (
|
||||||
feedbackCategory: IFeedbackCategory,
|
feedbackCategory: IFeedbackCategory,
|
||||||
mode: FeedbackMode,
|
mode: FeedbackMode,
|
||||||
|
variant: string = '',
|
||||||
) => {
|
) => {
|
||||||
const context = useFeedbackContext();
|
const context = useFeedbackContext();
|
||||||
const { hasSubmittedFeedback } = useUserSubmittedFeedback(feedbackCategory);
|
const { hasSubmittedFeedback } = useUserSubmittedFeedback(feedbackCategory);
|
||||||
@ -44,6 +45,7 @@ export const useFeedback = (
|
|||||||
category: feedbackCategory,
|
category: feedbackCategory,
|
||||||
},
|
},
|
||||||
mode,
|
mode,
|
||||||
|
variant,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -69,7 +69,7 @@ export type UiFlags = {
|
|||||||
automatedActions?: boolean;
|
automatedActions?: boolean;
|
||||||
celebrateUnleash?: boolean;
|
celebrateUnleash?: boolean;
|
||||||
increaseUnleashWidth?: boolean;
|
increaseUnleashWidth?: boolean;
|
||||||
featureSearchFeedback?: boolean;
|
featureSearchFeedback?: Variant;
|
||||||
enableLicense?: boolean;
|
enableLicense?: boolean;
|
||||||
newStrategyConfigurationFeedback?: boolean;
|
newStrategyConfigurationFeedback?: boolean;
|
||||||
extendedUsageMetricsUI?: boolean;
|
extendedUsageMetricsUI?: boolean;
|
||||||
|
@ -94,7 +94,14 @@ exports[`should create default config 1`] = `
|
|||||||
"executiveDashboard": false,
|
"executiveDashboard": false,
|
||||||
"extendedUsageMetrics": false,
|
"extendedUsageMetrics": false,
|
||||||
"extendedUsageMetricsUI": false,
|
"extendedUsageMetricsUI": false,
|
||||||
"featureSearchFeedback": false,
|
"featureSearchFeedback": {
|
||||||
|
"enabled": true,
|
||||||
|
"name": "withText",
|
||||||
|
"payload": {
|
||||||
|
"type": "json",
|
||||||
|
"value": "",
|
||||||
|
},
|
||||||
|
},
|
||||||
"featureSearchFeedbackPosting": false,
|
"featureSearchFeedbackPosting": false,
|
||||||
"featuresExportImport": true,
|
"featuresExportImport": true,
|
||||||
"feedbackComments": {
|
"feedbackComments": {
|
||||||
|
@ -157,10 +157,19 @@ const flags: IFlags = {
|
|||||||
process.env.UNLEASH_EXPERIMENTAL_INCREASE_UNLEASH_WIDTH,
|
process.env.UNLEASH_EXPERIMENTAL_INCREASE_UNLEASH_WIDTH,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
featureSearchFeedback: parseEnvVarBoolean(
|
featureSearchFeedback: {
|
||||||
process.env.UNLEASH_EXPERIMENTAL_FEATURE_SEARCH_FEEDBACK,
|
name: 'withText',
|
||||||
false,
|
enabled: parseEnvVarBoolean(
|
||||||
),
|
process.env.UNLEASH_EXPERIMENTAL_FEATURE_SEARCH_FEEDBACK,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
payload: {
|
||||||
|
type: PayloadType.JSON,
|
||||||
|
value:
|
||||||
|
process.env
|
||||||
|
.UNLEASH_EXPERIMENTAL_FEATURE_SEARCH_FEEDBACK_PAYLOAD ?? '',
|
||||||
|
},
|
||||||
|
},
|
||||||
featureSearchFeedbackPosting: parseEnvVarBoolean(
|
featureSearchFeedbackPosting: parseEnvVarBoolean(
|
||||||
process.env.UNLEASH_EXPERIMENTAL_FEATURE_SEARCH_FEEDBACK_POSTING,
|
process.env.UNLEASH_EXPERIMENTAL_FEATURE_SEARCH_FEEDBACK_POSTING,
|
||||||
false,
|
false,
|
||||||
|
@ -45,7 +45,6 @@ process.nextTick(async () => {
|
|||||||
stripHeadersOnAPI: true,
|
stripHeadersOnAPI: true,
|
||||||
celebrateUnleash: true,
|
celebrateUnleash: true,
|
||||||
increaseUnleashWidth: true,
|
increaseUnleashWidth: true,
|
||||||
featureSearchFeedback: true,
|
|
||||||
newStrategyConfigurationFeedback: true,
|
newStrategyConfigurationFeedback: true,
|
||||||
extendedUsageMetricsUI: true,
|
extendedUsageMetricsUI: true,
|
||||||
executiveDashboard: true,
|
executiveDashboard: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user