diff --git a/app/carnet/page.tsx b/app/carnet/page.tsx index 4b8e1edf..b69defbf 100644 --- a/app/carnet/page.tsx +++ b/app/carnet/page.tsx @@ -11,7 +11,7 @@ import { useMediaQuery } from "@/hooks/use-media-query"; import { ContactsView } from '@/components/carnet/contacts-view'; import { X, Menu } from "lucide-react"; import { ContactDetails } from '@/components/carnet/contact-details'; -import { VCard } from 'vcard-js'; +import { parse as parseVCard, format as formatVCard } from 'vcard-parser'; // Layout modes export enum PaneLayout { @@ -162,24 +162,23 @@ export default function CarnetPage() { } }, [selectedFolder, session?.user?.id]); - const parseVCard = (content: string): Contact[] => { + const parseVCardContent = (content: string): Contact[] => { try { // Split the content into individual vCards const vcards = content.split('BEGIN:VCARD').filter(section => section.trim()); return vcards.map(section => { - const vcard = new VCard(); - vcard.parse('BEGIN:VCARD' + section); + const vcard = parseVCard('BEGIN:VCARD' + section); // Extract contact properties with proper type handling - const uid = vcard.getProperty('UID')?.value; - const fullName = vcard.getProperty('FN')?.value; - const email = vcard.getProperty('EMAIL')?.value; - const phone = vcard.getProperty('TEL')?.value; - const organization = vcard.getProperty('ORG')?.value; - const address = vcard.getProperty('ADR')?.value; - const notes = vcard.getProperty('NOTE')?.value; - const group = vcard.getProperty('CATEGORIES')?.value; + const uid = vcard.uid?.[0]?.value; + const fullName = vcard.fn?.[0]?.value; + const email = vcard.email?.[0]?.value; + const phone = vcard.tel?.[0]?.value; + const organization = vcard.org?.[0]?.value; + const address = vcard.adr?.[0]?.value; + const notes = vcard.note?.[0]?.value; + const group = vcard.categories?.[0]?.value; // Create a clean contact object const contact: Contact = { @@ -210,7 +209,7 @@ export default function CarnetPage() { const response = await fetch(`/api/nextcloud/files/content?path=${encodeURIComponent(`/files/cube-${session?.user?.id}/Private/Contacts/${folder}`)}`); if (response.ok) { const { content } = await response.json(); - const contacts = parseVCard(content); + const contacts = parseVCardContent(content); setContacts(contacts.map(contact => ({ ...contact, group: folder.replace('.vcf', '') @@ -230,7 +229,7 @@ export default function CarnetPage() { const contentResponse = await fetch(`/api/nextcloud/files/content?path=${encodeURIComponent(file.filename)}`); if (contentResponse.ok) { const { content } = await contentResponse.json(); - const contacts = parseVCard(content); + const contacts = parseVCardContent(content); return contacts.map(contact => ({ ...contact, group: file.basename.replace('.vcf', '') @@ -394,7 +393,7 @@ export default function CarnetPage() { } const { content } = await response.json(); - const contacts = parseVCard(content); + const contacts = parseVCardContent(content); // Update or add the contact const existingIndex = contacts.findIndex(c => c.id === contact.id); @@ -405,7 +404,7 @@ export default function CarnetPage() { } // Generate new VCF content - const vcfContent = contacts.map(c => generateVCard(c)).join('\n'); + const vcfContent = contacts.map(c => generateVCardContent(c)).join('\n'); // Save the updated VCF file const saveResponse = await fetch('/api/nextcloud/files', { @@ -455,13 +454,13 @@ export default function CarnetPage() { } const { content } = await response.json(); - const contacts = parseVCard(content); + const contacts = parseVCardContent(content); // Remove the contact const updatedContacts = contacts.filter(c => c.id !== contact.id); // Generate new VCF content - const vcfContent = updatedContacts.map(c => generateVCard(c)).join('\n'); + const vcfContent = updatedContacts.map(c => generateVCardContent(c)).join('\n'); // Save the updated VCF file const saveResponse = await fetch('/api/nextcloud/files', { @@ -492,22 +491,20 @@ export default function CarnetPage() { } }; - const generateVCard = (contact: Contact): string => { - const vcard = new VCard(); - - // Ensure required fields are not undefined - vcard.setProperty('UID', contact.id || Math.random().toString(36).substr(2, 9)); - vcard.setProperty('FN', contact.fullName || 'Unknown Contact'); - - // Add optional fields only if they have values - if (contact.email) vcard.setProperty('EMAIL', contact.email); - if (contact.phone) vcard.setProperty('TEL', contact.phone); - if (contact.organization) vcard.setProperty('ORG', contact.organization); - if (contact.address) vcard.setProperty('ADR', contact.address); - if (contact.notes) vcard.setProperty('NOTE', contact.notes); - if (contact.group) vcard.setProperty('CATEGORIES', contact.group); - - return vcard.toString(); + const generateVCardContent = (contact: Contact): string => { + const vcard = { + version: '3.0', + uid: contact.id, + fn: contact.fullName, + email: contact.email ? [{ value: contact.email }] : undefined, + tel: contact.phone ? [{ value: contact.phone }] : undefined, + org: contact.organization ? [{ value: contact.organization }] : undefined, + adr: contact.address ? [{ value: contact.address }] : undefined, + note: contact.notes ? [{ value: contact.notes }] : undefined, + categories: contact.group ? [{ value: contact.group }] : undefined + }; + + return formatVCard(vcard); }; if (isLoading) {