Files
Newbie_CRM/src/app/api/conversations/route.ts
T
JCBSComputer 211d026fb8
Build & Auto-Repair / build (push) Has been cancelled
Add conversation pinning: pinned chats stay at top of sidebar
2026-07-02 16:09:07 +02:00

137 lines
4.8 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server"
import { getSessionUser } from "@/lib/auth"
import { query } from "@/lib/db"
import { avatarSvgUrl } from "@/lib/avatar"
export async function GET() {
try {
const user = await getSessionUser()
if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
const result = await query(
`SELECT
c.id,
c.updated_at,
cp_me.last_read_at,
cp_me.pinned_at,
u.id AS other_user_id,
u.first_name || ' ' || u.last_name AS other_user_name,
u.email AS other_user_email,
u.phone AS other_user_phone,
u.avatar_url AS other_user_avatar_url,
(SELECT content FROM messages WHERE conversation_id = c.id AND deleted_at IS NULL ORDER BY created_at DESC LIMIT 1) AS last_message,
(SELECT created_at FROM messages WHERE conversation_id = c.id AND deleted_at IS NULL ORDER BY created_at DESC LIMIT 1) AS last_message_time,
(SELECT count(*) FROM messages WHERE conversation_id = c.id AND sender_id != $1 AND created_at > COALESCE(cp_me.last_read_at, '1970-01-01')) AS unread
FROM conversations c
JOIN conversation_participants cp_me ON cp_me.conversation_id = c.id AND cp_me.user_id = $1
JOIN conversation_participants cp ON cp.conversation_id = c.id
JOIN users u ON u.id = cp.user_id AND u.id != $1
WHERE c.id IN (
SELECT conversation_id FROM conversation_participants WHERE user_id = $1
)
ORDER BY cp_me.pinned_at DESC NULLS LAST, c.updated_at DESC
LIMIT 50`,
[user.id],
)
const conversations = result.rows.map((row: any) => ({
id: row.id,
updatedAt: row.updated_at,
pinned: row.pinned_at !== null,
otherUser: {
id: row.other_user_id,
name: row.other_user_name,
email: row.other_user_email,
avatar: avatarSvgUrl(row.other_user_name),
},
lastMessage: row.last_message || "",
lastMessageTime: row.last_message_time ? timeAgo(new Date(row.last_message_time)) : "",
unread: parseInt(row.unread) || 0,
}))
return NextResponse.json({ conversations })
} catch (error) {
console.error("Conversations error:", error)
const message = error instanceof Error ? error.message : "Failed to load conversations"
return NextResponse.json({ error: message }, { status: 500 })
}
}
export async function POST(request: NextRequest) {
try {
const user = await getSessionUser()
if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
const { userId } = await request.json()
if (!userId) {
return NextResponse.json({ error: "userId is required" }, { status: 400 })
}
if (userId === user.id) {
return NextResponse.json({ error: "Cannot start a conversation with yourself" }, { status: 400 })
}
const existing = await query(
`SELECT c.id FROM conversations c
JOIN conversation_participants cp1 ON cp1.conversation_id = c.id AND cp1.user_id = $1
JOIN conversation_participants cp2 ON cp2.conversation_id = c.id AND cp2.user_id = $2
LIMIT 1`,
[user.id, userId],
)
if (existing.rows.length > 0) {
return NextResponse.json({ conversationId: existing.rows[0].id })
}
const convResult = await query(
`INSERT INTO conversations DEFAULT VALUES RETURNING id`,
)
const conversationId = convResult.rows[0].id
await query(
`INSERT INTO conversation_participants (conversation_id, user_id, last_read_at) VALUES ($1, $2, NOW()), ($1, $3, NOW())`,
[conversationId, user.id, userId],
)
const otherUser = await query(
`SELECT id, first_name || ' ' || last_name AS name, email, avatar_url
FROM users WHERE id = $1`,
[userId],
)
const other = otherUser.rows[0]
return NextResponse.json({
conversation: {
id: conversationId,
updatedAt: new Date().toISOString(),
otherUser: {
id: other.id,
name: other.name,
email: other.email,
avatar: avatarSvgUrl(other.name),
},
lastMessage: "",
lastMessageTime: "",
unread: 0,
},
})
} catch (error) {
console.error("Create conversation error:", error)
const message = error instanceof Error ? error.message : "Failed to create conversation"
return NextResponse.json({ error: message }, { status: 500 })
}
}
function timeAgo(date: Date): string {
const seconds = Math.floor((Date.now() - date.getTime()) / 1000)
if (seconds < 60) return "now"
const minutes = Math.floor(seconds / 60)
if (minutes < 60) return `${minutes}m ago`
const hours = Math.floor(minutes / 60)
if (hours < 24) return `${hours}h ago`
const days = Math.floor(hours / 24)
if (days < 7) return `${days}d ago`
return date.toLocaleDateString()
}