Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,12 @@ const project = (overrides: Partial<Project> = {}) =>
...overrides,
}) as unknown as Project;

const wrap = (p: Project) =>
const wrap = (p: Project, consentGiven?: boolean) =>
render(
<I18nProvider i18n={i18n}>
<MantineProvider>
<MemoryRouter initialEntries={["/en-US/p1/start"]}>
<ParticipantInitiateForm project={p} />
<ParticipantInitiateForm project={p} consentGiven={consentGiven} />
</MemoryRouter>
</MantineProvider>
</I18nProvider>,
Expand Down Expand Up @@ -114,6 +114,20 @@ it("starts the conversation itself when nothing is asked", async () => {
);
// No question was asked, so no button was offered.
expect(screen.queryByTestId("portal-initiate-next-button")).toBeNull();
expect(initiate).toHaveBeenCalledWith(
expect.objectContaining({ consentGiven: false }),
);
});

it("passes the deck's consent on to the start", async () => {
initiate.mockResolvedValue({ id: "c1" });
wrap(project(), true);

await waitFor(() =>
expect(initiate).toHaveBeenCalledWith(
expect.objectContaining({ consentGiven: true }),
),
);
});

it("creates one conversation even if the form is torn down mid-request", async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,13 @@ const autoStartedConversations = new Map<
export const ParticipantInitiateForm = ({
project,
onRefusedChange,
consentGiven = false,
}: {
project: Project;
onRefusedChange?: (refused: boolean) => void;
/** The participant ticked the deck's consent checkbox. Never true when
* ?skipOnboarding=1 skipped the deck. */
consentGiven?: boolean;
}) => {
const navigate = useI18nNavigate();
const [searchParams] = useSearchParams();
Expand Down Expand Up @@ -130,6 +134,7 @@ export const ParticipantInitiateForm = ({
});
initiateConversation(
{
consentGiven,
email: data.email || undefined,
// `??` not `||`: an empty name is intentional when the project does
// not ask for one, and keeps the dashboard's auto-title fallback
Expand All @@ -147,7 +152,7 @@ export const ParticipantInitiateForm = ({
},
);
},
[project.id, initiateConversation, portalSource],
[project.id, initiateConversation, portalSource, consentGiven],
);

const nothingToAsk = portalHasNothingToAsk(project);
Expand Down Expand Up @@ -193,6 +198,7 @@ export const ParticipantInitiateForm = ({
source: portalSource,
});
pending = requestConversation({
consentGiven,
email: defaultEmail || undefined,
name: defaultName || t`Participant`,
pin: "",
Expand Down Expand Up @@ -232,6 +238,7 @@ export const ParticipantInitiateForm = ({
searchParams,
goToConversation,
portalSource,
consentGiven,
]);

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,30 @@ vi.mock("@/components/common/Logo", () => ({ Logo: () => null }));
vi.mock("@/hooks/useLanguage", () => ({
useLanguage: () => ({ language: "en-US" }),
}));
const systemCards = vi.hoisted(() => ({
current: [
{ section: "Intro", slides: [{ content: "Hi", title: "Welcome" }] },
] as unknown[],
}));
vi.mock("./hooks/useOnboardingCards", () => ({
useOnboardingCards: () => ({
getSystemCards: () => [
{ section: "Intro", slides: [{ content: "Hi", title: "Welcome" }] },
],
getSystemCards: () => systemCards.current,
}),
}));
vi.mock("./ParticipantInitiateForm", () => ({
ParticipantInitiateForm: ({
onRefusedChange,
consentGiven,
}: {
onRefusedChange?: (refused: boolean) => void;
consentGiven?: boolean;
}) => (
<button type="button" onClick={() => onRefusedChange?.(true)}>
refuse
</button>
<>
<button type="button" onClick={() => onRefusedChange?.(true)}>
refuse
</button>
<span>{consentGiven ? "consented" : "no consent"}</span>
</>
),
portalHasNothingToAsk: () => false,
}));
Expand Down Expand Up @@ -87,3 +95,31 @@ it("drops the heading once the start is refused when onboarding is skipped", ()

expect(screen.queryByText("Ready to begin?")).toBeNull();
});

it("tells the form consent was given once the checkbox is ticked", () => {
const intro = systemCards.current;
systemCards.current = [
{
section: "Privacy",
slides: [
{
checkbox: { label: "I agree", required: true },
title: "Privacy",
},
],
},
];
try {
wrap("/en-US/p1/start");
fireEvent.click(screen.getByTestId("portal-onboarding-checkbox"));
fireEvent.click(screen.getByTestId("portal-onboarding-next-button"));
expect(screen.getByText("consented")).toBeTruthy();
} finally {
systemCards.current = intro;
}
});

it("never claims consent when onboarding is skipped", () => {
wrap("/en-US/p1/start?skipOnboarding=1");
expect(screen.getByText("no consent")).toBeTruthy();
});
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ const ParticipantOnboardingCards = ({
const [animationDirection, setAnimationDirection] = useState("");
// The form refused to start: nothing to begin and nowhere to go back to.
const [refused, setRefused] = useState(false);
// Set when the participant advances past a required checkbox, which comes
// on a slide before the form, so the form mounts already knowing.
const [consentGiven, setConsentGiven] = useState(false);

const { language } = useLanguage();

Expand Down Expand Up @@ -101,9 +104,13 @@ const ParticipantOnboardingCards = ({

const InitiateFormComponent = useMemo(
() => () => (
<ParticipantInitiateForm project={project} onRefusedChange={setRefused} />
<ParticipantInitiateForm
project={project}
onRefusedChange={setRefused}
consentGiven={consentGiven}
/>
),
[project],
[project, consentGiven],
);

// With no name and no tags to collect, the last card starts the conversation
Expand Down Expand Up @@ -284,6 +291,7 @@ const ParticipantOnboardingCards = ({
// Advancing past a required checkbox is the participant accepting consent.
if (currentCard.checkbox?.required) {
posthog.capture("consent_given", { project_id: project.id });
setConsentGiven(true);
}
if (currentSlideIndex < allSlides.length - 1) {
setAnimationDirection("slide-left");
Expand Down
2 changes: 2 additions & 0 deletions dembrane/frontend/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,12 @@ export const initiateConversation = async (payload: {
source: string;
tagIdList: string[];
visitorId?: string;
consentGiven?: boolean;
}) => {
return apiNoAuth.post<unknown, TConversation>(
`/participant/projects/${payload.projectId}/conversations/initiate`,
{
consent_given: payload.consentGiven ?? false,
email: payload.email ?? undefined,
name: payload.name,
pin: payload.pin,
Expand Down
24 changes: 12 additions & 12 deletions dembrane/frontend/src/locales/cs-CZ.po
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ msgid "{0} deleted"
msgstr "{0} deleted"

#. placeholder {0}: failed.length
#: src/lib/api.ts:622
#: src/lib/api.ts:624
msgid "{0} file(s) failed to upload. Try those again."
msgstr "{0} souborů se nepodařilo nahrát. Zkuste to znovu."

Expand Down Expand Up @@ -1626,7 +1626,7 @@ msgstr "přidat pracovní prostor"
#~ msgid "Add additional context (Optional)"
#~ msgstr "Add additional context (Optional)"

#: src/components/participant/ParticipantInitiateForm.tsx:302
#: src/components/participant/ParticipantInitiateForm.tsx:309
msgid "Add all that apply"
msgstr "Add all that apply"

Expand Down Expand Up @@ -1979,7 +1979,7 @@ msgid "All"
msgstr "All"

#. placeholder {0}: payload.chunks.length
#: src/lib/api.ts:752
#: src/lib/api.ts:754
msgid "All {0} file(s) uploaded successfully"
msgstr "Všech {0} souborů bylo úspěšně nahráno"

Expand Down Expand Up @@ -2861,7 +2861,7 @@ msgid "Back"
msgstr "Back"

#. js-lingui-explicit-id
#: src/components/participant/ParticipantOnboardingCards.tsx:437
#: src/components/participant/ParticipantOnboardingCards.tsx:445
#: src/components/layout/ParticipantHeader.tsx:94
msgid "participant.button.back"
msgstr "Back"
Expand Down Expand Up @@ -4139,12 +4139,12 @@ msgid "Continue"
msgstr "Continue"

#. js-lingui-explicit-id
#: src/components/participant/ParticipantOnboardingCards.tsx:424
#: src/components/participant/ParticipantOnboardingCards.tsx:432
msgid "participant.button.next"
msgstr "Pokračovat"

#. js-lingui-explicit-id
#: src/components/participant/ParticipantInitiateForm.tsx:339
#: src/components/participant/ParticipantInitiateForm.tsx:346
msgid "participant.ready.to.begin.button.text"
msgstr "Continue"

Expand Down Expand Up @@ -9640,7 +9640,7 @@ msgid "No canvases yet. Ask in chat when you want a live view of the conversatio
msgstr "Zatím žádná plátna. Až budete chtít živý přehled rozhovorů, požádejte v chatu. První plátno zůstane tady."

#. js-lingui-explicit-id
#: src/components/participant/ParticipantOnboardingCards.tsx:270
#: src/components/participant/ParticipantOnboardingCards.tsx:277
msgid "participant.onboarding.no.card"
msgstr "Pro aktuální jazyk a sekci není k dispozici žádná karta."

Expand Down Expand Up @@ -10974,8 +10974,8 @@ msgid "partially completed"
msgstr "částečně dokončeno"

#: src/components/report/ConversationStatusTable.tsx:56
#: src/components/participant/ParticipantInitiateForm.tsx:136
#: src/components/participant/ParticipantInitiateForm.tsx:197
#: src/components/participant/ParticipantInitiateForm.tsx:141
#: src/components/participant/ParticipantInitiateForm.tsx:203
msgid "Participant"
msgstr "Participant"

Expand Down Expand Up @@ -12241,7 +12241,7 @@ msgstr "Připraveno v"
#~ msgstr "Připraveno v {readyTime}"

#. js-lingui-explicit-id
#: src/components/participant/ParticipantOnboardingCards.tsx:330
#: src/components/participant/ParticipantOnboardingCards.tsx:338
msgid "participant.ready.to.begin"
msgstr "Připraveni začít?"

Expand Down Expand Up @@ -14047,7 +14047,7 @@ msgstr "Samostatný (klient)"
msgid "Separate with commas, spaces, or new lines."
msgstr "Separate with commas, spaces, or new lines."

#: src/components/participant/ParticipantInitiateForm.tsx:290
#: src/components/participant/ParticipantInitiateForm.tsx:297
msgid "Session name"
msgstr "Název setkání"

Expand Down Expand Up @@ -15257,7 +15257,7 @@ msgid "Tag deleted"
msgstr "Tag deleted"

#: src/components/project/ProjectTagsInput.tsx:255
#: src/components/participant/ParticipantInitiateForm.tsx:301
#: src/components/participant/ParticipantInitiateForm.tsx:308
#: src/components/map/panels/MapSettingsMenu.tsx:267
#: src/components/conversation/ProjectConversationsPanel.tsx:721
#: src/components/conversation/ConversationsMiniList.tsx:189
Expand Down
24 changes: 12 additions & 12 deletions dembrane/frontend/src/locales/de-DE.po
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ msgid "{0} deleted"
msgstr "{0} gelöscht"

#. placeholder {0}: failed.length
#: src/lib/api.ts:622
#: src/lib/api.ts:624
msgid "{0} file(s) failed to upload. Try those again."
msgstr "{0} Datei(en) konnten nicht hochgeladen werden. Versuchen Sie es erneut."

Expand Down Expand Up @@ -1627,7 +1627,7 @@ msgstr "einen Arbeitsbereich hinzufügen"
#~ msgid "Add additional context (Optional)"
#~ msgstr "Zusätzlichen Kontext hinzufügen (Optional)"

#: src/components/participant/ParticipantInitiateForm.tsx:302
#: src/components/participant/ParticipantInitiateForm.tsx:309
msgid "Add all that apply"
msgstr "Alle zutreffenden hinzufügen"

Expand Down Expand Up @@ -1980,7 +1980,7 @@ msgid "All"
msgstr "Alle"

#. placeholder {0}: payload.chunks.length
#: src/lib/api.ts:752
#: src/lib/api.ts:754
msgid "All {0} file(s) uploaded successfully"
msgstr "Alle {0} Datei(en) erfolgreich hochgeladen"

Expand Down Expand Up @@ -2862,7 +2862,7 @@ msgid "Back"
msgstr "Zurück"

#. js-lingui-explicit-id
#: src/components/participant/ParticipantOnboardingCards.tsx:437
#: src/components/participant/ParticipantOnboardingCards.tsx:445
#: src/components/layout/ParticipantHeader.tsx:94
msgid "participant.button.back"
msgstr "Zurück"
Expand Down Expand Up @@ -4140,12 +4140,12 @@ msgid "Continue"
msgstr "Weiter"

#. js-lingui-explicit-id
#: src/components/participant/ParticipantOnboardingCards.tsx:424
#: src/components/participant/ParticipantOnboardingCards.tsx:432
msgid "participant.button.next"
msgstr "Weiter"

#. js-lingui-explicit-id
#: src/components/participant/ParticipantInitiateForm.tsx:339
#: src/components/participant/ParticipantInitiateForm.tsx:346
msgid "participant.ready.to.begin.button.text"
msgstr "Weiter"

Expand Down Expand Up @@ -9641,7 +9641,7 @@ msgid "No canvases yet. Ask in chat when you want a live view of the conversatio
msgstr "Noch keine Canvases. Fragen Sie im Chat, wenn Sie eine Live-Ansicht der Gespräche wünschen. Das erste Canvas bleibt hier."

#. js-lingui-explicit-id
#: src/components/participant/ParticipantOnboardingCards.tsx:270
#: src/components/participant/ParticipantOnboardingCards.tsx:277
msgid "participant.onboarding.no.card"
msgstr "Für die aktuelle Sprache und den aktuellen Abschnitt ist keine Karte verfügbar."

Expand Down Expand Up @@ -10975,8 +10975,8 @@ msgid "partially completed"
msgstr "teilweise abgeschlossen"

#: src/components/report/ConversationStatusTable.tsx:56
#: src/components/participant/ParticipantInitiateForm.tsx:136
#: src/components/participant/ParticipantInitiateForm.tsx:197
#: src/components/participant/ParticipantInitiateForm.tsx:141
#: src/components/participant/ParticipantInitiateForm.tsx:203
msgid "Participant"
msgstr "Teilnehmer"

Expand Down Expand Up @@ -12242,7 +12242,7 @@ msgstr "Bereit um"
#~ msgstr "Bereit um {readyTime}"

#. js-lingui-explicit-id
#: src/components/participant/ParticipantOnboardingCards.tsx:330
#: src/components/participant/ParticipantOnboardingCards.tsx:338
msgid "participant.ready.to.begin"
msgstr "Bereit zum Start?"

Expand Down Expand Up @@ -14048,7 +14048,7 @@ msgstr "Separat (Kunde)"
msgid "Separate with commas, spaces, or new lines."
msgstr "Mit Kommas, Leerzeichen oder Zeilenumbrüchen trennen."

#: src/components/participant/ParticipantInitiateForm.tsx:290
#: src/components/participant/ParticipantInitiateForm.tsx:297
msgid "Session name"
msgstr "Sitzungsname"

Expand Down Expand Up @@ -15258,7 +15258,7 @@ msgid "Tag deleted"
msgstr "Tag gelöscht"

#: src/components/project/ProjectTagsInput.tsx:255
#: src/components/participant/ParticipantInitiateForm.tsx:301
#: src/components/participant/ParticipantInitiateForm.tsx:308
#: src/components/map/panels/MapSettingsMenu.tsx:267
#: src/components/conversation/ProjectConversationsPanel.tsx:721
#: src/components/conversation/ConversationsMiniList.tsx:189
Expand Down
Loading
Loading