From d2e698f08dbf0463e7f0e068b28423f2d9d79319 Mon Sep 17 00:00:00 2001 From: alma Date: Sun, 20 Apr 2025 16:32:53 +0200 Subject: [PATCH] carnet layout --- app/api/nextcloud/files/route.ts | 59 ++++++++++++++ app/carnet/page.tsx | 8 +- components/carnet/notes-view.tsx | 135 ++++++++++++++++++++----------- lib/auth.ts | 32 ++++++++ 4 files changed, 184 insertions(+), 50 deletions(-) create mode 100644 app/api/nextcloud/files/route.ts create mode 100644 lib/auth.ts diff --git a/app/api/nextcloud/files/route.ts b/app/api/nextcloud/files/route.ts new file mode 100644 index 00000000..894a49c6 --- /dev/null +++ b/app/api/nextcloud/files/route.ts @@ -0,0 +1,59 @@ +import { NextResponse } from 'next/server'; +import { getServerSession } from 'next-auth'; +import { PrismaClient } from '@prisma/client'; +import { authOptions } from '@/lib/auth'; +import { WebDAVClient } from 'webdav'; + +// Use a single PrismaClient instance +declare global { + var prisma: PrismaClient | undefined; +} + +const prisma = global.prisma || new PrismaClient(); +if (process.env.NODE_ENV !== 'production') global.prisma = prisma; + +export async function GET(request: Request) { + try { + const session = await getServerSession(authOptions); + if (!session?.user?.email) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + + const { searchParams } = new URL(request.url); + const folder = searchParams.get('folder') || 'Notes'; + + // Get WebDAV credentials + const credentials = await prisma.webDAVCredentials.findUnique({ + where: { userId: session.user.email }, + }); + + if (!credentials) { + return NextResponse.json({ error: 'No WebDAV credentials found' }, { status: 404 }); + } + + // Initialize WebDAV client + const client = new WebDAVClient({ + username: credentials.username, + password: credentials.password, + baseURL: process.env.NEXTCLOUD_URL, + }); + + // List files in the specified folder + const files = await client.getDirectoryContents(`/remote.php/dav/files/${credentials.username}/Private/${folder}`); + + // Filter for .md files and format the response + const markdownFiles = files + .filter((file: any) => file.basename.endsWith('.md')) + .map((file: any) => ({ + id: file.filename, + title: file.basename.replace('.md', ''), + lastModified: new Date(file.lastmod).toISOString(), + size: file.size, + })); + + return NextResponse.json(markdownFiles); + } catch (error) { + console.error('Error fetching files:', error); + return NextResponse.json({ error: 'Failed to fetch files' }, { status: 500 }); + } +} \ No newline at end of file diff --git a/app/carnet/page.tsx b/app/carnet/page.tsx index 8d4ddcf1..4b236791 100644 --- a/app/carnet/page.tsx +++ b/app/carnet/page.tsx @@ -33,6 +33,7 @@ export default function CarnetPage() { const [showNav, setShowNav] = useState(true); const [showNotes, setShowNotes] = useState(true); const [nextcloudFolders, setNextcloudFolders] = useState([]); + const [selectedFolder, setSelectedFolder] = useState('Notes'); // Panel widths state const [navWidth, setNavWidth] = useState(220); @@ -140,7 +141,7 @@ export default function CarnetPage() { const handleFolderSelect = (folder: string) => { console.log('Selected folder:', folder); - // TODO: Implement folder selection logic + setSelectedFolder(folder); setLayoutMode(PaneLayout.ItemSelection); }; @@ -188,7 +189,10 @@ export default function CarnetPage() { className="flex flex-col h-full bg-carnet-bg" style={{ width: `${notesWidth}px` }} > - + {/* Notes Resizer */} diff --git a/components/carnet/notes-view.tsx b/components/carnet/notes-view.tsx index 78d0c806..b2a9de8f 100644 --- a/components/carnet/notes-view.tsx +++ b/components/carnet/notes-view.tsx @@ -1,7 +1,7 @@ "use client"; -import React, { useState } from 'react'; -import { Plus, Search, X } from 'lucide-react'; +import React, { useState, useEffect } from 'react'; +import { Search, Plus, X, FileText, Calendar, Heart, Users } from 'lucide-react'; import { format } from 'date-fns'; import { fr } from 'date-fns/locale'; @@ -16,20 +16,34 @@ interface Note { interface NotesViewProps { onNoteSelect?: (note: Note) => void; + currentFolder?: string; } -export const NotesView: React.FC = ({ onNoteSelect }) => { +export const NotesView: React.FC = ({ onNoteSelect, currentFolder = 'Notes' }) => { const [searchQuery, setSearchQuery] = useState(''); - const [notes, setNotes] = useState([ - { - id: '1', - title: 'Budget and expenses', - content: 'Created with Secure Spreadsheets', - lastEdited: new Date('2022-03-24T19:16:00'), - category: 'Finance', - tags: ['Finance'] - } - ]); + const [notes, setNotes] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const fetchNotes = async () => { + try { + setLoading(true); + const response = await fetch(`/api/nextcloud/files?folder=${currentFolder}`); + if (!response.ok) { + throw new Error('Failed to fetch notes'); + } + const data = await response.json(); + setNotes(data.files || []); + } catch (err) { + console.error('Error fetching notes:', err); + setNotes([]); + } finally { + setLoading(false); + } + }; + + fetchNotes(); + }, [currentFolder]); const handleNewNote = () => { const newNote: Note = { @@ -46,6 +60,23 @@ export const NotesView: React.FC = ({ onNoteSelect }) => { return format(date, 'EEEE d MMM yyyy, HH:mm', { locale: fr }); }; + const getFolderIcon = (folder: string) => { + switch (folder) { + case 'Notes': + return FileText; + case 'Diary': + return Calendar; + case 'Health': + return Heart; + case 'Contacts': + return Users; + default: + return FileText; + } + }; + + const Icon = getFolderIcon(currentFolder); + return (
{/* Search Header */} @@ -55,7 +86,7 @@ export const NotesView: React.FC = ({ onNoteSelect }) => { type="text" value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} - placeholder="Link tags, notes, files..." + placeholder="Rechercher des notes..." className="w-full pl-9 pr-4 py-2 bg-white border border-carnet-border rounded-md text-sm text-carnet-text-primary placeholder-carnet-text-muted focus:outline-none focus:ring-1 focus:ring-primary" /> @@ -70,13 +101,11 @@ export const NotesView: React.FC = ({ onNoteSelect }) => {
- {/* Category Header */} + {/* Folder Header */}
-
- F -
- Finance + + {currentFolder}