diff --git a/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx b/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx index c9e38f93d7..f666bb819e 100644 --- a/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx +++ b/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx @@ -56,6 +56,7 @@ import useLoading from 'hooks/useLoading'; import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; import { useFeedback } from '../../feedbackNew/useFeedback'; import { ReviewsOutlined } from '@mui/icons-material'; +import { useUserSubmittedFeedback } from 'hooks/useSubmittedFeedback'; export const featuresPlaceholder = Array(15).fill({ name: 'Name of the feature', @@ -66,10 +67,13 @@ export const featuresPlaceholder = Array(15).fill({ }); const columnHelper = createColumnHelper(); +const feedbackCategory = 'search'; const FeatureToggleListTableComponent: VFC = () => { const theme = useTheme(); const { openFeedback } = useFeedback(); + const { hasSubmittedFeedback, setHasSubmittedFeedback } = + useUserSubmittedFeedback(feedbackCategory); const { trackEvent } = usePlausibleTracker(); const { environments } = useEnvironments(); const enabledEnvironments = environments @@ -81,6 +85,7 @@ const FeatureToggleListTableComponent: VFC = () => { const { setToastApiError } = useToast(); const { uiConfig, isPro, isOss, isEnterprise } = useUiConfig(); + const featureSearchFeedback = useUiFlag('featureSearchFeedback'); const stateConfig = { offset: withDefault(NumberParam, 0), @@ -278,7 +283,7 @@ const FeatureToggleListTableComponent: VFC = () => { ? 'enterprise' : 'unknown'; openFeedback({ - category: 'search', + category: feedbackCategory, userType, title: 'How easy was it to use search and filters?', positiveLabel: 'What do you like most about search and filters?', @@ -328,14 +333,23 @@ const FeatureToggleListTableComponent: VFC = () => { setShowExportDialog(true)} /> - - - - - + + + + + + } + /> } > diff --git a/frontend/src/component/feedbackNew/FeedbackComponent.tsx b/frontend/src/component/feedbackNew/FeedbackComponent.tsx index c630da8f66..c4f360cd3b 100644 --- a/frontend/src/component/feedbackNew/FeedbackComponent.tsx +++ b/frontend/src/component/feedbackNew/FeedbackComponent.tsx @@ -10,9 +10,10 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit import { useFeedback } from './useFeedback'; import React, { useState } from 'react'; import CloseIcon from '@mui/icons-material/Close'; -import { useUserFeedbackApi } from 'hooks/api/actions/useUserFeedbackApi/useUserFeedbackApi'; import useToast from 'hooks/useToast'; import { ProvideFeedbackSchema } from '../../openapi'; +import { useUserFeedbackApi } from 'hooks/api/actions/useUserFeedbackApi/useUserFeedbackApi'; +import { useUserSubmittedFeedback } from 'hooks/useSubmittedFeedback'; export const ParentContainer = styled('div')(({ theme }) => ({ position: 'relative', @@ -69,7 +70,7 @@ export const StyledForm = styled('form')(({ theme }) => ({ border: `1px solid ${theme.palette.divider}`, borderRadius: theme.spacing(1.5), borderColor: 'rgba(0, 0, 0, 0.12)', - backgroundColor: '#fff', + backgroundColor: theme.palette.background.paper, boxShadow: '0px 4px 4px 0px rgba(0, 0, 0, 0.12)', '& > *': { @@ -161,6 +162,9 @@ export const FeedbackComponent = () => { const { setToastData } = useToast(); const { addFeedback } = useUserFeedbackApi(); + const { setHasSubmittedFeedback } = useUserSubmittedFeedback( + feedbackData.category, + ); function isProvideFeedbackSchema(data: any): data is ProvideFeedbackSchema { data.difficultyScore = data.difficultyScore @@ -186,6 +190,7 @@ export const FeedbackComponent = () => { title: 'Feedback sent', type: 'success', }); + setHasSubmittedFeedback(true); } else { setToastData({ title: 'Feedback not sent', diff --git a/frontend/src/component/feedbackNew/FeedbackContext.ts b/frontend/src/component/feedbackNew/FeedbackContext.ts index 6eebadfa60..65c492bf36 100644 --- a/frontend/src/component/feedbackNew/FeedbackContext.ts +++ b/frontend/src/component/feedbackNew/FeedbackContext.ts @@ -1,5 +1,6 @@ import { createContext } from 'react'; import { ProvideFeedbackSchema } from '../../openapi'; +import { IFeedbackCategory } from 'hooks/useSubmittedFeedback'; interface IFeedbackContext { feedbackData: IFeedbackData | undefined; @@ -15,11 +16,8 @@ type IFeedbackText = { areasForImprovementsLabel: string; }; -export type IFeedbackData = Pick< - ProvideFeedbackSchema, - 'category' | 'userType' -> & - IFeedbackText; +export type IFeedbackData = Pick & + IFeedbackText & { category: IFeedbackCategory }; export const FeedbackContext = createContext( undefined, diff --git a/frontend/src/hooks/api/actions/useUserFeedbackApi/useUserFeedbackApi.ts b/frontend/src/hooks/api/actions/useUserFeedbackApi/useUserFeedbackApi.ts index 4287288fe1..a47d67d8da 100644 --- a/frontend/src/hooks/api/actions/useUserFeedbackApi/useUserFeedbackApi.ts +++ b/frontend/src/hooks/api/actions/useUserFeedbackApi/useUserFeedbackApi.ts @@ -2,15 +2,23 @@ import { IInternalBanner } from 'interfaces/banner'; import useAPI from '../useApi/useApi'; import { ProvideFeedbackSchema } from '../../../../openapi'; -const ENDPOINT = 'api/admin/user-feedback'; +const DIRECT_ENDPOINT = 'https://sandbox.getunleash.io/enterprise/feedback'; +const ENDPOINT = 'feedback'; export const useUserFeedbackApi = () => { + const addDirectFeedback = async (feedbackSchema: ProvideFeedbackSchema) => { + await fetch(DIRECT_ENDPOINT, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(feedbackSchema), + }); + }; const { loading, makeRequest, createRequest, errors } = useAPI({ propagateErrors: true, }); const addFeedback = async (feedbackSchema: ProvideFeedbackSchema) => { - const requestId = 'addBanner'; + const requestId = 'addFeedback'; const req = createRequest( ENDPOINT, { @@ -26,6 +34,7 @@ export const useUserFeedbackApi = () => { return { addFeedback, + addDirectFeedback, errors, loading, }; diff --git a/frontend/src/hooks/useSubmittedFeedback.ts b/frontend/src/hooks/useSubmittedFeedback.ts new file mode 100644 index 0000000000..c1a26642bf --- /dev/null +++ b/frontend/src/hooks/useSubmittedFeedback.ts @@ -0,0 +1,22 @@ +import { useEffect, useState } from 'react'; +import { getLocalStorageItem, setLocalStorageItem } from '../utils/storage'; +import { basePath } from 'utils/formatPath'; + +export type IFeedbackCategory = 'search'; + +export const useUserSubmittedFeedback = (category: IFeedbackCategory) => { + const key = `${basePath}:unleash-userSubmittedFeedback:${category}`; + + const [hasSubmittedFeedback, setHasSubmittedFeedback] = useState(() => { + return getLocalStorageItem(key) || false; + }); + + useEffect(() => { + setLocalStorageItem(key, hasSubmittedFeedback); + }, [hasSubmittedFeedback, key]); + + return { + hasSubmittedFeedback, + setHasSubmittedFeedback, + }; +}; diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts index c2a282d257..2f6d04dad8 100644 --- a/frontend/src/interfaces/uiConfig.ts +++ b/frontend/src/interfaces/uiConfig.ts @@ -70,6 +70,7 @@ export type UiFlags = { incomingWebhooks?: boolean; celebrateUnleash?: boolean; increaseUnleashWidth?: boolean; + featureSearchFeedback?: boolean; }; export interface IVersionInfo { diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap index 18d5e5be5e..f1d80a111e 100644 --- a/src/lib/__snapshots__/create-config.test.ts.snap +++ b/src/lib/__snapshots__/create-config.test.ts.snap @@ -83,6 +83,7 @@ exports[`should create default config 1`] = ` "embedProxy": true, "embedProxyFrontend": true, "featureSearchAPI": false, + "featureSearchFeedback": false, "featureSearchFrontend": false, "featuresExportImport": true, "filterInvalidClientMetrics": false, diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index dd2e778eeb..c36ad59ce4 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -34,7 +34,8 @@ export type IFlagKey = | 'stripHeadersOnAPI' | 'incomingWebhooks' | 'celebrateUnleash' - | 'increaseUnleashWidth'; + | 'increaseUnleashWidth' + | 'featureSearchFeedback'; export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>; @@ -156,6 +157,10 @@ const flags: IFlags = { process.env.UNLEASH_EXPERIMENTAL_INCREASE_UNLEASH_WIDTH, false, ), + featureSearchFeedback: parseEnvVarBoolean( + process.env.UNLEASH_EXPERIMENTAL_FEATURE_SEARCH_FEEDBACK, + false, + ), }; export const defaultExperimentalOptions: IExperimentalOptions = { diff --git a/src/server-dev.ts b/src/server-dev.ts index 81190f7db2..0cd709ac33 100644 --- a/src/server-dev.ts +++ b/src/server-dev.ts @@ -48,6 +48,7 @@ process.nextTick(async () => { stripHeadersOnAPI: true, celebrateUnleash: true, increaseUnleashWidth: true, + featureSearchFeedback: true, }, }, authentication: {