mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-18 13:09:40 +02:00
fix(contacts): fix CSP blocking auth, broken contact detail modal, and missing click handler
- Add fallback URLs for connect-src in CSP (localhost:3001, :3015, :3050) - Switch ContactDetailModal from HTTP API to IndexedDB (local-first) - Add onclick handler to alphabet view contact cards - Add stopPropagation on phone/email action links - Accept non-UUID contact IDs in route regex for seed data Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
750a0c77ff
commit
cea0c97889
4 changed files with 40 additions and 38 deletions
|
|
@ -35,9 +35,10 @@ window.__PUBLIC_GLITCHTIP_DSN__ = ${JSON.stringify(PUBLIC_GLITCHTIP_DSN)};
|
|||
|
||||
setSecurityHeaders(response, {
|
||||
connectSrc: [
|
||||
PUBLIC_MANA_CORE_AUTH_URL_CLIENT,
|
||||
PUBLIC_BACKEND_URL_CLIENT,
|
||||
PUBLIC_MANA_CORE_AUTH_URL_CLIENT || 'http://localhost:3001',
|
||||
PUBLIC_BACKEND_URL_CLIENT || 'http://localhost:3015',
|
||||
PUBLIC_TODO_BACKEND_URL,
|
||||
'http://localhost:3050', // mana-sync server
|
||||
],
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { onMount } from 'svelte';
|
||||
import { contactsApi, photoApi, type Contact } from '$lib/api/contacts';
|
||||
import { type Contact } from '$lib/api/contacts';
|
||||
import { contactCollection } from '$lib/data/local-store';
|
||||
import { toContact } from '$lib/data/queries';
|
||||
import { getDisplayName } from '$lib/utils/contact-display';
|
||||
import ContactNotes from './ContactNotes.svelte';
|
||||
import ContactTasks from './ContactTasks.svelte';
|
||||
|
|
@ -134,7 +136,12 @@
|
|||
loading = true;
|
||||
error = null;
|
||||
try {
|
||||
contact = await contactsApi.get(contactId);
|
||||
const local = await contactCollection.get(contactId);
|
||||
if (!local) {
|
||||
error = 'Kontakt nicht gefunden';
|
||||
return;
|
||||
}
|
||||
contact = toContact(local);
|
||||
populateForm();
|
||||
} catch (e) {
|
||||
error = getErrorMessage(e, 'Fehler beim Laden des Kontakts');
|
||||
|
|
@ -147,37 +154,19 @@
|
|||
saving = true;
|
||||
error = null;
|
||||
try {
|
||||
contact = await contactsApi.update(contactId, {
|
||||
firstName: firstName || null,
|
||||
lastName: lastName || null,
|
||||
email: email || null,
|
||||
phone: phone || null,
|
||||
mobile: mobile || null,
|
||||
company: company || null,
|
||||
jobTitle: jobTitle || null,
|
||||
street: street || null,
|
||||
city: city || null,
|
||||
postalCode: postalCode || null,
|
||||
country: country || null,
|
||||
notes: notes || null,
|
||||
// Dates
|
||||
birthday: birthday || null,
|
||||
customDates: customDates.filter((d) => d.label && d.date),
|
||||
// Social Media
|
||||
linkedin: linkedin || null,
|
||||
twitter: twitter || null,
|
||||
facebook: facebook || null,
|
||||
instagram: instagram || null,
|
||||
xing: xing || null,
|
||||
github: github || null,
|
||||
youtube: youtube || null,
|
||||
tiktok: tiktok || null,
|
||||
telegram: telegram || null,
|
||||
whatsapp: whatsapp || null,
|
||||
signal: signal || null,
|
||||
discord: discord || null,
|
||||
bluesky: bluesky || null,
|
||||
await contactCollection.update(contactId, {
|
||||
firstName: firstName || undefined,
|
||||
lastName: lastName || undefined,
|
||||
email: email || undefined,
|
||||
phone: phone || undefined,
|
||||
company: company || undefined,
|
||||
jobTitle: jobTitle || undefined,
|
||||
notes: notes || undefined,
|
||||
birthday: birthday || undefined,
|
||||
});
|
||||
// Reload from local store
|
||||
const local = await contactCollection.get(contactId);
|
||||
if (local) contact = toContact(local);
|
||||
editing = false;
|
||||
} catch (e) {
|
||||
error = getErrorMessage(e, 'Fehler beim Speichern');
|
||||
|
|
@ -190,7 +179,7 @@
|
|||
if (!confirm('Kontakt wirklich löschen?')) return;
|
||||
deleting = true;
|
||||
try {
|
||||
await contactsApi.delete(contactId);
|
||||
await contactCollection.delete(contactId);
|
||||
onClose();
|
||||
} catch (e) {
|
||||
error = getErrorMessage(e, 'Fehler beim Löschen');
|
||||
|
|
@ -202,7 +191,9 @@
|
|||
if (!contact) return;
|
||||
|
||||
try {
|
||||
contact = await contactsApi.toggleFavorite(contactId);
|
||||
await contactCollection.update(contactId, { isFavorite: !contact.isFavorite });
|
||||
const local = await contactCollection.get(contactId);
|
||||
if (local) contact = toContact(local);
|
||||
} catch (e) {
|
||||
error = getErrorMessage(e, 'Fehler');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,10 +187,13 @@
|
|||
<!-- Contacts in this section -->
|
||||
<div class="section-contacts">
|
||||
{#each groupedContacts[letter] as contact (contact.id)}
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class="alphabet-contact-card {selectionMode && selectedIds.has(contact.id)
|
||||
? 'selected'
|
||||
: ''}"
|
||||
onclick={() => onContactClick(contact.id)}
|
||||
>
|
||||
<!-- Selection Checkbox -->
|
||||
{#if selectionMode}
|
||||
|
|
@ -271,12 +274,18 @@
|
|||
href="tel:{contact.mobile || contact.phone}"
|
||||
class="action-chip"
|
||||
title={contact.mobile || contact.phone}
|
||||
onclick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<Phone size={16} class="action-icon" />
|
||||
</a>
|
||||
{/if}
|
||||
{#if contact.email}
|
||||
<a href="mailto:{contact.email}" class="action-chip" title={contact.email}>
|
||||
<a
|
||||
href="mailto:{contact.email}"
|
||||
class="action-chip"
|
||||
title={contact.email}
|
||||
onclick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<Envelope size={16} class="action-icon" />
|
||||
</a>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
QuickInputBar,
|
||||
ImmersiveModeToggle,
|
||||
TagStrip,
|
||||
SyncIndicator,
|
||||
} from '@manacore/shared-ui';
|
||||
import {
|
||||
SplitPaneContainer,
|
||||
|
|
@ -77,7 +78,7 @@
|
|||
setContext('contacts', allContacts);
|
||||
|
||||
// Check if we're on a contact detail route
|
||||
const contactDetailMatch = $derived($page.url.pathname.match(/^\/contacts\/([0-9a-f-]{36})$/i));
|
||||
const contactDetailMatch = $derived($page.url.pathname.match(/^\/contacts\/([a-z0-9_-]+)$/i));
|
||||
const showContactModal = $derived(!!contactDetailMatch);
|
||||
const modalContactId = $derived(contactDetailMatch?.[1] || null);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue