mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 22:21:10 +02:00
feat(help): improve help content across all 18 apps, add shared Mana & Privacy FAQs
- Expand FAQ entries from ~5 to 8-14 per app with app-specific feature documentation - Add comprehensive features, shortcuts, and keyboard shortcut sections - Integrate shared getManaFAQs() in 10 apps with /mana page - Integrate shared getPrivacyFAQs() in all 18 apps with app-specific data types - Add unit tests for help content in all 18 apps (72 tests total) - Tests verify: DE/EN content, matching FAQ/feature counts, unique IDs, contact info Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
13681df76c
commit
40ace53867
36 changed files with 1439 additions and 189 deletions
47
apps/calendar/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/calendar/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getCalendarHelpContent } from './index';
|
||||
|
||||
describe('Calendar Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getCalendarHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getCalendarHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getCalendarHelpContent('de');
|
||||
const en = getCalendarHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getCalendarHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getCalendarHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -82,19 +83,7 @@ export function getCalendarHelpContent(locale: string): HelpContent {
|
|||
? ['sync', 'caldav', 'google', 'apple', 'extern']
|
||||
: ['sync', 'caldav', 'google', 'apple', 'external'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: t('Wie werden meine Daten geschützt?', 'How is my data protected?'),
|
||||
answer: t(
|
||||
'<p>Deine Daten sind sicher:</p><ul><li><strong>Verschlüsselung</strong>: Alle Daten werden bei der Übertragung (TLS) verschlüsselt</li><li><strong>DSGVO-konform</strong>: Wir halten uns an die EU-Datenschutzverordnung</li><li><strong>Kein Datenverkauf</strong>: Deine Kalender-Daten werden nie an Dritte verkauft</li><li><strong>Export</strong>: Du kannst jederzeit alle Kalender als iCal exportieren</li></ul>',
|
||||
'<p>Your data is secure:</p><ul><li><strong>Encryption</strong>: All data is encrypted in transit (TLS)</li><li><strong>GDPR Compliant</strong>: We follow EU data protection regulations</li><li><strong>No Data Selling</strong>: Your calendar data is never sold to third parties</li><li><strong>Export</strong>: You can export all calendars as iCal anytime</li></ul>'
|
||||
),
|
||||
category: 'privacy',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
featured: true,
|
||||
tags: isDE ? ['datenschutz', 'dsgvo', 'sicherheit'] : ['privacy', 'gdpr', 'security'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, { dataTypeDE: 'Kalenderdaten', dataTypeEN: 'calendar data' }),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
47
apps/chat/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/chat/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getChatHelpContent } from './index';
|
||||
|
||||
describe('Chat Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getChatHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getChatHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getChatHelpContent('de');
|
||||
const en = getChatHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getChatHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getChatHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -56,18 +57,16 @@ export function getChatHelpContent(locale: string): HelpContent {
|
|||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['vergleich', 'modelle', 'test'] : ['compare', 'models', 'test'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: isDE ? 'Wie werden meine Chats geschützt?' : 'How are my chats protected?',
|
||||
answer: isDE
|
||||
? '<p>Deine Unterhaltungen sind sicher:</p><ul><li><strong>Verschlüsselung</strong>: Alle Daten werden bei der Übertragung (TLS) verschlüsselt</li><li><strong>Privat</strong>: Nur du hast Zugriff auf deine Chats</li><li><strong>Lokale Modelle</strong>: Bei lokalen Modellen verlassen deine Daten nie unseren Server</li><li><strong>DSGVO-konform</strong>: Wir halten uns an die EU-Datenschutzverordnung</li></ul>'
|
||||
: '<p>Your conversations are secure:</p><ul><li><strong>Encryption</strong>: All data is encrypted in transit (TLS)</li><li><strong>Private</strong>: Only you have access to your chats</li><li><strong>Local models</strong>: With local models, your data never leaves our server</li><li><strong>GDPR Compliant</strong>: We follow EU data protection regulations</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
featured: true,
|
||||
tags: isDE ? ['datenschutz', 'sicherheit', 'dsgvo'] : ['privacy', 'security', 'gdpr'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, {
|
||||
dataTypeDE: 'Chats',
|
||||
dataTypeEN: 'chats',
|
||||
extraBulletsDE: [
|
||||
'<strong>Lokale Modelle</strong>: Bei lokalen Modellen verlassen deine Daten nie unseren Server',
|
||||
],
|
||||
extraBulletsEN: [
|
||||
'<strong>Local models</strong>: With local models, your data never leaves our server',
|
||||
],
|
||||
}),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
47
apps/citycorners/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/citycorners/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getCityCornersHelpContent } from './index';
|
||||
|
||||
describe('CityCorners Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getCityCornersHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getCityCornersHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getCityCornersHelpContent('de');
|
||||
const en = getCityCornersHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getCityCornersHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
258
apps/citycorners/apps/web/src/lib/content/help/index.ts
Normal file
258
apps/citycorners/apps/web/src/lib/content/help/index.ts
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
/**
|
||||
* Help content for CityCorners app
|
||||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getCityCornersHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
||||
return {
|
||||
faq: [
|
||||
{
|
||||
id: 'faq-locations',
|
||||
question: isDE ? 'Wie finde ich Orte in Konstanz?' : 'How do I find places in Konstanz?',
|
||||
answer: isDE
|
||||
? '<p>CityCorners zeigt dir die besten Orte in Konstanz:</p><ul><li>Nutze die <strong>Kategoriefilter</strong> (Sehenswürdigkeiten, Restaurants, Cafés, Bars, Parks, Museen, etc.)</li><li>Durchsuche die Karte mit farbcodierten Markern</li><li>Nutze die <strong>Suche</strong> in der QuickInputBar für gezielte Ergebnisse</li><li>11 verschiedene Kategorien stehen zur Verfügung</li></ul>'
|
||||
: '<p>CityCorners shows you the best places in Konstanz:</p><ul><li>Use <strong>category filters</strong> (sights, restaurants, cafés, bars, parks, museums, etc.)</li><li>Browse the map with color-coded markers</li><li>Use <strong>search</strong> in the QuickInputBar for targeted results</li><li>11 different categories are available</li></ul>',
|
||||
category: 'features',
|
||||
order: 1,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['orte', 'suche', 'kategorien'] : ['locations', 'search', 'categories'],
|
||||
},
|
||||
{
|
||||
id: 'faq-map',
|
||||
question: isDE ? 'Wie funktioniert die Kartenansicht?' : 'How does the map view work?',
|
||||
answer: isDE
|
||||
? '<p>Die interaktive Leaflet-Karte zeigt alle Orte mit farbcodierten Markern nach Kategorie:</p><ul><li><strong>Blau</strong> — Sehenswürdigkeiten</li><li><strong>Rot</strong> — Restaurants</li><li><strong>Gelb</strong> — Cafés</li><li><strong>Orange</strong> — Bars</li><li><strong>Grün</strong> — Parks und Läden</li><li>Klicke auf einen Marker für Details und Wegbeschreibung</li></ul>'
|
||||
: '<p>The interactive Leaflet map shows all locations with color-coded markers by category:</p><ul><li><strong>Blue</strong> — Sights</li><li><strong>Red</strong> — Restaurants</li><li><strong>Yellow</strong> — Cafés</li><li><strong>Orange</strong> — Bars</li><li><strong>Green</strong> — Parks and shops</li><li>Click a marker for details and directions</li></ul>',
|
||||
category: 'features',
|
||||
order: 2,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['karte', 'marker', 'navigation'] : ['map', 'markers', 'navigation'],
|
||||
},
|
||||
{
|
||||
id: 'faq-favorites',
|
||||
question: isDE ? 'Wie speichere ich Favoriten?' : 'How do I save favorites?',
|
||||
answer: isDE
|
||||
? '<p>Melde dich an und klicke auf das <strong>Herz-Symbol</strong> bei einem Ort, um ihn als Favorit zu speichern. Alle Favoriten findest du im Bereich <strong>Favoriten</strong>. Favoriten werden optimistisch aktualisiert — du siehst die Änderung sofort.</p>'
|
||||
: '<p>Sign in and click the <strong>heart icon</strong> on a location to save it as a favorite. Find all favorites in the <strong>Favorites</strong> section. Favorites are optimistically updated — you see the change immediately.</p>',
|
||||
category: 'features',
|
||||
order: 3,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['favoriten', 'speichern', 'merken'] : ['favorites', 'save', 'bookmarks'],
|
||||
},
|
||||
{
|
||||
id: 'faq-add-location',
|
||||
question: isDE ? 'Kann ich eigene Orte hinzufügen?' : 'Can I add my own locations?',
|
||||
answer: isDE
|
||||
? '<p>Ja! Melde dich an und nutze die Funktion <strong>Ort hinzufügen</strong>:</p><ol><li>Suche den Ort per <strong>Web-Lookup</strong> — Informationen werden automatisch aus dem Web extrahiert</li><li>Ergänze oder bearbeite die Informationen (Name, Beschreibung, Adresse)</li><li>Wähle eine der 11 Kategorien</li><li>Sende den Ort ab</li></ol><p>Der Web-Lookup nutzt unseren eigenen Suchdienst (mana-search).</p>'
|
||||
: '<p>Yes! Sign in and use the <strong>Add Location</strong> feature:</p><ol><li>Search for the place via <strong>web lookup</strong> — information is automatically extracted from the web</li><li>Complete or edit the information (name, description, address)</li><li>Choose one of the 11 categories</li><li>Submit the location</li></ol><p>The web lookup uses our own search service (mana-search).</p>',
|
||||
category: 'features',
|
||||
order: 4,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['hinzufügen', 'beitragen', 'orte'] : ['add', 'contribute', 'locations'],
|
||||
},
|
||||
{
|
||||
id: 'faq-detail-timeline',
|
||||
question: isDE ? 'Was zeigen die Detailseiten?' : 'What do detail pages show?',
|
||||
answer: isDE
|
||||
? '<p>Jeder Ort hat eine ausführliche Detailseite:</p><ul><li><strong>Beschreibung</strong> und Adresse</li><li><strong>Mini-Karte</strong> mit dem Standort</li><li><strong>Timeline</strong> — Historische Ereignisse des Ortes (z.B. Gründungsjahr, wichtige Ereignisse)</li><li><strong>Favoriten-Button</strong> zum Speichern</li><li>Möglichkeit, den Ort zu bearbeiten</li></ul>'
|
||||
: '<p>Each location has a detailed page:</p><ul><li><strong>Description</strong> and address</li><li><strong>Mini-map</strong> with the location</li><li><strong>Timeline</strong> — Historical events of the place (e.g., founding year, important events)</li><li><strong>Favorite button</strong> to save</li><li>Option to edit the location</li></ul>',
|
||||
category: 'features',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['details', 'timeline', 'historie'] : ['details', 'timeline', 'history'],
|
||||
},
|
||||
{
|
||||
id: 'faq-categories',
|
||||
question: isDE ? 'Welche Kategorien gibt es?' : 'What categories are available?',
|
||||
answer: isDE
|
||||
? '<p>CityCorners bietet <strong>11 Kategorien</strong>:</p><ul><li>Sehenswürdigkeit, Restaurant, Laden, Museum, Café</li><li>Bar, Park, Strandbad, Hotel, Veranstaltungsort, Aussichtspunkt</li></ul><p>Jede Kategorie hat eine eigene Farbe auf der Karte und in den Karten-Ansichten.</p>'
|
||||
: '<p>CityCorners offers <strong>11 categories</strong>:</p><ul><li>Sight, Restaurant, Shop, Museum, Café</li><li>Bar, Park, Beach, Hotel, Event Venue, Viewpoint</li></ul><p>Each category has its own color on the map and in card views.</p>',
|
||||
category: 'features',
|
||||
order: 6,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['kategorien', 'typen', 'filter'] : ['categories', 'types', 'filter'],
|
||||
},
|
||||
{
|
||||
id: 'faq-i18n',
|
||||
question: isDE ? 'Ist CityCorners mehrsprachig?' : 'Is CityCorners multilingual?',
|
||||
answer: isDE
|
||||
? '<p>Ja! CityCorners ist in <strong>Deutsch und Englisch</strong> verfügbar. Du kannst die Sprache jederzeit über den Sprachumschalter in der Navigation ändern. Die Einstellung wird lokal gespeichert.</p>'
|
||||
: '<p>Yes! CityCorners is available in <strong>German and English</strong>. You can change the language at any time via the language switcher in the navigation. The setting is saved locally.</p>',
|
||||
category: 'general',
|
||||
order: 7,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['sprache', 'deutsch', 'englisch'] : ['language', 'german', 'english'],
|
||||
},
|
||||
{
|
||||
id: 'faq-feedback',
|
||||
question: isDE ? 'Wie kann ich Feedback geben?' : 'How can I give feedback?',
|
||||
answer: isDE
|
||||
? '<p>Dein Feedback hilft uns, CityCorners zu verbessern:</p><ul><li>Nutze die <strong>Feedback-Seite</strong> im Menü, um Verbesserungsvorschläge, Fehlermeldungen oder neue Ort-Vorschläge einzureichen</li><li>Wir lesen jedes Feedback und arbeiten kontinuierlich an Verbesserungen</li></ul>'
|
||||
: '<p>Your feedback helps us improve CityCorners:</p><ul><li>Use the <strong>Feedback page</strong> in the menu to submit improvement suggestions, bug reports, or new location ideas</li><li>We read every piece of feedback and continuously work on improvements</li></ul>',
|
||||
category: 'general',
|
||||
order: 8,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE
|
||||
? ['feedback', 'verbesserung', 'kontakt']
|
||||
: ['feedback', 'improvement', 'contact'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, { dataTypeDE: 'Daten', dataTypeEN: 'data' }),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
id: 'feature-explore',
|
||||
title: isDE ? 'Orte entdecken' : 'Explore Places',
|
||||
description: isDE
|
||||
? 'Entdecke Sehenswürdigkeiten, Restaurants, Cafés und mehr in Konstanz am Bodensee'
|
||||
: 'Discover sights, restaurants, cafés, and more in Konstanz at Lake Constance',
|
||||
icon: '🏛️',
|
||||
category: 'core',
|
||||
highlights: isDE
|
||||
? ['11 Kategorien', 'Detailseiten mit Timeline', 'Farbcodierte Karten', 'Suche']
|
||||
: ['11 categories', 'Detail pages with timeline', 'Color-coded cards', 'Search'],
|
||||
content: '',
|
||||
order: 1,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
{
|
||||
id: 'feature-map',
|
||||
title: isDE ? 'Interaktive Karte' : 'Interactive Map',
|
||||
description: isDE
|
||||
? 'Leaflet-basierte Karte mit farbcodierten Markern für alle Kategorien'
|
||||
: 'Leaflet-based map with color-coded markers for all categories',
|
||||
icon: '🗺️',
|
||||
category: 'core',
|
||||
highlights: isDE
|
||||
? ['Farbcodierte Marker', 'Kategorie-Filter', 'Detailansicht per Klick', 'Mini-Karte']
|
||||
: ['Color-coded markers', 'Category filters', 'Detail view on click', 'Mini-map'],
|
||||
content: '',
|
||||
order: 2,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
{
|
||||
id: 'feature-favorites',
|
||||
title: isDE ? 'Favoriten' : 'Favorites',
|
||||
description: isDE
|
||||
? 'Speichere deine Lieblingsorte und finde sie schnell wieder'
|
||||
: 'Save your favorite places and find them quickly',
|
||||
icon: '❤️',
|
||||
category: 'core',
|
||||
highlights: isDE
|
||||
? ['Herz-Button', 'Optimistische Updates', 'Dedizierte Ansicht']
|
||||
: ['Heart button', 'Optimistic updates', 'Dedicated view'],
|
||||
content: '',
|
||||
order: 3,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
{
|
||||
id: 'feature-add',
|
||||
title: isDE ? 'Orte hinzufügen' : 'Add Locations',
|
||||
description: isDE
|
||||
? 'Trage neue Orte bei — mit Web-Lookup für automatische Informationsextraktion'
|
||||
: 'Contribute new locations — with web lookup for automatic information extraction',
|
||||
icon: '➕',
|
||||
category: 'core',
|
||||
highlights: isDE
|
||||
? ['Web-Lookup', 'Auto-Extraktion', '11 Kategorien', 'Bearbeiten']
|
||||
: ['Web lookup', 'Auto extraction', '11 categories', 'Editing'],
|
||||
content: '',
|
||||
order: 4,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
{
|
||||
id: 'feature-timeline',
|
||||
title: 'Timeline',
|
||||
description: isDE
|
||||
? 'Historische Ereignisse und Meilensteine für jeden Ort'
|
||||
: 'Historical events and milestones for every location',
|
||||
icon: '📅',
|
||||
category: 'advanced',
|
||||
highlights: isDE
|
||||
? ['Historische Ereignisse', 'Gründungsjahre', 'Meilensteine']
|
||||
: ['Historical events', 'Founding years', 'Milestones'],
|
||||
content: '',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
{
|
||||
id: 'feature-i18n',
|
||||
title: isDE ? 'Mehrsprachig' : 'Multilingual',
|
||||
description: isDE
|
||||
? 'Verfügbar in Deutsch und Englisch mit einfachem Sprachumschalter'
|
||||
: 'Available in German and English with easy language switcher',
|
||||
icon: '🌍',
|
||||
category: 'core',
|
||||
highlights: isDE
|
||||
? ['Deutsch & Englisch', 'Sofort umschaltbar', 'Lokal gespeichert']
|
||||
: ['German & English', 'Instant switching', 'Locally saved'],
|
||||
content: '',
|
||||
order: 6,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
{
|
||||
id: 'feature-pwa',
|
||||
title: isDE ? 'Progressive Web App' : 'Progressive Web App',
|
||||
description: isDE
|
||||
? 'Installierbar auf jedem Gerät — mit Offline-Fallback und Service Worker'
|
||||
: 'Installable on any device — with offline fallback and service worker',
|
||||
icon: '📱',
|
||||
category: 'advanced',
|
||||
highlights: isDE
|
||||
? ['Installierbar', 'Offline-Fallback', 'Service Worker Caching']
|
||||
: ['Installable', 'Offline fallback', 'Service worker caching'],
|
||||
content: '',
|
||||
order: 7,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
{
|
||||
id: 'feature-settings',
|
||||
title: isDE ? 'Einstellungen' : 'Settings',
|
||||
description: isDE
|
||||
? 'Passe CityCorners an — Theme-Modus, Theme-Variante und Kontoeinstellungen'
|
||||
: 'Customize CityCorners — theme mode, theme variant, and account settings',
|
||||
icon: '⚙️',
|
||||
category: 'core',
|
||||
highlights: isDE
|
||||
? ['Hell/Dunkel-Modus', 'Theme-Varianten', 'Kontoeinstellungen']
|
||||
: ['Light/Dark mode', 'Theme variants', 'Account settings'],
|
||||
content: '',
|
||||
order: 8,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
{
|
||||
id: 'feature-reviews',
|
||||
title: isDE ? 'Bewertungen' : 'Reviews',
|
||||
description: isDE
|
||||
? 'Bewerte Orte und lies Bewertungen anderer Nutzer'
|
||||
: 'Rate locations and read reviews from other users',
|
||||
icon: '⭐',
|
||||
category: 'core',
|
||||
highlights: isDE
|
||||
? ['Sternebewertung', 'Textbewertungen', 'Community-Feedback']
|
||||
: ['Star ratings', 'Text reviews', 'Community feedback'],
|
||||
content: '',
|
||||
order: 9,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
],
|
||||
shortcuts: [],
|
||||
gettingStarted: [],
|
||||
changelog: [],
|
||||
contact: {
|
||||
id: 'contact-support',
|
||||
title: isDE ? 'Support kontaktieren' : 'Contact Support',
|
||||
content: isDE
|
||||
? '<p>Unser Support-Team hilft dir bei allen Fragen rund um CityCorners. Nutze auch die Feedback-Funktion im Menü, um uns direkt Verbesserungsvorschläge oder neue Ort-Vorschläge zu schicken.</p>'
|
||||
: '<p>Our support team is here to help you with any questions about CityCorners. You can also use the feedback feature in the menu to send us improvement suggestions or new location ideas directly.</p>',
|
||||
language: isDE ? 'de' : 'en',
|
||||
order: 1,
|
||||
supportEmail: 'support@mana.how',
|
||||
documentationUrl: 'https://mana.how/docs',
|
||||
responseTime: isDE ? 'Normalerweise innerhalb von 24 Stunden' : 'Usually within 24 hours',
|
||||
},
|
||||
};
|
||||
}
|
||||
47
apps/clock/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/clock/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getClockHelpContent } from './index';
|
||||
|
||||
describe('Clock Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getClockHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getClockHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getClockHelpContent('de');
|
||||
const en = getClockHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getClockHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getClockHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -59,18 +60,16 @@ export function getClockHelpContent(locale: string): HelpContent {
|
|||
? ['life-clock', 'lebenszeit', 'visualisierung']
|
||||
: ['life-clock', 'lifetime', 'visualization'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: isDE ? 'Wie werden meine Daten geschützt?' : 'How is my data protected?',
|
||||
answer: isDE
|
||||
? '<p>Deine Daten sind sicher:</p><ul><li><strong>Lokale Speicherung</strong>: Wecker und Timer werden lokal auf deinem Gerät gespeichert</li><li><strong>Verschlüsselung</strong>: Alle synchronisierten Daten werden bei der Übertragung (TLS) verschlüsselt</li><li><strong>DSGVO-konform</strong>: Wir halten uns an die EU-Datenschutzverordnung</li><li><strong>Kein Tracking</strong>: Deine Nutzungsdaten werden nicht an Dritte weitergegeben</li></ul>'
|
||||
: '<p>Your data is secure:</p><ul><li><strong>Local storage</strong>: Alarms and timers are stored locally on your device</li><li><strong>Encryption</strong>: All synced data is encrypted in transit (TLS)</li><li><strong>GDPR compliant</strong>: We follow EU data protection regulations</li><li><strong>No tracking</strong>: Your usage data is never shared with third parties</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
featured: true,
|
||||
tags: isDE ? ['datenschutz', 'dsgvo', 'sicherheit'] : ['privacy', 'gdpr', 'security'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, {
|
||||
dataTypeDE: 'Daten',
|
||||
dataTypeEN: 'data',
|
||||
extraBulletsDE: [
|
||||
'<strong>Lokale Speicherung</strong>: Wecker und Timer werden lokal auf deinem Gerät gespeichert',
|
||||
],
|
||||
extraBulletsEN: [
|
||||
'<strong>Local storage</strong>: Alarms and timers are stored locally on your device',
|
||||
],
|
||||
}),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
47
apps/contacts/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/contacts/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getContactsHelpContent } from './index';
|
||||
|
||||
describe('Contacts Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getContactsHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getContactsHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getContactsHelpContent('de');
|
||||
const en = getContactsHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getContactsHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getContactsHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -56,18 +57,7 @@ export function getContactsHelpContent(locale: string): HelpContent {
|
|||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['abo', 'kündigung', 'abrechnung'] : ['subscription', 'cancel', 'billing'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: isDE ? 'Wie werden meine Daten geschützt?' : 'How is my data protected?',
|
||||
answer: isDE
|
||||
? '<p>Wir nehmen deinen Datenschutz ernst:</p><ul><li><strong>Verschlüsselung</strong>: Alle Daten werden bei der Übertragung (TLS) und im Ruhezustand verschlüsselt</li><li><strong>DSGVO-konform</strong>: Wir halten uns an die EU-Datenschutzverordnung</li><li><strong>Kein Datenverkauf</strong>: Wir verkaufen niemals deine persönlichen Daten</li><li><strong>Datenexport</strong>: Du kannst jederzeit alle deine Daten exportieren</li><li><strong>Kontolöschung</strong>: Du kannst dein Konto und alle Daten dauerhaft löschen</li></ul>'
|
||||
: '<p>We take your privacy seriously:</p><ul><li><strong>Encryption</strong>: All data is encrypted in transit (TLS) and at rest</li><li><strong>GDPR Compliant</strong>: We follow EU data protection regulations</li><li><strong>No Data Selling</strong>: We never sell your personal data</li><li><strong>Data Export</strong>: You can export all your data at any time</li><li><strong>Account Deletion</strong>: You can permanently delete your account and all data</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
featured: true,
|
||||
tags: isDE ? ['datenschutz', 'dsgvo', 'sicherheit'] : ['privacy', 'gdpr', 'security'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, { dataTypeDE: 'Kontakte', dataTypeEN: 'contacts' }),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
47
apps/context/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/context/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getContextHelpContent } from './index';
|
||||
|
||||
describe('Context Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getContextHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getContextHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getContextHelpContent('de');
|
||||
const en = getContextHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getContextHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getContextHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -59,18 +60,7 @@ export function getContextHelpContent(locale: string): HelpContent {
|
|||
? ['versionierung', 'historie', 'wiederherstellen']
|
||||
: ['versioning', 'history', 'restore'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: isDE ? 'Wie werden meine Daten geschützt?' : 'How is my data protected?',
|
||||
answer: isDE
|
||||
? '<p>Deine Daten sind sicher:</p><ul><li><strong>Verschlüsselung</strong>: Alle Daten werden bei der Übertragung (TLS) und im Ruhezustand verschlüsselt</li><li><strong>DSGVO-konform</strong>: Wir halten uns an die EU-Datenschutzverordnung</li><li><strong>KI-Datenschutz</strong>: Deine Dokumente werden nicht zum Trainieren von KI-Modellen verwendet</li><li><strong>Datenexport</strong>: Du kannst jederzeit alle Dokumente exportieren</li></ul>'
|
||||
: '<p>Your data is secure:</p><ul><li><strong>Encryption</strong>: All data is encrypted in transit (TLS) and at rest</li><li><strong>GDPR compliant</strong>: We follow EU data protection regulations</li><li><strong>AI privacy</strong>: Your documents are not used to train AI models</li><li><strong>Data export</strong>: You can export all documents at any time</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
featured: true,
|
||||
tags: isDE ? ['datenschutz', 'dsgvo', 'sicherheit'] : ['privacy', 'gdpr', 'security'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, { dataTypeDE: 'Dokumente', dataTypeEN: 'documents' }),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
47
apps/manacore/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/manacore/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getManaCoreHelpContent } from './index';
|
||||
|
||||
describe('ManaCore Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getManaCoreHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getManaCoreHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getManaCoreHelpContent('de');
|
||||
const en = getManaCoreHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getManaCoreHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getManaCoreHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -59,18 +60,7 @@ export function getManaCoreHelpContent(locale: string): HelpContent {
|
|||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['wechseln', 'apps', 'navigation'] : ['switch', 'apps', 'navigation'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: isDE ? 'Wie werden meine Daten geschützt?' : 'How is my data protected?',
|
||||
answer: isDE
|
||||
? '<p>Deine Daten sind sicher:</p><ul><li><strong>Verschlüsselung</strong>: Alle Daten werden bei der Übertragung (TLS) und im Ruhezustand verschlüsselt</li><li><strong>DSGVO-konform</strong>: Wir halten uns an die EU-Datenschutzverordnung</li><li><strong>Datenhoheit</strong>: Deine Daten gehören dir — exportiere oder lösche sie jederzeit</li><li><strong>Kein Datenverkauf</strong>: Deine Daten werden nie an Dritte verkauft</li><li><strong>Self-Hosted</strong>: ManaCore läuft auf unserer eigenen Infrastruktur</li></ul>'
|
||||
: '<p>Your data is secure:</p><ul><li><strong>Encryption</strong>: All data is encrypted in transit (TLS) and at rest</li><li><strong>GDPR compliant</strong>: We follow EU data protection regulations</li><li><strong>Data sovereignty</strong>: Your data belongs to you — export or delete it anytime</li><li><strong>No data selling</strong>: Your data is never sold to third parties</li><li><strong>Self-hosted</strong>: ManaCore runs on our own infrastructure</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
featured: true,
|
||||
tags: isDE ? ['datenschutz', 'dsgvo', 'sicherheit'] : ['privacy', 'gdpr', 'security'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, { dataTypeDE: 'Daten', dataTypeEN: 'data' }),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
47
apps/manadeck/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/manadeck/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getManaDeckHelpContent } from './index';
|
||||
|
||||
describe('ManaDeck Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getManaDeckHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getManaDeckHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getManaDeckHelpContent('de');
|
||||
const en = getManaDeckHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getManaDeckHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getManaDeckHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -57,18 +58,7 @@ export function getManaDeckHelpContent(locale: string): HelpContent {
|
|||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['import', 'export', 'csv', 'anki'] : ['import', 'export', 'csv', 'anki'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: isDE ? 'Wie werden meine Daten geschützt?' : 'How is my data protected?',
|
||||
answer: isDE
|
||||
? '<p>Deine Daten sind sicher:</p><ul><li><strong>Verschlüsselung</strong>: Alle Daten werden bei der Übertragung (TLS) verschlüsselt</li><li><strong>DSGVO-konform</strong>: Wir halten uns an die EU-Datenschutzverordnung</li><li><strong>Kein Datenverkauf</strong>: Deine Lernkarten und Fortschritte werden nie an Dritte verkauft</li><li><strong>Datenexport</strong>: Du kannst jederzeit alle Decks und Karten exportieren</li></ul>'
|
||||
: '<p>Your data is secure:</p><ul><li><strong>Encryption</strong>: All data is encrypted in transit (TLS)</li><li><strong>GDPR compliant</strong>: We follow EU data protection regulations</li><li><strong>No data selling</strong>: Your flashcards and progress are never sold to third parties</li><li><strong>Data export</strong>: You can export all decks and cards at any time</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
featured: true,
|
||||
tags: isDE ? ['datenschutz', 'dsgvo', 'sicherheit'] : ['privacy', 'gdpr', 'security'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, { dataTypeDE: 'Karten', dataTypeEN: 'cards' }),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
47
apps/matrix/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/matrix/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getManalinkHelpContent } from './index';
|
||||
|
||||
describe('Manalink Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getManalinkHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getManalinkHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getManalinkHelpContent('de');
|
||||
const en = getManalinkHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getManalinkHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
276
apps/matrix/apps/web/src/lib/content/help/index.ts
Normal file
276
apps/matrix/apps/web/src/lib/content/help/index.ts
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
/**
|
||||
* Help content for Manalink (Matrix) app
|
||||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getManalinkHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
||||
return {
|
||||
faq: [
|
||||
{
|
||||
id: 'faq-what-is-matrix',
|
||||
question: isDE ? 'Was ist Matrix und Manalink?' : 'What is Matrix and Manalink?',
|
||||
answer: isDE
|
||||
? '<p>Manalink ist ein sicherer Messenger auf Basis des <strong>Matrix-Protokolls</strong> — einem dezentralen, offenen Standard für Kommunikation:</p><ul><li>Ende-zu-Ende-verschlüsselt</li><li>Dezentral — kein einzelner Server kontrolliert deine Daten</li><li>Kompatibel mit anderen Matrix-Clients (Element, FluffyChat, etc.)</li><li>Der Standard-Homeserver ist <code>matrix.mana.how</code></li></ul>'
|
||||
: '<p>Manalink is a secure messenger based on the <strong>Matrix protocol</strong> — a decentralized, open standard for communication:</p><ul><li>End-to-end encrypted</li><li>Decentralized — no single server controls your data</li><li>Compatible with other Matrix clients (Element, FluffyChat, etc.)</li><li>The default homeserver is <code>matrix.mana.how</code></li></ul>',
|
||||
category: 'features',
|
||||
order: 1,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['matrix', 'protokoll', 'dezentral'] : ['matrix', 'protocol', 'decentralized'],
|
||||
},
|
||||
{
|
||||
id: 'faq-login',
|
||||
question: isDE ? 'Wie melde ich mich an?' : 'How do I log in?',
|
||||
answer: isDE
|
||||
? '<p>Du kannst dich auf zwei Wegen anmelden:</p><ul><li><strong>Matrix-Konto</strong> — Benutzername und Passwort eines Matrix-Homeservers</li><li><strong>SSO über Mana Core</strong> — Anmeldung mit deinem ManaCore-Konto</li></ul><p>Der Standard-Homeserver ist <code>matrix.mana.how</code>, aber du kannst jeden beliebigen Matrix-Homeserver verwenden.</p>'
|
||||
: '<p>You can log in two ways:</p><ul><li><strong>Matrix account</strong> — Username and password from a Matrix homeserver</li><li><strong>SSO via Mana Core</strong> — Login with your ManaCore account</li></ul><p>The default homeserver is <code>matrix.mana.how</code>, but you can use any Matrix homeserver.</p>',
|
||||
category: 'getting-started',
|
||||
order: 2,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['anmeldung', 'login', 'sso'] : ['login', 'auth', 'sso'],
|
||||
},
|
||||
{
|
||||
id: 'faq-rooms',
|
||||
question: isDE ? 'Wie funktionieren Räume?' : 'How do rooms work?',
|
||||
answer: isDE
|
||||
? '<p>Räume sind Chatgruppen in Matrix:</p><ul><li><strong>Direktnachrichten</strong> — 1:1 Gespräche</li><li><strong>Gruppenräume</strong> — Mehrere Teilnehmer</li><li>Du kannst Räume erstellen, beitreten und verwalten</li><li>Räume zeigen ungelesene Nachrichten und Highlight-Zähler an</li></ul>'
|
||||
: '<p>Rooms are chat groups in Matrix:</p><ul><li><strong>Direct messages</strong> — 1:1 conversations</li><li><strong>Group rooms</strong> — Multiple participants</li><li>You can create, join, and manage rooms</li><li>Rooms show unread message and highlight counters</li></ul>',
|
||||
category: 'features',
|
||||
order: 3,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['räume', 'chat', 'gruppen'] : ['rooms', 'chat', 'groups'],
|
||||
},
|
||||
{
|
||||
id: 'faq-messaging',
|
||||
question: isDE
|
||||
? 'Welche Nachrichtenfunktionen gibt es?'
|
||||
: 'What messaging features are available?',
|
||||
answer: isDE
|
||||
? '<p>Manalink bietet umfangreiche Nachrichtenfunktionen:</p><ul><li><strong>Textnachrichten</strong> senden und empfangen</li><li><strong>Tipp-Indikatoren</strong> — Sieh, wenn jemand gerade tippt</li><li><strong>Lesebestätigungen</strong> — Wisse, wann deine Nachricht gelesen wurde</li><li><strong>Nachrichtensuche</strong> — Durchsuche den Chatverlauf</li><li><strong>Paginierung</strong> — Lade ältere Nachrichten nach</li></ul>'
|
||||
: '<p>Manalink offers comprehensive messaging features:</p><ul><li><strong>Text messages</strong> — send and receive</li><li><strong>Typing indicators</strong> — See when someone is typing</li><li><strong>Read receipts</strong> — Know when your message was read</li><li><strong>Message search</strong> — Search through chat history</li><li><strong>Pagination</strong> — Load older messages</li></ul>',
|
||||
category: 'features',
|
||||
order: 4,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE
|
||||
? ['nachrichten', 'tippen', 'lesen', 'suche']
|
||||
: ['messages', 'typing', 'read', 'search'],
|
||||
},
|
||||
{
|
||||
id: 'faq-encryption',
|
||||
question: isDE ? 'Sind meine Nachrichten verschlüsselt?' : 'Are my messages encrypted?',
|
||||
answer: isDE
|
||||
? '<p>Ja, Manalink unterstützt <strong>Ende-zu-Ende-Verschlüsselung (E2EE)</strong> über das Matrix-Protokoll:</p><ul><li>Verschlüsselte Räume sind nur für die Teilnehmer lesbar</li><li>Nicht einmal der Server kann die Nachrichten lesen</li><li>Die Verschlüsselung verwendet bewährte kryptographische Verfahren (Olm/Megolm)</li></ul>'
|
||||
: '<p>Yes, Manalink supports <strong>end-to-end encryption (E2EE)</strong> via the Matrix protocol:</p><ul><li>Encrypted rooms are only readable by participants</li><li>Not even the server can read the messages</li><li>Encryption uses proven cryptographic methods (Olm/Megolm)</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['verschlüsselung', 'e2ee', 'sicherheit'] : ['encryption', 'e2ee', 'security'],
|
||||
},
|
||||
{
|
||||
id: 'faq-room-settings',
|
||||
question: isDE ? 'Wie verwalte ich Raumeinstellungen?' : 'How do I manage room settings?',
|
||||
answer: isDE
|
||||
? '<p>Jeder Raum hat eigene Einstellungen:</p><ul><li><strong>Name und Thema</strong> des Raums ändern</li><li><strong>Mitglieder</strong> einladen und verwalten</li><li><strong>Benachrichtigungen</strong> pro Raum konfigurieren</li></ul>'
|
||||
: '<p>Each room has its own settings:</p><ul><li>Change the <strong>name and topic</strong> of the room</li><li><strong>Invite and manage</strong> members</li><li>Configure <strong>notifications</strong> per room</li></ul>',
|
||||
category: 'features',
|
||||
order: 6,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['einstellungen', 'raum', 'mitglieder'] : ['settings', 'room', 'members'],
|
||||
},
|
||||
{
|
||||
id: 'faq-bots',
|
||||
question: isDE ? 'Was sind Bots?' : 'What are bots?',
|
||||
answer: isDE
|
||||
? '<p>Unter <strong>Bots</strong> findest du automatisierte Assistenten, die in Räumen helfen können. Bots können Aufgaben automatisieren, Informationen bereitstellen und den Chat bereichern.</p>'
|
||||
: '<p>Under <strong>Bots</strong> you can find automated assistants that can help in rooms. Bots can automate tasks, provide information, and enrich the chat experience.</p>',
|
||||
category: 'features',
|
||||
order: 7,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE
|
||||
? ['bots', 'automatisierung', 'assistenten']
|
||||
: ['bots', 'automation', 'assistants'],
|
||||
},
|
||||
{
|
||||
id: 'faq-pwa',
|
||||
question: isDE
|
||||
? 'Kann ich Manalink auf dem Handy nutzen?'
|
||||
: 'Can I use Manalink on my phone?',
|
||||
answer: isDE
|
||||
? '<p>Ja! Manalink ist eine <strong>Progressive Web App (PWA)</strong>:</p><ul><li>Öffne die App im Browser und tippe auf <strong>"Zum Startbildschirm hinzufügen"</strong></li><li>Funktioniert auch offline dank Service Worker Caching</li><li>Push-Benachrichtigungen für neue Nachrichten</li><li>Vollbild-App-Erfahrung ohne Browser-Leiste</li></ul>'
|
||||
: '<p>Yes! Manalink is a <strong>Progressive Web App (PWA)</strong>:</p><ul><li>Open the app in your browser and tap <strong>"Add to Home Screen"</strong></li><li>Works offline thanks to service worker caching</li><li>Push notifications for new messages</li><li>Fullscreen app experience without browser bar</li></ul>',
|
||||
category: 'getting-started',
|
||||
order: 8,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['pwa', 'mobil', 'installieren'] : ['pwa', 'mobile', 'install'],
|
||||
},
|
||||
{
|
||||
id: 'faq-feedback',
|
||||
question: isDE ? 'Wie kann ich Feedback geben?' : 'How can I give feedback?',
|
||||
answer: isDE
|
||||
? '<p>Dein Feedback hilft uns, Manalink zu verbessern:</p><ul><li>Nutze die <strong>Feedback-Seite</strong> im Menü, um Verbesserungsvorschläge, Fehlermeldungen oder Feature-Wünsche einzureichen</li><li>Wir lesen jedes Feedback und arbeiten kontinuierlich an Verbesserungen</li></ul>'
|
||||
: '<p>Your feedback helps us improve Manalink:</p><ul><li>Use the <strong>Feedback page</strong> in the menu to submit improvement suggestions, bug reports, or feature requests</li><li>We read every piece of feedback and continuously work on improvements</li></ul>',
|
||||
category: 'general',
|
||||
order: 9,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE
|
||||
? ['feedback', 'verbesserung', 'kontakt']
|
||||
: ['feedback', 'improvement', 'contact'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, {
|
||||
dataTypeDE: 'Nachrichten',
|
||||
dataTypeEN: 'messages',
|
||||
extraBulletsDE: [
|
||||
'<strong>Ende-zu-Ende-Verschlüsselung</strong>: Verschlüsselte Räume sind nur für Teilnehmer lesbar — nicht einmal der Server kann mitlesen',
|
||||
],
|
||||
extraBulletsEN: [
|
||||
'<strong>End-to-end encryption</strong>: Encrypted rooms are only readable by participants — not even the server can read them',
|
||||
],
|
||||
}),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
id: 'feature-messaging',
|
||||
title: isDE ? 'Sichere Nachrichten' : 'Secure Messaging',
|
||||
description: isDE
|
||||
? 'Ende-zu-Ende-verschlüsselte Nachrichten über das dezentrale Matrix-Protokoll'
|
||||
: 'End-to-end encrypted messaging via the decentralized Matrix protocol',
|
||||
icon: '🔒',
|
||||
category: 'core',
|
||||
highlights: isDE
|
||||
? [
|
||||
'E2E-Verschlüsselung',
|
||||
'Direktnachrichten & Gruppen',
|
||||
'Lesebestätigungen',
|
||||
'Tipp-Indikatoren',
|
||||
]
|
||||
: ['E2E encryption', 'Direct messages & groups', 'Read receipts', 'Typing indicators'],
|
||||
content: '',
|
||||
order: 1,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
{
|
||||
id: 'feature-rooms',
|
||||
title: isDE ? 'Räume' : 'Rooms',
|
||||
description: isDE
|
||||
? 'Erstelle und verwalte Räume für Direktnachrichten und Gruppen'
|
||||
: 'Create and manage rooms for direct messages and groups',
|
||||
icon: '💬',
|
||||
category: 'core',
|
||||
highlights: isDE
|
||||
? ['Raum erstellen', 'Raumeinstellungen', 'Mitgliederverwaltung', 'Ungelesen-Zähler']
|
||||
: ['Create rooms', 'Room settings', 'Member management', 'Unread counter'],
|
||||
content: '',
|
||||
order: 2,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
{
|
||||
id: 'feature-search',
|
||||
title: isDE ? 'Nachrichtensuche' : 'Message Search',
|
||||
description: isDE
|
||||
? 'Durchsuche den Chatverlauf nach Nachrichten und Inhalten'
|
||||
: 'Search through chat history for messages and content',
|
||||
icon: '🔍',
|
||||
category: 'core',
|
||||
highlights: isDE
|
||||
? ['Volltextsuche', 'Raum-übergreifend', 'Schnelle Ergebnisse']
|
||||
: ['Full-text search', 'Cross-room', 'Quick results'],
|
||||
content: '',
|
||||
order: 3,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
{
|
||||
id: 'feature-sso',
|
||||
title: isDE ? 'SSO-Anmeldung' : 'SSO Login',
|
||||
description: isDE
|
||||
? 'Melde dich mit deinem ManaCore-Konto an — kein separates Matrix-Passwort nötig'
|
||||
: 'Sign in with your ManaCore account — no separate Matrix password needed',
|
||||
icon: '🔐',
|
||||
category: 'core',
|
||||
highlights: isDE
|
||||
? ['ManaCore SSO', 'Ein-Klick-Login', 'Sicher', 'Passwort-Login']
|
||||
: ['ManaCore SSO', 'One-click login', 'Secure', 'Password login'],
|
||||
content: '',
|
||||
order: 4,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
{
|
||||
id: 'feature-bots',
|
||||
title: 'Bots',
|
||||
description: isDE
|
||||
? 'Automatisierte Assistenten für Aufgaben und Informationen in Räumen'
|
||||
: 'Automated assistants for tasks and information in rooms',
|
||||
icon: '🤖',
|
||||
category: 'advanced',
|
||||
highlights: isDE
|
||||
? ['Chat-Assistenten', 'Automatisierung', 'Informationsdienste']
|
||||
: ['Chat assistants', 'Automation', 'Information services'],
|
||||
content: '',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
{
|
||||
id: 'feature-pwa',
|
||||
title: isDE ? 'Progressive Web App' : 'Progressive Web App',
|
||||
description: isDE
|
||||
? 'Installierbar auf jedem Gerät — offline-fähig und mit Push-Benachrichtigungen'
|
||||
: 'Installable on any device — works offline and supports push notifications',
|
||||
icon: '📱',
|
||||
category: 'core',
|
||||
highlights: isDE
|
||||
? ['Installierbar', 'Offline-fähig', 'Push-Benachrichtigungen', 'Vollbild']
|
||||
: ['Installable', 'Works offline', 'Push notifications', 'Fullscreen'],
|
||||
content: '',
|
||||
order: 6,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
{
|
||||
id: 'feature-federation',
|
||||
title: isDE ? 'Föderation' : 'Federation',
|
||||
description: isDE
|
||||
? 'Kommuniziere mit Nutzern auf anderen Matrix-Homeservern'
|
||||
: 'Communicate with users on other Matrix homeservers',
|
||||
icon: '🌐',
|
||||
category: 'advanced',
|
||||
highlights: isDE
|
||||
? ['Server-übergreifend', 'Offenes Protokoll', 'Element-kompatibel']
|
||||
: ['Cross-server', 'Open protocol', 'Element-compatible'],
|
||||
content: '',
|
||||
order: 7,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
{
|
||||
id: 'feature-settings',
|
||||
title: isDE ? 'Einstellungen' : 'Settings',
|
||||
description: isDE
|
||||
? 'Passe Manalink an — Themes, Benachrichtigungen und Kontoeinstellungen'
|
||||
: 'Customize Manalink — themes, notifications, and account settings',
|
||||
icon: '⚙️',
|
||||
category: 'core',
|
||||
highlights: isDE
|
||||
? ['Hell/Dunkel-Modus', 'Benachrichtigungen', 'Kontoeinstellungen']
|
||||
: ['Light/Dark mode', 'Notifications', 'Account settings'],
|
||||
content: '',
|
||||
order: 8,
|
||||
language: isDE ? 'de' : 'en',
|
||||
},
|
||||
],
|
||||
shortcuts: [],
|
||||
gettingStarted: [],
|
||||
changelog: [],
|
||||
contact: {
|
||||
id: 'contact-support',
|
||||
title: isDE ? 'Support kontaktieren' : 'Contact Support',
|
||||
content: isDE
|
||||
? '<p>Unser Support-Team hilft dir bei allen Fragen rund um Manalink. Nutze auch die Feedback-Funktion im Menü, um uns direkt Verbesserungsvorschläge zu schicken.</p>'
|
||||
: '<p>Our support team is here to help you with any questions about Manalink. You can also use the feedback feature in the menu to send us improvement suggestions directly.</p>',
|
||||
language: isDE ? 'de' : 'en',
|
||||
order: 1,
|
||||
supportEmail: 'support@mana.how',
|
||||
documentationUrl: 'https://mana.how/docs',
|
||||
responseTime: isDE ? 'Normalerweise innerhalb von 24 Stunden' : 'Usually within 24 hours',
|
||||
},
|
||||
};
|
||||
}
|
||||
47
apps/mukke/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/mukke/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getMukkeHelpContent } from './index';
|
||||
|
||||
describe('Mukke Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getMukkeHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getMukkeHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getMukkeHelpContent('de');
|
||||
const en = getMukkeHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getMukkeHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getMukkeHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -47,18 +48,7 @@ export function getMukkeHelpContent(locale: string): HelpContent {
|
|||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['playlist', 'erstellen', 'sortieren'] : ['playlist', 'create', 'sort'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: isDE ? 'Wie werden meine Daten geschützt?' : 'How is my data protected?',
|
||||
answer: isDE
|
||||
? '<p>Deine Musik ist sicher:</p><ul><li><strong>Privat</strong>: Nur du hast Zugriff auf deine Bibliothek</li><li><strong>Verschlüsselung</strong>: Alle Daten werden bei der Übertragung (TLS) verschlüsselt</li><li><strong>DSGVO-konform</strong>: Wir halten uns an die EU-Datenschutzverordnung</li></ul>'
|
||||
: '<p>Your music is secure:</p><ul><li><strong>Private</strong>: Only you have access to your library</li><li><strong>Encryption</strong>: All data is encrypted in transit (TLS)</li><li><strong>GDPR Compliant</strong>: We follow EU data protection regulations</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 4,
|
||||
language: isDE ? 'de' : 'en',
|
||||
featured: true,
|
||||
tags: isDE ? ['datenschutz', 'dsgvo', 'sicherheit'] : ['privacy', 'gdpr', 'security'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, { dataTypeDE: 'Musik', dataTypeEN: 'music' }),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
47
apps/photos/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/photos/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getPhotosHelpContent } from './index';
|
||||
|
||||
describe('Photos Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getPhotosHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getPhotosHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getPhotosHelpContent('de');
|
||||
const en = getPhotosHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getPhotosHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getPhotosHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -53,17 +54,7 @@ export function getPhotosHelpContent(locale: string): HelpContent {
|
|||
language: isDE ? 'de' : 'en',
|
||||
tags: ['favorites', 'heart', 'bookmarks'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: isDE ? 'Wie werden meine Fotos geschützt?' : 'How are my photos protected?',
|
||||
answer: isDE
|
||||
? '<p>Deine Fotos sind sicher bei ManaCore:</p><ul><li>Alle Fotos werden verschlüsselt übertragen und gespeichert</li><li>Nur du hast Zugriff auf deine Galerie</li><li>Fotos werden nicht für KI-Training oder andere Zwecke verwendet</li><li>Du kannst jederzeit Fotos löschen — sie werden dann dauerhaft entfernt</li></ul>'
|
||||
: '<p>Your photos are safe with ManaCore:</p><ul><li>All photos are encrypted in transit and at rest</li><li>Only you have access to your gallery</li><li>Photos are not used for AI training or other purposes</li><li>You can delete photos at any time — they are permanently removed</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: ['privacy', 'security', 'data'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, { dataTypeDE: 'Fotos', dataTypeEN: 'photos' }),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
47
apps/picture/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/picture/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getPictureHelpContent } from './index';
|
||||
|
||||
describe('Picture Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getPictureHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getPictureHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getPictureHelpContent('de');
|
||||
const en = getPictureHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getPictureHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getPictureHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -60,18 +61,7 @@ export function getPictureHelpContent(locale: string): HelpContent {
|
|||
? ['explore', 'entdecken', 'inspiration']
|
||||
: ['explore', 'discover', 'inspiration'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: isDE ? 'Wie werden meine Bilder geschützt?' : 'How are my images protected?',
|
||||
answer: isDE
|
||||
? '<p>Deine Bilder sind sicher:</p><ul><li><strong>Privat</strong>: Generierte Bilder sind standardmäßig nur für dich sichtbar</li><li><strong>Verschlüsselung</strong>: Alle Daten werden bei der Übertragung (TLS) verschlüsselt</li><li><strong>DSGVO-konform</strong>: Wir halten uns an die EU-Datenschutzverordnung</li><li><strong>Löschung</strong>: Du kannst Bilder jederzeit dauerhaft löschen</li></ul>'
|
||||
: '<p>Your images are secure:</p><ul><li><strong>Private</strong>: Generated images are only visible to you by default</li><li><strong>Encryption</strong>: All data is encrypted in transit (TLS)</li><li><strong>GDPR Compliant</strong>: We follow EU data protection regulations</li><li><strong>Deletion</strong>: You can permanently delete images at any time</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
featured: true,
|
||||
tags: isDE ? ['datenschutz', 'sicherheit', 'dsgvo'] : ['privacy', 'security', 'gdpr'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, { dataTypeDE: 'Bilder', dataTypeEN: 'images' }),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
47
apps/planta/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/planta/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getPlantaHelpContent } from './index';
|
||||
|
||||
describe('Planta Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getPlantaHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getPlantaHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getPlantaHelpContent('de');
|
||||
const en = getPlantaHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getPlantaHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getPlantaHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -57,17 +58,7 @@ export function getPlantaHelpContent(locale: string): HelpContent {
|
|||
language: isDE ? 'de' : 'en',
|
||||
tags: ['health', 'diseases', 'pests', 'monitoring'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: isDE ? 'Wie werden meine Daten geschützt?' : 'How is my data protected?',
|
||||
answer: isDE
|
||||
? '<p>Deine Pflanzendaten sind sicher bei Planta:</p><ul><li>Fotos werden nur zur Pflanzenidentifizierung verwendet und nicht an Dritte weitergegeben</li><li>Deine Pflanzensammlung ist nur für dich sichtbar</li><li>Standortdaten werden nur lokal für Wetteranpassungen genutzt</li><li>Du kannst jederzeit alle Daten exportieren oder löschen</li></ul>'
|
||||
: '<p>Your plant data is safe with Planta:</p><ul><li>Photos are only used for plant identification and are not shared with third parties</li><li>Your plant collection is visible only to you</li><li>Location data is only used locally for weather adjustments</li><li>You can export or delete all data at any time</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: ['privacy', 'security', 'data', 'photos'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, { dataTypeDE: 'Pflanzendaten', dataTypeEN: 'plant data' }),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
47
apps/presi/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/presi/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getPresiHelpContent } from './index';
|
||||
|
||||
describe('Presi Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getPresiHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getPresiHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getPresiHelpContent('de');
|
||||
const en = getPresiHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getPresiHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getPresiHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -53,17 +54,7 @@ export function getPresiHelpContent(locale: string): HelpContent {
|
|||
language: isDE ? 'de' : 'en',
|
||||
tags: ['themes', 'design', 'customization', 'styles'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: isDE ? 'Wie werden meine Daten geschützt?' : 'How is my data protected?',
|
||||
answer: isDE
|
||||
? '<p>Deine Präsentationen sind sicher bei Presi:</p><ul><li>Alle Daten werden verschlüsselt übertragen und gespeichert</li><li>Geteilte Links können jederzeit widerrufen werden</li><li>Du bestimmst, wer Zugriff auf deine Präsentationen hat</li><li>Gelöschte Präsentationen werden dauerhaft entfernt</li></ul>'
|
||||
: '<p>Your presentations are safe with Presi:</p><ul><li>All data is encrypted in transit and at rest</li><li>Shared links can be revoked at any time</li><li>You control who has access to your presentations</li><li>Deleted presentations are permanently removed</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: ['privacy', 'security', 'data', 'sharing'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, { dataTypeDE: 'Präsentationen', dataTypeEN: 'presentations' }),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
47
apps/questions/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/questions/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getQuestionsHelpContent } from './index';
|
||||
|
||||
describe('Questions Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getQuestionsHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getQuestionsHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getQuestionsHelpContent('de');
|
||||
const en = getQuestionsHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getQuestionsHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getQuestionsHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -53,17 +54,7 @@ export function getQuestionsHelpContent(locale: string): HelpContent {
|
|||
language: isDE ? 'de' : 'en',
|
||||
tags: ['collections', 'organize', 'save', 'share'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: isDE ? 'Wie werden meine Daten geschützt?' : 'How is my data protected?',
|
||||
answer: isDE
|
||||
? '<p>Deine Recherchen sind privat und sicher:</p><ul><li>Suchanfragen werden nicht mit Dritten geteilt</li><li>Dein Rechercheverlauf ist nur für dich sichtbar</li><li>Die Websuche erfolgt über unseren eigenen Suchdienst, nicht über Google</li><li>Du kannst deinen Verlauf jederzeit löschen</li></ul>'
|
||||
: '<p>Your research is private and secure:</p><ul><li>Search queries are not shared with third parties</li><li>Your research history is visible only to you</li><li>Web search is performed through our own search service, not through Google</li><li>You can delete your history at any time</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
tags: ['privacy', 'security', 'data', 'history'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, { dataTypeDE: 'Fragen', dataTypeEN: 'questions' }),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
47
apps/storage/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/storage/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getStorageHelpContent } from './index';
|
||||
|
||||
describe('Storage Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getStorageHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getStorageHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getStorageHelpContent('de');
|
||||
const en = getStorageHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getStorageHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getStorageHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -53,18 +54,16 @@ export function getStorageHelpContent(locale: string): HelpContent {
|
|||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['papierkorb', 'löschen', 'wiederherstellen'] : ['trash', 'delete', 'restore'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: isDE ? 'Wie werden meine Dateien geschützt?' : 'How are my files protected?',
|
||||
answer: isDE
|
||||
? '<p>Deine Dateien sind sicher:</p><ul><li><strong>Verschlüsselung</strong>: Alle Daten werden bei der Übertragung (TLS) verschlüsselt</li><li><strong>Privat</strong>: Nur du hast Zugriff auf deine Dateien</li><li><strong>DSGVO-konform</strong>: Wir halten uns an die EU-Datenschutzverordnung</li><li><strong>Share-Kontrolle</strong>: Du bestimmst, wer Zugriff hat (Passwort, Ablauf, Limit)</li></ul>'
|
||||
: '<p>Your files are secure:</p><ul><li><strong>Encryption</strong>: All data is encrypted in transit (TLS)</li><li><strong>Private</strong>: Only you have access to your files</li><li><strong>GDPR Compliant</strong>: We follow EU data protection regulations</li><li><strong>Share control</strong>: You decide who has access (password, expiry, limits)</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
featured: true,
|
||||
tags: isDE ? ['datenschutz', 'sicherheit', 'dsgvo'] : ['privacy', 'security', 'gdpr'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, {
|
||||
dataTypeDE: 'Dateien',
|
||||
dataTypeEN: 'files',
|
||||
extraBulletsDE: [
|
||||
'<strong>S3-Storage</strong>: Dateien werden sicher in S3-kompatiblem Speicher (MinIO) abgelegt',
|
||||
],
|
||||
extraBulletsEN: [
|
||||
'<strong>S3 storage</strong>: Files are securely stored in S3-compatible storage (MinIO)',
|
||||
],
|
||||
}),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
47
apps/todo/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/todo/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getTodoHelpContent } from './index';
|
||||
|
||||
describe('Todo Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getTodoHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getTodoHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getTodoHelpContent('de');
|
||||
const en = getTodoHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getTodoHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getTodoHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -60,18 +61,7 @@ export function getTodoHelpContent(locale: string): HelpContent {
|
|||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['wiederkehrend', 'wiederholung', 'serie'] : ['recurring', 'repeat', 'series'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: isDE ? 'Wie werden meine Daten geschützt?' : 'How is my data protected?',
|
||||
answer: isDE
|
||||
? '<p>Deine Daten sind sicher:</p><ul><li><strong>Verschlüsselung</strong>: Alle Daten werden bei der Übertragung (TLS) verschlüsselt</li><li><strong>DSGVO-konform</strong>: Wir halten uns an die EU-Datenschutzverordnung</li><li><strong>Kein Datenverkauf</strong>: Deine Aufgaben werden nie an Dritte verkauft</li><li><strong>Datenexport</strong>: Du kannst jederzeit alle Daten exportieren</li></ul>'
|
||||
: '<p>Your data is secure:</p><ul><li><strong>Encryption</strong>: All data is encrypted in transit (TLS)</li><li><strong>GDPR Compliant</strong>: We follow EU data protection regulations</li><li><strong>No Data Selling</strong>: Your tasks are never sold to third parties</li><li><strong>Data Export</strong>: You can export all your data anytime</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 5,
|
||||
language: isDE ? 'de' : 'en',
|
||||
featured: true,
|
||||
tags: isDE ? ['datenschutz', 'dsgvo', 'sicherheit'] : ['privacy', 'gdpr', 'security'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, { dataTypeDE: 'Aufgaben', dataTypeEN: 'tasks' }),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
47
apps/zitare/apps/web/src/lib/content/help/index.test.ts
Normal file
47
apps/zitare/apps/web/src/lib/content/help/index.test.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getZitareHelpContent } from './index';
|
||||
|
||||
describe('Zitare Help Content', () => {
|
||||
it('returns valid German content', () => {
|
||||
const content = getZitareHelpContent('de');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
expect(content.contact.supportEmail).toBe('support@mana.how');
|
||||
});
|
||||
|
||||
it('returns valid English content', () => {
|
||||
const content = getZitareHelpContent('en');
|
||||
|
||||
expect(content.faq.length).toBeGreaterThan(0);
|
||||
content.faq.forEach((faq) => {
|
||||
expect(faq.id).toBeTruthy();
|
||||
expect(faq.question).toBeTruthy();
|
||||
expect(faq.answer).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(content.features).toBeDefined();
|
||||
expect(content.contact).toBeDefined();
|
||||
});
|
||||
|
||||
it('returns same number of FAQ items for both languages', () => {
|
||||
const de = getZitareHelpContent('de');
|
||||
const en = getZitareHelpContent('en');
|
||||
|
||||
expect(de.faq.length).toBe(en.faq.length);
|
||||
expect(de.features.length).toBe(en.features.length);
|
||||
});
|
||||
|
||||
it('has unique FAQ IDs', () => {
|
||||
const content = getZitareHelpContent('de');
|
||||
const ids = content.faq.map((f) => f.id);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { HelpContent } from '@manacore/shared-help-types';
|
||||
import { getPrivacyFAQs } from '@manacore/shared-help-types';
|
||||
|
||||
export function getZitareHelpContent(locale: string): HelpContent {
|
||||
const isDE = locale === 'de';
|
||||
|
|
@ -42,18 +43,7 @@ export function getZitareHelpContent(locale: string): HelpContent {
|
|||
language: isDE ? 'de' : 'en',
|
||||
tags: isDE ? ['listen', 'sammlung', 'organisieren'] : ['lists', 'collection', 'organize'],
|
||||
},
|
||||
{
|
||||
id: 'faq-privacy',
|
||||
question: isDE ? 'Wie werden meine Daten geschützt?' : 'How is my data protected?',
|
||||
answer: isDE
|
||||
? '<p>Deine Daten sind sicher:</p><ul><li><strong>Verschlüsselung</strong>: Alle Daten werden bei der Übertragung (TLS) verschlüsselt</li><li><strong>Privat</strong>: Deine Favoriten und Listen sind nur für dich sichtbar</li><li><strong>DSGVO-konform</strong>: Wir halten uns an die EU-Datenschutzverordnung</li></ul>'
|
||||
: '<p>Your data is secure:</p><ul><li><strong>Encryption</strong>: All data is encrypted in transit (TLS)</li><li><strong>Private</strong>: Your favorites and lists are only visible to you</li><li><strong>GDPR Compliant</strong>: We follow EU data protection regulations</li></ul>',
|
||||
category: 'privacy',
|
||||
order: 4,
|
||||
language: isDE ? 'de' : 'en',
|
||||
featured: true,
|
||||
tags: isDE ? ['datenschutz', 'dsgvo', 'sicherheit'] : ['privacy', 'gdpr', 'security'],
|
||||
},
|
||||
...getPrivacyFAQs(locale, { dataTypeDE: 'Zitate', dataTypeEN: 'quotes' }),
|
||||
],
|
||||
features: [
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue