From 725752e39aa1aae5ecd1a1ac68e04067d1e72bf5 Mon Sep 17 00:00:00 2001 From: briannelson95 <71141646+briannelson95@users.noreply.github.com> Date: Fri, 4 Jul 2025 16:09:55 -0400 Subject: [PATCH] added shadcn dashbaord --- app/(auth)/events/[eventId]/page.tsx | 2 +- app/(auth)/events/page.tsx | 2 +- app/(auth)/guest-book/page.tsx | 2 +- app/(auth)/layout.tsx | 31 +- app/globals.css | 140 +- components.json | 21 + components/EventInfoDisplay.tsx | 6 +- components/GuestBookPageClient.tsx | 2 +- components/ToDoList.tsx | 100 +- components/app-sidebar.tsx | 173 ++ components/chart-area-interactive.tsx | 292 +++ components/data-table.tsx | 807 ++++++++ components/nav-documents.tsx | 92 + components/nav-main.tsx | 41 + components/nav-secondary.tsx | 42 + components/nav-user.tsx | 116 ++ components/section-cards.tsx | 102 + components/site-header.tsx | 30 + components/ui/avatar.tsx | 53 + components/ui/badge.tsx | 46 + components/ui/breadcrumb.tsx | 109 ++ components/ui/button.tsx | 59 + components/ui/card.tsx | 92 + components/ui/chart.tsx | 353 ++++ components/ui/checkbox.tsx | 32 + components/ui/drawer.tsx | 135 ++ components/ui/dropdown-menu.tsx | 257 +++ components/ui/input.tsx | 21 + components/ui/label.tsx | 24 + components/ui/select.tsx | 185 ++ components/ui/separator.tsx | 28 + components/ui/sheet.tsx | 139 ++ components/ui/sidebar.tsx | 726 ++++++++ components/ui/skeleton.tsx | 13 + components/ui/sonner.tsx | 25 + components/ui/table.tsx | 116 ++ components/ui/tabs.tsx | 66 + components/ui/toggle-group.tsx | 73 + components/ui/toggle.tsx | 47 + components/ui/tooltip.tsx | 61 + hooks/use-mobile.ts | 19 + lib/utils.ts | 6 + package-lock.json | 1646 ++++++++++++++++- package.json | 30 +- .../migration.sql | 2 + prisma/schema.prisma | 1 + 46 files changed, 6332 insertions(+), 33 deletions(-) create mode 100644 components.json create mode 100644 components/app-sidebar.tsx create mode 100644 components/chart-area-interactive.tsx create mode 100644 components/data-table.tsx create mode 100644 components/nav-documents.tsx create mode 100644 components/nav-main.tsx create mode 100644 components/nav-secondary.tsx create mode 100644 components/nav-user.tsx create mode 100644 components/section-cards.tsx create mode 100644 components/site-header.tsx create mode 100644 components/ui/avatar.tsx create mode 100644 components/ui/badge.tsx create mode 100644 components/ui/breadcrumb.tsx create mode 100644 components/ui/button.tsx create mode 100644 components/ui/card.tsx create mode 100644 components/ui/chart.tsx create mode 100644 components/ui/checkbox.tsx create mode 100644 components/ui/drawer.tsx create mode 100644 components/ui/dropdown-menu.tsx create mode 100644 components/ui/input.tsx create mode 100644 components/ui/label.tsx create mode 100644 components/ui/select.tsx create mode 100644 components/ui/separator.tsx create mode 100644 components/ui/sheet.tsx create mode 100644 components/ui/sidebar.tsx create mode 100644 components/ui/skeleton.tsx create mode 100644 components/ui/sonner.tsx create mode 100644 components/ui/table.tsx create mode 100644 components/ui/tabs.tsx create mode 100644 components/ui/toggle-group.tsx create mode 100644 components/ui/toggle.tsx create mode 100644 components/ui/tooltip.tsx create mode 100644 hooks/use-mobile.ts create mode 100644 lib/utils.ts create mode 100644 prisma/migrations/20250704195331_add_notes_to_eventtodo/migration.sql diff --git a/app/(auth)/events/[eventId]/page.tsx b/app/(auth)/events/[eventId]/page.tsx index 272452c..a6a2a57 100644 --- a/app/(auth)/events/[eventId]/page.tsx +++ b/app/(auth)/events/[eventId]/page.tsx @@ -8,7 +8,7 @@ export default async function SingleEventPage({ params }: { params: { eventId: s console.log(data) return ( -
+
{data ? ( // @ts-ignore diff --git a/app/(auth)/events/page.tsx b/app/(auth)/events/page.tsx index 7de53d5..b3e1e53 100644 --- a/app/(auth)/events/page.tsx +++ b/app/(auth)/events/page.tsx @@ -7,7 +7,7 @@ export default async function EventsPage() { console.log(allEvents) return ( -
+

Your Events

diff --git a/app/(auth)/guest-book/page.tsx b/app/(auth)/guest-book/page.tsx index 8a2b4b2..4db8178 100644 --- a/app/(auth)/guest-book/page.tsx +++ b/app/(auth)/guest-book/page.tsx @@ -11,7 +11,7 @@ export default async function GuestBookPage({ searchParams }: { searchParams: { const guestBookData = await queries.fetchGuestBookEntries({ page: currentPage, - pageSize: 10, + pageSize: 20, }) const { entries, totalPages, currentPage: verifiedPage } = !Array.isArray(guestBookData) diff --git a/app/(auth)/layout.tsx b/app/(auth)/layout.tsx index 69083c8..6043603 100644 --- a/app/(auth)/layout.tsx +++ b/app/(auth)/layout.tsx @@ -3,20 +3,35 @@ import { SessionProvider } from 'next-auth/react' import { ReactNode } from 'react' import DashboardNavbar from '@/components/DashboardNavbar' +import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar' +import { AppSidebar } from '@/components/app-sidebar' +import { SiteHeader } from '@/components/site-header' export default function AuthLayout({ children }: { children: ReactNode }) { return ( <> -
-
- -
- {children} -
-
-
+ + + + +
+
+
+ {children} +
+
+
+
+
) diff --git a/app/globals.css b/app/globals.css index edbd5e6..31f1eec 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,4 +1,8 @@ @import "tailwindcss"; +@import "tw-animate-css"; +/* + ---break--- */ +@custom-variant dark (&:is(.dark *)); @plugin "@tailwindcss/typography"; @theme { @@ -51,7 +55,7 @@ --color-brand-secondary-800: rgb(188, 220, 189); --color-brand-secondary-900: rgb(222, 237, 222); --color-brand-secondary-950: rgb(238, 246, 239); */ - + --color-brand-text: rgb(87, 77, 61); --color-brand-background: rgb(242, 246, 248); --color-brand-primary:rgb(134, 159, 207); @@ -109,3 +113,137 @@ .textarea-bordered { @apply border border-gray-300; } + +/* + ---break--- */ + +@theme inline { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); + +} + +/* + ---break--- */ + +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.147 0.004 49.25); + --card: oklch(1 0 0); + --card-foreground: oklch(0.147 0.004 49.25); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.147 0.004 49.25); + --primary: oklch(0.216 0.006 56.043); + --primary-foreground: oklch(0.985 0.001 106.423); + --secondary: oklch(0.97 0.001 106.424); + --secondary-foreground: oklch(0.216 0.006 56.043); + --muted: oklch(0.97 0.001 106.424); + --muted-foreground: oklch(0.553 0.013 58.071); + --accent: oklch(0.97 0.001 106.424); + --accent-foreground: oklch(0.216 0.006 56.043); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.923 0.003 48.717); + --input: oklch(0.923 0.003 48.717); + --ring: oklch(0.709 0.01 56.259); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0.001 106.423); + --sidebar-foreground: oklch(0.147 0.004 49.25); + --sidebar-primary: oklch(0.216 0.006 56.043); + --sidebar-primary-foreground: oklch(0.985 0.001 106.423); + --sidebar-accent: oklch(0.97 0.001 106.424); + --sidebar-accent-foreground: oklch(0.216 0.006 56.043); + --sidebar-border: oklch(0.923 0.003 48.717); + --sidebar-ring: oklch(0.709 0.01 56.259); + +} + +/* + ---break--- */ + +.dark { + --background: oklch(0.147 0.004 49.25); + --foreground: oklch(0.985 0.001 106.423); + --card: oklch(0.216 0.006 56.043); + --card-foreground: oklch(0.985 0.001 106.423); + --popover: oklch(0.216 0.006 56.043); + --popover-foreground: oklch(0.985 0.001 106.423); + --primary: oklch(0.923 0.003 48.717); + --primary-foreground: oklch(0.216 0.006 56.043); + --secondary: oklch(0.268 0.007 34.298); + --secondary-foreground: oklch(0.985 0.001 106.423); + --muted: oklch(0.268 0.007 34.298); + --muted-foreground: oklch(0.709 0.01 56.259); + --accent: oklch(0.268 0.007 34.298); + --accent-foreground: oklch(0.985 0.001 106.423); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.553 0.013 58.071); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.216 0.006 56.043); + --sidebar-foreground: oklch(0.985 0.001 106.423); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0.001 106.423); + --sidebar-accent: oklch(0.268 0.007 34.298); + --sidebar-accent-foreground: oklch(0.985 0.001 106.423); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.553 0.013 58.071); + +} + +/* + ---break--- */ + +@layer base { + * { + @apply border-border outline-ring/50; + + } + body { + @apply bg-background text-foreground; + + } + +} diff --git a/components.json b/components.json new file mode 100644 index 0000000..2883c94 --- /dev/null +++ b/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "app/globals.css", + "baseColor": "stone", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/components/EventInfoDisplay.tsx b/components/EventInfoDisplay.tsx index bb7fa5a..59f757e 100644 --- a/components/EventInfoDisplay.tsx +++ b/components/EventInfoDisplay.tsx @@ -116,7 +116,7 @@ export default function EventInfoDisplay({ event }: Props) { const notAttendingGuests = eventGuests.filter((g) => g.rsvp === 'NO'); const pendingGuests = eventGuests.filter((g) => g.rsvp === 'PENDING'); - let daysLeft + let daysLeft: number | undefined if (event.date !== null) { daysLeft = getDaysUntilEvent(event.date); @@ -202,11 +202,11 @@ export default function EventInfoDisplay({ event }: Props) {

Countdown

- {daysLeft && daysLeft > 0 + {daysLeft !== undefined && daysLeft > 0 ? `${daysLeft} day${daysLeft !== 1 ? 's' : ''} until the event` : daysLeft === 0 ? 'Today is the big day!' - : `This event happened ${Math.abs(daysLeft)} day${Math.abs(daysLeft) !== 1 ? 's' : ''} ago` + : `This event happened ${daysLeft !== undefined && Math.abs(daysLeft)} day${daysLeft !== undefined && Math.abs(daysLeft) !== 1 ? 's' : ''} ago` }
diff --git a/components/GuestBookPageClient.tsx b/components/GuestBookPageClient.tsx index 2f5844b..ce53271 100644 --- a/components/GuestBookPageClient.tsx +++ b/components/GuestBookPageClient.tsx @@ -64,7 +64,7 @@ export default function GuestBookPageClient({ } return ( -
+

Guest Book

diff --git a/components/ToDoList.tsx b/components/ToDoList.tsx index 0c3b7a2..27495f4 100644 --- a/components/ToDoList.tsx +++ b/components/ToDoList.tsx @@ -6,6 +6,7 @@ interface Todo { name: string complete: boolean dueDate?: string | null + notes?: string | null } interface Props { @@ -18,6 +19,8 @@ export default function ToDoList({ eventId, initialTodos, onUpdate }: Props) { const [todos, setTodos] = useState(initialTodos) const [newName, setNewName] = useState('') const [newDueDate, setNewDueDate] = useState('') + const [editingNoteId, setEditingNoteId] = useState(null) + const [noteDraft, setNoteDraft] = useState('') async function handleAdd() { if (!newName.trim()) return @@ -65,6 +68,25 @@ export default function ToDoList({ eventId, initialTodos, onUpdate }: Props) { if (onUpdate) await onUpdate() } + async function saveNote(id: string) { + const res = await fetch(`/api/events/${eventId}/todo/${id}`, { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ notes: noteDraft }), + }) + + if (res.ok) { + setTodos(prev => + prev.map(todo => + todo.id === id ? { ...todo, notes: noteDraft } : todo + ) + ) + setEditingNoteId(null) + setNoteDraft('') + } + if (onUpdate) await onUpdate() + } + return (

To Do List

@@ -82,33 +104,85 @@ export default function ToDoList({ eventId, initialTodos, onUpdate }: Props) { value={newDueDate} onChange={e => setNewDueDate(e.target.value)} /> - +
    {todos.map(todo => (
  • -
    - +
    + toggleComplete(todo.id, e.target.checked)} - /> - + /> + {todo.name} - - {todo.dueDate && ( - - (Due {new Date(todo.dueDate).toLocaleDateString()}) + {todo.dueDate && ( + + (Due {new Date(todo.dueDate).toLocaleDateString()}) + + )} +
    + +
    + + {/* Notes Section */} +
    + {editingNoteId === todo.id ? ( +
    +