diff --git a/next.config.ts b/next.config.ts index e9ffa30..a9194aa 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,14 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "images.unsplash.com", + }, + ], + }, }; export default nextConfig; diff --git a/src/app/globals.css b/src/app/globals.css index a2dc41e..c24a7a8 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,26 +1,163 @@ @import "tailwindcss"; +@import "tw-animate-css"; +@import "shadcn/tailwind.css"; + +@custom-variant dark (&:is(.dark *)); :root { - --background: #ffffff; - --foreground: #171717; + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --destructive-foreground: #fafafa; + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --chart-1: oklch(0.87 0 0); + --chart-2: oklch(0.556 0 0); + --chart-3: oklch(0.439 0 0); + --chart-4: oklch(0.371 0 0); + --chart-5: oklch(0.269 0 0); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); } @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); - --font-sans: var(--font-geist-sans); - --font-mono: var(--font-geist-mono); -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } + --color-card: var(--card); + --color-card-foreground: var(--card-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-destructive-foreground: var(--destructive-foreground); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --radius: var(--radius); + --font-sans: var(--font-sans); + --font-mono: var(--font-geist-mono), ui-monospace, monospace; + --font-heading: var(--font-sans); + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --radius-sm: calc(var(--radius) * 0.6); + --radius-md: calc(var(--radius) * 0.8); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) * 1.4); + --radius-2xl: calc(var(--radius) * 1.8); + --radius-3xl: calc(var(--radius) * 2.2); + --radius-4xl: calc(var(--radius) * 2.6); } body { - background: var(--background); - color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; + font-family: var(--font-poppins), var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } + +/* Scrollbar */ +::-webkit-scrollbar { + width: 6px; + height: 6px; +} + +::-webkit-scrollbar-track { + background: transparent; +} + +::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 9999px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--muted-foreground); +} + +* { + scrollbar-width: thin; + scrollbar-color: var(--border) transparent; +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.87 0 0); + --chart-2: oklch(0.556 0 0); + --chart-3: oklch(0.439 0 0); + --chart-4: oklch(0.371 0 0); + --chart-5: oklch(0.269 0 0); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } + html { + @apply font-sans; + } +} \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 976eb90..2d6e9c0 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,9 @@ import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; +import { Geist, Geist_Mono, Poppins, Inter } from "next/font/google"; import "./globals.css"; +import { cn } from "@/lib/utils"; + +const inter = Inter({ subsets: ['latin'], variable: '--font-sans' }); const geistSans = Geist({ variable: "--font-geist-sans", @@ -12,9 +15,15 @@ const geistMono = Geist_Mono({ subsets: ["latin"], }); +const poppins = Poppins({ + variable: "--font-poppins", + subsets: ["latin"], + weight: ["400", "500", "600", "700"], +}); + export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Profitra - Kelola Bisnis Anda", + description: "Platform manajemen bisnis dengan POS, Inventory, Laporan Penjualan, dan lainnya.", }; export default function RootLayout({ @@ -24,8 +33,8 @@ export default function RootLayout({ }>) { return ( {children} diff --git a/src/app/onboarding/page.tsx b/src/app/onboarding/page.tsx new file mode 100644 index 0000000..cbac17d --- /dev/null +++ b/src/app/onboarding/page.tsx @@ -0,0 +1,439 @@ +"use client"; + +import { useState } from "react"; +import Image from "next/image"; +import { Input } from "@/components/ui/input"; +import { Textarea } from "@/components/ui/textarea"; +import { Button } from "@/components/ui/button"; +import { Label } from "@/components/ui/label"; +import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; + +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { ArrowRightIcon, CheckCircle, ChevronRightIcon } from "lucide-react"; +import onboardingData from "@/data/onboarding.json"; + +export default function OnboardingPage() { + const [step, setStep] = useState(1); + const [selectedBusiness, setSelectedBusiness] = useState(null); + const [selectedPlan, setSelectedPlan] = useState(null); + const [form, setForm] = useState({ + businessName: "", + ownerName: "", + email: "", + whatsapp: "", + address: "", + currency: "IDR", + timezone: "Asia/Jakarta", + }); + + const handleNext = () => { + if (step < 3) setStep(step + 1); + }; + + const handleBack = () => { + if (step > 1) setStep(step - 1); + }; + + const handleFormChange = (name: string, value: string) => { + setForm({ ...form, [name]: value }); + }; + + const handleSubmit = () => { + console.log("Onboarding complete:", { selectedBusiness, form, selectedPlan }); + }; + + return ( +
+ {/* Left Panel */} +
+ {/* Logo */} +
+
+
+ P +
+ + Profitra + +
+
+ + {/* Step Indicator */} +
+
+ {[1, 2, 3].map((s) => ( +
+
+ {step === s && ( + + {onboardingData.stepLabels[String(s) as keyof typeof onboardingData.stepLabels]} + + )} +
+ ))} +
+
+ + {/* Step Content */} +
+ {step === 1 && ( + + )} + {step === 2 && ( + + )} + {step === 3 && ( + + )} +
+ + {/* Actions */} +
+ + + {step < 3 ? ( + + ) : ( + + )} +
+ + {step === 1 && !selectedBusiness && ( +

+ Silakan pilih jenis bisnis terlebih dahulu. +

+ )} +
+ + {/* Right Panel */} +
+
+ Onboarding illustration +
+
+

+ {onboardingData.rightPanelContent[String(step) as keyof typeof onboardingData.rightPanelContent].title} +

+

+ {onboardingData.rightPanelContent[String(step) as keyof typeof onboardingData.rightPanelContent].description} +

+
+
+
+
+ ); +} + +function StepOne({ + selected, + onSelect, + businessTypes, +}: { + selected: string | null; + onSelect: (val: string) => void; + businessTypes: { label: string; image: string }[]; +}) { + return ( +
+

+ Pilih Jenis Bisnis Anda +

+

+ Profitra akan menyesuaikan fitur dan pengaturan awal berdasarkan jenis + usaha yang Anda jalankan. +

+ +
+ {businessTypes.map((type) => ( + + ))} +
+
+ ); +} + +function StepTwo({ + form, + onChange, + currencies, + timezones, +}: { + form: { + businessName: string; + ownerName: string; + email: string; + whatsapp: string; + address: string; + currency: string; + timezone: string; + }; + onChange: (name: string, value: string) => void; + currencies: { value: string; label: string }[]; + timezones: { value: string; label: string }[]; +}) { + return ( +
+

+ Lengkapi Informasi Bisnis +

+

+ Masukkan informasi dasar mengenai usaha Anda. +

+ +
+
+ + onChange("businessName", e.target.value)} + placeholder="Contoh: Warung Berkah" + /> +
+ +
+ + onChange("ownerName", e.target.value)} + placeholder="Yoga Pangestu" + /> +
+ +
+
+ + onChange("email", e.target.value)} + placeholder="owner@email.com" + /> +
+ +
+ + onChange("whatsapp", e.target.value)} + placeholder="0812xxxxxxxx" + /> +
+
+ +
+ +