Skip to content

Onboarding cards update#392

Closed
ussaama wants to merge 2 commits intomainfrom
onboarding-cards-update
Closed

Onboarding cards update#392
ussaama wants to merge 2 commits intomainfrom
onboarding-cards-update

Conversation

@ussaama
Copy link
Copy Markdown
Contributor

@ussaama ussaama commented Dec 9, 2025

Summary by CodeRabbit

  • New Features

    • Added tutorial configuration option to skip data privacy slide with host-managed consent
    • Expanded tutorial modes: None, Basic, and Advanced
  • Improvements

    • Clarified tutorial selection labels in project settings (e.g., "Tips and best practices")
    • Normalized tutorial configuration options for consistency
  • Localization

    • Updated translations for tutorial options across German, Spanish, French, and Dutch

✏️ Tip: You can customize this high-level summary in your review settings.

…ponent

- Removed initialCards prop and integrated tutorialSlug for system card retrieval
- Updated useOnboardingCards hook to support tutorial slug normalization and added new tutorial card definitions
- Adjusted ProjectPortalEditor to ensure consistent tutorial slug handling
- translations
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Dec 9, 2025

Walkthrough

This PR refactors the participant onboarding tutorial system from initialCards-driven to tutorialSlug-driven architecture. Updates Directus sync operations, adds slug-based configuration (skip-consent, none, basic, advanced), removes initialCards component prop, and propagates corresponding UI label and translation updates across five locales.

Changes

Cohort / File(s) Change Summary
Directus Sync & Configuration
echo/directus/sync/collections/operations.json, echo/directus/sync/snapshot/fields/project/default_conversation_tutorial_slug.json
UUID identifiers swapped between operation nodes; tutorial slug field note changed from manual sync URL to null; added "Skip Consent" option and normalized "None" to "none".
Onboarding Component & Hook Refactoring
echo/frontend/src/components/participant/ParticipantOnboardingCards.tsx, echo/frontend/src/components/participant/hooks/useOnboardingCards.ts, echo/frontend/src/routes/participant/ParticipantStart.tsx
Removed initialCards prop contract; introduced tutorialSlug derivation from project; replaced getSystemCards(lang, hasDirectusCards) → getSystemCards(lang, tutorialSlug?); added getBasicTutorialCards and getAdvancedTutorialCards helpers with slug-based control flow (skip-consent, none, basic, advanced); eliminated tutorial card fetch and simplified loading logic.
Project Portal Editor UI
echo/frontend/src/components/project/ProjectPortalEditor.tsx
Normalized and validated default_conversation_tutorial_slug against allowed values; updated option labels ("No tutorial (only Privacy statements)" → "Skip data privacy slide (Host manages consent)", "Advanced (Tips and tricks)" → "Advanced (Tips and best practices)").
Localization Updates
echo/frontend/src/locales/de-DE.po, echo/frontend/src/locales/en-US.po, echo/frontend/src/locales/es-ES.po, echo/frontend/src/locales/fr-FR.po, echo/frontend/src/locales/nl-NL.po
Added new translation entries for updated UI labels across all locales; deprecated obsolete "Advanced (Tips and tricks)" entries; reanchored reference line numbers reflecting source code repositioning.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • API contract changes: initialCards prop removal and tutorialSlug parameter introduction require verification across component tree and hook consumers
  • Logic density: Slug-based control flow in getSystemCards with four branches (skip-consent/none/basic/advanced) and new helper functions need careful trace-through
  • Locale file repetition: Five PO files follow consistent pattern of additions/deprecations—high redundancy mitigates review complexity despite file count
  • Cross-file dependencies: ParticipantStart → ParticipantOnboardingCards → useOnboardingCards chain needs end-to-end validation

Areas requiring extra attention:

  • Verify all call sites of getSystemCards() properly pass tutorialSlug (check ParticipantOnboardingCards language blocks)
  • Confirm fallback logic in getSystemCards (defaults to "none" for invalid/undefined values)
  • Validate slug normalization in ProjectPortalEditor matches allowed set ["skip-consent", "none", "basic", "advanced"]
  • Check that removed tutorial card fetch in ParticipantStart doesn't break error handling or edge cases

Possibly related PRs

Suggested labels

improvement

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Onboarding cards update' directly aligns with the main changeset focus: refactoring onboarding card logic by removing initialCards prop, introducing tutorialSlug-based control flow, and updating related components and translations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch onboarding-cards-update

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ussaama ussaama closed this Dec 9, 2025
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
echo/frontend/src/components/participant/ParticipantOnboardingCards.tsx (2)

2-2: Nuke this IDE artifact.

"Start of Selection" is classic IDE cruft - ship it clean.

-// Start of Selection

220-223: Fallback message isn't localized.

Edge case guard is good, but hardcoded English breaks i18n for the ~0.01% of users who hit this. Worth a quick <Trans> wrap.

 	// If there's no valid card, render a fallback
 	if (!currentCard) {
-		return <div>No card available for the current language and section.</div>;
+		return (
+			<div className="flex h-full items-center justify-center p-4">
+				<Trans>No card available for the current language and section.</Trans>
+			</div>
+		);
 	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 441a45d and 10f0caa.

📒 Files selected for processing (11)
  • echo/directus/sync/collections/operations.json (12 hunks)
  • echo/directus/sync/snapshot/fields/project/default_conversation_tutorial_slug.json (1 hunks)
  • echo/frontend/src/components/participant/ParticipantOnboardingCards.tsx (6 hunks)
  • echo/frontend/src/components/participant/hooks/useOnboardingCards.ts (1 hunks)
  • echo/frontend/src/components/project/ProjectPortalEditor.tsx (3 hunks)
  • echo/frontend/src/locales/de-DE.po (42 hunks)
  • echo/frontend/src/locales/en-US.po (43 hunks)
  • echo/frontend/src/locales/es-ES.po (42 hunks)
  • echo/frontend/src/locales/fr-FR.po (42 hunks)
  • echo/frontend/src/locales/nl-NL.po (43 hunks)
  • echo/frontend/src/routes/participant/ParticipantStart.tsx (3 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
echo/frontend/**/src/routes/**/*.tsx

📄 CodeRabbit inference engine (echo/frontend/AGENTS.md)

Use Lingui macros t from @lingui/core/macro and Trans from @lingui/react/macro for localizing UI strings in routed screens

Files:

  • echo/frontend/src/routes/participant/ParticipantStart.tsx
echo/frontend/**/src/{routes,components}/**/*.tsx

📄 CodeRabbit inference engine (echo/frontend/AGENTS.md)

echo/frontend/**/src/{routes,components}/**/*.tsx: Compose Mantine primitives (Stack, Group, ActionIcon, etc.) while layering Tailwind utility classes via className, alongside toast feedback via @/components/common/Toaster
For Tailwind classes that need dynamic values, replace with inline style props using CSS variables instead of hardcoded hex values

Files:

  • echo/frontend/src/routes/participant/ParticipantStart.tsx
  • echo/frontend/src/components/participant/ParticipantOnboardingCards.tsx
  • echo/frontend/src/components/project/ProjectPortalEditor.tsx
echo/frontend/**/src/**/*.{css,tsx,ts}

📄 CodeRabbit inference engine (echo/frontend/AGENTS.md)

Use CSS variables var(--app-background) and var(--app-text) instead of hardcoded colors like #F6F4F1 or #2D2D2C to ensure theme changes propagate

Files:

  • echo/frontend/src/routes/participant/ParticipantStart.tsx
  • echo/frontend/src/components/participant/hooks/useOnboardingCards.ts
  • echo/frontend/src/components/participant/ParticipantOnboardingCards.tsx
  • echo/frontend/src/components/project/ProjectPortalEditor.tsx
echo/frontend/**/src/{theme.tsx,components,routes}/**/*.tsx

📄 CodeRabbit inference engine (echo/frontend/AGENTS.md)

When adding new Mantine components, reference the global Mantine theme in src/theme.tsx with custom primary color palette and component defaults, preferring CSS variables in styles over hardcoded hex values

Files:

  • echo/frontend/src/routes/participant/ParticipantStart.tsx
  • echo/frontend/src/components/participant/ParticipantOnboardingCards.tsx
  • echo/frontend/src/components/project/ProjectPortalEditor.tsx
echo/frontend/**/src/{components,routes}/**/*.tsx

📄 CodeRabbit inference engine (echo/frontend/AGENTS.md)

UI mutations should surface inline feedback: pair toasts with contextual Mantine Alert components inside modals/forms for errors or warnings

Files:

  • echo/frontend/src/routes/participant/ParticipantStart.tsx
  • echo/frontend/src/components/participant/ParticipantOnboardingCards.tsx
  • echo/frontend/src/components/project/ProjectPortalEditor.tsx
🧠 Learnings (12)
📓 Common learnings
Learnt from: ussaama
Repo: Dembrane/echo PR: 205
File: echo/frontend/src/lib/query.ts:1444-1506
Timestamp: 2025-07-10T12:48:20.683Z
Learning: ussaama prefers string concatenation over template literals for simple cases where readability is clearer, even when linting tools suggest template literals. Human readability takes precedence over strict linting rules in straightforward concatenation scenarios.
📚 Learning: 2025-08-08T10:39:31.114Z
Learnt from: ussaama
Repo: Dembrane/echo PR: 259
File: echo/frontend/src/components/layout/ParticipantLayout.tsx:33-33
Timestamp: 2025-08-08T10:39:31.114Z
Learning: In echo/frontend/src/components/layout/ParticipantLayout.tsx, prefer using simple pathname.includes("start") and pathname.includes("finish") to control the settings button visibility. No need to switch to segment-based matching or add a useEffect to auto-close the modal for these routes, per ussaama’s preference in PR #259.

Applied to files:

  • echo/frontend/src/routes/participant/ParticipantStart.tsx
  • echo/frontend/src/components/participant/hooks/useOnboardingCards.ts
  • echo/frontend/src/components/participant/ParticipantOnboardingCards.tsx
  • echo/frontend/src/locales/en-US.po
📚 Learning: 2025-12-05T00:33:33.442Z
Learnt from: CR
Repo: Dembrane/echo PR: 0
File: echo/frontend/AGENTS.md:0-0
Timestamp: 2025-12-05T00:33:33.442Z
Learning: Applies to echo/frontend/**/src/routes/**/*.tsx : Use Lingui macros `t` from `lingui/core/macro` and `Trans` from `lingui/react/macro` for localizing UI strings in routed screens

Applied to files:

  • echo/frontend/src/routes/participant/ParticipantStart.tsx
  • echo/frontend/src/locales/de-DE.po
  • echo/frontend/src/locales/es-ES.po
  • echo/frontend/src/locales/en-US.po
  • echo/frontend/src/locales/nl-NL.po
  • echo/frontend/src/locales/fr-FR.po
📚 Learning: 2025-12-05T00:33:33.442Z
Learnt from: CR
Repo: Dembrane/echo PR: 0
File: echo/frontend/AGENTS.md:0-0
Timestamp: 2025-12-05T00:33:33.442Z
Learning: Applies to echo/frontend/**/src/routes/auth/**/*.tsx : Gentle login/logout flows use `useTransitionCurtain().runTransition()` before navigation—animations expect Directus session mutations to await that promise

Applied to files:

  • echo/frontend/src/routes/participant/ParticipantStart.tsx
📚 Learning: 2025-12-05T00:33:33.442Z
Learnt from: CR
Repo: Dembrane/echo PR: 0
File: echo/frontend/AGENTS.md:0-0
Timestamp: 2025-12-05T00:33:33.442Z
Learning: Applies to echo/frontend/**/src/routes/auth/**/*.tsx : Auth hero uses `/public/video/auth-hero.mp4` with `/public/video/auth-hero-poster.jpg` as poster; keep the bright blur overlay consistent when iterating on onboarding screens

Applied to files:

  • echo/frontend/src/routes/participant/ParticipantStart.tsx
📚 Learning: 2025-12-05T00:33:33.442Z
Learnt from: CR
Repo: Dembrane/echo PR: 0
File: echo/frontend/AGENTS.md:0-0
Timestamp: 2025-12-05T00:33:33.442Z
Learning: Applies to echo/frontend/**/src/routes/settings/**/*.tsx : Provide ergonomic navigation in settings-like routes: breadcrumb + back action (ActionIcon + navigate(-1)) with relevant iconography is the default

Applied to files:

  • echo/frontend/src/routes/participant/ParticipantStart.tsx
📚 Learning: 2025-12-05T00:33:33.442Z
Learnt from: CR
Repo: Dembrane/echo PR: 0
File: echo/frontend/AGENTS.md:0-0
Timestamp: 2025-12-05T00:33:33.442Z
Learning: Applies to echo/frontend/**/src/routes/auth/**/*.tsx : Auth surfaces reuse `HeaderView` by passing `isAuthenticated`/`loading` props—avoid rolling bespoke headers inside layouts

Applied to files:

  • echo/frontend/src/routes/participant/ParticipantStart.tsx
📚 Learning: 2025-07-10T12:47:06.269Z
Learnt from: ussaama
Repo: Dembrane/echo PR: 205
File: echo/frontend/src/locales/nl-NL.po:1246-1247
Timestamp: 2025-07-10T12:47:06.269Z
Learning: .po files (gettext internationalization files) are auto-generated by i18n tools like lingui/cli and should not be manually edited. The format of component paths and line numbers in these files is determined by the tool configuration, not manually written. Do not suggest manual edits to .po files.

Applied to files:

  • echo/frontend/src/locales/de-DE.po
  • echo/frontend/src/locales/es-ES.po
  • echo/frontend/src/locales/en-US.po
📚 Learning: 2025-05-30T15:38:44.413Z
Learnt from: ussaama
Repo: Dembrane/echo PR: 169
File: echo/frontend/src/components/project/ProjectPortalEditor.tsx:409-464
Timestamp: 2025-05-30T15:38:44.413Z
Learning: Badge-based selectors in ProjectPortalEditor.tsx: Keyboard navigation enhancements for accessibility are considered optional improvements rather than critical issues. The user acknowledges these suggestions but doesn't prioritize them as blockers.

Applied to files:

  • echo/frontend/src/locales/de-DE.po
  • echo/frontend/src/locales/es-ES.po
  • echo/frontend/src/locales/en-US.po
  • echo/frontend/src/locales/nl-NL.po
  • echo/frontend/src/locales/fr-FR.po
📚 Learning: 2025-10-28T13:47:02.926Z
Learnt from: ussaama
Repo: Dembrane/echo PR: 350
File: echo/frontend/src/components/participant/ParticipantConversationText.tsx:82-85
Timestamp: 2025-10-28T13:47:02.926Z
Learning: In text mode (echo/frontend/src/components/participant/ParticipantConversationText.tsx), participants only submit PORTAL_TEXT chunks (no audio). The “Finish” button is shown only after at least one text message is saved to Directus.

Applied to files:

  • echo/frontend/src/locales/de-DE.po
  • echo/frontend/src/locales/en-US.po
  • echo/frontend/src/locales/nl-NL.po
  • echo/frontend/src/locales/fr-FR.po
📚 Learning: 2025-08-19T10:14:31.647Z
Learnt from: ussaama
Repo: Dembrane/echo PR: 266
File: echo/frontend/src/components/chat/ChatAccordion.tsx:214-221
Timestamp: 2025-08-19T10:14:31.647Z
Learning: In the Echo frontend codebase using Lingui, i18n IDs in Trans components (e.g., `<Trans id="any.string.here">`) can be arbitrary strings and don't need to follow specific naming conventions. They are just references used in .po files, and the actual translations need to be manually defined in the locale files.

Applied to files:

  • echo/frontend/src/locales/en-US.po
📚 Learning: 2025-09-16T08:34:38.109Z
Learnt from: ussaama
Repo: Dembrane/echo PR: 293
File: echo/frontend/src/components/chat/ChatTemplatesMenu.tsx:15-16
Timestamp: 2025-09-16T08:34:38.109Z
Learning: In ChatTemplatesMenu.tsx, titles are preferred over IDs for template selection logic since titles are unique one-liners and work effectively as identifiers. IDs were added primarily for better list rendering rather than selection purposes.

Applied to files:

  • echo/frontend/src/locales/en-US.po
🧬 Code graph analysis (1)
echo/frontend/src/components/participant/hooks/useOnboardingCards.ts (1)
echo/frontend/src/components/participant/ParticipantOnboardingCards.tsx (1)
  • LanguageCards (41-43)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: ci-check-server
🔇 Additional comments (24)
echo/directus/sync/collections/operations.json (1)

17-20: No issues found with UUID reassignments.

All resolve/reject references point to valid operations, no circular paths exist, and workflow graph integrity is intact. The changes are routine data migrations within the Directus sync ecosystem with proper structure.

Likely an incorrect or invalid review comment.

echo/directus/sync/snapshot/fields/project/default_conversation_tutorial_slug.json (1)

14-24: Slug choices now line up with the new tutorial flow; check legacy data once.

The new "skip-consent" option and lowercased "none" value match the frontend slug contract nicely and keep the schema default coherent. One thing to sanity‑check: if there are existing rows still storing "None" (capitalized), Directus’ dropdown won’t show a matching choice anymore—worth a small backfill to "none" to avoid “empty” selections in the admin UI.

echo/frontend/src/components/project/ProjectPortalEditor.tsx (1)

529-546: Select options are correctly wired to the new slug model.

The NativeSelect data now cleanly mirrors the four slugs (skip-consent, none, basic, advanced) with clearer copy. Values line up with the normalization logic and the Directus field config, so changing the default in one place won’t silently desync the UI.

echo/frontend/src/routes/participant/ParticipantStart.tsx (1)

7-8: Route simplification to project‑only onboarding is clean; just watch the project null edge.

Nice cleanup—one data source, one spinner, and a clear error surface via Mantine Alert using Lingui t checks all the boxes. The only assumption you’re making is that useParticipantProjectById never hits a state where isLoadingProject === false, projectError is falsy, and project is still undefined; in that case project as Project would blow up inside ParticipantOnboardingCards. If that’s guaranteed by the hook contract, you’re good; otherwise a tiny guard before rendering the cards would harden this further.

Also applies to: 26-32, 44-48

echo/frontend/src/locales/nl-NL.po (1)

535-545: PO churn here is just reference/structure updates; translations themselves are stable.

All the other ~ hunks around the onboarding buttons (participant.button.back, .continue, .next, "Concrete Topics", "Portal Editor", "Live Preview", etc.) are just updated source references and line numbers from the refactor—msgids/msgstrs remain semantically identical. No functional or UX risk here.

Also applies to: 710-713, 803-807, 819-823, 895-899, 1109-1127, 1791-1793, 1865-1868, 1958-1960, 2017-2021, 2200-2203, 2479-2483, 2573-2576, 3609-3612, 3617-3620, 3627-3630

echo/frontend/src/components/participant/ParticipantOnboardingCards.tsx (2)

76-77: Clean refactor to slug-based flow.

tutorialSlug derivation with "none" fallback is clean and aligns with the new architecture. Spreading getSystemCards() per language is the right call.


45-45: The Project type is properly available through the ambient type declarations in echo/frontend/src/lib/typesDirectus.d.ts. Since this .d.ts file is included via the tsconfig.json source directory, the Project interface is globally declared and requires no explicit import. The component will compile successfully.

Likely an incorrect or invalid review comment.

echo/frontend/src/locales/fr-FR.po (8)

112-115: Generic {0} placeholder: adding ProjectPortalEditor ref is perfectly safe

Just wiring another usage site into the same generic {0} message; no translation risk here. Ship it.


229-236: Advanced tutorial label rename is wired + localized correctly

The new "Advanced (Tips and best practices)" label and retirement of the old "Tips and tricks" variant look consistent, and the FR "Avancé (Astuces et conseils)" still matches intent. The extra reference for "Advanced Settings" is just a pointer shuffle.

Also applies to: 237-240


280-283: Portal load error copy is clean

New "An error occurred while loading the Portal..." message is clearly translated and aligned with product tone. Nothing to tighten here.


400-407: Onboarding / navigation buttons are consistent and UX‑sound

Nice job normalizing the onboarding CTA surface:

  • "Ask for Name?", "Ask participants to provide their name..." → FR copy reads naturally.
  • Back/Continue/Next/Ready/Skip (Retour, Continuer, Suivant, Prêt à commencer, Passer) are consistent and match existing tone (tu form) across the participant flows.
  • "At least one topic must be selected to enable Make it concrete""Sélectionne au moins un sujet..." is clear and keeps the feature name as a product label.

No blockers here; this is shippable UX.

Also applies to: 424-427, 481-488, 710-713, 1932-1935, 2559-2562, 3062-3065


499-506: Portal Editor + concrete feature surface area looks coherent in FR

Scanning this cluster:

  • Tutorial mode labels (Basic, Advanced, Brainstorm Ideas, Concrete Topics, Custom, Default, Select tutorial, instruction/tooltips) map cleanly into FR and keep the mental model intact.
  • Status strings around concrete topics (loading / none available) are idiomatic.
  • Page scaffolding (Page Content, Page Title, Portal Content, Portal Editor, post‑conversation page descriptions, title/portal language hints) all read like production copy, not machine leftovers.
  • Feature toggles (Enable Go deeper, Enable Make it concrete, Report Notifications and the long descriptions) are understandable and consistent with how the rest of the product talks about these capabilities.

From a localization + product‑semantics standpoint this whole block is good to go.

Also applies to: 518-523, 530-533, 656-659, 857-860, 880-883, 1748-1751, 1778-1781, 1910-1913, 1983-1986, 2073-2076, 2171-2174, 2179-2182, 2435-2438, 2439-2443, 2611-2614, 2707-2710, 2919-2925, 2926-2929, 3438-3441, 3442-3445, 3446-3449, 3469-3472, 1091-1094, 1095-1098, 1099-1102, 1109-1111, 1121-1123


1006-1009: Language + mode labels are standard and predictable

Locale and mode selectors are crisp:

  • English / French / German / Dutch / SpanishAnglais / Français / Allemand / Néerlandais / Espagnol.
  • "Language""Langue", "Mode""Mode".

Exactly what a French user expects in a settings/editor surface.

Also applies to: 1137-1140, 1163-1166, 1440-1443, 1673-1675, 1862-1865, 3138-3141


2188-2191: Polish a few FR phrasings for Portal Editor copy

Couple of copy cleanups to make the FR feel native‑level:

  1. "Participant Features"
    Current: Fonctionnalités participant
    → missing preposition.

  2. "Reply Prompt"
    Prompt de réponse is understandable, but you might prefer a more FR‑native "Consigne de réponse" if you want to avoid the borrowed “prompt”.

  3. "Thank You Page Content"
    Contenu de la page Merci reads like a literal label.

  4. "This is a live preview of the participant's portal..."
    Current: Cette est une vue en direct... (incorrect demonstrative; should be C'est or Ceci est).

  5. "This prompt guides how the AI responds..."
    Current: Cette prompt guide... (gender mismatch; prompt is treated as masculine in FR).

Concrete diff proposal:

-msgid "Participant Features"
-msgstr "Fonctionnalités participant"
+msgid "Participant Features"
+msgstr "Fonctionnalités pour les participants"
@@
-msgid "Reply Prompt"
-msgstr "Prompt de réponse"
+msgid "Reply Prompt"
+msgstr "Consigne de réponse"
@@
-msgid "Thank You Page Content"
-msgstr "Contenu de la page Merci"
+msgid "Thank You Page Content"
+msgstr "Contenu de la page de remerciement"
@@
-msgid "This is a live preview of the participant's portal. You will need to refresh the page to see the latest changes."
-msgstr "Cette est une vue en direct du portail du participant. Vous devrez actualiser la page pour voir les dernières modifications."
+msgid "This is a live preview of the participant's portal. You will need to refresh the page to see the latest changes."
+msgstr "Ceci est une vue en direct du portail du participant. Vous devrez actualiser la page pour voir les dernières modifications."
@@
-msgid "This prompt guides how the AI responds to participants. Customize it to shape the type of feedback or engagement you want to encourage."
-msgstr "Cette prompt guide comment l'IA répond aux participants. Personnalisez-la pour former le type de feedback ou d'engagement que vous souhaitez encourager."
+msgid "This prompt guides how the AI responds to participants. Customize it to shape the type of feedback or engagement you want to encourage."
+msgstr "Ce prompt guide la façon dont l'IA répond aux participants. Personnalisez-le pour définir le type de retour ou d'engagement que vous souhaitez encourager."

Also applies to: 2684-2687, 3297-3300, 3420-3423, 3453-3456

⛔ Skipped due to learnings
Learnt from: ussaama
Repo: Dembrane/echo PR: 169
File: echo/frontend/src/locales/fr-FR.po:1298-1301
Timestamp: 2025-05-30T15:37:46.279Z
Learning: In French localization files, UI terms like "Portail" should maintain their proper capitalization according to French language conventions, even if it appears inconsistent with lowercase usage in other translations. French capitalization rules for UI terms should be respected over assumed consistency patterns.
Learnt from: ussaama
Repo: Dembrane/echo PR: 169
File: echo/frontend/src/locales/fr-FR.po:1880-1882
Timestamp: 2025-05-30T15:37:52.403Z
Learning: In French technical contexts, especially AI/ML domains, English technical terms like "prompt" are commonly adopted and used without translation. This is acceptable and not considered an error.
Learnt from: ussaama
Repo: Dembrane/echo PR: 169
File: echo/frontend/src/locales/fr-FR.po:1778-1780
Timestamp: 2025-05-30T15:37:29.029Z
Learning: Translation and localization suggestions should be treated as preferences rather than errors. Different phrasings in target languages can be equally valid, and users may have specific reasons for choosing particular translations.

884-887: Tighten French grammar for default/skip consent options

Two small FR nits worth fixing before shipping:

  1. "Default - No tutorial (Only privacy statements)"
    Current:
    Par défaut - Pas de tutoriel (Seulement les déclarations de confidentialité)

    • Mid‑sentence "Seulement" should be lowercase.
    • Slightly smoother FR to avoid sounding literal.
  2. "Skip data privacy slide (Host manages consent)"
    Current:
    Passer la carte de confidentialité (L'hôte gère la consentement)

    • consentement is masculine → le consentement.
    • "carte" vs "diapositive" is a bit off for “slide”.

Suggested patch:

-msgid "Default - No tutorial (Only privacy statements)"
-msgstr "Par défaut - Pas de tutoriel (Seulement les déclarations de confidentialité)"
+msgid "Default - No tutorial (Only privacy statements)"
+msgstr "Par défaut - Pas de tutoriel (seulement les déclarations de confidentialité)"
@@
-msgid "Skip data privacy slide (Host manages consent)"
-msgstr "Passer la carte de confidentialité (L'hôte gère la consentement)"
+msgid "Skip data privacy slide (Host manages consent)"
+msgstr "Passer la diapositive de confidentialité (l'hôte gère le consentement)"

Also applies to: 3069-3072

⛔ Skipped due to learnings
Learnt from: ussaama
Repo: Dembrane/echo PR: 169
File: echo/frontend/src/locales/fr-FR.po:1298-1301
Timestamp: 2025-05-30T15:37:46.279Z
Learning: In French localization files, UI terms like "Portail" should maintain their proper capitalization according to French language conventions, even if it appears inconsistent with lowercase usage in other translations. French capitalization rules for UI terms should be respected over assumed consistency patterns.
Learnt from: ussaama
Repo: Dembrane/echo PR: 169
File: echo/frontend/src/locales/fr-FR.po:1847-1849
Timestamp: 2025-05-30T15:37:46.616Z
Learning: User ussaama prefers not to address minor French translation grammar issues when they don't impact functionality, considering them acceptable as "language things" rather than errors that need fixing.
echo/frontend/src/locales/en-US.po (3)

478-485: LGTM - New tutorial slug translations shipped.

Auto-generated i18n entries for the new onboarding card options look clean. The Advanced (Tips and best practices) and related strings are properly added. Based on learnings, these .po files are managed by lingui/cli, so no manual edits needed.


1164-1166: LGTM - Default tutorial option entry added.

New Default - No tutorial (Only privacy statements) translation entry properly added for the slug-based configuration. Clean.


3394-3396: LGTM - Skip consent option added.

The Skip data privacy slide (Host manages consent) entry is properly localized. This enables hosts to handle consent externally - solid addition for enterprise use cases.

echo/frontend/src/components/participant/hooks/useOnboardingCards.ts (5)

1-12: LGTM - Clean icon imports.

Solid selection of lucide-react icons for the onboarding UX. Using named imports keeps the bundle lean.


16-51: LGTM - Slug normalization is bulletproof.

Clean defensive coding here:

  • Lowercase normalization handles case mismatches
  • Explicit validation against validSlugs array
  • Safe fallback to "none" for garbage input

This will handle whatever the backend throws at it. Ship it.


53-406: LGTM - Comprehensive localized basic tutorial content.

Five languages fully supported with consistent structure. The en-US fallback on line 405 ensures users never see a blank onboarding. Content is static but that's fine for tutorial flows that don't change frequently.


1043-1044: Inconsistent language fallback - returns null instead of en-US.

getBasicTutorialCards and getAdvancedTutorialCards both fallback to en-US when language isn't found. But getPrivacyCard returns null, meaning users with unsupported languages get no privacy consent slide when using slug="none".

If this is intentional (strict localization for legal/compliance content), add a comment explaining why. Otherwise, consider matching the fallback behavior:

- return privacyCards[lang] || null;
+ return privacyCards[lang] || privacyCards["en-US"] || null;

1046-1046: LGTM - Clean hook API surface.

Only exposing getSystemCards keeps the API tight. The helper functions are implementation details - good encapsulation. Ship it 🚀

echo/frontend/src/locales/de-DE.po (1)

229-231: LGTM! Translation updates ship clean.

The new tutorial options are properly translated and the old entries correctly obsoleted. Auto-generated by lingui/cli as expected—line refs updated, new strings present, obsolete markers in place. Ship it.

Based on learnings, .po files are auto-generated by lingui/cli.

Also applies to: 233-235, 881-883, 3063-3065

Comment on lines +408 to +512
const getAdvancedTutorialCards = (lang: string): LanguageCards[string] => {
const tutorialCards: Record<string, LanguageCards[string]> = {
"de-DE": [
{
section: "Willkommen",
slides: [
{
content:
"Nehmen Sie Ihre Stimme auf, um Fragen zu beantworten und Einfluss zu nehmen.",
cta: "Los geht's!",
extraHelp:
"Dies ist ein Mini-Tutorial. Nutzen Sie die Vor- und Zurück-Tasten zur Navigation. Nach Abschluss gelangen Sie zum Aufnahmeportal.",
icon: PartyPopper,
title: "Willkommen bei Dembrane!",
},
{
content:
"Dembrane hilft Menschen, einfach Input von großen Gruppen zu sammeln.",
cta: "Mehr erfahren",
extraHelp:
"Ob Feedback für eine Kommune, Input im Arbeitsumfeld oder Teilnahme an Forschung – Ihre Stimme zählt!",
icon: Orbit,
title: "Was ist Dembrane?",
},
{
content:
"Beantworten Sie Fragen in Ihrem eigenen Tempo durch Sprechen oder Tippen.",
cta: "Weiter",
extraHelp:
"Spracheingabe ist unser bevorzugter Modus, da sie natürlichere und detailliertere Antworten ermöglicht. Tippen steht immer als Alternative zur Verfügung.",
icon: Speech,
title: "Sagen Sie einfach Ihre Meinung",
},
{
content: "Dembrane macht in Gruppen mehr Spaß!",
cta: "Weiter",
extraHelp:
"Dembrane macht mehr Spaß, wenn Sie jemanden finden, um die Fragen gemeinsam zu besprechen und Ihr Gespräch aufzunehmen. Wir können nicht sagen, wer was gesagt hat, nur welche Ideen geteilt wurden.",
icon: MessagesSquare,
title: "Allein oder in der Gruppe",
},
],
},
{
section: "Wie es funktioniert",
slides: [
{
content:
"Sie erhalten die Fragen, sobald Sie im Aufnahmeportal sind.",
cta: "Verstanden",
extraHelp:
"Die Fragen variieren je nach den Bedürfnissen des Gastgebers. Sie können sich auf kommunale Themen, Arbeitserfahrungen oder Forschungsthemen beziehen. Wenn es keine spezifischen Fragen gibt, können Sie gerne alle Gedanken oder Anliegen teilen.",
icon: HelpCircle,
title: "Fragerunde",
},
],
},
{
section: "Datenschutz",
slides: [
{
content:
"Als Aufnehmer haben Sie die Kontrolle über das, was Sie teilen.",
cta: "Mehr erfahren",
extraHelp:
"Vermeiden Sie die Weitergabe von Details, die Sie dem Gastgeber nicht mitteilen möchten. Seien Sie achtsam und nehmen Sie andere nicht ohne deren Zustimmung auf.",
icon: Lock,
title: "Datenschutz ist wichtig",
},
...(getPrivacyCard("de-DE")?.slides || []),
],
},
{
section: "Best Practices",
slides: [
{
content:
"Stellen Sie sich vor, Dembrane ist auf Lautsprecher mit Ihnen. Wenn Sie sich selbst hören können, ist alles in Ordnung.",
cta: "Verstanden",
extraHelp:
"Etwas Hintergrundgeräusch ist in Ordnung, solange klar ist, wer spricht.",
icon: Volume2,
title: "Hintergrundgeräusche reduzieren",
},
{
content:
"Stellen Sie eine stabile Verbindung für eine reibungslose Aufnahme sicher.",
cta: "Bereit!",
extraHelp:
"WLAN oder gute mobile Daten funktionieren am besten. Wenn Ihre Verbindung abbricht, keine Sorge. Sie können immer dort weitermachen, wo Sie aufgehört haben.",
icon: Wifi,
title: "Starke Internetverbindung",
},
{
content:
"Vermeiden Sie Unterbrechungen, indem Sie Ihr Gerät entsperrt halten. Wenn es sich sperrt, entsperren Sie es einfach und fahren Sie fort.",
cta: "Okay",
extraHelp:
"Dembrane versucht, Ihr Gerät aktiv zu halten, aber manchmal können Geräte dies überschreiben. Sie können Ihre Geräteeinstellungen anpassen, um länger entsperrt zu bleiben, wenn nötig.",
icon: Smartphone,
title: "Gerät nicht sperren!",
},
],
},
],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider extracting shared sections to reduce duplication.

The Welcome, How it works, and Privacy sections are nearly identical between getBasicTutorialCards and getAdvancedTutorialCards. The only difference is that advanced adds the "Best Practices" section.

Could DRY this up by composing:

const getAdvancedTutorialCards = (lang: string): LanguageCards[string] => {
  const basicCards = getBasicTutorialCards(lang);
  const bestPractices = getBestPracticesCards(lang);
  // Merge privacy card slides and append best practices section
  return [...basicCards, bestPractices];
};

Not blocking - the current approach is explicit and easy to reason about. Just a thought if localization updates become a maintenance burden.

🤖 Prompt for AI Agents
In echo/frontend/src/components/participant/hooks/useOnboardingCards.ts around
lines 408-512, the Welcome, How it works, and Privacy sections are duplicated
between getBasicTutorialCards and getAdvancedTutorialCards; extract the shared
sections into a small helper (e.g., getSharedTutorialSections(lang) or reuse
getBasicTutorialCards(lang)) and implement a getBestPracticesSection(lang) for
the extra advanced slides, then have getAdvancedTutorialCards call the shared
helper/getBasicTutorialCards and append the Best Practices section (ensuring
privacy slides are merged via getPrivacyCard(lang) as before) to avoid
duplication and keep behavior identical.

Comment on lines +230 to +236
const rawTutorialSlug =
project.default_conversation_tutorial_slug?.toLowerCase();
const validSlugs = ["skip-consent", "none", "basic", "advanced"];
const normalizedTutorialSlug = validSlugs.includes(rawTutorialSlug || "")
? rawTutorialSlug
: "none";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Slug normalization looks solid; consider DRY’ing the allowed list.

Lowercasing + whitelist + fallback to "none" is exactly what you want here, and it protects you from old "None" values or random garbage. The only nit: the validSlugs literal is now another source of truth alongside Directus config / onboarding hooks. Hoisting this into a shared TUTORIAL_SLUGS constant (and maybe a TutorialSlug type) would keep things 100% in sync as you evolve the flows.

Also applies to: 247-247

🤖 Prompt for AI Agents
In echo/frontend/src/components/project/ProjectPortalEditor.tsx around lines
230-236 (and also update line 247), the allowed tutorial slugs are hardcoded
locally; hoist that array into a shared exported constant (e.g., TUTORIAL_SLUGS)
in a common module (or a new constants file) and export a corresponding
TutorialSlug type (union of literals). Replace the local validSlugs with an
import of TUTORIAL_SLUGS, use it for normalization and any other occurrences
(line 247) so both the component and other code use the same single source of
truth; ensure the constant is lowercased or compare using toLowerCase() as
currently implemented.

Comment on lines +1104 to 1107
#: src/components/project/ProjectPortalEditor.tsx:763
msgid "dashboard.dembrane.concrete.description"
msgstr "dashboard.dembrane.concrete.description"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don't ship raw js‑lingui IDs as FR “translations”

These explicit‑ID entries still have the key copied into msgstr:

  • dashboard.dembrane.concrete.description
  • dashboard.dembrane.concrete.topic.select
  • participant.concrete.regenerating.artefact.description
  • participant.concrete.loading.artefact.description

If these are rendered anywhere, FR users will see opaque IDs instead of real text. That’s a UX‑breaking regression for the concrete/verify flows.

Recommend:

  • Either provide proper French copy for each, mirroring the English source strings from en-US.po, or
  • If you intentionally want to fall back to English, set msgstr to the English sentence, not the technical key.

Until these are translated or explicitly set to a user‑facing fallback, I’d treat this as non‑ship‑ready for FR.

Also applies to: 2931-2934, 3486-3489, 3491-3494

🤖 Prompt for AI Agents
In echo/frontend/src/locales/fr-FR.po around lines 1104-1107 (and also at
2931-2934, 3486-3489, 3491-3494), several msgstr entries currently contain raw
js‑lingui keys (e.g. "dashboard.dembrane.concrete.description") instead of
user‑facing text; replace each msgstr with either the proper French translation
mirroring the English source from en-US.po, or if you intentionally want English
fallbacks set msgstr to the English sentence (not the key); update all listed
entries so French users see readable sentences rather than technical IDs.

Comment on lines +244 to +247
#: src/components/project/ProjectPortalEditor.tsx:543
msgid "Advanced (Tips and best practices)"
msgstr "Geavanceerd (Tips en best practices)"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Tutorial option translations are aligned with the new slugs; one minor copy glitch.

The Dutch strings for the tutorial choices all line up with the new semantics:

  • Advanced: "Geavanceerd (Tips en best practices)"
  • Basic: "Basis (Alleen essentiële tutorial slides)"
  • Default/none: "Standaard - Geen tutorial (Alleen privacy verklaringen)"
  • Error text for loading the Portal is also wired correctly to the new ParticipantStart route.

Only nit: "Datenschutzkarte overslaan (Organisatie beheert toestemming)" mixes a German noun into the Dutch sentence. Might be worth tightening that to a fully Dutch phrase so it doesn’t stand out in production.

Also applies to: 553-556, 944-947, 2200-2203, 301-304

🤖 Prompt for AI Agents
In echo/frontend/src/locales/nl-NL.po around lines 244-247 (and also update
occurrences at 553-556, 944-947, 2200-2203, 301-304), a German noun
"Datenschutzkarte" is present in Dutch strings; replace it with the proper Dutch
term (e.g., "privacykaart") and keep the rest of the sentence intact so it reads
fully Dutch ("privacykaart overslaan (Organisatie beheert toestemming)"),
updating each listed location consistently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant