Initial commit

This commit is contained in:
2026-06-17 13:51:22 +02:00
commit 4898bf7142
81 changed files with 12522 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
"use client"
import { useState } from "react"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Textarea } from "@/components/ui/textarea"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Send } from "lucide-react"
interface NoteFormProps {
leadId: string
}
export function NoteForm({ leadId }: NoteFormProps) {
const [note, setNote] = useState("")
const [submitting, setSubmitting] = useState(false)
const handleSubmit = () => {
if (!note.trim()) return
setSubmitting(true)
setTimeout(() => {
console.log("Note added:", { leadId, note })
setNote("")
setSubmitting(false)
}, 500)
}
return (
<Card>
<CardHeader>
<CardTitle>Add Note</CardTitle>
</CardHeader>
<CardContent>
<div className="flex gap-4">
<Avatar className="h-10 w-10 shrink-0">
<AvatarImage src="https://ui-avatars.com/api/?name=Sarah+Chen&background=1d4ed8&color=fff&size=64" />
<AvatarFallback>SC</AvatarFallback>
</Avatar>
<div className="flex-1 space-y-3">
<Textarea
placeholder="Write a note about this lead..."
value={note}
onChange={(e) => setNote(e.target.value)}
className="min-h-[100px] resize-none"
/>
<div className="flex justify-end">
<Button
onClick={handleSubmit}
disabled={!note.trim() || submitting}
className="gap-2"
>
<Send className="h-4 w-4" />
{submitting ? "Adding..." : "Add Note"}
</Button>
</div>
</div>
</div>
</CardContent>
</Card>
)
}
+94
View File
@@ -0,0 +1,94 @@
"use client"
import { motion } from "framer-motion"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Note } from "@/types"
import { EmptyState } from "@/components/shared/empty-state"
import { MessageSquare, Edit2, Trash2 } from "lucide-react"
interface NoteTimelineProps {
notes: Note[]
}
export function NoteTimeline({ notes }: NoteTimelineProps) {
if (notes.length === 0) {
return (
<Card>
<CardHeader>
<CardTitle>Notes</CardTitle>
</CardHeader>
<CardContent>
<EmptyState
icon={MessageSquare}
title="No notes yet"
description="Add the first note to this lead."
/>
</CardContent>
</Card>
)
}
return (
<Card>
<CardHeader>
<CardTitle>Notes ({notes.length})</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-0">
{notes.map((note, i) => (
<motion.div
key={note.id}
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: i * 0.05 }}
className="relative flex gap-4 pb-8 last:pb-0"
>
{/* Timeline line */}
{i < notes.length - 1 && (
<div className="absolute left-5 top-12 bottom-0 w-px bg-border" />
)}
{/* Avatar */}
<div className="relative z-10 shrink-0">
<Avatar className="h-10 w-10">
<AvatarImage src={note.authorAvatar} />
<AvatarFallback>{note.authorName[0]}</AvatarFallback>
</Avatar>
</div>
{/* Content */}
<div className="flex-1 space-y-1">
<div className="flex items-center gap-2">
<span className="text-sm font-medium">{note.authorName}</span>
<Badge variant="secondary" className="text-[10px] px-1.5 py-0">
{note.authorRole}
</Badge>
<span className="text-xs text-muted-foreground">
{new Date(note.createdAt).toLocaleDateString(undefined, {
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
})}
</span>
</div>
<p className="text-sm leading-relaxed text-muted-foreground">{note.note}</p>
<div className="flex items-center gap-2 pt-1">
<Button variant="ghost" size="icon" className="h-6 w-6 text-muted-foreground/50 hover:text-muted-foreground">
<Edit2 className="h-3 w-3" />
</Button>
<Button variant="ghost" size="icon" className="h-6 w-6 text-muted-foreground/50 hover:text-destructive">
<Trash2 className="h-3 w-3" />
</Button>
</div>
</div>
</motion.div>
))}
</div>
</CardContent>
</Card>
)
}