2026-04-07 13:23:29 -04:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
import * as React from "react";
|
|
|
|
|
import Link from "next/link";
|
|
|
|
|
import {
|
|
|
|
|
Bell,
|
|
|
|
|
CheckCircle2,
|
|
|
|
|
AlertCircle,
|
|
|
|
|
RefreshCw,
|
|
|
|
|
Mail,
|
|
|
|
|
Monitor,
|
|
|
|
|
LayoutGrid,
|
|
|
|
|
Globe,
|
|
|
|
|
Clock,
|
|
|
|
|
CheckCheck,
|
|
|
|
|
} from "lucide-react";
|
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
|
import { Badge } from "@/components/ui/badge";
|
Add dynamic fields, people directory, analytics, security hardening, and UX polish
Phase 1 - Security & Bug Fixes:
- Add requireApiAuth helper and protect all 25 unprotected API routes
- Add org-tenant scoping to all card, job, stats, and notification queries
- Fix SSRF in ai-test, mask secrets in settings API, fix middleware bypass
- Fix cards pagination routing, stat filter sync, drag-drop file passing
- Add PUT /api/auth/me for profile persistence, stuck job recovery
- Fix email watcher MIME type detection
Phase 2 - Dynamic Fields & Digital Survey:
- Add FormTemplate, FormField, Person, PasswordResetToken models to schema
- Add fieldData, formTemplateId, firstName, lastName, personId to ResponseCard
- Build FormTemplate CRUD API with field management and org scoping
- Build Form Builder UI with field ordering, type config, and section management
- Refactor card detail page to render fields dynamically from templates
- Add dynamic OCR prompt/schema generation from template fields
- Build public survey page at /s/[orgSlug]/[formSlug] with branding
- Add QR code generation API and share section component
Phase 3 - People & Analytics:
- Build People CRUD API with merge and batch auto-link endpoints
- Build People list and detail pages with search, merge dialog
- Add auto-link logic in OCR completion to match/create Person records
- Add /api/stats/trends endpoint with time series and team activity
- Build Reports page with Recharts (area charts, bar charts, pipeline)
- Upgrade dashboard with sparklines and People stat card
Phase 4 - UX Polish:
- Replace silent error handling with toast notifications across all pages
- Add loading skeletons, differentiated empty states
- Add ARIA labels, skip-to-content link, accessible column toggle
- Add forgot password flow, Cmd+K command palette, Collection Days pages
- Unify Echo branding and theme toggle consistency
Made-with: Cursor
2026-04-17 00:29:26 -04:00
|
|
|
import { toast } from "sonner";
|
2026-04-07 13:23:29 -04:00
|
|
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
Add dynamic fields, people directory, analytics, security hardening, and UX polish
Phase 1 - Security & Bug Fixes:
- Add requireApiAuth helper and protect all 25 unprotected API routes
- Add org-tenant scoping to all card, job, stats, and notification queries
- Fix SSRF in ai-test, mask secrets in settings API, fix middleware bypass
- Fix cards pagination routing, stat filter sync, drag-drop file passing
- Add PUT /api/auth/me for profile persistence, stuck job recovery
- Fix email watcher MIME type detection
Phase 2 - Dynamic Fields & Digital Survey:
- Add FormTemplate, FormField, Person, PasswordResetToken models to schema
- Add fieldData, formTemplateId, firstName, lastName, personId to ResponseCard
- Build FormTemplate CRUD API with field management and org scoping
- Build Form Builder UI with field ordering, type config, and section management
- Refactor card detail page to render fields dynamically from templates
- Add dynamic OCR prompt/schema generation from template fields
- Build public survey page at /s/[orgSlug]/[formSlug] with branding
- Add QR code generation API and share section component
Phase 3 - People & Analytics:
- Build People CRUD API with merge and batch auto-link endpoints
- Build People list and detail pages with search, merge dialog
- Add auto-link logic in OCR completion to match/create Person records
- Add /api/stats/trends endpoint with time series and team activity
- Build Reports page with Recharts (area charts, bar charts, pipeline)
- Upgrade dashboard with sparklines and People stat card
Phase 4 - UX Polish:
- Replace silent error handling with toast notifications across all pages
- Add loading skeletons, differentiated empty states
- Add ARIA labels, skip-to-content link, accessible column toggle
- Add forgot password flow, Cmd+K command palette, Collection Days pages
- Unify Echo branding and theme toggle consistency
Made-with: Cursor
2026-04-17 00:29:26 -04:00
|
|
|
import { Skeleton } from "@/components/ui/skeleton";
|
2026-04-07 13:23:29 -04:00
|
|
|
import { cn } from "@/lib/utils";
|
|
|
|
|
|
|
|
|
|
type Notification = {
|
|
|
|
|
id: string;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
read: boolean;
|
|
|
|
|
type: string;
|
|
|
|
|
title: string;
|
|
|
|
|
message: string;
|
|
|
|
|
cardId: string | null;
|
|
|
|
|
actionUrl: string | null;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export function NotificationCenter() {
|
|
|
|
|
const [open, setOpen] = React.useState(false);
|
|
|
|
|
const [notifications, setNotifications] = React.useState<Notification[]>([]);
|
|
|
|
|
const [unreadCount, setUnreadCount] = React.useState(0);
|
Add dynamic fields, people directory, analytics, security hardening, and UX polish
Phase 1 - Security & Bug Fixes:
- Add requireApiAuth helper and protect all 25 unprotected API routes
- Add org-tenant scoping to all card, job, stats, and notification queries
- Fix SSRF in ai-test, mask secrets in settings API, fix middleware bypass
- Fix cards pagination routing, stat filter sync, drag-drop file passing
- Add PUT /api/auth/me for profile persistence, stuck job recovery
- Fix email watcher MIME type detection
Phase 2 - Dynamic Fields & Digital Survey:
- Add FormTemplate, FormField, Person, PasswordResetToken models to schema
- Add fieldData, formTemplateId, firstName, lastName, personId to ResponseCard
- Build FormTemplate CRUD API with field management and org scoping
- Build Form Builder UI with field ordering, type config, and section management
- Refactor card detail page to render fields dynamically from templates
- Add dynamic OCR prompt/schema generation from template fields
- Build public survey page at /s/[orgSlug]/[formSlug] with branding
- Add QR code generation API and share section component
Phase 3 - People & Analytics:
- Build People CRUD API with merge and batch auto-link endpoints
- Build People list and detail pages with search, merge dialog
- Add auto-link logic in OCR completion to match/create Person records
- Add /api/stats/trends endpoint with time series and team activity
- Build Reports page with Recharts (area charts, bar charts, pipeline)
- Upgrade dashboard with sparklines and People stat card
Phase 4 - UX Polish:
- Replace silent error handling with toast notifications across all pages
- Add loading skeletons, differentiated empty states
- Add ARIA labels, skip-to-content link, accessible column toggle
- Add forgot password flow, Cmd+K command palette, Collection Days pages
- Unify Echo branding and theme toggle consistency
Made-with: Cursor
2026-04-17 00:29:26 -04:00
|
|
|
const [listLoading, setListLoading] = React.useState(false);
|
2026-04-07 13:23:29 -04:00
|
|
|
|
|
|
|
|
const fetchUnreadCount = React.useCallback(async () => {
|
|
|
|
|
try {
|
|
|
|
|
const res = await fetch("/api/notifications?unreadOnly=true&limit=1");
|
|
|
|
|
if (res.ok) {
|
|
|
|
|
const data = await res.json();
|
|
|
|
|
setUnreadCount(data.unreadCount ?? 0);
|
|
|
|
|
}
|
Add dynamic fields, people directory, analytics, security hardening, and UX polish
Phase 1 - Security & Bug Fixes:
- Add requireApiAuth helper and protect all 25 unprotected API routes
- Add org-tenant scoping to all card, job, stats, and notification queries
- Fix SSRF in ai-test, mask secrets in settings API, fix middleware bypass
- Fix cards pagination routing, stat filter sync, drag-drop file passing
- Add PUT /api/auth/me for profile persistence, stuck job recovery
- Fix email watcher MIME type detection
Phase 2 - Dynamic Fields & Digital Survey:
- Add FormTemplate, FormField, Person, PasswordResetToken models to schema
- Add fieldData, formTemplateId, firstName, lastName, personId to ResponseCard
- Build FormTemplate CRUD API with field management and org scoping
- Build Form Builder UI with field ordering, type config, and section management
- Refactor card detail page to render fields dynamically from templates
- Add dynamic OCR prompt/schema generation from template fields
- Build public survey page at /s/[orgSlug]/[formSlug] with branding
- Add QR code generation API and share section component
Phase 3 - People & Analytics:
- Build People CRUD API with merge and batch auto-link endpoints
- Build People list and detail pages with search, merge dialog
- Add auto-link logic in OCR completion to match/create Person records
- Add /api/stats/trends endpoint with time series and team activity
- Build Reports page with Recharts (area charts, bar charts, pipeline)
- Upgrade dashboard with sparklines and People stat card
Phase 4 - UX Polish:
- Replace silent error handling with toast notifications across all pages
- Add loading skeletons, differentiated empty states
- Add ARIA labels, skip-to-content link, accessible column toggle
- Add forgot password flow, Cmd+K command palette, Collection Days pages
- Unify Echo branding and theme toggle consistency
Made-with: Cursor
2026-04-17 00:29:26 -04:00
|
|
|
} catch {
|
|
|
|
|
// Polling failure — don't toast on every interval tick
|
|
|
|
|
}
|
2026-04-07 13:23:29 -04:00
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
React.useEffect(() => {
|
|
|
|
|
fetchUnreadCount();
|
|
|
|
|
const interval = setInterval(fetchUnreadCount, 30_000);
|
|
|
|
|
return () => clearInterval(interval);
|
|
|
|
|
}, [fetchUnreadCount]);
|
|
|
|
|
|
|
|
|
|
const fetchNotifications = React.useCallback(async () => {
|
Add dynamic fields, people directory, analytics, security hardening, and UX polish
Phase 1 - Security & Bug Fixes:
- Add requireApiAuth helper and protect all 25 unprotected API routes
- Add org-tenant scoping to all card, job, stats, and notification queries
- Fix SSRF in ai-test, mask secrets in settings API, fix middleware bypass
- Fix cards pagination routing, stat filter sync, drag-drop file passing
- Add PUT /api/auth/me for profile persistence, stuck job recovery
- Fix email watcher MIME type detection
Phase 2 - Dynamic Fields & Digital Survey:
- Add FormTemplate, FormField, Person, PasswordResetToken models to schema
- Add fieldData, formTemplateId, firstName, lastName, personId to ResponseCard
- Build FormTemplate CRUD API with field management and org scoping
- Build Form Builder UI with field ordering, type config, and section management
- Refactor card detail page to render fields dynamically from templates
- Add dynamic OCR prompt/schema generation from template fields
- Build public survey page at /s/[orgSlug]/[formSlug] with branding
- Add QR code generation API and share section component
Phase 3 - People & Analytics:
- Build People CRUD API with merge and batch auto-link endpoints
- Build People list and detail pages with search, merge dialog
- Add auto-link logic in OCR completion to match/create Person records
- Add /api/stats/trends endpoint with time series and team activity
- Build Reports page with Recharts (area charts, bar charts, pipeline)
- Upgrade dashboard with sparklines and People stat card
Phase 4 - UX Polish:
- Replace silent error handling with toast notifications across all pages
- Add loading skeletons, differentiated empty states
- Add ARIA labels, skip-to-content link, accessible column toggle
- Add forgot password flow, Cmd+K command palette, Collection Days pages
- Unify Echo branding and theme toggle consistency
Made-with: Cursor
2026-04-17 00:29:26 -04:00
|
|
|
setListLoading(true);
|
2026-04-07 13:23:29 -04:00
|
|
|
try {
|
|
|
|
|
const res = await fetch("/api/notifications?limit=30");
|
|
|
|
|
if (res.ok) {
|
|
|
|
|
const data = await res.json();
|
|
|
|
|
setNotifications(data.notifications ?? []);
|
|
|
|
|
setUnreadCount(data.unreadCount ?? 0);
|
|
|
|
|
}
|
Add dynamic fields, people directory, analytics, security hardening, and UX polish
Phase 1 - Security & Bug Fixes:
- Add requireApiAuth helper and protect all 25 unprotected API routes
- Add org-tenant scoping to all card, job, stats, and notification queries
- Fix SSRF in ai-test, mask secrets in settings API, fix middleware bypass
- Fix cards pagination routing, stat filter sync, drag-drop file passing
- Add PUT /api/auth/me for profile persistence, stuck job recovery
- Fix email watcher MIME type detection
Phase 2 - Dynamic Fields & Digital Survey:
- Add FormTemplate, FormField, Person, PasswordResetToken models to schema
- Add fieldData, formTemplateId, firstName, lastName, personId to ResponseCard
- Build FormTemplate CRUD API with field management and org scoping
- Build Form Builder UI with field ordering, type config, and section management
- Refactor card detail page to render fields dynamically from templates
- Add dynamic OCR prompt/schema generation from template fields
- Build public survey page at /s/[orgSlug]/[formSlug] with branding
- Add QR code generation API and share section component
Phase 3 - People & Analytics:
- Build People CRUD API with merge and batch auto-link endpoints
- Build People list and detail pages with search, merge dialog
- Add auto-link logic in OCR completion to match/create Person records
- Add /api/stats/trends endpoint with time series and team activity
- Build Reports page with Recharts (area charts, bar charts, pipeline)
- Upgrade dashboard with sparklines and People stat card
Phase 4 - UX Polish:
- Replace silent error handling with toast notifications across all pages
- Add loading skeletons, differentiated empty states
- Add ARIA labels, skip-to-content link, accessible column toggle
- Add forgot password flow, Cmd+K command palette, Collection Days pages
- Unify Echo branding and theme toggle consistency
Made-with: Cursor
2026-04-17 00:29:26 -04:00
|
|
|
} catch {
|
|
|
|
|
toast.error("Failed to load notifications");
|
|
|
|
|
} finally {
|
|
|
|
|
setListLoading(false);
|
|
|
|
|
}
|
2026-04-07 13:23:29 -04:00
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
React.useEffect(() => {
|
|
|
|
|
if (open) fetchNotifications();
|
|
|
|
|
}, [open, fetchNotifications]);
|
|
|
|
|
|
|
|
|
|
const markAllRead = async () => {
|
|
|
|
|
try {
|
|
|
|
|
await fetch("/api/notifications", {
|
|
|
|
|
method: "PUT",
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
body: JSON.stringify({ action: "mark_all_read" }),
|
|
|
|
|
});
|
|
|
|
|
setNotifications((prev) => prev.map((n) => ({ ...n, read: true })));
|
|
|
|
|
setUnreadCount(0);
|
Add dynamic fields, people directory, analytics, security hardening, and UX polish
Phase 1 - Security & Bug Fixes:
- Add requireApiAuth helper and protect all 25 unprotected API routes
- Add org-tenant scoping to all card, job, stats, and notification queries
- Fix SSRF in ai-test, mask secrets in settings API, fix middleware bypass
- Fix cards pagination routing, stat filter sync, drag-drop file passing
- Add PUT /api/auth/me for profile persistence, stuck job recovery
- Fix email watcher MIME type detection
Phase 2 - Dynamic Fields & Digital Survey:
- Add FormTemplate, FormField, Person, PasswordResetToken models to schema
- Add fieldData, formTemplateId, firstName, lastName, personId to ResponseCard
- Build FormTemplate CRUD API with field management and org scoping
- Build Form Builder UI with field ordering, type config, and section management
- Refactor card detail page to render fields dynamically from templates
- Add dynamic OCR prompt/schema generation from template fields
- Build public survey page at /s/[orgSlug]/[formSlug] with branding
- Add QR code generation API and share section component
Phase 3 - People & Analytics:
- Build People CRUD API with merge and batch auto-link endpoints
- Build People list and detail pages with search, merge dialog
- Add auto-link logic in OCR completion to match/create Person records
- Add /api/stats/trends endpoint with time series and team activity
- Build Reports page with Recharts (area charts, bar charts, pipeline)
- Upgrade dashboard with sparklines and People stat card
Phase 4 - UX Polish:
- Replace silent error handling with toast notifications across all pages
- Add loading skeletons, differentiated empty states
- Add ARIA labels, skip-to-content link, accessible column toggle
- Add forgot password flow, Cmd+K command palette, Collection Days pages
- Unify Echo branding and theme toggle consistency
Made-with: Cursor
2026-04-17 00:29:26 -04:00
|
|
|
} catch {
|
|
|
|
|
toast.error("Failed to mark notifications as read");
|
|
|
|
|
}
|
2026-04-07 13:23:29 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const markRead = async (id: string) => {
|
|
|
|
|
try {
|
|
|
|
|
await fetch("/api/notifications", {
|
|
|
|
|
method: "PUT",
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
body: JSON.stringify({ action: "mark_read", id }),
|
|
|
|
|
});
|
|
|
|
|
setNotifications((prev) => prev.map((n) => n.id === id ? { ...n, read: true } : n));
|
|
|
|
|
setUnreadCount((c) => Math.max(0, c - 1));
|
Add dynamic fields, people directory, analytics, security hardening, and UX polish
Phase 1 - Security & Bug Fixes:
- Add requireApiAuth helper and protect all 25 unprotected API routes
- Add org-tenant scoping to all card, job, stats, and notification queries
- Fix SSRF in ai-test, mask secrets in settings API, fix middleware bypass
- Fix cards pagination routing, stat filter sync, drag-drop file passing
- Add PUT /api/auth/me for profile persistence, stuck job recovery
- Fix email watcher MIME type detection
Phase 2 - Dynamic Fields & Digital Survey:
- Add FormTemplate, FormField, Person, PasswordResetToken models to schema
- Add fieldData, formTemplateId, firstName, lastName, personId to ResponseCard
- Build FormTemplate CRUD API with field management and org scoping
- Build Form Builder UI with field ordering, type config, and section management
- Refactor card detail page to render fields dynamically from templates
- Add dynamic OCR prompt/schema generation from template fields
- Build public survey page at /s/[orgSlug]/[formSlug] with branding
- Add QR code generation API and share section component
Phase 3 - People & Analytics:
- Build People CRUD API with merge and batch auto-link endpoints
- Build People list and detail pages with search, merge dialog
- Add auto-link logic in OCR completion to match/create Person records
- Add /api/stats/trends endpoint with time series and team activity
- Build Reports page with Recharts (area charts, bar charts, pipeline)
- Upgrade dashboard with sparklines and People stat card
Phase 4 - UX Polish:
- Replace silent error handling with toast notifications across all pages
- Add loading skeletons, differentiated empty states
- Add ARIA labels, skip-to-content link, accessible column toggle
- Add forgot password flow, Cmd+K command palette, Collection Days pages
- Unify Echo branding and theme toggle consistency
Made-with: Cursor
2026-04-17 00:29:26 -04:00
|
|
|
} catch {
|
|
|
|
|
toast.error("Failed to update notification");
|
|
|
|
|
}
|
2026-04-07 13:23:29 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Popover open={open} onOpenChange={setOpen}>
|
|
|
|
|
<PopoverTrigger
|
|
|
|
|
render={
|
|
|
|
|
<Button variant="ghost" size="icon" className="relative size-9 rounded-xl" />
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<Bell className="size-4" />
|
|
|
|
|
{unreadCount > 0 && (
|
|
|
|
|
<span className="absolute -right-0.5 -top-0.5 flex size-4.5 items-center justify-center rounded-full bg-red-500 text-[10px] font-bold text-white">
|
|
|
|
|
{unreadCount > 9 ? "9+" : unreadCount}
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
<span className="sr-only">Notifications</span>
|
|
|
|
|
</PopoverTrigger>
|
|
|
|
|
<PopoverContent align="end" sideOffset={8} className="w-80 p-0">
|
|
|
|
|
<div className="flex items-center justify-between border-b border-border/50 px-3 py-2.5">
|
|
|
|
|
<span className="text-sm font-medium">Notifications</span>
|
|
|
|
|
{unreadCount > 0 && (
|
|
|
|
|
<Button variant="ghost" size="sm" className="h-7 text-xs px-2" onClick={markAllRead}>
|
|
|
|
|
<CheckCheck className="mr-1 size-3" /> Mark all read
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
<div className="max-h-80 overflow-y-auto">
|
Add dynamic fields, people directory, analytics, security hardening, and UX polish
Phase 1 - Security & Bug Fixes:
- Add requireApiAuth helper and protect all 25 unprotected API routes
- Add org-tenant scoping to all card, job, stats, and notification queries
- Fix SSRF in ai-test, mask secrets in settings API, fix middleware bypass
- Fix cards pagination routing, stat filter sync, drag-drop file passing
- Add PUT /api/auth/me for profile persistence, stuck job recovery
- Fix email watcher MIME type detection
Phase 2 - Dynamic Fields & Digital Survey:
- Add FormTemplate, FormField, Person, PasswordResetToken models to schema
- Add fieldData, formTemplateId, firstName, lastName, personId to ResponseCard
- Build FormTemplate CRUD API with field management and org scoping
- Build Form Builder UI with field ordering, type config, and section management
- Refactor card detail page to render fields dynamically from templates
- Add dynamic OCR prompt/schema generation from template fields
- Build public survey page at /s/[orgSlug]/[formSlug] with branding
- Add QR code generation API and share section component
Phase 3 - People & Analytics:
- Build People CRUD API with merge and batch auto-link endpoints
- Build People list and detail pages with search, merge dialog
- Add auto-link logic in OCR completion to match/create Person records
- Add /api/stats/trends endpoint with time series and team activity
- Build Reports page with Recharts (area charts, bar charts, pipeline)
- Upgrade dashboard with sparklines and People stat card
Phase 4 - UX Polish:
- Replace silent error handling with toast notifications across all pages
- Add loading skeletons, differentiated empty states
- Add ARIA labels, skip-to-content link, accessible column toggle
- Add forgot password flow, Cmd+K command palette, Collection Days pages
- Unify Echo branding and theme toggle consistency
Made-with: Cursor
2026-04-17 00:29:26 -04:00
|
|
|
{listLoading ? (
|
|
|
|
|
<div className="space-y-1 p-3">
|
|
|
|
|
{Array.from({ length: 4 }).map((_, i) => (
|
|
|
|
|
<div key={i} className="flex gap-3 py-2">
|
|
|
|
|
<Skeleton className="size-7 shrink-0 rounded-full" />
|
|
|
|
|
<div className="flex-1 space-y-1.5">
|
|
|
|
|
<Skeleton className="h-3 w-3/4 rounded" />
|
|
|
|
|
<Skeleton className="h-3 w-1/2 rounded" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
) : notifications.length === 0 ? (
|
2026-04-07 13:23:29 -04:00
|
|
|
<div className="flex flex-col items-center justify-center py-10 text-muted-foreground">
|
|
|
|
|
<Bell className="size-8 mb-2 opacity-20" />
|
|
|
|
|
<p className="text-sm">No notifications</p>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
notifications.map((n) => (
|
|
|
|
|
<NotificationItem key={n.id} notification={n} onRead={markRead} onClose={() => setOpen(false)} />
|
|
|
|
|
))
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</PopoverContent>
|
|
|
|
|
</Popover>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function NotificationItem({
|
|
|
|
|
notification: n,
|
|
|
|
|
onRead,
|
|
|
|
|
onClose,
|
|
|
|
|
}: {
|
|
|
|
|
notification: Notification;
|
|
|
|
|
onRead: (id: string) => void;
|
|
|
|
|
onClose: () => void;
|
|
|
|
|
}) {
|
|
|
|
|
const iconMap: Record<string, { icon: React.ReactNode; color: string }> = {
|
|
|
|
|
ocr_complete: { icon: <CheckCircle2 className="size-3.5" />, color: "text-emerald-600 bg-emerald-500/10" },
|
|
|
|
|
ocr_error: { icon: <AlertCircle className="size-3.5" />, color: "text-red-600 bg-red-500/10" },
|
|
|
|
|
card_needs_review: { icon: <RefreshCw className="size-3.5" />, color: "text-amber-600 bg-amber-500/10" },
|
|
|
|
|
monday_sync: { icon: <LayoutGrid className="size-3.5" />, color: "text-blue-600 bg-blue-500/10" },
|
|
|
|
|
monday_error: { icon: <LayoutGrid className="size-3.5" />, color: "text-red-600 bg-red-500/10" },
|
|
|
|
|
webhook_error: { icon: <Globe className="size-3.5" />, color: "text-red-600 bg-red-500/10" },
|
|
|
|
|
email_watcher: { icon: <Mail className="size-3.5" />, color: "text-purple-600 bg-purple-500/10" },
|
|
|
|
|
system: { icon: <Monitor className="size-3.5" />, color: "text-muted-foreground bg-muted" },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const { icon, color } = iconMap[n.type] ?? iconMap.system;
|
|
|
|
|
|
|
|
|
|
const handleClick = () => {
|
|
|
|
|
if (!n.read) onRead(n.id);
|
|
|
|
|
if (n.actionUrl) onClose();
|
|
|
|
|
};
|
|
|
|
|
|
Add dynamic fields, people directory, analytics, security hardening, and UX polish
Phase 1 - Security & Bug Fixes:
- Add requireApiAuth helper and protect all 25 unprotected API routes
- Add org-tenant scoping to all card, job, stats, and notification queries
- Fix SSRF in ai-test, mask secrets in settings API, fix middleware bypass
- Fix cards pagination routing, stat filter sync, drag-drop file passing
- Add PUT /api/auth/me for profile persistence, stuck job recovery
- Fix email watcher MIME type detection
Phase 2 - Dynamic Fields & Digital Survey:
- Add FormTemplate, FormField, Person, PasswordResetToken models to schema
- Add fieldData, formTemplateId, firstName, lastName, personId to ResponseCard
- Build FormTemplate CRUD API with field management and org scoping
- Build Form Builder UI with field ordering, type config, and section management
- Refactor card detail page to render fields dynamically from templates
- Add dynamic OCR prompt/schema generation from template fields
- Build public survey page at /s/[orgSlug]/[formSlug] with branding
- Add QR code generation API and share section component
Phase 3 - People & Analytics:
- Build People CRUD API with merge and batch auto-link endpoints
- Build People list and detail pages with search, merge dialog
- Add auto-link logic in OCR completion to match/create Person records
- Add /api/stats/trends endpoint with time series and team activity
- Build Reports page with Recharts (area charts, bar charts, pipeline)
- Upgrade dashboard with sparklines and People stat card
Phase 4 - UX Polish:
- Replace silent error handling with toast notifications across all pages
- Add loading skeletons, differentiated empty states
- Add ARIA labels, skip-to-content link, accessible column toggle
- Add forgot password flow, Cmd+K command palette, Collection Days pages
- Unify Echo branding and theme toggle consistency
Made-with: Cursor
2026-04-17 00:29:26 -04:00
|
|
|
const inner = (
|
|
|
|
|
<>
|
2026-04-07 13:23:29 -04:00
|
|
|
<div className={cn("flex size-7 shrink-0 items-center justify-center rounded-full mt-0.5", color)}>
|
|
|
|
|
{icon}
|
|
|
|
|
</div>
|
Add dynamic fields, people directory, analytics, security hardening, and UX polish
Phase 1 - Security & Bug Fixes:
- Add requireApiAuth helper and protect all 25 unprotected API routes
- Add org-tenant scoping to all card, job, stats, and notification queries
- Fix SSRF in ai-test, mask secrets in settings API, fix middleware bypass
- Fix cards pagination routing, stat filter sync, drag-drop file passing
- Add PUT /api/auth/me for profile persistence, stuck job recovery
- Fix email watcher MIME type detection
Phase 2 - Dynamic Fields & Digital Survey:
- Add FormTemplate, FormField, Person, PasswordResetToken models to schema
- Add fieldData, formTemplateId, firstName, lastName, personId to ResponseCard
- Build FormTemplate CRUD API with field management and org scoping
- Build Form Builder UI with field ordering, type config, and section management
- Refactor card detail page to render fields dynamically from templates
- Add dynamic OCR prompt/schema generation from template fields
- Build public survey page at /s/[orgSlug]/[formSlug] with branding
- Add QR code generation API and share section component
Phase 3 - People & Analytics:
- Build People CRUD API with merge and batch auto-link endpoints
- Build People list and detail pages with search, merge dialog
- Add auto-link logic in OCR completion to match/create Person records
- Add /api/stats/trends endpoint with time series and team activity
- Build Reports page with Recharts (area charts, bar charts, pipeline)
- Upgrade dashboard with sparklines and People stat card
Phase 4 - UX Polish:
- Replace silent error handling with toast notifications across all pages
- Add loading skeletons, differentiated empty states
- Add ARIA labels, skip-to-content link, accessible column toggle
- Add forgot password flow, Cmd+K command palette, Collection Days pages
- Unify Echo branding and theme toggle consistency
Made-with: Cursor
2026-04-17 00:29:26 -04:00
|
|
|
<div className="min-w-0 flex-1 text-left">
|
2026-04-07 13:23:29 -04:00
|
|
|
<div className="flex items-center gap-1.5">
|
|
|
|
|
<span className={cn("text-xs font-medium truncate", !n.read && "text-foreground")}>{n.title}</span>
|
|
|
|
|
{!n.read && <span className="size-1.5 shrink-0 rounded-full bg-primary" />}
|
|
|
|
|
</div>
|
|
|
|
|
<p className="text-xs text-muted-foreground line-clamp-2 mt-0.5">{n.message}</p>
|
|
|
|
|
<span className="text-[10px] text-muted-foreground/70 flex items-center gap-1 mt-1">
|
|
|
|
|
<Clock className="size-2.5" />
|
|
|
|
|
{formatTimeAgo(n.createdAt)}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
Add dynamic fields, people directory, analytics, security hardening, and UX polish
Phase 1 - Security & Bug Fixes:
- Add requireApiAuth helper and protect all 25 unprotected API routes
- Add org-tenant scoping to all card, job, stats, and notification queries
- Fix SSRF in ai-test, mask secrets in settings API, fix middleware bypass
- Fix cards pagination routing, stat filter sync, drag-drop file passing
- Add PUT /api/auth/me for profile persistence, stuck job recovery
- Fix email watcher MIME type detection
Phase 2 - Dynamic Fields & Digital Survey:
- Add FormTemplate, FormField, Person, PasswordResetToken models to schema
- Add fieldData, formTemplateId, firstName, lastName, personId to ResponseCard
- Build FormTemplate CRUD API with field management and org scoping
- Build Form Builder UI with field ordering, type config, and section management
- Refactor card detail page to render fields dynamically from templates
- Add dynamic OCR prompt/schema generation from template fields
- Build public survey page at /s/[orgSlug]/[formSlug] with branding
- Add QR code generation API and share section component
Phase 3 - People & Analytics:
- Build People CRUD API with merge and batch auto-link endpoints
- Build People list and detail pages with search, merge dialog
- Add auto-link logic in OCR completion to match/create Person records
- Add /api/stats/trends endpoint with time series and team activity
- Build Reports page with Recharts (area charts, bar charts, pipeline)
- Upgrade dashboard with sparklines and People stat card
Phase 4 - UX Polish:
- Replace silent error handling with toast notifications across all pages
- Add loading skeletons, differentiated empty states
- Add ARIA labels, skip-to-content link, accessible column toggle
- Add forgot password flow, Cmd+K command palette, Collection Days pages
- Unify Echo branding and theme toggle consistency
Made-with: Cursor
2026-04-17 00:29:26 -04:00
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const sharedClasses = cn(
|
|
|
|
|
"flex w-full gap-3 px-3 py-2.5 border-b border-border/30 transition-colors hover:bg-muted/50 cursor-pointer",
|
|
|
|
|
!n.read && "bg-primary/[0.03]"
|
2026-04-07 13:23:29 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (n.actionUrl) {
|
Add dynamic fields, people directory, analytics, security hardening, and UX polish
Phase 1 - Security & Bug Fixes:
- Add requireApiAuth helper and protect all 25 unprotected API routes
- Add org-tenant scoping to all card, job, stats, and notification queries
- Fix SSRF in ai-test, mask secrets in settings API, fix middleware bypass
- Fix cards pagination routing, stat filter sync, drag-drop file passing
- Add PUT /api/auth/me for profile persistence, stuck job recovery
- Fix email watcher MIME type detection
Phase 2 - Dynamic Fields & Digital Survey:
- Add FormTemplate, FormField, Person, PasswordResetToken models to schema
- Add fieldData, formTemplateId, firstName, lastName, personId to ResponseCard
- Build FormTemplate CRUD API with field management and org scoping
- Build Form Builder UI with field ordering, type config, and section management
- Refactor card detail page to render fields dynamically from templates
- Add dynamic OCR prompt/schema generation from template fields
- Build public survey page at /s/[orgSlug]/[formSlug] with branding
- Add QR code generation API and share section component
Phase 3 - People & Analytics:
- Build People CRUD API with merge and batch auto-link endpoints
- Build People list and detail pages with search, merge dialog
- Add auto-link logic in OCR completion to match/create Person records
- Add /api/stats/trends endpoint with time series and team activity
- Build Reports page with Recharts (area charts, bar charts, pipeline)
- Upgrade dashboard with sparklines and People stat card
Phase 4 - UX Polish:
- Replace silent error handling with toast notifications across all pages
- Add loading skeletons, differentiated empty states
- Add ARIA labels, skip-to-content link, accessible column toggle
- Add forgot password flow, Cmd+K command palette, Collection Days pages
- Unify Echo branding and theme toggle consistency
Made-with: Cursor
2026-04-17 00:29:26 -04:00
|
|
|
return (
|
|
|
|
|
<Link href={n.actionUrl} className={sharedClasses} onClick={handleClick}>
|
|
|
|
|
{inner}
|
|
|
|
|
</Link>
|
|
|
|
|
);
|
2026-04-07 13:23:29 -04:00
|
|
|
}
|
Add dynamic fields, people directory, analytics, security hardening, and UX polish
Phase 1 - Security & Bug Fixes:
- Add requireApiAuth helper and protect all 25 unprotected API routes
- Add org-tenant scoping to all card, job, stats, and notification queries
- Fix SSRF in ai-test, mask secrets in settings API, fix middleware bypass
- Fix cards pagination routing, stat filter sync, drag-drop file passing
- Add PUT /api/auth/me for profile persistence, stuck job recovery
- Fix email watcher MIME type detection
Phase 2 - Dynamic Fields & Digital Survey:
- Add FormTemplate, FormField, Person, PasswordResetToken models to schema
- Add fieldData, formTemplateId, firstName, lastName, personId to ResponseCard
- Build FormTemplate CRUD API with field management and org scoping
- Build Form Builder UI with field ordering, type config, and section management
- Refactor card detail page to render fields dynamically from templates
- Add dynamic OCR prompt/schema generation from template fields
- Build public survey page at /s/[orgSlug]/[formSlug] with branding
- Add QR code generation API and share section component
Phase 3 - People & Analytics:
- Build People CRUD API with merge and batch auto-link endpoints
- Build People list and detail pages with search, merge dialog
- Add auto-link logic in OCR completion to match/create Person records
- Add /api/stats/trends endpoint with time series and team activity
- Build Reports page with Recharts (area charts, bar charts, pipeline)
- Upgrade dashboard with sparklines and People stat card
Phase 4 - UX Polish:
- Replace silent error handling with toast notifications across all pages
- Add loading skeletons, differentiated empty states
- Add ARIA labels, skip-to-content link, accessible column toggle
- Add forgot password flow, Cmd+K command palette, Collection Days pages
- Unify Echo branding and theme toggle consistency
Made-with: Cursor
2026-04-17 00:29:26 -04:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<button type="button" className={sharedClasses} onClick={handleClick}>
|
|
|
|
|
{inner}
|
|
|
|
|
</button>
|
|
|
|
|
);
|
2026-04-07 13:23:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function formatTimeAgo(dateStr: string): string {
|
|
|
|
|
const diff = Date.now() - new Date(dateStr).getTime();
|
|
|
|
|
const mins = Math.floor(diff / 60000);
|
|
|
|
|
if (mins < 1) return "just now";
|
|
|
|
|
if (mins < 60) return `${mins}m ago`;
|
|
|
|
|
const hours = Math.floor(mins / 60);
|
|
|
|
|
if (hours < 24) return `${hours}h ago`;
|
|
|
|
|
const days = Math.floor(hours / 24);
|
|
|
|
|
if (days < 30) return `${days}d ago`;
|
|
|
|
|
return new Date(dateStr).toLocaleDateString();
|
|
|
|
|
}
|