Merge branch 'worktree-neo-surveillance-redesign'
This commit is contained in:
@@ -1,31 +1,53 @@
|
||||
"use client";
|
||||
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { MessageCard } from "./message-card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import type { MessageRecord } from "@/lib/types";
|
||||
|
||||
interface MessageListProps {
|
||||
messages: MessageRecord[];
|
||||
selectedId?: string | null;
|
||||
selectedId: string | null;
|
||||
onSelect: (id: string) => void;
|
||||
onReanalyze?: (id: string) => void;
|
||||
hasMore?: boolean;
|
||||
onLoadMore?: () => void;
|
||||
isLoadingMore?: boolean;
|
||||
}
|
||||
|
||||
export function MessageList({ messages, selectedId, onSelect }: MessageListProps) {
|
||||
export function MessageList({
|
||||
messages,
|
||||
selectedId: _selectedId,
|
||||
onSelect,
|
||||
onReanalyze,
|
||||
hasMore,
|
||||
onLoadMore,
|
||||
isLoadingMore,
|
||||
}: MessageListProps) {
|
||||
return (
|
||||
<div className="space-y-1.5 overflow-y-auto max-h-[calc(100vh-200px)] pr-1">
|
||||
{messages.length === 0 ? (
|
||||
<div className="flex items-center justify-center py-12 text-text-secondary/40 text-sm">
|
||||
No messages
|
||||
<>
|
||||
{messages.map((msg) => (
|
||||
<MessageCard
|
||||
key={msg.id}
|
||||
message={msg}
|
||||
onClick={onSelect}
|
||||
onReanalyze={(id) => onReanalyze?.(id)}
|
||||
/>
|
||||
))}
|
||||
{hasMore && (
|
||||
<div className="flex justify-center py-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={onLoadMore}
|
||||
disabled={isLoadingMore}
|
||||
className="text-xs glass"
|
||||
>
|
||||
{isLoadingMore && <Loader2 className="size-3 animate-spin mr-1" />}
|
||||
Load more
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
messages.map((msg) => (
|
||||
<MessageCard
|
||||
key={msg.id}
|
||||
message={msg}
|
||||
selected={selectedId === msg.id}
|
||||
onClick={onSelect}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@ export function SearchOverlay({ open, onClose, onSelect }: SearchOverlayProps) {
|
||||
const [query, setQuery] = useState("");
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const { data: results } = useQuery<{ results: MessageRecord[] }>({
|
||||
const { data: results } = useQuery<MessageRecord[]>({
|
||||
queryKey: ["messages-search", query],
|
||||
queryFn: async () => {
|
||||
const res = await messagesApi.search(query, 20);
|
||||
return res;
|
||||
return res.results;
|
||||
},
|
||||
enabled: query.length >= 2,
|
||||
});
|
||||
@@ -37,7 +37,7 @@ export function SearchOverlay({ open, onClose, onSelect }: SearchOverlayProps) {
|
||||
const handleKey = (e: KeyboardEvent) => {
|
||||
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
|
||||
e.preventDefault();
|
||||
onClose();
|
||||
onClose(); // this is called when Cmd+K is pressed globally — toggle
|
||||
}
|
||||
if (e.key === "Escape") onClose();
|
||||
};
|
||||
@@ -69,12 +69,12 @@ export function SearchOverlay({ open, onClose, onSelect }: SearchOverlayProps) {
|
||||
|
||||
{/* Results */}
|
||||
<div className="max-h-80 overflow-y-auto p-2 space-y-1">
|
||||
{!results || results.results.length === 0 ? (
|
||||
{!results || results.length === 0 ? (
|
||||
<div className="py-8 text-center text-xs text-text-secondary/40">
|
||||
{query.length < 2 ? "Type at least 2 characters" : "No results found"}
|
||||
</div>
|
||||
) : (
|
||||
results.results.map((msg: MessageRecord) => (
|
||||
results.map((msg) => (
|
||||
<button
|
||||
key={msg.id}
|
||||
type="button"
|
||||
|
||||
Reference in New Issue
Block a user