Add BMAD framework, authentication, and new features
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import { revalidatePath } from 'next/cache'
|
||||
import prisma from '@/lib/prisma'
|
||||
import { Note, CheckItem } from '@/lib/types'
|
||||
import { auth } from '@/auth'
|
||||
|
||||
// Helper function to parse JSON strings from database
|
||||
function parseNote(dbNote: any): Note {
|
||||
@@ -11,14 +12,21 @@ function parseNote(dbNote: any): Note {
|
||||
checkItems: dbNote.checkItems ? JSON.parse(dbNote.checkItems) : null,
|
||||
labels: dbNote.labels ? JSON.parse(dbNote.labels) : null,
|
||||
images: dbNote.images ? JSON.parse(dbNote.images) : null,
|
||||
links: dbNote.links ? JSON.parse(dbNote.links) : null,
|
||||
}
|
||||
}
|
||||
|
||||
// Get all notes (non-archived by default)
|
||||
export async function getNotes(includeArchived = false) {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) return [];
|
||||
|
||||
try {
|
||||
const notes = await prisma.note.findMany({
|
||||
where: includeArchived ? {} : { isArchived: false },
|
||||
where: {
|
||||
userId: session.user.id,
|
||||
isArchived: includeArchived ? {} : { isArchived: false },
|
||||
},
|
||||
orderBy: [
|
||||
{ isPinned: 'desc' },
|
||||
{ order: 'asc' },
|
||||
@@ -35,9 +43,15 @@ export async function getNotes(includeArchived = false) {
|
||||
|
||||
// Get archived notes only
|
||||
export async function getArchivedNotes() {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) return [];
|
||||
|
||||
try {
|
||||
const notes = await prisma.note.findMany({
|
||||
where: { isArchived: true },
|
||||
where: {
|
||||
userId: session.user.id,
|
||||
isArchived: true
|
||||
},
|
||||
orderBy: { updatedAt: 'desc' }
|
||||
})
|
||||
|
||||
@@ -50,6 +64,9 @@ export async function getArchivedNotes() {
|
||||
|
||||
// Search notes
|
||||
export async function searchNotes(query: string) {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) return [];
|
||||
|
||||
try {
|
||||
if (!query.trim()) {
|
||||
return await getNotes()
|
||||
@@ -57,6 +74,7 @@ export async function searchNotes(query: string) {
|
||||
|
||||
const notes = await prisma.note.findMany({
|
||||
where: {
|
||||
userId: session.user.id,
|
||||
isArchived: false,
|
||||
OR: [
|
||||
{ title: { contains: query } },
|
||||
@@ -72,7 +90,7 @@ export async function searchNotes(query: string) {
|
||||
})
|
||||
|
||||
// Enhanced ranking: prioritize title matches
|
||||
const rankedNotes = notes.map(note => {
|
||||
const rankedNotes = notes.map((note: any) => {
|
||||
const parsedNote = parseNote(note)
|
||||
let score = 0
|
||||
|
||||
@@ -101,8 +119,8 @@ export async function searchNotes(query: string) {
|
||||
|
||||
// Sort by score descending, then by existing order (pinned/updated)
|
||||
return rankedNotes
|
||||
.sort((a, b) => b.score - a.score)
|
||||
.map(item => item.note)
|
||||
.sort((a: any, b: any) => b.score - a.score)
|
||||
.map((item: any) => item.note)
|
||||
} catch (error) {
|
||||
console.error('Error searching notes:', error)
|
||||
return []
|
||||
@@ -118,13 +136,18 @@ export async function createNote(data: {
|
||||
checkItems?: CheckItem[]
|
||||
labels?: string[]
|
||||
images?: string[]
|
||||
links?: any[]
|
||||
isArchived?: boolean
|
||||
reminder?: Date | null
|
||||
isMarkdown?: boolean
|
||||
}) {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) throw new Error('Unauthorized');
|
||||
|
||||
try {
|
||||
const note = await prisma.note.create({
|
||||
data: {
|
||||
userId: session.user.id,
|
||||
title: data.title || null,
|
||||
content: data.content,
|
||||
color: data.color || 'default',
|
||||
@@ -132,6 +155,7 @@ export async function createNote(data: {
|
||||
checkItems: data.checkItems ? JSON.stringify(data.checkItems) : null,
|
||||
labels: data.labels ? JSON.stringify(data.labels) : null,
|
||||
images: data.images ? JSON.stringify(data.images) : null,
|
||||
links: data.links ? JSON.stringify(data.links) : null,
|
||||
isArchived: data.isArchived || false,
|
||||
reminder: data.reminder || null,
|
||||
isMarkdown: data.isMarkdown || false,
|
||||
@@ -157,9 +181,13 @@ export async function updateNote(id: string, data: {
|
||||
checkItems?: CheckItem[] | null
|
||||
labels?: string[] | null
|
||||
images?: string[] | null
|
||||
links?: any[] | null
|
||||
reminder?: Date | null
|
||||
isMarkdown?: boolean
|
||||
}) {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) throw new Error('Unauthorized');
|
||||
|
||||
try {
|
||||
// Stringify JSON fields if they exist
|
||||
const updateData: any = { ...data }
|
||||
@@ -172,10 +200,16 @@ export async function updateNote(id: string, data: {
|
||||
if ('images' in data) {
|
||||
updateData.images = data.images ? JSON.stringify(data.images) : null
|
||||
}
|
||||
if ('links' in data) {
|
||||
updateData.links = data.links ? JSON.stringify(data.links) : null
|
||||
}
|
||||
updateData.updatedAt = new Date()
|
||||
|
||||
const note = await prisma.note.update({
|
||||
where: { id },
|
||||
where: {
|
||||
id,
|
||||
userId: session.user.id
|
||||
},
|
||||
data: updateData
|
||||
})
|
||||
|
||||
@@ -189,9 +223,15 @@ export async function updateNote(id: string, data: {
|
||||
|
||||
// Delete a note
|
||||
export async function deleteNote(id: string) {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) throw new Error('Unauthorized');
|
||||
|
||||
try {
|
||||
await prisma.note.delete({
|
||||
where: { id }
|
||||
where: {
|
||||
id,
|
||||
userId: session.user.id
|
||||
}
|
||||
})
|
||||
|
||||
revalidatePath('/')
|
||||
@@ -230,7 +270,7 @@ export async function getAllLabels() {
|
||||
})
|
||||
|
||||
const labelsSet = new Set<string>()
|
||||
notes.forEach(note => {
|
||||
notes.forEach((note: any) => {
|
||||
const labels = note.labels ? JSON.parse(note.labels) : null
|
||||
if (labels) {
|
||||
labels.forEach((label: string) => labelsSet.add(label))
|
||||
@@ -246,11 +286,14 @@ export async function getAllLabels() {
|
||||
|
||||
// Reorder notes (drag and drop)
|
||||
export async function reorderNotes(draggedId: string, targetId: string) {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) throw new Error('Unauthorized');
|
||||
|
||||
console.log('[REORDER-DEBUG] reorderNotes called:', { draggedId, targetId })
|
||||
|
||||
try {
|
||||
const draggedNote = await prisma.note.findUnique({ where: { id: draggedId } })
|
||||
const targetNote = await prisma.note.findUnique({ where: { id: targetId } })
|
||||
const draggedNote = await prisma.note.findUnique({ where: { id: draggedId, userId: session.user.id } })
|
||||
const targetNote = await prisma.note.findUnique({ where: { id: targetId, userId: session.user.id } })
|
||||
|
||||
console.log('[REORDER-DEBUG] Notes found:', {
|
||||
draggedNote: draggedNote ? { id: draggedNote.id, title: draggedNote.title, isPinned: draggedNote.isPinned, order: draggedNote.order } : null,
|
||||
@@ -265,23 +308,24 @@ export async function reorderNotes(draggedId: string, targetId: string) {
|
||||
// Get all notes in the same category (pinned or unpinned)
|
||||
const allNotes = await prisma.note.findMany({
|
||||
where: {
|
||||
userId: session.user.id,
|
||||
isPinned: draggedNote.isPinned,
|
||||
isArchived: false
|
||||
},
|
||||
orderBy: { order: 'asc' }
|
||||
})
|
||||
|
||||
console.log('[REORDER-DEBUG] All notes in category:', allNotes.map(n => ({ id: n.id, title: n.title, order: n.order })))
|
||||
console.log('[REORDER-DEBUG] All notes in category:', allNotes.map((n: any) => ({ id: n.id, title: n.title, order: n.order })))
|
||||
|
||||
// Create new order array
|
||||
const reorderedNotes = allNotes.filter(n => n.id !== draggedId)
|
||||
const targetIndex = reorderedNotes.findIndex(n => n.id === targetId)
|
||||
const reorderedNotes = allNotes.filter((n: any) => n.id !== draggedId)
|
||||
const targetIndex = reorderedNotes.findIndex((n: any) => n.id === targetId)
|
||||
reorderedNotes.splice(targetIndex, 0, draggedNote)
|
||||
|
||||
console.log('[REORDER-DEBUG] New order:', reorderedNotes.map((n, i) => ({ id: n.id, title: n.title, newOrder: i })))
|
||||
console.log('[REORDER-DEBUG] New order:', reorderedNotes.map((n: any, i: number) => ({ id: n.id, title: n.title, newOrder: i })))
|
||||
|
||||
// Update all notes with new order
|
||||
const updates = reorderedNotes.map((note, index) =>
|
||||
const updates = reorderedNotes.map((note: any, index: number) =>
|
||||
prisma.note.update({
|
||||
where: { id: note.id },
|
||||
data: { order: index }
|
||||
@@ -299,3 +343,27 @@ export async function reorderNotes(draggedId: string, targetId: string) {
|
||||
throw new Error('Failed to reorder notes')
|
||||
}
|
||||
}
|
||||
|
||||
// Update full order of notes
|
||||
export async function updateFullOrder(ids: string[]) {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) throw new Error('Unauthorized');
|
||||
|
||||
const userId = session.user.id;
|
||||
|
||||
try {
|
||||
const updates = ids.map((id: string, index: number) =>
|
||||
prisma.note.update({
|
||||
where: { id, userId },
|
||||
data: { order: index }
|
||||
})
|
||||
)
|
||||
|
||||
await prisma.$transaction(updates)
|
||||
revalidatePath('/')
|
||||
return { success: true }
|
||||
} catch (error) {
|
||||
console.error('Error updating full order:', error)
|
||||
throw new Error('Failed to update order')
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user