Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20,589 changes: 20,589 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"@tailwindcss/postcss": "^4.1.3",
"@tailwindcss/typography": "^0.5.16",
"@tanstack/react-query": "^4.36.1",
"@tanstack/react-table": "^8.21.2",
"@testing-library/react": "^14.3.1",
"@types/jsonwebtoken": "^9.0.9",
"@types/nprogress": "^0.2.3",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,52 +1,95 @@
import { Suspense } from 'react';
import Link from 'next/link';
import {
PlusCircle,
Lock,
Globe,
ArrowRight,
LayoutDashboard,
Clock
} from 'lucide-react';

import { T } from '@/components/ui/Typography';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader } from '@/components/ui/card';
import { Skeleton } from '@/components/ui/skeleton';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { T } from '@/components/ui/Typography';
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle
} from '@/components/ui/card';
import { getAllItems } from '@/data/anon/items';
import { getAllPrivateItems } from '@/data/anon/privateItems';
import { PlusCircle } from 'lucide-react';
import Link from 'next/link';
import { Suspense } from 'react';
import { ItemsList } from '../../ItemsList';
import { PrivateItemsList } from '../../PrivateItemsList';

export const dynamic = 'force-dynamic';

async function ItemsListContainer() {
async function ItemsStats() {
const items = await getAllItems();
return <ItemsList items={items} showActions={false} />;
}

async function PrivateItemsListContainer() {
const privateItems = await getAllPrivateItems();
return <PrivateItemsList privateItems={privateItems} showActions={false} />;
}

function ListSkeleton() {

return (
<div className="space-y-8">
<div className="flex justify-between items-center">
<div className="space-y-2">
<Skeleton className="h-8 w-40" />
<Skeleton className="h-4 w-64" />
</div>
<Skeleton className="h-10 w-32" />
</div>

<Card>
<CardHeader>
<Skeleton className="h-6 w-full mb-2" />
<Skeleton className="h-4 w-3/4" />
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
<Card className="border-l-4 border-l-primary">
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">Total Items</CardTitle>
<CardDescription>All items in your database</CardDescription>
</CardHeader>
<CardContent className="space-y-2">
{Array(3)
.fill(0)
.map((_, i) => (
<Skeleton key={i} className="h-16 w-full" />
))}
<CardContent>
<div className="text-2xl font-bold">{items.length + privateItems.length}</div>
<p className="text-xs text-muted-foreground mt-1">
{items.length} public, {privateItems.length} private
</p>
</CardContent>
</Card>

<Card className="border-l-4 border-l-blue-500">
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">Public Items</CardTitle>
<CardDescription>Visible to everyone</CardDescription>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{items.length}</div>
<div className="flex items-center gap-1 mt-1 text-muted-foreground text-xs">
<Clock className="h-3 w-3" />
<span>Cleared every 24 hours</span>
</div>
</CardContent>
</Card>

<Card className="border-l-4 border-l-green-500">
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">Private Items</CardTitle>
<CardDescription>Only visible to you</CardDescription>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{privateItems.length}</div>
<div className="flex items-center gap-1 mt-1 text-muted-foreground text-xs">
<Lock className="h-3 w-3" />
<span>Secure and persistent</span>
</div>
</CardContent>
</Card>
</div>
);
}

function StatsSkeletons() {
return (
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{[1, 2, 3].map((i) => (
<Card key={i}>
<CardHeader className="pb-2">
<Skeleton className="h-4 w-[140px]" />
<Skeleton className="h-3 w-[100px] mt-1" />
</CardHeader>
<CardContent>
<Skeleton className="h-8 w-[60px]" />
<Skeleton className="h-3 w-[120px] mt-2" />
</CardContent>
</Card>
))}
</div>
);
}
Expand All @@ -55,32 +98,84 @@ export default function DashboardPage() {
return (
<div className="container mx-auto py-6 space-y-8">
<div className="flex justify-between items-center">
<T.H1>Dashboard</T.H1>
<Link href="/dashboard/new">
<Button className="flex items-center gap-2">
<PlusCircle className="h-4 w-4" /> New Private Item
</Button>
</Link>
<div>
<T.H1>Dashboard</T.H1>
<T.Subtle>Overview of your items and quick actions</T.Subtle>
</div>
<div className="flex gap-2">
<Link href="/dashboard/new">
<Button className="flex items-center gap-2">
<PlusCircle className="h-4 w-4" /> New Private Item
</Button>
</Link>
</div>
</div>

<Tabs defaultValue="private" className="w-full">
<TabsList className="mb-4">
<TabsTrigger value="private">Private Items</TabsTrigger>
<TabsTrigger value="public">Public Items</TabsTrigger>
</TabsList>
<Suspense fallback={<StatsSkeletons />}>
<ItemsStats />
</Suspense>

<TabsContent value="private" className="space-y-4">
<Suspense fallback={<ListSkeleton />}>
<PrivateItemsListContainer />
</Suspense>
</TabsContent>
<div className="grid gap-4 md:grid-cols-2">
<Card className="border-t-4 border-t-blue-500">
<CardHeader>
<div className="flex items-center gap-2">
<Globe className="h-5 w-5 text-blue-500" />
<CardTitle>Public Items</CardTitle>
</div>
<CardDescription>
Manage your public items that are visible to everyone
</CardDescription>
</CardHeader>
<CardContent>
<p className="text-sm text-muted-foreground">
Public items are stored in an open database and are automatically cleared every 24 hours.
Anyone can view these items without logging in.
</p>
</CardContent>
<CardFooter className="flex justify-between">
<Link href="/new">
<Button variant="outline" className="flex items-center gap-2">
<PlusCircle className="h-4 w-4" /> New Item
</Button>
</Link>
<Link href="/dashboard/public">
<Button variant="secondary" className="flex items-center gap-2">
View All <ArrowRight className="h-4 w-4" />
</Button>
</Link>
</CardFooter>
</Card>

<TabsContent value="public" className="space-y-4">
<Suspense fallback={<ListSkeleton />}>
<ItemsListContainer />
</Suspense>
</TabsContent>
</Tabs>
<Card className="border-t-4 border-t-green-500">
<CardHeader>
<div className="flex items-center gap-2">
<Lock className="h-5 w-5 text-green-500" />
<CardTitle>Private Items</CardTitle>
</div>
<CardDescription>
Manage your private items that are only visible to you
</CardDescription>
</CardHeader>
<CardContent>
<p className="text-sm text-muted-foreground">
Private items are secure and only visible when you're logged in.
They are stored persistently and won't be automatically cleared.
</p>
</CardContent>
<CardFooter className="flex justify-between">
<Link href="/dashboard/new">
<Button variant="outline" className="flex items-center gap-2">
<PlusCircle className="h-4 w-4" /> New Item
</Button>
</Link>
<Link href="/dashboard/private">
<Button variant="secondary" className="flex items-center gap-2">
View All <ArrowRight className="h-4 w-4" />
</Button>
</Link>
</CardFooter>
</Card>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { Suspense } from 'react';
import Link from 'next/link';
import { PlusCircle, ArrowLeft } from 'lucide-react';

import { T } from '@/components/ui/Typography';
import { Button } from '@/components/ui/button';
import { Skeleton } from '@/components/ui/skeleton';
import { Card, CardContent, CardHeader } from '@/components/ui/card';
import { getAllPrivateItems } from '@/data/anon/privateItems';
import { EnhancedPrivateItemsList } from '../../../EnhancedPrivateItemsList';

export const dynamic = 'force-dynamic';

async function PrivateItemsListContainer() {
const privateItems = await getAllPrivateItems();
return <EnhancedPrivateItemsList privateItems={privateItems} showActions={true} />;
}

function ListSkeleton() {
return (
<div className="space-y-8">
<div className="flex justify-between items-center">
<div className="space-y-2">
<Skeleton className="h-8 w-40" />
<Skeleton className="h-4 w-64" />
</div>
<Skeleton className="h-10 w-32" />
</div>

<Card>
<CardHeader>
<Skeleton className="h-6 w-full mb-2" />
<Skeleton className="h-4 w-3/4" />
</CardHeader>
<CardContent className="space-y-2">
{Array(3)
.fill(0)
.map((_, i) => (
<Skeleton key={i} className="h-16 w-full" />
))}
</CardContent>
</Card>
</div>
);
}

export default function PrivateItemsPage() {
return (
<div className="container mx-auto py-6 space-y-6">
<div className="flex items-center gap-2 text-sm text-muted-foreground mb-2">
<Link href="/dashboard" className="hover:text-primary transition-colors">
Dashboard
</Link>
<span>/</span>
<span className="font-medium text-foreground">Private Items</span>
</div>

<div className="flex justify-between items-center">
<div>
<T.H1>Private Items</T.H1>
<T.Subtle>Manage your private items that are only visible to you</T.Subtle>
</div>
<div className="flex gap-2">
<Link href="/dashboard">
<Button variant="outline" className="flex items-center gap-2">
<ArrowLeft className="h-4 w-4" /> Back to Dashboard
</Button>
</Link>
<Link href="/dashboard/new">
<Button className="flex items-center gap-2">
<PlusCircle className="h-4 w-4" /> New Private Item
</Button>
</Link>
</div>
</div>

<Suspense fallback={<ListSkeleton />}>
<PrivateItemsListContainer />
</Suspense>
</div>
);
}
Loading