Voice Notes (DM): - WhatsApp-style voice recording bar (shared VoiceRecordingBar component) - Audio bubbles: 80 fixed-2dp bars (Instagram-style thin), space-between layout, deterministic waveform, moving blue position dot, WA gray bar colors - Cancel flash fix: setIsVoiceRecording delayed 350ms so trash flash is visible - Mic button 44pt (Apple min), hitSlop on all recording controls - startReply shows 🎤/📷 label for voice/image instead of empty Chat list: - lastAttachmentType from backend (getDmConversations now selects attachmentType) - Shows '🎤 Sprachnachricht' / '📷 Foto' / '📎 Medien' as fallback per type - User search second stage: GET /api/users/search?q= + debounced frontend section - Push preview: audio → '🎤 Sprachnachricht', image → '📷 Foto' (was '📎 Anhang') Blocker iOS Layer 3 (Screen Time): - ScreentimePasscodeCard visible in locked-in state (was hidden once both layers active) - Confirmed status loaded from backend on mount - Numbered step instructions (iOS has no deep link to passcode dialog) - Guard: only for unsupervised VPN+FC path (!mdmManaged && !nefilterActive) - URL fallback: App-Prefs:SCREEN_TIME → App-Prefs:root=SCREEN_TIME → openSettings DiGA Milestone Modal: - Day 3/7/10 celebratory bottom sheet with soft demographic data ask - Per-user/milestone AsyncStorage tracking, never shows if demographics filled - Opens DemographicsAccordion in profile via ?openDemo=1 param Lyra coach: contextual DiGA demographic nudge (optional, positive moments only) i18n: DE/EN/FR/AR for voice_message, photo, media_sent, mic_access, diga_milestone, screentime steps, chat search strings Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
31 lines
842 B
TypeScript
31 lines
842 B
TypeScript
/** GET /api/users/search?q=... — Nickname-Suche für neue DM-Gespräche */
|
|
export default defineEventHandler(async (event) => {
|
|
const user = await requireUser(event);
|
|
const query = getQuery(event);
|
|
const q = ((query.q as string) ?? "").trim();
|
|
|
|
if (!q || q.length < 2) return [];
|
|
|
|
const db = usePrisma();
|
|
|
|
const results = await db.profile.findMany({
|
|
where: {
|
|
id: { not: user.id },
|
|
deletedAt: null,
|
|
OR: [
|
|
{ nickname: { contains: q, mode: "insensitive" } },
|
|
{ username: { contains: q, mode: "insensitive" } },
|
|
],
|
|
},
|
|
select: { id: true, nickname: true, username: true, avatar: true },
|
|
take: 20,
|
|
orderBy: { nickname: "asc" },
|
|
});
|
|
|
|
return results.map((p) => ({
|
|
id: p.id,
|
|
nickname: p.nickname ?? p.username ?? "Anonym",
|
|
avatar: p.avatar ?? null,
|
|
}));
|
|
});
|