mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 09:22:43 +03:00
console: add onboarding wizard tests
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6041 GitOrigin-RevId: 72e5f6e0fc7c51c9a4db70665059771194be2730
This commit is contained in:
parent
c89d283dd2
commit
90543c99ae
@ -2,7 +2,7 @@
|
|||||||
* GraphQl query to fetch all growth experiments data related to the current user.
|
* GraphQl query to fetch all growth experiments data related to the current user.
|
||||||
*/
|
*/
|
||||||
export const query = `
|
export const query = `
|
||||||
query {
|
query fetchAllExperimentsData {
|
||||||
experiments_config {
|
experiments_config {
|
||||||
experiment
|
experiment
|
||||||
metadata
|
metadata
|
||||||
|
@ -5,20 +5,21 @@ export type ExperimentConfig = {
|
|||||||
userActivity: ExperimentsResponseData['data']['experiments_cohort'][0]['activity'];
|
userActivity: ExperimentsResponseData['data']['experiments_cohort'][0]['activity'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: These types should be replaced by autogenerated types, when we use typescript graphql codegen
|
||||||
|
type ExperimentsConfig = {
|
||||||
|
experiment: string;
|
||||||
|
metadata: Record<string, unknown>;
|
||||||
|
status: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ExperimentsCohort = {
|
||||||
|
experiment: string;
|
||||||
|
activity: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
|
||||||
export type ExperimentsResponseData = {
|
export type ExperimentsResponseData = {
|
||||||
data: {
|
data: {
|
||||||
experiments_config: [
|
experiments_config: ExperimentsConfig[];
|
||||||
{
|
experiments_cohort: ExperimentsCohort[];
|
||||||
experiment: string;
|
|
||||||
metadata: Record<string, unknown>;
|
|
||||||
status: string;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
experiments_cohort: [
|
|
||||||
{
|
|
||||||
experiment: string;
|
|
||||||
activity: Record<string, unknown>;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,30 +1,50 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ComponentMeta, Story } from '@storybook/react';
|
import { ComponentMeta, Story } from '@storybook/react';
|
||||||
import { ReactQueryDecorator } from '@/storybook/decorators/react-query';
|
import { ReactQueryDecorator } from '@/storybook/decorators/react-query';
|
||||||
|
import { useQueryClient } from 'react-query';
|
||||||
import { Root } from './Root';
|
import { Root } from './Root';
|
||||||
import { handlers } from './mocks/handlers.mock';
|
import {
|
||||||
|
baseHandlers,
|
||||||
|
fetchAnsweredSurveysHandler,
|
||||||
|
fetchUnansweredSurveysHandler,
|
||||||
|
} from './mocks/handlers.mock';
|
||||||
|
import { mockGrowthClient } from './mocks/constants';
|
||||||
|
import { surveysQueryKey } from '../Surveys/constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'features/Onboarding Wizard/Root',
|
title: 'features/Onboarding Wizard/Root',
|
||||||
component: Root,
|
component: Root,
|
||||||
decorators: [ReactQueryDecorator()],
|
decorators: [ReactQueryDecorator()],
|
||||||
parameters: {
|
|
||||||
msw: handlers(),
|
|
||||||
},
|
|
||||||
} as ComponentMeta<typeof Root>;
|
} as ComponentMeta<typeof Root>;
|
||||||
|
|
||||||
const mockGrowthClient = {
|
export const WithSurvey: Story = () => {
|
||||||
getAllExperimentConfig: () => [
|
const queryClient = useQueryClient();
|
||||||
{
|
// need to invalidate as useSurveysData hook is using a stale time
|
||||||
experiment: 'console_onboarding_wizard_v1',
|
queryClient.invalidateQueries(surveysQueryKey, {
|
||||||
status: 'enabled',
|
refetchActive: false,
|
||||||
metadata: {},
|
});
|
||||||
userActivity: {},
|
|
||||||
},
|
return (
|
||||||
],
|
<Root growthExperimentsClient={mockGrowthClient.enabledWithoutActivity} />
|
||||||
setAllExperimentConfig: () => Promise.resolve(),
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Base: Story = () => (
|
WithSurvey.parameters = {
|
||||||
<Root growthExperimentsClient={mockGrowthClient} />
|
msw: [...baseHandlers(), fetchUnansweredSurveysHandler],
|
||||||
);
|
};
|
||||||
|
|
||||||
|
export const WithoutSurvey: Story = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
// need to invalidate as `useSurveysData` hook is using a stale time
|
||||||
|
queryClient.invalidateQueries(surveysQueryKey, {
|
||||||
|
refetchActive: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Root growthExperimentsClient={mockGrowthClient.enabledWithoutActivity} />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
WithoutSurvey.parameters = {
|
||||||
|
msw: [...baseHandlers(), fetchAnsweredSurveysHandler],
|
||||||
|
};
|
||||||
|
87
console/src/features/OnboardingWizard/Root.test.tsx
Normal file
87
console/src/features/OnboardingWizard/Root.test.tsx
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||||
|
import { setupServer } from 'msw/node';
|
||||||
|
import { Provider as ReduxProvider } from 'react-redux';
|
||||||
|
import { configureStore } from '@reduxjs/toolkit';
|
||||||
|
import { GrowthExperimentsClient } from '../GrowthExperiments';
|
||||||
|
import { baseHandlers } from './mocks/handlers.mock';
|
||||||
|
import { mockGrowthClient } from './mocks/constants';
|
||||||
|
import { OnboardingWizard } from '.';
|
||||||
|
|
||||||
|
const server = setupServer(...baseHandlers());
|
||||||
|
|
||||||
|
beforeAll(() => server.listen());
|
||||||
|
afterAll(() => server.close());
|
||||||
|
|
||||||
|
const OnboardingWizardRender = async (
|
||||||
|
mockedGrowthClient: GrowthExperimentsClient
|
||||||
|
) => {
|
||||||
|
// redux provider is needed as ConnectDBScreen is using dispatch to push routes
|
||||||
|
const store = configureStore({
|
||||||
|
reducer: {
|
||||||
|
tables: () => ({ currentDataSource: 'postgres' }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// react query provider is needed as surveys component is using it
|
||||||
|
const reactQueryClient = new QueryClient();
|
||||||
|
|
||||||
|
render(
|
||||||
|
<ReduxProvider store={store} key="provider">
|
||||||
|
<QueryClientProvider client={reactQueryClient}>
|
||||||
|
<OnboardingWizard growthExperimentsClient={mockedGrowthClient} />
|
||||||
|
</QueryClientProvider>
|
||||||
|
</ReduxProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Check different configurations of experiments client', () => {
|
||||||
|
it('should hide wizard as error in experiment name', async () => {
|
||||||
|
await OnboardingWizardRender(mockGrowthClient.nameError);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.queryByText('Welcome to your new Hasura project!')
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show wizard as experiment is enabled and user activity is empty', async () => {
|
||||||
|
await OnboardingWizardRender(mockGrowthClient.enabledWithoutActivity);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.queryByText('Welcome to your new Hasura project!')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should hide wizard as experiment is disabled', async () => {
|
||||||
|
await OnboardingWizardRender(mockGrowthClient.disabledWithoutActivity);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.queryByText('Welcome to your new Hasura project!')
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should hide wizard as user has completed the onboarding', async () => {
|
||||||
|
await OnboardingWizardRender(mockGrowthClient.enabledWithCorrectActivity);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.queryByText('Welcome to your new Hasura project!')
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should hide wizard as experiment is disabled, user activity does not matter in this case', async () => {
|
||||||
|
await OnboardingWizardRender(mockGrowthClient.disabledWithCorrectActivity);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.queryByText('Welcome to your new Hasura project!')
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show wizard as experiment is enabled, and user activity is incorrect. Could mean a error on backend.', async () => {
|
||||||
|
await OnboardingWizardRender(mockGrowthClient.enabledWithWrongActivity);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.queryByText('Welcome to your new Hasura project!')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
@ -4,7 +4,7 @@ import globals from '@/Globals';
|
|||||||
export const experimentId = growthExperimentsIds.onboardingWizardV1;
|
export const experimentId = growthExperimentsIds.onboardingWizardV1;
|
||||||
|
|
||||||
export const graphQlMutation = `
|
export const graphQlMutation = `
|
||||||
mutation ($projectId: uuid!, $experimentId: String!, $kind: String!) {
|
mutation trackExperimentsCohortActivity ($projectId: uuid!, $experimentId: String!, $kind: String!) {
|
||||||
trackExperimentsCohortActivity(experiment: $experimentId, payload: {kind: $kind, project_id: $projectId}) {
|
trackExperimentsCohortActivity(experiment: $experimentId, payload: {kind: $kind, project_id: $projectId}) {
|
||||||
status
|
status
|
||||||
}
|
}
|
||||||
|
177
console/src/features/OnboardingWizard/mocks/constants.ts
Normal file
177
console/src/features/OnboardingWizard/mocks/constants.ts
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
import { GrowthExperimentsClient } from '@/features/GrowthExperiments';
|
||||||
|
import { SurveysResponseData } from '@/features/Surveys';
|
||||||
|
|
||||||
|
export const mockGrowthClient: Record<string, GrowthExperimentsClient> = {
|
||||||
|
/**
|
||||||
|
* config to hide wizard as experiment name error
|
||||||
|
*/
|
||||||
|
nameError: {
|
||||||
|
getAllExperimentConfig: () => [
|
||||||
|
{
|
||||||
|
experiment: 'console_onboarding_wizardddd_v1',
|
||||||
|
status: 'enabled',
|
||||||
|
metadata: {},
|
||||||
|
userActivity: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
setAllExperimentConfig: () => Promise.resolve(),
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* config to show wizard as experiment enabled and
|
||||||
|
* user activity is empty
|
||||||
|
*/
|
||||||
|
enabledWithoutActivity: {
|
||||||
|
getAllExperimentConfig: () => [
|
||||||
|
{
|
||||||
|
experiment: 'console_onboarding_wizard_v1',
|
||||||
|
status: 'enabled',
|
||||||
|
metadata: {},
|
||||||
|
userActivity: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
setAllExperimentConfig: () => Promise.resolve(),
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* config to hide wizard as experiment is disabled
|
||||||
|
*/
|
||||||
|
disabledWithoutActivity: {
|
||||||
|
getAllExperimentConfig: () => [
|
||||||
|
{
|
||||||
|
experiment: 'console_onboarding_wizard_v1',
|
||||||
|
status: 'disabled',
|
||||||
|
metadata: {},
|
||||||
|
userActivity: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
setAllExperimentConfig: () => Promise.resolve(),
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* config to hide wizard as user has completed
|
||||||
|
* the onboarding
|
||||||
|
*/
|
||||||
|
enabledWithCorrectActivity: {
|
||||||
|
getAllExperimentConfig: () => [
|
||||||
|
{
|
||||||
|
experiment: 'console_onboarding_wizard_v1',
|
||||||
|
status: 'enabled',
|
||||||
|
metadata: {},
|
||||||
|
userActivity: {
|
||||||
|
onboarding_complete: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
setAllExperimentConfig: () => Promise.resolve(),
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* config to hide wizard as experiment is disabled,
|
||||||
|
* user has completed the onboarding or not should not matter
|
||||||
|
* in this case.
|
||||||
|
*/
|
||||||
|
disabledWithCorrectActivity: {
|
||||||
|
getAllExperimentConfig: () => [
|
||||||
|
{
|
||||||
|
experiment: 'console_onboarding_wizard_v1',
|
||||||
|
status: 'disabled',
|
||||||
|
metadata: {},
|
||||||
|
userActivity: {
|
||||||
|
onboarding_complete: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
setAllExperimentConfig: () => Promise.resolve(),
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* config to show wizard as experiment is enabled,
|
||||||
|
* and user activity is incorrect. Could mean a error on backend
|
||||||
|
* while saving user activity.
|
||||||
|
*/
|
||||||
|
enabledWithWrongActivity: {
|
||||||
|
getAllExperimentConfig: () => [
|
||||||
|
{
|
||||||
|
experiment: 'console_onboarding_wizard_v1',
|
||||||
|
status: 'enabled',
|
||||||
|
metadata: {},
|
||||||
|
userActivity: {
|
||||||
|
onboarding_completessss: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
setAllExperimentConfig: () => Promise.resolve(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fetchSurveysDataResponse: Record<
|
||||||
|
string,
|
||||||
|
SurveysResponseData['data']
|
||||||
|
> = {
|
||||||
|
unanswered: {
|
||||||
|
survey: [
|
||||||
|
{
|
||||||
|
survey_name: 'Hasura familiarity survey',
|
||||||
|
survey_questions: [
|
||||||
|
{
|
||||||
|
kind: 'radio',
|
||||||
|
question: 'How familiar are you with Hasura?',
|
||||||
|
id: '4595916a-1c5b-4d55-b7ca-11616131d1d3',
|
||||||
|
survey_question_options: [
|
||||||
|
{
|
||||||
|
option: 'new user',
|
||||||
|
id: 'dcd2480b-cc1b-4e1a-b111-27aed8b89b8b',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
option: 'active user',
|
||||||
|
id: '53ed19af-7ae7-4225-9969-13b06d9b8f66',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
option: 'recurring user',
|
||||||
|
id: '8f81e3d0-f45b-40ba-9456-8865a5a1cb93',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
option: 'past user',
|
||||||
|
id: 'b25edd78-0af3-4448-8302-14e2b818c4c6',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
survey_question_answers: [],
|
||||||
|
},
|
||||||
|
answered: {
|
||||||
|
survey: [
|
||||||
|
{
|
||||||
|
survey_name: 'Hasura familiarity survey',
|
||||||
|
survey_questions: [
|
||||||
|
{
|
||||||
|
kind: 'radio',
|
||||||
|
question: 'How familiar are you with Hasura?',
|
||||||
|
id: '4595916a-1c5b-4d55-b7ca-11616131d1d3',
|
||||||
|
survey_question_options: [
|
||||||
|
{
|
||||||
|
option: 'new user',
|
||||||
|
id: 'dcd2480b-cc1b-4e1a-b111-27aed8b89b8b',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
option: 'active user',
|
||||||
|
id: '53ed19af-7ae7-4225-9969-13b06d9b8f66',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
option: 'recurring user',
|
||||||
|
id: '8f81e3d0-f45b-40ba-9456-8865a5a1cb93',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
option: 'past user',
|
||||||
|
id: 'b25edd78-0af3-4448-8302-14e2b818c4c6',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
survey_question_answers: [
|
||||||
|
{
|
||||||
|
survey_question_id: '4595916a-1c5b-4d55-b7ca-11616131d1d3',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
@ -1,5 +1,7 @@
|
|||||||
import { graphql } from 'msw';
|
import { graphql } from 'msw';
|
||||||
import Endpoints from '@/Endpoints';
|
import Endpoints from '@/Endpoints';
|
||||||
|
import { SurveysResponseData } from '@/features/Surveys';
|
||||||
|
import { fetchSurveysDataResponse } from './constants';
|
||||||
|
|
||||||
type ResponseBodyOnSuccess = {
|
type ResponseBodyOnSuccess = {
|
||||||
status: 'success';
|
status: 'success';
|
||||||
@ -7,13 +9,50 @@ type ResponseBodyOnSuccess = {
|
|||||||
|
|
||||||
const controlPlaneApi = graphql.link(Endpoints.luxDataGraphql);
|
const controlPlaneApi = graphql.link(Endpoints.luxDataGraphql);
|
||||||
|
|
||||||
export const handlers = () => [
|
export const baseHandlers = () => [
|
||||||
controlPlaneApi.operation<any, ResponseBodyOnSuccess>((req, res, ctx) => {
|
controlPlaneApi.query<ResponseBodyOnSuccess>(
|
||||||
return res(
|
'fetchAllExperimentsData',
|
||||||
ctx.status(200),
|
(req, res, ctx) => {
|
||||||
ctx.data({
|
return res(
|
||||||
status: 'success',
|
ctx.status(200),
|
||||||
})
|
ctx.data({
|
||||||
);
|
status: 'success',
|
||||||
}),
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
controlPlaneApi.mutation<ResponseBodyOnSuccess>(
|
||||||
|
'addSurveyAnswer',
|
||||||
|
(req, res, ctx) => {
|
||||||
|
return res(
|
||||||
|
ctx.status(200),
|
||||||
|
ctx.data({
|
||||||
|
status: 'success',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
controlPlaneApi.mutation<ResponseBodyOnSuccess>(
|
||||||
|
'trackExperimentsCohortActivity',
|
||||||
|
(req, res, ctx) => {
|
||||||
|
return res(
|
||||||
|
ctx.status(200),
|
||||||
|
ctx.data({
|
||||||
|
status: 'success',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const fetchUnansweredSurveysHandler = controlPlaneApi.query<
|
||||||
|
SurveysResponseData['data']
|
||||||
|
>('fetchAllSurveysData', (req, res, ctx) => {
|
||||||
|
return res(ctx.status(200), ctx.data(fetchSurveysDataResponse.unanswered));
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchAnsweredSurveysHandler = controlPlaneApi.query<
|
||||||
|
SurveysResponseData['data']
|
||||||
|
>('fetchAllSurveysData', (req, res, ctx) => {
|
||||||
|
return res(ctx.status(200), ctx.data(fetchSurveysDataResponse.answered));
|
||||||
|
});
|
||||||
|
@ -7,7 +7,7 @@ export const surveyName = 'Hasura familiarity survey';
|
|||||||
* GraphQl query to fetch all surveys related data
|
* GraphQl query to fetch all surveys related data
|
||||||
*/
|
*/
|
||||||
export const fetchAllSurveysDataQuery = `
|
export const fetchAllSurveysDataQuery = `
|
||||||
query ($currentTime: timestamptz!) {
|
query fetchAllSurveysData($currentTime: timestamptz!) {
|
||||||
survey(where: {
|
survey(where: {
|
||||||
_or: [
|
_or: [
|
||||||
{ended_at: {_gte: $currentTime}}
|
{ended_at: {_gte: $currentTime}}
|
||||||
@ -39,7 +39,7 @@ export const fetchAllSurveysDataQueryVariables = {
|
|||||||
* GraphQl mutation to save the survey answer
|
* GraphQl mutation to save the survey answer
|
||||||
*/
|
*/
|
||||||
export const addSurveyAnswerMutation = `
|
export const addSurveyAnswerMutation = `
|
||||||
mutation ($responses: [QuestionAnswers]!, $surveyName: String!) {
|
mutation addSurveyAnswer ($responses: [QuestionAnswers]!, $surveyName: String!) {
|
||||||
saveSurveyAnswer(payload: {responses: $responses, surveyName: $surveyName}) {
|
saveSurveyAnswer(payload: {responses: $responses, surveyName: $surveyName}) {
|
||||||
status
|
status
|
||||||
}
|
}
|
||||||
|
@ -3,3 +3,4 @@ export {
|
|||||||
useFamiliaritySurveyData,
|
useFamiliaritySurveyData,
|
||||||
} from './HasuraFamiliaritySurvey';
|
} from './HasuraFamiliaritySurvey';
|
||||||
export { prefetchSurveysData } from './utils';
|
export { prefetchSurveysData } from './utils';
|
||||||
|
export { SurveysResponseData } from './types';
|
||||||
|
@ -1,40 +1,40 @@
|
|||||||
|
// TODO: These types should be replaced by autogenerated types, when we use typescript graphql codegen
|
||||||
|
|
||||||
|
type SurveyQuestionOptions = {
|
||||||
|
// Note: `option` comes from cloud backend, and is not strongly typed in backend. Hence it is typed as `string`
|
||||||
|
// As the form is dynamic in nature, there could be additions/deletions to survey options in future
|
||||||
|
option: string;
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SurveyQuestion = {
|
||||||
|
kind: string;
|
||||||
|
question: string;
|
||||||
|
id: string;
|
||||||
|
survey_question_options: SurveyQuestionOptions[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type SurveyDetail = {
|
||||||
|
survey_name: string;
|
||||||
|
survey_questions: SurveyQuestion[];
|
||||||
|
};
|
||||||
|
|
||||||
export type SurveysResponseData = {
|
export type SurveysResponseData = {
|
||||||
data: {
|
data: {
|
||||||
survey: [
|
survey: SurveyDetail[];
|
||||||
{
|
survey_question_answers: {
|
||||||
survey_name: string;
|
survey_question_id: string;
|
||||||
survey_questions: [
|
}[];
|
||||||
{
|
|
||||||
kind: string;
|
|
||||||
question: string;
|
|
||||||
id: string;
|
|
||||||
survey_question_options: [
|
|
||||||
{
|
|
||||||
// Note: this value comes from the cloud backend, and is not strongly typed in backend.
|
|
||||||
// As the form is dynamic in nature, there could be additions/deletions to survey options in future
|
|
||||||
option: string;
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
survey_question_answers: [
|
|
||||||
{
|
|
||||||
survey_question_id: string;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type QuestionAnswersResponse = {
|
||||||
|
answer?: string;
|
||||||
|
optionsSelected?: string;
|
||||||
|
question_id: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type QuestionAnswers = {
|
export type QuestionAnswers = {
|
||||||
surveyName: string;
|
surveyName: string;
|
||||||
responses: [
|
responses: QuestionAnswersResponse[];
|
||||||
{
|
|
||||||
answer?: string;
|
|
||||||
optionsSelected?: string;
|
|
||||||
question_id: string;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
@ -6,9 +6,9 @@ import { ReactQueryDevtools } from 'react-query/devtools';
|
|||||||
|
|
||||||
export const ReactQueryDecorator = (): DecoratorFn => {
|
export const ReactQueryDecorator = (): DecoratorFn => {
|
||||||
const reactQueryClient = new QueryClient();
|
const reactQueryClient = new QueryClient();
|
||||||
return story => (
|
return Story => (
|
||||||
<QueryClientProvider client={reactQueryClient}>
|
<QueryClientProvider client={reactQueryClient}>
|
||||||
{story()}
|
<Story />
|
||||||
<ReactQueryDevtools />
|
<ReactQueryDevtools />
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
);
|
);
|
||||||
|
@ -27,5 +27,9 @@ export const ReduxDecorator = (
|
|||||||
devTools: true,
|
devTools: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
return story => <Provider store={store}>{story()}</Provider>;
|
return Story => (
|
||||||
|
<Provider store={store}>
|
||||||
|
<Story />
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user