Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
82b28ec
chore: update api
iacopolea Mar 9, 2026
969dddd
feat: refactor CreateTaskListsWithAI to remove processItemOutput and …
iacopolea Mar 9, 2026
832c92d
fix: correct records access in handleClick function for context gathe…
iacopolea Mar 11, 2026
11a53d3
Merge pull request #1536 from AppQuality/UN-2452-context
marcbon Mar 11, 2026
e7b7301
feat: add ModulePersonas and OutputModulePersonas to schema and API t…
Kariamos Mar 6, 2026
ede4bd5
feat: add Personas module with component, hooks, and integration into…
Kariamos Mar 6, 2026
eb86fa9
feat: replace ModulePersonas with ModuleACNSaver in schema and API types
Kariamos Mar 10, 2026
4fdcdeb
feat: add ACNSaverPersonas module with component, hooks, and integrat…
Kariamos Mar 10, 2026
f0bc91d
feat: filter out modules with variant "hidden" in various components …
Kariamos Mar 10, 2026
38c435c
refactor: simplify useIcon, useSubtitle, and useTitle functions for c…
Kariamos Mar 10, 2026
a2faa79
feat: update ACN personas in schema and add test data for hidden pers…
Kariamos Mar 12, 2026
6f1267e
refactor: remove validation options from useIcon and related exports
Kariamos Mar 12, 2026
a051c62
feat: update module filtering to exclude records not present in curre…
Kariamos Mar 12, 2026
54c16cc
fix: prevent actual API call during tests in sendToHubspot function
cannarocks Mar 12, 2026
487c22f
Merge pull request #1538 from AppQuality/prevent-hs-fake-trigger-duri…
cannarocks Mar 13, 2026
0d14437
feat: add hint, placeholder and info tooltip to goal module
sinatragianpaolo Mar 13, 2026
d3f1d74
test: add e2e tests for goal module hint, placeholder and tooltip
sinatragianpaolo Mar 13, 2026
ae2b557
fix: add line break before last sentence in goal tooltip description
sinatragianpaolo Mar 13, 2026
d7b9ca9
fix: improve tooltip description formatting for goal module
sinatragianpaolo Mar 13, 2026
0a7b735
test: fix placeholder and tooltip description assertions in goal e2e …
sinatragianpaolo Mar 13, 2026
07aa851
test: remove tooltip description assertion and clean up fixture
sinatragianpaolo Mar 13, 2026
8139cc3
Merge pull request #1540 from AppQuality/UN-2457
sinatragianpaolo Mar 13, 2026
10a58f8
refactor: remove unused test data for hidden personas module
Kariamos Mar 16, 2026
c7ebb7f
Merge pull request #1537 from AppQuality/UN-2423-hidden-modules
Kariamos Mar 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions src/common/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1115,7 +1115,8 @@ export interface components {
| components["schemas"]["ModuleMobileInternet"]
| components["schemas"]["ModuleHomeInternet"]
| components["schemas"]["ModuleGasSupply"]
| components["schemas"]["ModuleAnnualIncomeRange"];
| components["schemas"]["ModuleAnnualIncomeRange"]
| components["schemas"]["ModuleACNSaver"];
/** ModuleAdditionalTarget */
ModuleAdditionalTarget: {
output: string;
Expand Down Expand Up @@ -1966,6 +1967,22 @@ export interface components {
data?: { [key: string]: unknown };
}[];
};
/**
* ModuleACNSaver
* @description This module is created ad-hoc for Accenture to target their saver/investor personas.
*/
ModuleACNSaver: {
output: (
| "ACN.PRAGMATICO DIGITALE"
| "ACN.EMERGENTE ASPIRAZIONALE"
| "ACN.INVESTITORE SOFISTICATO"
| "ACN.SOCIALE COLLABORATIVO"
| "ACN.CONSERVATORE PRUDENTE"
)[];
/** @enum {undefined} */
type: "acn_saver_personas";
variant: string;
};
};
responses: {
/** Shared error response */
Expand Down Expand Up @@ -3927,6 +3944,7 @@ export interface operations {
count: number;
/** @description The plan ID to associate with the generation */
planId: string;
context?: string;
};
};
};
Expand Down Expand Up @@ -5258,7 +5276,6 @@ export interface operations {
400: components["responses"]["Error"];
403: components["responses"]["Error"];
404: components["responses"]["Error"];
406: components["responses"]["Error"];
500: components["responses"]["Error"];
502: components["responses"]["Error"];
};
Expand Down
15 changes: 14 additions & 1 deletion src/features/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1902,6 +1902,7 @@ export type PostServicesApiKUsecasesApiArg = {
count: number;
/** The plan ID to associate with the generation */
planId: string;
context?: string;
};
};
export type GetServicesApiKJobsByJobIdApiResponse =
Expand Down Expand Up @@ -3179,6 +3180,17 @@ export type ModuleAnnualIncomeRange = {
type: 'annual_income_range';
variant: string;
};
export type ModuleAcnSaver = {
output: (
| 'ACN.PRAGMATICO DIGITALE'
| 'ACN.EMERGENTE ASPIRAZIONALE'
| 'ACN.INVESTITORE SOFISTICATO'
| 'ACN.SOCIALE COLLABORATIVO'
| 'ACN.CONSERVATORE PRUDENTE'
)[];
type: 'acn_saver_personas';
variant: string;
};
export type Module =
| ModuleTitle
| ModuleDate
Expand All @@ -3203,7 +3215,8 @@ export type Module =
| ModuleMobileInternet
| ModuleHomeInternet
| ModuleGasSupply
| ModuleAnnualIncomeRange;
| ModuleAnnualIncomeRange
| ModuleAcnSaver;
export type PlanStatus = 'pending_review' | 'draft' | 'approved' | 'paying';
export type PurchasablePlanRules =
| 'number_of_modules'
Expand Down
2 changes: 2 additions & 0 deletions src/features/planModules/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ const planModuleSlice = createSlice({
state.records[action.payload.type] = {
...oldVal,
output: action.payload.output,
// Preserve variant or use 'default' if not set
variant: oldVal?.variant || 'default',
};
if (!state.currentModules.includes(action.payload.type)) {
state.currentModules.push(action.payload.type);
Expand Down
6 changes: 4 additions & 2 deletions src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -921,10 +921,12 @@
"__PLAN_PAGE_MODULE_GENDER_TOTAL_PERCENTAGE_LABEL": "Total:",
"__PLAN_PAGE_MODULE_GENDER_UNASSIGNED_PERCENTAGE_ERROR": "Please assign a percentage to each selected gender.",
"__PLAN_PAGE_MODULE_GOAL_INFO": "Enter goal (max 256 characters)",
"__PLAN_PAGE_MODULE_GOAL_LABEL": "Specify the main goal of this activity",
"__PLAN_PAGE_MODULE_GOAL_PLACEHOLDER": "Describe what you want to achieve",
"__PLAN_PAGE_MODULE_GOAL_LABEL": "What do you want to understand from this activity?",
"__PLAN_PAGE_MODULE_GOAL_PLACEHOLDER": "e.g., Understand whether new visitors can find a product, add it to the cart smoothly, and notice the gift card option.",
"__PLAN_PAGE_MODULE_GOAL_REMOVE_TOOLTIP_BUTTON": "Delete",
"__PLAN_PAGE_MODULE_GOAL_TITLE": "Goal of the activity",
"__PLAN_PAGE_MODULE_GOAL_TOOLTIP_TITLE": "How to write a good goal",
"__PLAN_PAGE_MODULE_GOAL_TOOLTIP_DESCRIPTION": "Specify the goal of this activity to help us set it up effectively.<br/><br/>Tip: concentrate on the outcome you want to explore in the user journey, not on each step.<br/><br/>Testers won't see this field.",
"__PLAN_PAGE_MODULE_INCOME_25K_TO_50K_LABEL": "€25,000 - €50,000",
"__PLAN_PAGE_MODULE_INCOME_ALL_LABEL": "All income levels",
"__PLAN_PAGE_MODULE_INCOME_ALL_LABEL_HINT": "Participants equally distributed across income brackets",
Expand Down
2 changes: 2 additions & 0 deletions src/pages/JoinPage/sendToHubspot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
firstName: string;
lastName: string;
}) {
if (process.env.NODE_ENV === 'test') return false; // Skip actual API call during tests

const PORTAL_ID = isDev() ? '50612068' : '6087279';
const FORM_ID = isDev() ? STAGING_FORM_ID : PRODUCTION_FORM_ID;
const url = `https://api.hsforms.com/submissions/v3/integration/submit/${PORTAL_ID}/${FORM_ID}`;
Expand Down Expand Up @@ -101,13 +103,13 @@
});

if (!response.ok) {
console.error(`HubSpot API error: ${response.statusText}`);

Check warning on line 106 in src/pages/JoinPage/sendToHubspot.ts

View workflow job for this annotation

GitHub Actions / validate

Unexpected console statement
return false;
}

return await response.json();
} catch (error) {
console.error('Error submitting to HubSpot:', error);

Check warning on line 112 in src/pages/JoinPage/sendToHubspot.ts

View workflow job for this annotation

GitHub Actions / validate

Unexpected console statement
return false;
}
}
15 changes: 10 additions & 5 deletions src/pages/Plan/ModulesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@
const breakpointSm = parseInt(appTheme.breakpoints.sm, 10);
const isMobile = width < breakpointSm;

const currentModules = useAppSelector(
(state) => state.planModules.currentModules
const { currentModules, records } = useAppSelector(
(state) => state.planModules
);
const { activeTab, newModule, setNewModule } = usePlanContext();
const { t } = useTranslation();
Expand Down Expand Up @@ -139,9 +139,14 @@
)}
<GroupsWrapper>
{groupConfig.map((group) => {
const groupModules = group.modules.filter((module) =>
currentModules.includes(module)
);
// Filter modules that are in currentModules and don't have variant "hidden"
const groupModules = group.modules.filter((module) => {
if (!currentModules.includes(module)) return false;
if (!Object.hasOwn(records, module)) return true;
const moduleRecord = records[module];

Check warning on line 146 in src/pages/Plan/ModulesList.tsx

View workflow job for this annotation

GitHub Actions / validate

Variable Assigned to Object Injection Sink
if (moduleRecord?.variant === 'hidden') return false;
return true;
});
if (groupModules.length === 0) return null;
return (
<div key={group.id}>
Expand Down
2 changes: 2 additions & 0 deletions src/pages/Plan/modules/Factory/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { LanguageModule } from './modules/Language';
import { LiteracyModule } from './modules/Literacy';
import { LocalityModule } from './modules/Locality';
import { OutOfScopeModule } from './modules/OutOfScope';
import { ACNSaverPersonasModule } from './modules/CustomModules/Accenture/ACNSaverPersonas';
import { SetupNoteModule } from './modules/SetupNote';
import { TargetNoteModule } from './modules/TargetNote';
import { TargetSizeModule } from './modules/TargetSize';
Expand Down Expand Up @@ -53,6 +54,7 @@ const modules: Record<
[InternetHomeModule.slug]: InternetHomeModule,
[TitleModule.slug]: TitleModule,
[DatesModule.slug]: DatesModule,
[ACNSaverPersonasModule.slug]: ACNSaverPersonasModule,
};

export function getModuleBySlug(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { useModule } from 'src/features/modules/useModule';

const ACNSaverPersonas = () => {
const { value } = useModule('acn_saver_personas');

if (value?.variant === 'hidden') {
return null;
}

return <div>Personas Module - Default Variant</div>;
};

export default ACNSaverPersonas;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { createModuleDefinition } from '../../../../ModuleDefinition';
import Personas from './Component';
import useIcon from './useIcon';
import useSubtitle from './useSubtitle';
import useTitle from './useTitle';

export const ACNSaverPersonasModule = createModuleDefinition({
slug: 'acn_saver_personas',
Component: Personas,
useTitle,
useIcon,
useSubtitle,
defaultData: [],
defaultVariant: 'default',
tab: 'setup',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const useIcon = () => null;

export default useIcon;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const useSubtitle = () => 'User personas';

export default useSubtitle;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const useTitle = () => 'Personas';

export default useTitle;
44 changes: 38 additions & 6 deletions src/pages/Plan/modules/Factory/modules/Goal/Component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
FormField,
IconButton,
Label,
MD,
Notification,
SM,
Span,
Expand Down Expand Up @@ -234,12 +235,42 @@ const GoalContent = () => {
<AccordionNew.Panel>
<div style={{ padding: appTheme.space.xs }}>
<FormField style={{ marginBottom: appTheme.space.md }}>
<Label>
<Trans i18nKey="__PLAN_PAGE_MODULE_GOAL_LABEL">
Which is the objective of the test?
</Trans>
<Span style={{ color: appTheme.palette.red[700] }}>*</Span>
</Label>
<div
style={{
display: 'flex',
alignItems: 'center',
gap: appTheme.space.xs,
}}
>
<Label style={{ marginBottom: 0 }}>
<Trans i18nKey="__PLAN_PAGE_MODULE_GOAL_LABEL">
What do you want to understand from this activity?
</Trans>
<Span style={{ color: appTheme.palette.red[700] }}>*</Span>
</Label>
<Tooltip
placement="end"
type="light"
size="large"
content={
<>
<MD isBold style={{ marginBottom: appTheme.space.xs }}>
{t('__PLAN_PAGE_MODULE_GOAL_TOOLTIP_TITLE')}
</MD>
<MD>
<Trans
i18nKey="__PLAN_PAGE_MODULE_GOAL_TOOLTIP_DESCRIPTION"
components={{ br: <br /> }}
/>
</MD>
</>
}
>
<IconButton isBasic data-qa="goal-info-button">
<InfoIcon />
</IconButton>
</Tooltip>
</div>
<div style={{ marginTop: appTheme.space.xs }}>
<Editor
editable={getPlanStatus() === 'draft'}
Expand All @@ -250,6 +281,7 @@ const GoalContent = () => {
ref={editorRef}
placeholderOptions={{
placeholder: t('__PLAN_PAGE_MODULE_GOAL_PLACEHOLDER'),
showOnlyCurrent: false,
}}
headerTitle={' '}
disableSaveShortcut
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import {
} from 'src/features/api';
import { useModuleTasksContext } from '../../context';
import { useModuleTasks } from '../../hooks';
import { processItemOutput } from '../processItemOutput';
import { LoadingSpinner } from './LoadingSpinner';

// constants
Expand All @@ -39,7 +38,6 @@ const MODULES_TO_PROMPT = [
'language',
'touchpoints',
];
const MAX_PROMPT_LENGTH = 102300;

const CreateTaskListsWithAI = () => {
const { setOutput, value: currentTasks } = useModuleTasks();
Expand Down Expand Up @@ -93,20 +91,18 @@ const CreateTaskListsWithAI = () => {

const handleClick = async () => {
// gather modules info to prepend to the user prompt
const modulesInfo = Object.entries(records)
.filter(([key]) => MODULES_TO_PROMPT.includes(key))
.map(
([key, item]) =>
`Module: ${key}, Config: ${JSON.stringify(processItemOutput(item))}`
const context = JSON.stringify(
Object.entries(records.records).filter(([key]) =>
MODULES_TO_PROMPT.includes(key)
)
.join('\n');
const fullPrompt = `User prompt:\n${userPrompt}\n[Modules info]:\n${modulesInfo}`;
);

await postServicesApiKUsecases({
body: {
planId: planId || '',
count: usecaseNumber as number, // usecaseNumber always have a value here because the button is disabled when it's undefined
requirements: fullPrompt.slice(0, MAX_PROMPT_LENGTH),
requirements: userPrompt,
context,
},
});
};
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import { useModule } from 'src/features/modules/useModule';
import { ModuleTouchpointsContextProvider } from './context';
import { TouchpointsList } from './parts';

const TouchPoints = () => (
<ModuleTouchpointsContextProvider>
<TouchpointsList />
</ModuleTouchpointsContextProvider>
);
const TouchPoints = () => {
const { value } = useModule('touchpoints');

if (value?.variant === 'hidden') {
return null;
}

return (
<ModuleTouchpointsContextProvider>
<TouchpointsList />
</ModuleTouchpointsContextProvider>
);
};

export default TouchPoints;
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { ReactComponent as TouchpointsIcon } from 'src/assets/icons/touchpoints-icon.svg';
import { useModule } from 'src/features/modules/useModule';
import useIconColor from '../../useIconColor';

const useIcon = (withValidation: boolean = true) => {
const { value } = useModule('touchpoints');
const color = useIconColor({
module_type: 'touchpoints',
withValidation,
});

if (value?.variant === 'hidden') {
return null;
}

return <TouchpointsIcon color={color} />;
};

Expand Down
9 changes: 8 additions & 1 deletion src/pages/Plan/navigation/aside/AddBlockButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,17 @@
const { planComposedStatus } = usePlan(planId);
const { activeTab } = usePlanContext();
const availableModules = getModulesByTab(activeTab.name);
const { currentModules } = useAppSelector((state) => state.planModules);
const { currentModules, records } = useAppSelector(
(state) => state.planModules
);

// Filter out modules that are already added or have variant "hidden"
const items = availableModules.filter((module_type) => {
// Don't show modules that are already added
if (currentModules.find((module) => module === module_type)) return false;
// Don't show modules with variant "hidden" (preconfigurated)
const module = records[module_type];

Check warning on line 51 in src/pages/Plan/navigation/aside/AddBlockButton.tsx

View workflow job for this annotation

GitHub Actions / validate

Variable Assigned to Object Injection Sink
if (module?.variant === 'hidden') return false;
return true;
});

Expand Down
Loading
Loading