From c49a9dac1a544241bdc23c6f56011842849accea Mon Sep 17 00:00:00 2001 From: Yunus M Date: Mon, 28 Oct 2024 17:30:11 +0530 Subject: [PATCH] feat: feedback updates --- .../api/preferences/updateOrgPreference.ts | 9 +- .../AboutSigNozQuestions.tsx | 8 +- .../InviteTeamMembers/InviteTeamMembers.tsx | 2 +- .../OnboardingFooter.styles.scss | 3 + .../OnboardingFooter/OnboardingFooter.tsx | 26 +--- .../OnboardingHeader.styles.scss | 1 + .../OnboardingHeader/OnboardingHeader.tsx | 11 +- .../OnboardingQuestionaire.styles.scss | 10 ++ .../OptimiseSignozNeeds.tsx | 14 +- .../OrgQuestions/OrgQuestions.tsx | 10 +- .../OnboardingQuestionaire/index.tsx | 146 +++++++++++++----- frontend/src/container/SideNav/SideNav.tsx | 4 +- frontend/src/pages/SignUp/SignUp.tsx | 2 +- .../api/preferences/userOrgPreferences.ts | 4 +- 14 files changed, 160 insertions(+), 90 deletions(-) diff --git a/frontend/src/api/preferences/updateOrgPreference.ts b/frontend/src/api/preferences/updateOrgPreference.ts index 76e5a68640..aae4d83ddf 100644 --- a/frontend/src/api/preferences/updateOrgPreference.ts +++ b/frontend/src/api/preferences/updateOrgPreference.ts @@ -10,9 +10,12 @@ const updateOrgPreference = async ( ): Promise< SuccessResponse | ErrorResponse > => { - const response = await axios.put(`/org/preferences`, { - preference_value: preferencePayload.value, - }); + const response = await axios.put( + `/org/preferences/${preferencePayload.preferenceID}`, + { + preference_value: preferencePayload.value, + }, + ); return { statusCode: 200, diff --git a/frontend/src/container/OnboardingQuestionaire/AboutSigNozQuestions/AboutSigNozQuestions.tsx b/frontend/src/container/OnboardingQuestionaire/AboutSigNozQuestions/AboutSigNozQuestions.tsx index df8066b358..c6f0320d1a 100644 --- a/frontend/src/container/OnboardingQuestionaire/AboutSigNozQuestions/AboutSigNozQuestions.tsx +++ b/frontend/src/container/OnboardingQuestionaire/AboutSigNozQuestions/AboutSigNozQuestions.tsx @@ -22,7 +22,7 @@ interface AboutSigNozQuestionsProps { } const hearAboutSignozOptions: Record = { - blog: 'Blog', + search: 'Google / Search', hackerNews: 'Hacker News', linkedin: 'LinkedIn', twitter: 'Twitter', @@ -144,7 +144,7 @@ export function AboutSigNozQuestions({
-
- What are you interested in doing with SigNoz? -
+
What got you interested in SigNoz?
{Object.keys(interestedInOptions).map((option: string) => (
); diff --git a/frontend/src/container/OnboardingQuestionaire/OnboardingHeader/OnboardingHeader.styles.scss b/frontend/src/container/OnboardingQuestionaire/OnboardingHeader/OnboardingHeader.styles.scss index 0b2cecaac6..984b89828b 100644 --- a/frontend/src/container/OnboardingQuestionaire/OnboardingHeader/OnboardingHeader.styles.scss +++ b/frontend/src/container/OnboardingQuestionaire/OnboardingHeader/OnboardingHeader.styles.scss @@ -40,6 +40,7 @@ border-radius: 2px; border: 1px solid var(--Greyscale-Slate-400, #1d212d); background: var(--Ink-300, #16181d); + box-shadow: none; } .header-container .get-help-container img { diff --git a/frontend/src/container/OnboardingQuestionaire/OnboardingHeader/OnboardingHeader.tsx b/frontend/src/container/OnboardingQuestionaire/OnboardingHeader/OnboardingHeader.tsx index 76801d7620..f1b54d50dd 100644 --- a/frontend/src/container/OnboardingQuestionaire/OnboardingHeader/OnboardingHeader.tsx +++ b/frontend/src/container/OnboardingQuestionaire/OnboardingHeader/OnboardingHeader.tsx @@ -1,19 +1,26 @@ import './OnboardingHeader.styles.scss'; import { Color } from '@signozhq/design-tokens'; +import { Button } from 'antd'; import { LifeBuoy } from 'lucide-react'; export function OnboardingHeader(): JSX.Element { + const handleGetHelpClick = (): void => { + if (window.Intercom) { + window.Intercom('showNewMessage', ''); + } + }; + return (
SigNoz SigNoz
-
+
+
); } diff --git a/frontend/src/container/OnboardingQuestionaire/OnboardingQuestionaire.styles.scss b/frontend/src/container/OnboardingQuestionaire/OnboardingQuestionaire.styles.scss index 00b091d1d8..d50ca325b7 100644 --- a/frontend/src/container/OnboardingQuestionaire/OnboardingQuestionaire.styles.scss +++ b/frontend/src/container/OnboardingQuestionaire/OnboardingQuestionaire.styles.scss @@ -386,3 +386,13 @@ margin-top: 12px; } } + +.onboarding-questionaire-loading-container { + width: 100%; + display: flex; + height: 100vh; + max-width: 600px; + justify-content: center; + align-items: center; + margin: 0 auto; +} diff --git a/frontend/src/container/OnboardingQuestionaire/OptimiseSignozNeeds/OptimiseSignozNeeds.tsx b/frontend/src/container/OnboardingQuestionaire/OptimiseSignozNeeds/OptimiseSignozNeeds.tsx index d564158059..a801c2784e 100644 --- a/frontend/src/container/OnboardingQuestionaire/OptimiseSignozNeeds/OptimiseSignozNeeds.tsx +++ b/frontend/src/container/OnboardingQuestionaire/OptimiseSignozNeeds/OptimiseSignozNeeds.tsx @@ -16,10 +16,11 @@ interface OptimiseSignozNeedsProps { onBack: () => void; onWillDoLater: () => void; isUpdatingProfile: boolean; + isNextDisabled: boolean; } const logMarks: SliderSingleProps['marks'] = { - 0: '2 GB', + 0: '0 GB', 25: '25 GB', 50: '50 GB', 100: '100 GB', @@ -50,15 +51,16 @@ function OptimiseSignozNeeds({ onNext, onBack, onWillDoLater, + isNextDisabled, }: OptimiseSignozNeedsProps): JSX.Element { const [logsPerDay, setLogsPerDay] = useState( - optimiseSignozDetails?.logsPerDay || 25, + optimiseSignozDetails?.logsPerDay || 0, ); const [hostsPerDay, setHostsPerDay] = useState( - optimiseSignozDetails?.hostsPerDay || 40, + optimiseSignozDetails?.hostsPerDay || 0, ); const [services, setServices] = useState( - optimiseSignozDetails?.services || 10, + optimiseSignozDetails?.services || 0, ); useEffect(() => { @@ -191,7 +193,7 @@ function OptimiseSignozNeeds({ type="primary" className="next-button" onClick={handleOnNext} - disabled={isUpdatingProfile} + disabled={isUpdatingProfile || isNextDisabled} > Next{' '} {isUpdatingProfile ? ( @@ -204,7 +206,7 @@ function OptimiseSignozNeeds({
diff --git a/frontend/src/container/OnboardingQuestionaire/OrgQuestions/OrgQuestions.tsx b/frontend/src/container/OnboardingQuestionaire/OrgQuestions/OrgQuestions.tsx index a1fea0aaf8..ea6bad53d6 100644 --- a/frontend/src/container/OnboardingQuestionaire/OrgQuestions/OrgQuestions.tsx +++ b/frontend/src/container/OnboardingQuestionaire/OrgQuestions/OrgQuestions.tsx @@ -42,10 +42,10 @@ const observabilityTools = { }; const o11yFamiliarityOptions: Record = { - new: "I'm completely new", - builtStack: "I've built a stack before", - experienced: 'I have some experience', - dontKnow: "I don't know what it is", + beginner: 'Basic Understanding', + intermediate: 'Somewhat Familiar', + expert: 'Very Familiar', + notFamiliar: "I'm not familiar with it", }; function OrgQuestions({ @@ -254,7 +254,7 @@ function OrgQuestions({
- Are you familiar with observability (o11y)? + Are you familiar with setting upobservability (o11y)?
{Object.keys(o11yFamiliarityOptions).map((option: string) => ( diff --git a/frontend/src/container/OnboardingQuestionaire/index.tsx b/frontend/src/container/OnboardingQuestionaire/index.tsx index a5d1f83254..77bde17848 100644 --- a/frontend/src/container/OnboardingQuestionaire/index.tsx +++ b/frontend/src/container/OnboardingQuestionaire/index.tsx @@ -1,7 +1,10 @@ import './OnboardingQuestionaire.styles.scss'; +import { Skeleton } from 'antd'; import { NotificationInstance } from 'antd/es/notification/interface'; import updateProfileAPI from 'api/onboarding/updateProfile'; +import getOrgPreference from 'api/preferences/getOrgPreference'; +import updateOrgPreferenceAPI from 'api/preferences/updateOrgPreference'; import editOrg from 'api/user/editOrg'; import getOrgUser from 'api/user/getOrgUser'; import { AxiosError } from 'axios'; @@ -10,6 +13,7 @@ import ROUTES from 'constants/routes'; import { InviteTeamMembersProps } from 'container/OrganizationSettings/PendingInvitesContainer'; import { useNotifications } from 'hooks/useNotifications'; import history from 'lib/history'; +import { isEmpty } from 'lodash-es'; import { Dispatch, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useMutation, useQuery } from 'react-query'; @@ -56,9 +60,9 @@ const INITIAL_SIGNOZ_DETAILS: SignozDetails = { }; const INITIAL_OPTIMISE_SIGNOZ_DETAILS: OptimiseSignozDetails = { - logsPerDay: 25, - hostsPerDay: 40, - services: 10, + logsPerDay: 0, + hostsPerDay: 0, + services: 0, }; function OnboardingQuestionaire(): JSX.Element { @@ -92,6 +96,44 @@ function OnboardingQuestionaire(): JSX.Element { const dispatch = useDispatch>(); const [orgData, setOrgData] = useState(null); + const [isOnboardingComplete, setIsOnboardingComplete] = useState( + false, + ); + + const { data: orgPreferences, isLoading: isLoadingOrgPreferences } = useQuery({ + queryFn: () => getOrgPreference({ preferenceID: 'ORG_ONBOARDING' }), + queryKey: ['getOrgPreferences', 'ORG_ONBOARDING'], + }); + + useEffect(() => { + if (!isLoadingOrgPreferences && !isEmpty(orgPreferences?.payload?.data)) { + const preferenceId = orgPreferences?.payload?.data?.preference_id; + const preferenceValue = orgPreferences?.payload?.data?.preference_value; + + if (preferenceId === 'ORG_ONBOARDING') { + setIsOnboardingComplete(preferenceValue as boolean); + } + } + }, [orgPreferences, isLoadingOrgPreferences]); + + const checkFirstTimeUser = (): boolean => { + const users = orgUsers?.payload || []; + + const remainingUsers = users.filter( + (user) => user.email !== 'admin@signoz.cloud', + ); + + return remainingUsers.length === 1; + }; + + useEffect(() => { + const isFirstUser = checkFirstTimeUser(); + + if (isOnboardingComplete || !isFirstUser) { + history.push(ROUTES.GET_STARTED); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isOnboardingComplete, orgUsers]); useEffect(() => { if (org) { @@ -105,6 +147,11 @@ function OnboardingQuestionaire(): JSX.Element { // eslint-disable-next-line react-hooks/exhaustive-deps }, [org]); + const isNextDisabled = + optimiseSignozDetails.logsPerDay === 0 || + optimiseSignozDetails.hostsPerDay === 0 || + optimiseSignozDetails.services === 0; + const [isLoading, setIsLoading] = useState(false); const handleOrgNameUpdate = async (): Promise => { @@ -164,9 +211,7 @@ function OnboardingQuestionaire(): JSX.Element { const { mutate: updateProfile, isLoading: isUpdatingProfile } = useMutation( updateProfileAPI, { - onSuccess: (data) => { - console.log('data', data); - + onSuccess: () => { setCurrentStep(4); }, onError: (error) => { @@ -175,6 +220,15 @@ function OnboardingQuestionaire(): JSX.Element { }, ); + const { mutate: updateOrgPreference } = useMutation(updateOrgPreferenceAPI, { + onSuccess: () => { + setIsOnboardingComplete(true); + }, + onError: (error) => { + showErrorNotification(notifications, error as AxiosError); + }, + }); + const handleUpdateProfile = (): void => { updateProfile({ familiarity_with_observability: orgDetails?.familiarity as string, @@ -200,7 +254,10 @@ function OnboardingQuestionaire(): JSX.Element { }; const handleOnboardingComplete = (): void => { - history.push(ROUTES.GET_STARTED); + updateOrgPreference({ + preferenceID: 'ORG_ONBOARDING', + value: true, + }); }; return ( @@ -210,42 +267,53 @@ function OnboardingQuestionaire(): JSX.Element {
- {currentStep === 1 && ( - + {(isLoadingOrgPreferences || isLoadingOrgUsers) && ( +
+ +
)} - {currentStep === 2 && ( - setCurrentStep(1)} - onNext={(): void => setCurrentStep(3)} - /> - )} + {!isLoadingOrgPreferences && !isLoadingOrgUsers && ( + <> + {currentStep === 1 && ( + + )} - {currentStep === 3 && ( - setCurrentStep(2)} - onNext={handleUpdateProfile} - onWillDoLater={(): void => setCurrentStep(4)} // This is temporary, only to skip gateway api call as it's not setup on staging yet - /> - )} + {currentStep === 2 && ( + setCurrentStep(1)} + onNext={(): void => setCurrentStep(3)} + /> + )} - {currentStep === 4 && ( - setCurrentStep(3)} - onNext={handleOnboardingComplete} - /> + {currentStep === 3 && ( + setCurrentStep(2)} + onNext={handleUpdateProfile} + onWillDoLater={(): void => setCurrentStep(4)} // This is temporary, only to skip gateway api call as it's not setup on staging yet + /> + )} + + {currentStep === 4 && ( + setCurrentStep(3)} + onNext={handleOnboardingComplete} + /> + )} + )}
diff --git a/frontend/src/container/SideNav/SideNav.tsx b/frontend/src/container/SideNav/SideNav.tsx index 16787bc3d8..8ccafacb0a 100644 --- a/frontend/src/container/SideNav/SideNav.tsx +++ b/frontend/src/container/SideNav/SideNav.tsx @@ -113,7 +113,9 @@ function SideNav({ if (!isOnboardingEnabled || !isCloudUser()) { let items = [...menuItems]; - items = items.filter((item) => item.key !== ROUTES.GET_STARTED); + items = items.filter( + (item) => item.key !== ROUTES.GET_STARTED && item.key !== ROUTES.ONBOARDING, + ); setMenuItems(items); } diff --git a/frontend/src/pages/SignUp/SignUp.tsx b/frontend/src/pages/SignUp/SignUp.tsx index 4917b0fe2d..68f9c19dd1 100644 --- a/frontend/src/pages/SignUp/SignUp.tsx +++ b/frontend/src/pages/SignUp/SignUp.tsx @@ -261,7 +261,7 @@ function SignUp({ version }: SignUpProps): JSX.Element { values, async (): Promise => { if (isOnboardingEnabled && isCloudUser()) { - history.push(ROUTES.GET_STARTED); + history.push(ROUTES.ONBOARDING); } else { history.push(ROUTES.APPLICATION); } diff --git a/frontend/src/types/api/preferences/userOrgPreferences.ts b/frontend/src/types/api/preferences/userOrgPreferences.ts index 6faa75d5f1..2c77090769 100644 --- a/frontend/src/types/api/preferences/userOrgPreferences.ts +++ b/frontend/src/types/api/preferences/userOrgPreferences.ts @@ -19,12 +19,12 @@ export interface GetAllUserPreferencesResponseProps { } export interface UpdateOrgPreferenceProps { - key: string; + preferenceID: string; value: unknown; } export interface UpdateUserPreferenceProps { - key: string; + preferenceID: string; value: unknown; }