feat: bootstrap TitipIn application with fullstack architecture, Prisma ORM, and shadcn/ui components

This commit is contained in:
Firman Ramdhani
2026-08-28 11:18:13 +07:00
parent 84f0c1fa99
commit 5faea68379
37 changed files with 11881 additions and 250 deletions
+92 -59
View File
@@ -1,69 +1,102 @@
import Image from "next/image";
import { getAvailableOrders } from './actions'
import { OrderCard } from '@/components/OrderCard'
import { Sparkles, Plus, Store } from 'lucide-react'
import Link from 'next/link'
import { buttonVariants } from '@/components/ui/button'
import { cn } from '@/lib/utils'
export const dynamic = 'force-dynamic'
export default async function Dashboard() {
const orders = await getAvailableOrders()
export default function Home() {
return (
<div className="flex flex-col flex-1 items-center justify-center bg-zinc-50 font-sans dark:bg-black">
<main className="flex flex-1 w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
<Image
className="dark:invert h-5 w-[100px]"
src="/next.svg"
alt="Next.js logo"
width={100}
height={20}
priority
/>
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
To get started, edit the{" "}
<code className="rounded bg-black/[.06] px-1.5 py-0.5 font-mono text-[0.9em] dark:bg-white/[.08]">
page.tsx
</code>{" "}
file.
</h1>
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Looking for a starting point or more instructions? Head over to{" "}
<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
<div className="space-y-8 animate-in fade-in duration-500">
{/* Banner / Hero Section */}
<div className="relative overflow-hidden rounded-3xl bg-gradient-to-r from-[#1B2CC1] via-[#2135E0] to-[#121E85] p-6 sm:p-8 text-white shadow-xl shadow-[#1B2CC1]/15">
<div className="absolute right-0 top-0 -mt-10 -mr-10 h-64 w-64 rounded-full bg-white/10 blur-3xl pointer-events-none" />
<div className="relative z-10 max-w-2xl space-y-3">
<div className="inline-flex items-center gap-2 rounded-full bg-white/15 px-3 py-1 text-xs font-bold text-blue-100 backdrop-blur-md border border-white/20">
<Sparkles className="h-3.5 w-3.5" />
<span>Sistem Titip & Jastip Cepat</span>
</div>
<h2 className="text-2xl sm:text-3xl font-black tracking-tight leading-tight">
Titip Makanan & Minuman Bareng Teman Kantor
</h2>
<p className="text-sm text-blue-100/90 leading-relaxed max-w-xl">
Pilih PO yang sedang buka hari ini, tentukan menu favoritmu, dan biarkan pembuat PO mengurus tagihan secara praktis.
</p>
<div className="pt-2 flex flex-wrap gap-3">
<Link
href="/my-orders"
className={cn(
buttonVariants(),
"rounded-xl bg-white text-[#1B2CC1] hover:bg-blue-50 font-bold shadow-md h-10 px-5 gap-2"
)}
>
Templates
</a>{" "}
or the{" "}
<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
<Plus className="w-4 h-4" />
Buka Jasa PO Baru
</Link>
<Link
href="/my-purchases"
className={cn(
buttonVariants({ variant: "outline" }),
"rounded-xl bg-white/10 hover:bg-white/20 text-white border-white/20 font-semibold h-10 px-4"
)}
>
Learning
</a>{" "}
center.
Lihat Titipan Saya
</Link>
</div>
</div>
</div>
{/* Main Grid Header */}
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
<div>
<div className="flex items-center gap-2">
<div className="w-2.5 h-2.5 rounded-full bg-[#1B2CC1] animate-pulse" />
<h2 className="text-xl font-black text-slate-900 dark:text-white tracking-tight">
Daftar PO Terbuka Hari Ini
</h2>
</div>
<p className="text-xs text-slate-500 dark:text-slate-400 mt-0.5">
Pesanan dengan status OPEN yang bisa Anda ikuti hari ini.
</p>
</div>
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
<a
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
<span className="text-xs font-bold text-[#1B2CC1] bg-[#1B2CC1]/10 px-3 py-1.5 rounded-xl">
Total: {orders.length} PO Aktif
</span>
</div>
{orders.length === 0 ? (
<div className="flex flex-col items-center justify-center p-12 sm:p-16 text-center rounded-3xl border-2 border-dashed border-slate-200 dark:border-slate-800 bg-white dark:bg-slate-900 shadow-sm">
<div className="w-16 h-16 bg-[#1B2CC1]/10 rounded-2xl flex items-center justify-center mb-4 text-[#1B2CC1]">
<Store className="w-8 h-8" />
</div>
<h3 className="text-lg font-bold text-slate-800 dark:text-slate-200 mb-1">Belum Ada PO yang Dibuka Hari Ini</h3>
<p className="text-xs text-slate-500 max-w-md mb-6 leading-relaxed">
Mau jajan atau beli sesuatu? Jadilah orang pertama yang membuka jasa titip pesanan untuk teman-teman Anda!
</p>
<Link
href="/my-orders"
className={cn(
buttonVariants(),
"bg-[#1B2CC1] hover:bg-[#15229E] text-white font-bold rounded-xl shadow-md shadow-[#1B2CC1]/25 h-10 px-5 gap-2"
)}
>
<Image
className="dark:invert h-[14px] w-4"
src="/vercel.svg"
alt="Vercel logomark"
width={16}
height={14}
/>
Deploy Now
</a>
<a
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Documentation
</a>
<Plus className="w-4 h-4" /> Buka PO Sekarang
</Link>
</div>
</main>
) : (
<div className="flex flex-col h-full space-y-4">
<div className="flex flex-col space-y-4 max-h-[calc(100vh-260px)] overflow-y-auto pr-2 scrollbar-thin">
{orders.map((order: any) => (
<OrderCard key={order.id} order={order} />
))}
</div>
</div>
)}
</div>
);
)
}