- ποΈ
+
+
Belum ada trip tersedia
@@ -312,19 +314,11 @@ export default async function HomePage() {
{/* Lagi Ramai β social proof, bukan price proof */}
{buzzingTrips.length > 0 && (
-
-
- π€
-
-
-
- Lagi Ramai
-
-
- Banyak yang sudah gabung β kamu nggak bakal jalan sendirian
-
-
-
+
{buzzingTrips.map((trip) => (
- +
+
);
}
+
+/** Heading section homepage β ikon stroke + judul, opsional aksi di kanan. */
+function SectionHeading({
+ icon: Icon,
+ title,
+ subtitle,
+ action,
+}: {
+ icon: LucideIcon;
+ title: string;
+ subtitle?: string;
+ action?: React.ReactNode;
+}) {
+ return (
+
+
+
+
+
+ {title}
+
+ {subtitle && (
+
+ {subtitle}
+
+ )}
+
+
+ {action}
+
+ );
+}
diff --git a/app/(public)/people/page.tsx b/app/(public)/people/page.tsx
index f632e89..499b76f 100644
--- a/app/(public)/people/page.tsx
+++ b/app/(public)/people/page.tsx
@@ -5,6 +5,7 @@ import { UserCard } from "@/features/profile/components/user-card";
import { PeopleFilter } from "@/features/profile/components/people-filter";
import { isVibe, vibeLabel } from "@/lib/vibe";
import { siteConfig } from "@/lib/site";
+import { Users } from "lucide-react";
interface PeoplePageProps {
searchParams: Promise<{
@@ -68,8 +69,13 @@ export default async function PeoplePage({ searchParams }: PeoplePageProps) {
{people.length === 0 ? (
-
- π
+
+
{hasFilters
diff --git a/app/(public)/privacy/page.tsx b/app/(public)/privacy/page.tsx
index f3bd8f5..572e0f0 100644
--- a/app/(public)/privacy/page.tsx
+++ b/app/(public)/privacy/page.tsx
@@ -1,12 +1,19 @@
import Link from "next/link";
+import { ShieldCheck, CircleCheck } from "lucide-react";
export default function PrivacyPage() {
return (
-
- π Kebijakan Privasi SeTrip
+
+
+ Kebijakan Privasi SeTrip
Terakhir diperbarui: 2026-04-27
@@ -205,7 +212,15 @@ export default function PrivacyPage() {
- β
Persetujuan
+
+
+ Persetujuan
+
Dengan menggunakan SeTrip, Anda menyatakan bahwa:
diff --git a/app/(public)/profile/page.tsx b/app/(public)/profile/page.tsx
index b22bf24..4b8c26f 100644
--- a/app/(public)/profile/page.tsx
+++ b/app/(public)/profile/page.tsx
@@ -10,6 +10,7 @@ import { TripCard } from "@/features/trip/components/trip-card";
import { ProfileTripRow } from "@/features/profile/components/profile-trip-row";
import { ProfileEditor } from "@/features/profile/components/profile-editor";
import { EarningsSection } from "@/features/payout/components/earnings-section";
+import { Plus, ChevronRight } from "lucide-react";
export const metadata: Metadata = {
title: "Profil Saya",
@@ -81,9 +82,10 @@ export default async function ProfilePage() {
- + Buat trip
+
+ Buat trip
@@ -133,13 +135,14 @@ export default async function ProfilePage() {
endDate={t.endDate}
rightSlot={
- {hasReview ? "Ubah ulasan β" : "Beri ulasan β"}
+ {hasReview ? "Ubah ulasan" : "Beri ulasan"}
+
}
/>
diff --git a/app/(public)/register/page.tsx b/app/(public)/register/page.tsx
index a7c963b..cf5eef7 100644
--- a/app/(public)/register/page.tsx
+++ b/app/(public)/register/page.tsx
@@ -77,7 +77,7 @@ export default function RegisterPage() {
{/* Card */}
-
+
{error && (
{error}
diff --git a/app/(public)/terms/page.tsx b/app/(public)/terms/page.tsx
index f2d3e83..213d8a2 100644
--- a/app/(public)/terms/page.tsx
+++ b/app/(public)/terms/page.tsx
@@ -1,12 +1,19 @@
import Link from "next/link";
+import { FileText, CircleCheck } from "lucide-react";
export default function TermsPage() {
return (
-
- π Syarat & Ketentuan SeTrip
+
+
+ Syarat & Ketentuan SeTrip
Terakhir diperbarui: 2026-04-27
@@ -262,7 +269,15 @@ export default function TermsPage() {
- β
Persetujuan
+
+
+ Persetujuan
+
Dengan menggunakan SeTrip, Anda menyatakan bahwa:
diff --git a/app/(public)/trips/[id]/page.tsx b/app/(public)/trips/[id]/page.tsx
index 9f8ec9c..5d90737 100644
--- a/app/(public)/trips/[id]/page.tsx
+++ b/app/(public)/trips/[id]/page.tsx
@@ -28,6 +28,14 @@ import {
isTripDepartureDayPast,
} from "@/lib/trip-dates";
import { previewRefund } from "@/lib/refund-policy";
+import {
+ MapPin,
+ CalendarDays,
+ Wallet,
+ UserRound,
+ Zap,
+ Users,
+} from "lucide-react";
export async function generateMetadata({
params,
@@ -309,8 +317,13 @@ export default async function TripDetailPage({
{/* Info Grid */}
-
- π
+
+
Lokasi
@@ -319,8 +332,13 @@ export default async function TripDetailPage({
-
- π
+
+
Tanggal
@@ -331,8 +349,13 @@ export default async function TripDetailPage({
-
- π°
+
+
Harga
@@ -343,8 +366,13 @@ export default async function TripDetailPage({
-
- π€
+
+
Organizer
@@ -372,8 +400,9 @@ export default async function TripDetailPage({
Peserta
{spotsLeft > 0 && spotsLeft <= 3 && (
-
- β‘ Tinggal {spotsLeft} spot!
+
+
+ Tinggal {spotsLeft} spot!
)}
{spotsLeft <= 0 && (
@@ -418,8 +447,14 @@ export default async function TripDetailPage({
)}
{confirmedCount > 0 && (
-
- π₯ Sudah join:{" "}
+
+
+ Sudah join:{" "}
{confirmedParticipants
.slice(0, 3)
@@ -547,7 +582,7 @@ export default async function TripDetailPage({
Belum ada peserta yang dikonfirmasi.{" "}
{pendingParticipants.length > 0
? "Cek permintaan join di atas untuk menyetujui peserta."
- : "Jadilah yang pertama mendaftar! π"}
+ : "Jadilah yang pertama mendaftar!"}
) : (
@@ -578,8 +613,14 @@ export default async function TripDetailPage({
{p.user.name}
{city && (
-
- π {city}
+
+
+ {city}
)}
{interests.length > 0 && (
diff --git a/app/(public)/trips/[id]/payment/page.tsx b/app/(public)/trips/[id]/payment/page.tsx
index 620c2ff..91d687d 100644
--- a/app/(public)/trips/[id]/payment/page.tsx
+++ b/app/(public)/trips/[id]/payment/page.tsx
@@ -11,6 +11,15 @@ import { formatTripCalendarDateRangeLong } from "@/lib/trip-dates";
import { isFreeTrip } from "@/lib/trip-pricing";
import { categoryMeta } from "@/lib/activity-category";
import { MidtransPayButton } from "@/features/booking/components/midtrans-pay-button";
+import {
+ ArrowLeft,
+ CalendarDays,
+ MapPin,
+ PartyPopper,
+ CircleCheck,
+ Clock,
+ Check,
+} from "lucide-react";
export const metadata: Metadata = {
title: "Detail Pembayaran",
@@ -82,8 +91,15 @@ export default async function PaymentPage({ params, searchParams }: PageProps) {
{trip.title}
-
- π
{dateRange} Β· π {trip.location}
+
+
+
+ {dateRange}
+
+
+
+ {trip.location}
+
Organizer:{" "}
@@ -102,8 +118,12 @@ export default async function PaymentPage({ params, searchParams }: PageProps) {
return (
-
- β Kembali ke trip
+
+
+ Kembali ke trip
@@ -170,8 +190,13 @@ function FreeTripSection({
}) {
return (
-
- π
+
Trip ini gratis
@@ -184,10 +209,28 @@ function FreeTripSection({
Status keikutsertaan
-
- {bookingStatus === "PAID"
- ? "β
Terkonfirmasi sebagai peserta"
- : "β³ Menunggu persetujuan organizer"}
+
+ {bookingStatus === "PAID" ? (
+ <>
+
+ Terkonfirmasi sebagai peserta
+ >
+ ) : (
+ <>
+
+ Menunggu persetujuan organizer
+ >
+ )}
@@ -250,10 +293,15 @@ function PaidTripSection({
{canPay && }
{isFullyPaid && (
-
+
+
- β
Pembayaran kamu sudah terkonfirmasi. Sampai jumpa di trip
- bareng{" "}
+ Pembayaran kamu sudah terkonfirmasi. Sampai jumpa di trip bareng{" "}
{organizerName} !
@@ -262,9 +310,10 @@ function PaidTripSection({
- β Kembali ke detail trip
+
+ Kembali ke detail trip
@@ -298,7 +347,11 @@ function PaymentTimeline({
: "bg-neutral-200 text-neutral-500"
}`}
>
- {s.done ? "β" : i + 1}
+ {s.done ? (
+
+ ) : (
+ i + 1
+ )}
- + Buat Trip
+
+ Buat Trip
@@ -113,8 +115,22 @@ export default async function TripsPage({ searchParams }: TripsPageProps) {
{trips.length === 0 ? (
-
- {hasFilters ? "π" : "ποΈ"}
+
+ {hasFilters ? (
+
+ ) : (
+
+ )}
{hasFilters
diff --git a/app/(public)/u/[id]/page.tsx b/app/(public)/u/[id]/page.tsx
index 020e9c9..e6163ff 100644
--- a/app/(public)/u/[id]/page.tsx
+++ b/app/(public)/u/[id]/page.tsx
@@ -11,6 +11,7 @@ import { OrganizerStatsPanel } from "@/features/profile/components/organizer-sta
import { OrganizerReviewsList } from "@/features/review/components/organizer-reviews-list";
import { siteConfig } from "@/lib/site";
import { vibeMeta } from "@/lib/vibe";
+import { BadgeCheck, MapPin, AtSign } from "lucide-react";
interface PageProps {
params: Promise<{ id: string }>;
@@ -86,10 +87,11 @@ export default async function PublicProfilePage({ params }: PageProps) {
{isVerifiedOrganizer && (
- β
Verified Organizer
+
+ Verified Organizer
)}
@@ -97,7 +99,8 @@ export default async function PublicProfilePage({ params }: PageProps) {
{profile?.city && (
- π {profile.city}
+
+ {profile.city}
)}
Bergabung sejak {memberSince}
@@ -141,8 +144,8 @@ export default async function PublicProfilePage({ params }: PageProps) {
rel="noopener noreferrer nofollow"
className="mt-3 inline-flex items-center gap-1.5 text-sm font-medium text-primary-600 hover:text-primary-700"
>
-
πΈ
-
@{profile.instagram}
+
+
{profile.instagram}
)}
diff --git a/app/(public)/verify/page.tsx b/app/(public)/verify/page.tsx
index 56ba83d..dec046a 100644
--- a/app/(public)/verify/page.tsx
+++ b/app/(public)/verify/page.tsx
@@ -1,5 +1,6 @@
import { redirect } from "next/navigation";
import Link from "next/link";
+import { Clock, RefreshCw, CircleX, ArrowLeft } from "lucide-react";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { organizerService } from "@/server/services/organizer.service";
@@ -72,8 +73,9 @@ export default async function VerifyPage() {
{verification?.status === "PENDING" && !verification.reuploadRequested && (
-
- β³ Menunggu review admin
+
+
+ Menunggu review admin
Pengajuanmu sedang diproses. Kami akan memberitahu via email setelah selesai.
@@ -83,8 +85,9 @@ export default async function VerifyPage() {
{verification?.reuploadRequested && (
-
- π Admin minta kamu upload ulang
+
+
+ Admin minta kamu upload ulang
{verification.reuploadNote && (
@@ -117,7 +120,10 @@ export default async function VerifyPage() {
{verification?.status === "REJECTED" && (
-
β Pengajuan ditolak
+
+
+ Pengajuan ditolak
+
{verification.rejectionReason && (
Alasan: {" "}
@@ -135,8 +141,12 @@ export default async function VerifyPage() {
verification?.reuploadRequested)) && }
-
- β Kembali ke profil
+
+
+ Kembali ke profil
diff --git a/app/admin/bookings/[id]/page.tsx b/app/admin/bookings/[id]/page.tsx
index 3cd7e34..0c99e74 100644
--- a/app/admin/bookings/[id]/page.tsx
+++ b/app/admin/bookings/[id]/page.tsx
@@ -1,6 +1,7 @@
import Link from "next/link";
import { notFound, redirect } from "next/navigation";
import { getServerSession } from "next-auth";
+import { ArrowLeft, CalendarDays, CircleAlert, MapPin } from "lucide-react";
import { authOptions } from "@/lib/auth";
import { isAdminEmail } from "@/lib/admin";
import { bookingRepo } from "@/server/repositories/booking.repo";
@@ -69,8 +70,12 @@ export default async function AdminBookingDetailPage({ params }: PageProps) {
return (
-
- β Dashboard
+
+
+ Dashboard
{booking.trip.title}
-
- π
{formatTripCalendarDateRangeLong(booking.trip.date, booking.trip.endDate)}{" "}
- Β· π {booking.trip.destination}, {booking.trip.location}
+
+
+ {formatTripCalendarDateRangeLong(booking.trip.date, booking.trip.endDate)}
+ Β·
+
+ {booking.trip.destination}, {booking.trip.location}
@@ -300,8 +318,14 @@ function PaymentEventCard({
)}
{payment.rejectionReason && (
-
- β οΈ {payment.rejectionReason}
+
+
+ {payment.rejectionReason}
)}
diff --git a/app/admin/layout.tsx b/app/admin/layout.tsx
index 621fb6b..78a37e5 100644
--- a/app/admin/layout.tsx
+++ b/app/admin/layout.tsx
@@ -2,6 +2,7 @@ import type { Metadata } from "next";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getServerSession } from "next-auth";
+import { Lock } from "lucide-react";
import { authOptions } from "@/lib/auth";
import { AdminSidebar } from "@/components/admin/admin-sidebar";
@@ -31,7 +32,12 @@ export default async function AdminLayout({
return (
-
π
+
Halaman khusus admin
diff --git a/app/admin/page.tsx b/app/admin/page.tsx
index b258796..924d803 100644
--- a/app/admin/page.tsx
+++ b/app/admin/page.tsx
@@ -1,6 +1,7 @@
import { redirect } from "next/navigation";
import Link from "next/link";
import { getServerSession } from "next-auth";
+import { ChevronRight } from "lucide-react";
import { authOptions } from "@/lib/auth";
import { organizerRepo } from "@/server/repositories/organizer.repo";
import { refundRepo } from "@/server/repositories/refund.repo";
@@ -155,8 +156,9 @@ export default async function AdminDashboardPage() {
>
{s.label}
-
- Buka β
+
+ Buka
+
{s.value}
diff --git a/app/admin/system/page.tsx b/app/admin/system/page.tsx
index ff5420a..cc9b400 100644
--- a/app/admin/system/page.tsx
+++ b/app/admin/system/page.tsx
@@ -1,6 +1,12 @@
import Link from "next/link";
import { redirect } from "next/navigation";
import { getServerSession } from "next-auth";
+import {
+ ArrowUpRight,
+ CircleAlert,
+ CircleCheck,
+ CircleX,
+} from "lucide-react";
import { authOptions } from "@/lib/auth";
import { isAdminEmail } from "@/lib/admin";
import { prisma } from "@/lib/prisma";
@@ -112,8 +118,9 @@ export default async function AdminSystemPage() {
{hasAnyStale && (
-
- β οΈ Stale State Alerts
+
+
+ Stale State Alerts
{stale.stalePaymentsCount > 0 && (
@@ -137,9 +144,10 @@ export default async function AdminSystemPage() {
cron history di bawah.{" "}
- Lihat HELD β
+ Lihat HELD
+
)}
@@ -149,9 +157,10 @@ export default async function AdminSystemPage() {
> 7 hari belum di-process.{" "}
- Lihat APPROVED β
+ Lihat APPROVED
+
)}
@@ -162,9 +171,10 @@ export default async function AdminSystemPage() {
manual.{" "}
- Lihat email gagal β
+ Lihat email gagal
+
)}
@@ -187,16 +197,23 @@ export default async function AdminSystemPage() {
: "border-red-200 bg-red-50/50";
const badge =
health === "ok"
- ? { label: "π’ OK", cls: "bg-emerald-100 text-emerald-800" }
+ ? {
+ label: "OK",
+ icon: CircleCheck,
+ cls: "bg-emerald-100 text-emerald-800",
+ }
: health === "stale"
? {
- label: "π‘ STALE",
+ label: "STALE",
+ icon: CircleAlert,
cls: "bg-amber-100 text-amber-800",
}
: {
- label: "π΄ FAILED",
+ label: "FAILED",
+ icon: CircleX,
cls: "bg-red-100 text-red-800",
};
+ const BadgeIcon = badge.icon;
return (
+
{badge.label}
@@ -276,9 +294,10 @@ export default async function AdminSystemPage() {
- Buka Email Log β
+ Buka Email Log
+
diff --git a/app/admin/trips/[id]/page.tsx b/app/admin/trips/[id]/page.tsx
index 1b0e15f..8cc4f6d 100644
--- a/app/admin/trips/[id]/page.tsx
+++ b/app/admin/trips/[id]/page.tsx
@@ -1,6 +1,7 @@
import Link from "next/link";
import { notFound, redirect } from "next/navigation";
import { getServerSession } from "next-auth";
+import { ArrowLeft, CalendarDays, MapPin } from "lucide-react";
import { authOptions } from "@/lib/auth";
import { isAdminEmail } from "@/lib/admin";
import { tripService } from "@/server/services/trip.service";
@@ -67,8 +68,12 @@ export default async function AdminTripDetailPage({ params }: PageProps) {
return (
-
- β Kembali ke list trips
+
+
+ Kembali ke list trips
@@ -84,9 +89,22 @@ export default async function AdminTripDetailPage({ params }: PageProps) {
{trip.title}
-
- π
{formatTripCalendarDateRangeLong(trip.date, trip.endDate)} Β·
- π {trip.destination}, {trip.location}
+
+
+ {formatTripCalendarDateRangeLong(trip.date, trip.endDate)}
+ Β·
+
+ {trip.destination}, {trip.location}
Organizer:{" "}
@@ -220,8 +238,9 @@ export default async function AdminTripDetailPage({ params }: PageProps) {
{p.user.name}
{p.user.profile?.city && (
-
- π {p.user.profile.city}
+
+
+ {p.user.profile.city}
)}
diff --git a/app/admin/trips/page.tsx b/app/admin/trips/page.tsx
index af61631..d62da75 100644
--- a/app/admin/trips/page.tsx
+++ b/app/admin/trips/page.tsx
@@ -1,6 +1,7 @@
import Link from "next/link";
import { redirect } from "next/navigation";
import { getServerSession } from "next-auth";
+import { CalendarDays, MapPin } from "lucide-react";
import { authOptions } from "@/lib/auth";
import { isAdminEmail } from "@/lib/admin";
import { tripRepo } from "@/server/repositories/trip.repo";
@@ -127,9 +128,22 @@ export default async function AdminTripsPage({ searchParams }: PageProps) {
{t.title}
-
- π
{formatTripCalendarDateRangeLong(t.date, t.endDate)}
- {" Β· "}π {t.location}
+
+
+ {formatTripCalendarDateRangeLong(t.date, t.endDate)}
+ Β·
+
+ {t.location}
Organizer:{" "}
diff --git a/app/admin/users/[id]/page.tsx b/app/admin/users/[id]/page.tsx
index d6de8b3..f911e16 100644
--- a/app/admin/users/[id]/page.tsx
+++ b/app/admin/users/[id]/page.tsx
@@ -2,6 +2,7 @@ import Link from "next/link";
import Image from "next/image";
import { notFound, redirect } from "next/navigation";
import { getServerSession } from "next-auth";
+import { ArrowLeft, ArrowUpRight, Ban, Check } from "lucide-react";
import { authOptions } from "@/lib/auth";
import { isAdminEmail } from "@/lib/admin";
import { userRepo } from "@/server/repositories/user.repo";
@@ -38,8 +39,12 @@ export default async function AdminUserDetailPage({ params }: PageProps) {
return (
-
- β Kembali ke list users
+
+
+ Kembali ke list users
@@ -75,8 +80,9 @@ export default async function AdminUserDetailPage({ params }: PageProps) {
)}
{user.organizerVerification?.status === "APPROVED" && (
-
- β Verified Organizer
+
+
+ Verified Organizer
)}
@@ -122,8 +128,9 @@ export default async function AdminUserDetailPage({ params }: PageProps) {
{user.suspended && (
-
- β Akun ditangguhkan
+
+
+ Akun ditangguhkan
{user.suspendedReason ?? "Tidak ada alasan tercatat."}
@@ -244,9 +251,10 @@ export default async function AdminUserDetailPage({ params }: PageProps) {
{" Β· "}
- Buka di /admin/verifications β
+ Buka di /admin/verifications
+
{user.organizerVerification.rejectionReason && (
diff --git a/app/admin/users/page.tsx b/app/admin/users/page.tsx
index ed5f51b..b3f4063 100644
--- a/app/admin/users/page.tsx
+++ b/app/admin/users/page.tsx
@@ -2,6 +2,7 @@ import Link from "next/link";
import Image from "next/image";
import { redirect } from "next/navigation";
import { getServerSession } from "next-auth";
+import { Check, ChartColumn } from "lucide-react";
import { authOptions } from "@/lib/auth";
import { isAdminEmail } from "@/lib/admin";
import { userRepo } from "@/server/repositories/user.repo";
@@ -56,9 +57,10 @@ export default async function AdminUsersPage({ searchParams }: PageProps) {
- π Stats
+
+ Stats
@@ -147,8 +149,9 @@ export default async function AdminUsersPage({ searchParams }: PageProps) {
)}
{u.organizerVerification?.status === "APPROVED" && (
-
- β Organizer
+
+
+ Organizer
)}
diff --git a/app/admin/users/stats/page.tsx b/app/admin/users/stats/page.tsx
index dedf4ac..006a30f 100644
--- a/app/admin/users/stats/page.tsx
+++ b/app/admin/users/stats/page.tsx
@@ -1,6 +1,7 @@
import Link from "next/link";
import { redirect } from "next/navigation";
import { getServerSession } from "next-auth";
+import { ArrowLeft } from "lucide-react";
import { authOptions } from "@/lib/auth";
import { isAdminEmail } from "@/lib/admin";
import { prisma } from "@/lib/prisma";
@@ -97,8 +98,12 @@ export default async function AdminUserStatsPage() {
return (
-
- β Kembali ke list users
+
+
+ Kembali ke list users
diff --git a/components/admin/admin-sidebar.tsx b/components/admin/admin-sidebar.tsx
index eee9d7e..214fe9b 100644
--- a/components/admin/admin-sidebar.tsx
+++ b/components/admin/admin-sidebar.tsx
@@ -5,18 +5,33 @@ import Link from "next/link";
import { usePathname } from "next/navigation";
import Image from "next/image";
import { signOut } from "next-auth/react";
+import {
+ ArrowLeft,
+ ArrowUpRight,
+ Banknote,
+ Compass,
+ IdCard,
+ LayoutDashboard,
+ Mail,
+ Menu,
+ ScrollText,
+ Settings,
+ Users,
+ X,
+ type LucideIcon,
+} from "lucide-react";
import { AdminSearchBar } from "@/features/admin/components/admin-search-bar";
-const NAV_ITEMS: { href: string; label: string; icon: string }[] = [
- { href: "/admin", label: "Dashboard", icon: "π" },
- { href: "/admin/trips", label: "Trips", icon: "π§" },
- { href: "/admin/users", label: "Users", icon: "π₯" },
- { href: "/admin/verifications", label: "Verifikasi", icon: "πͺͺ" },
- { href: "/admin/refunds", label: "Refund", icon: "β©οΈ" },
- { href: "/admin/payouts", label: "Payout", icon: "πΈ" },
- { href: "/admin/emails", label: "Email", icon: "βοΈ" },
- { href: "/admin/audit-log", label: "Audit Log", icon: "π" },
- { href: "/admin/system", label: "System", icon: "βοΈ" },
+const NAV_ITEMS: { href: string; label: string; icon: LucideIcon }[] = [
+ { href: "/admin", label: "Dashboard", icon: LayoutDashboard },
+ { href: "/admin/trips", label: "Trips", icon: Compass },
+ { href: "/admin/users", label: "Users", icon: Users },
+ { href: "/admin/verifications", label: "Verifikasi", icon: IdCard },
+ { href: "/admin/refunds", label: "Refund", icon: ArrowLeft },
+ { href: "/admin/payouts", label: "Payout", icon: Banknote },
+ { href: "/admin/emails", label: "Email", icon: Mail },
+ { href: "/admin/audit-log", label: "Audit Log", icon: ScrollText },
+ { href: "/admin/system", label: "System", icon: Settings },
];
interface AdminSidebarProps {
@@ -51,13 +66,9 @@ export function AdminSidebar({ user }: AdminSidebarProps) {
aria-expanded={open}
>
{open ? (
-
-
-
+
) : (
-
-
-
+
)}
@@ -106,6 +117,7 @@ export function AdminSidebar({ user }: AdminSidebarProps) {
const isActive =
pathname === item.href ||
(item.href !== "/admin" && pathname?.startsWith(item.href));
+ const Icon = item.icon;
return (
-
- {item.icon}
-
+
{item.label}
@@ -136,7 +146,7 @@ export function AdminSidebar({ user }: AdminSidebarProps) {
onClick={() => setOpen(false)}
className="flex items-center gap-3 rounded-lg px-3 py-2 text-xs font-medium text-neutral-500 hover:bg-neutral-100 hover:text-neutral-700"
>
-
β©
+
Lihat situs publik
diff --git a/components/shared/navbar.tsx b/components/shared/navbar.tsx
index 822d538..70ee9c7 100644
--- a/components/shared/navbar.tsx
+++ b/components/shared/navbar.tsx
@@ -4,6 +4,7 @@ import { useState } from "react";
import Link from "next/link";
import Image from "next/image";
import { useSession, signOut } from "next-auth/react";
+import { Menu, X } from "lucide-react";
export function Navbar() {
const { data: session } = useSession();
@@ -109,29 +110,9 @@ export function Navbar() {
aria-label="Toggle menu"
>
{menuOpen ? (
-
-
-
+
) : (
-
-
-
+
)}
diff --git a/components/shared/verified-badge.tsx b/components/shared/verified-badge.tsx
index e008874..a8a0a17 100644
--- a/components/shared/verified-badge.tsx
+++ b/components/shared/verified-badge.tsx
@@ -1,23 +1,20 @@
+import { BadgeCheck } from "lucide-react";
+
type Size = "sm" | "md";
export function VerifiedBadge({ size = "sm" }: { size?: Size }) {
const cls =
- size === "md"
- ? "px-2.5 py-1 text-xs"
- : "px-2 py-0.5 text-[10px]";
+ size === "md" ? "px-2.5 py-1 text-xs" : "px-2 py-0.5 text-[10px]";
return (
-
-
-
+
Verified
);
diff --git a/features/admin/components/export-csv-link.tsx b/features/admin/components/export-csv-link.tsx
index 15fca4e..764abac 100644
--- a/features/admin/components/export-csv-link.tsx
+++ b/features/admin/components/export-csv-link.tsx
@@ -1,3 +1,5 @@
+import { Download } from "lucide-react";
+
interface ExportCsvLinkProps {
/** URL endpoint export, mis. `/api/admin/export/refunds`. */
href: string;
@@ -22,7 +24,7 @@ export function ExportCsvLink({
className="inline-flex items-center gap-1.5 rounded-xl border border-neutral-200 bg-white px-3 py-1.5 text-xs font-semibold text-neutral-700 hover:bg-neutral-50"
download
>
-
β¬οΈ
+
{label}
);
diff --git a/features/admin/components/manual-verify-button.tsx b/features/admin/components/manual-verify-button.tsx
index 6878ead..3c5dc2b 100644
--- a/features/admin/components/manual-verify-button.tsx
+++ b/features/admin/components/manual-verify-button.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
+import { Lock } from "lucide-react";
import { manualOverrideVerificationAction } from "@/features/organizer/actions";
interface ManualVerifyButtonProps {
@@ -49,9 +50,10 @@ export function ManualVerifyButton({
setOpen(true)}
- className="rounded-xl border border-secondary-300 bg-white px-4 py-2 text-sm font-bold text-secondary-700 hover:bg-secondary-50"
+ className="inline-flex items-center gap-1.5 rounded-xl border border-secondary-300 bg-white px-4 py-2 text-sm font-bold text-secondary-700 hover:bg-secondary-50"
>
- π Manual verify (tanpa KYC)
+
+ Manual verify (tanpa KYC)
);
}
diff --git a/features/booking/components/admin-reconcile-button.tsx b/features/booking/components/admin-reconcile-button.tsx
index 4e1e824..7d8ee7a 100644
--- a/features/booking/components/admin-reconcile-button.tsx
+++ b/features/booking/components/admin-reconcile-button.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
+import { Check } from "lucide-react";
import { adminReconcileMidtransAction } from "@/features/booking/actions";
interface AdminReconcileButtonProps {
@@ -45,8 +46,9 @@ export function AdminReconcileButton({
{loading ? "Reconciling..." : "Reconcile Midtrans"}
{status && (
-
- β {reconcileOutcomeLabel(status)}
+
+
+ {reconcileOutcomeLabel(status)}
)}
{error && (
diff --git a/features/booking/components/cancel-booking-button.tsx b/features/booking/components/cancel-booking-button.tsx
index 3c13c65..2cbdb79 100644
--- a/features/booking/components/cancel-booking-button.tsx
+++ b/features/booking/components/cancel-booking-button.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
+import { CircleAlert } from "lucide-react";
import { cancelBookingWithRefundAction } from "@/features/booking/actions";
import { formatRupiah } from "@/lib/utils";
@@ -112,9 +113,17 @@ export function CancelBookingButton({ tripId, preview }: CancelBookingButtonProp
Tier: {preview.tierLabel}
{noRefund ? (
-
- β οΈ Di luar window refund β uang tidak dikembalikan. Booking akan
- di-cancel langsung.
+
+
+
+ Di luar window refund β uang tidak dikembalikan. Booking akan
+ di-cancel langsung.
+
) : (
diff --git a/features/booking/components/copy-button.tsx b/features/booking/components/copy-button.tsx
index 5543e5b..17bf9d1 100644
--- a/features/booking/components/copy-button.tsx
+++ b/features/booking/components/copy-button.tsx
@@ -1,6 +1,7 @@
"use client";
import { useState } from "react";
+import { Check, Copy } from "lucide-react";
interface CopyButtonProps {
value: string;
@@ -24,9 +25,19 @@ export function CopyButton({ value, label = "Salin" }: CopyButtonProps) {
- {copied ? "β Tersalin" : label}
+ {copied ? (
+ <>
+
+ Tersalin
+ >
+ ) : (
+ <>
+
+ {label}
+ >
+ )}
);
}
diff --git a/features/email/components/email-row-actions.tsx b/features/email/components/email-row-actions.tsx
index 41ea9a0..2c19d5a 100644
--- a/features/email/components/email-row-actions.tsx
+++ b/features/email/components/email-row-actions.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
+import { Check } from "lucide-react";
import { retryEmailJobAction, resendEmailAction } from "@/features/email/actions";
const BTN_CLS =
@@ -85,9 +86,18 @@ export function ResendEmailButton({
type="button"
onClick={handleResend}
disabled={loading || done}
- className={BTN_CLS}
+ className={`${BTN_CLS} inline-flex items-center gap-1`}
>
- {loading ? "Mengirimβ¦" : done ? "β Terkirim" : "Resend"}
+ {loading ? (
+ "Mengirimβ¦"
+ ) : done ? (
+ <>
+
+ Terkirim
+ >
+ ) : (
+ "Resend"
+ )}
{error && (
{error}
diff --git a/features/organizer/components/review-card.tsx b/features/organizer/components/review-card.tsx
index 749b2c7..ff614bc 100644
--- a/features/organizer/components/review-card.tsx
+++ b/features/organizer/components/review-card.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
+import { CircleCheck, CircleX, RefreshCw } from "lucide-react";
import {
reopenVerificationAction,
requestReuploadAction,
@@ -180,9 +181,10 @@ export function ReviewCard({ verification }: { verification: Verification }) {
type="button"
onClick={() => setShowReopen(true)}
disabled={loading}
- className="rounded-xl border border-amber-300 bg-white px-4 py-2 text-sm font-bold text-amber-700 hover:bg-amber-50 disabled:opacity-50"
+ className="inline-flex items-center gap-1.5 rounded-xl border border-amber-300 bg-white px-4 py-2 text-sm font-bold text-amber-700 hover:bg-amber-50 disabled:opacity-50"
>
- π Buka kembali ke PENDING
+
+ Buka kembali ke PENDING
) : (
@@ -336,25 +338,28 @@ export function ReviewCard({ verification }: { verification: Verification }) {
type="button"
onClick={() => decide("APPROVED")}
disabled={loading}
- className="rounded-xl bg-primary-600 px-4 py-2 text-sm font-bold text-white hover:bg-primary-700 disabled:opacity-50"
+ className="inline-flex items-center gap-1.5 rounded-xl bg-primary-600 px-4 py-2 text-sm font-bold text-white hover:bg-primary-700 disabled:opacity-50"
>
- β
Setujui
+
+ Setujui
setShowReupload(true)}
disabled={loading}
- className="rounded-xl border border-amber-300 bg-white px-4 py-2 text-sm font-bold text-amber-700 hover:bg-amber-50 disabled:opacity-50"
+ className="inline-flex items-center gap-1.5 rounded-xl border border-amber-300 bg-white px-4 py-2 text-sm font-bold text-amber-700 hover:bg-amber-50 disabled:opacity-50"
>
- π Minta re-upload
+
+ Minta re-upload
setShowReject(true)}
disabled={loading}
- className="rounded-xl border border-red-200 bg-white px-4 py-2 text-sm font-bold text-red-600 hover:bg-red-50 disabled:opacity-50"
+ className="inline-flex items-center gap-1.5 rounded-xl border border-red-200 bg-white px-4 py-2 text-sm font-bold text-red-600 hover:bg-red-50 disabled:opacity-50"
>
- β Tolak
+
+ Tolak
)}
diff --git a/features/organizer/components/verify-form.tsx b/features/organizer/components/verify-form.tsx
index c6729ee..c9c146f 100644
--- a/features/organizer/components/verify-form.tsx
+++ b/features/organizer/components/verify-form.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
+import { IdCard, Image as ImageIcon, Landmark, Check } from "lucide-react";
import { submitVerificationAction } from "@/features/organizer/actions";
import { DateField } from "@/components/shared/date-picker";
@@ -79,7 +80,15 @@ export function VerifyForm({ initial }: { initial: Initial }) {
)}
- π Data KTP
+
+
+ Data KTP
+
@@ -145,7 +154,15 @@ export function VerifyForm({ initial }: { initial: Initial }) {
- πΌοΈ Foto
+
+
+ Foto
+
Foto disimpan terenkripsi di server SeTrip dan hanya bisa dilihat oleh
tim admin saat review. Maks 5MB, JPG/PNG/WebP.
@@ -178,7 +195,15 @@ export function VerifyForm({ initial }: { initial: Initial }) {
- π¦ Rekening Bank
+
+
+ Rekening Bank
+
@@ -312,7 +337,10 @@ function FileUpload({
/>
{value && !busy && (
- β Terunggah
+
+
+ Terunggah
+
)}
{previewUrl && (
diff --git a/features/payout/components/payout-review-card.tsx b/features/payout/components/payout-review-card.tsx
index 049136a..23de943 100644
--- a/features/payout/components/payout-review-card.tsx
+++ b/features/payout/components/payout-review-card.tsx
@@ -3,6 +3,7 @@
import { useState } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
+import { ArrowRight, Banknote, CircleAlert } from "lucide-react";
import { markPayoutPaidAction } from "@/features/payout/actions";
import { formatRupiah } from "@/lib/utils";
@@ -95,9 +96,10 @@ export function PayoutReviewCard({ payout }: { payout: PayoutCardData }) {
- β Lihat timeline booking
+
+ Lihat timeline booking
@@ -142,9 +144,18 @@ export function PayoutReviewCard({ payout }: { payout: PayoutCardData }) {
) : (
-
- β οΈ Organizer belum menyelesaikan verifikasi (KYC) β tidak ada rekening
- snapshot. Hubungi organizer untuk konfirmasi rekening sebelum transfer.
+
+
+
+ Organizer belum menyelesaikan verifikasi (KYC) β tidak ada
+ rekening snapshot. Hubungi organizer untuk konfirmasi rekening
+ sebelum transfer.
+
)}
@@ -212,9 +223,10 @@ export function PayoutReviewCard({ payout }: { payout: PayoutCardData }) {
type="button"
onClick={() => setOpen(true)}
disabled={loading}
- className="rounded-xl bg-primary-600 px-4 py-2 text-sm font-bold text-white hover:bg-primary-700 disabled:opacity-50"
+ className="inline-flex items-center gap-1.5 rounded-xl bg-primary-600 px-4 py-2 text-sm font-bold text-white hover:bg-primary-700 disabled:opacity-50"
>
- πΈ Tandai sudah ditransfer ke organizer
+
+ Tandai sudah ditransfer ke organizer
)}
diff --git a/features/profile/components/organizer-stats-panel.tsx b/features/profile/components/organizer-stats-panel.tsx
index 5f182fe..ecbf1e6 100644
--- a/features/profile/components/organizer-stats-panel.tsx
+++ b/features/profile/components/organizer-stats-panel.tsx
@@ -1,3 +1,4 @@
+import { BadgeCheck, Star } from "lucide-react";
import type { OrganizerTrust } from "@/server/services/trust.service";
interface OrganizerStatsPanelProps {
@@ -47,7 +48,8 @@ export function OrganizerStatsPanel({ trust }: OrganizerStatsPanelProps) {
className="inline-flex items-center gap-1 rounded-full bg-primary-100 px-2.5 py-0.5 text-[11px] font-bold uppercase tracking-wide text-primary-800"
title="Identitas organizer telah diverifikasi (KTP & rekening)"
>
- β
Verified Organizer
+
+ Verified Organizer
)}
{isTripLeader && (
@@ -83,7 +85,21 @@ export function OrganizerStatsPanel({ trust }: OrganizerStatsPanelProps) {
/>
+ {avgRating}
+
+
+ ) : (
+ "β"
+ )
+ }
subtitle={
reviewCount > 0
? `${reviewCount} ulasan`
@@ -107,8 +123,15 @@ export function OrganizerStatsPanel({ trust }: OrganizerStatsPanelProps) {
key={star}
className="flex items-center gap-2 text-xs"
>
-
- {star} β
+
+ {star}
+
- Lihat publik β
+ Lihat publik
+
- Lihat publik β
+ Lihat publik
+
diff --git a/features/profile/components/user-card.tsx b/features/profile/components/user-card.tsx
index 4a448a4..6322fef 100644
--- a/features/profile/components/user-card.tsx
+++ b/features/profile/components/user-card.tsx
@@ -1,5 +1,6 @@
import Image from "next/image";
import Link from "next/link";
+import { MapPin, BadgeCheck } from "lucide-react";
import { vibeMeta } from "@/lib/vibe";
import type { Vibe } from "@/app/generated/prisma/enums";
@@ -48,17 +49,19 @@ export function UserCard({
{name}
{profile?.city && (
-
- π {profile.city}
+
+
+ {profile.city}
)}
{isVerifiedOrganizer && (
- β
Organizer
+
+ Organizer
)}
{profile?.vibe && (
diff --git a/features/refund/components/refund-policy-section.tsx b/features/refund/components/refund-policy-section.tsx
index 7d4d267..ec7614a 100644
--- a/features/refund/components/refund-policy-section.tsx
+++ b/features/refund/components/refund-policy-section.tsx
@@ -1,3 +1,4 @@
+import { LifeBuoy } from "lucide-react";
import { getRefundPolicyTiers } from "@/lib/refund-policy";
/**
@@ -9,7 +10,13 @@ export function RefundPolicySection() {
return (
- π Kebijakan refund saat peserta cancel
+
+ Kebijakan refund saat peserta cancel
diff --git a/features/refund/components/refund-review-card.tsx b/features/refund/components/refund-review-card.tsx
index df0516b..82ccbdf 100644
--- a/features/refund/components/refund-review-card.tsx
+++ b/features/refund/components/refund-review-card.tsx
@@ -3,6 +3,13 @@
import { useState } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
+import {
+ ArrowRight,
+ Banknote,
+ CircleAlert,
+ CircleCheck,
+ CircleX,
+} from "lucide-react";
import { decideRefundAction } from "@/features/refund/actions";
import { formatRupiah } from "@/lib/utils";
@@ -129,9 +136,10 @@ export function RefundReviewCard({ refund }: { refund: RefundCardData }) {
- β Lihat timeline payment & refund
+
+ Lihat timeline payment & refund
setOpenAction("APPROVE")}
disabled={loading}
- className="rounded-xl bg-primary-600 px-4 py-2 text-sm font-bold text-white hover:bg-primary-700 disabled:opacity-50"
+ className="inline-flex items-center gap-1.5 rounded-xl bg-primary-600 px-4 py-2 text-sm font-bold text-white hover:bg-primary-700 disabled:opacity-50"
>
- β
Setujui
+
+ Setujui
setOpenAction("REJECT")}
disabled={loading}
- className="rounded-xl border border-red-200 bg-white px-4 py-2 text-sm font-bold text-red-600 hover:bg-red-50 disabled:opacity-50"
+ className="inline-flex items-center gap-1.5 rounded-xl border border-red-200 bg-white px-4 py-2 text-sm font-bold text-red-600 hover:bg-red-50 disabled:opacity-50"
>
- β Tolak
+
+ Tolak
>
)}
@@ -231,17 +241,19 @@ export function RefundReviewCard({ refund }: { refund: RefundCardData }) {
type="button"
onClick={() => setOpenAction("SUCCEEDED")}
disabled={loading}
- className="rounded-xl bg-primary-600 px-4 py-2 text-sm font-bold text-white hover:bg-primary-700 disabled:opacity-50"
+ className="inline-flex items-center gap-1.5 rounded-xl bg-primary-600 px-4 py-2 text-sm font-bold text-white hover:bg-primary-700 disabled:opacity-50"
>
- πΈ Tandai sudah ditransfer
+
+ Tandai sudah ditransfer
setOpenAction("FAILED")}
disabled={loading}
- className="rounded-xl border border-red-200 bg-white px-4 py-2 text-sm font-bold text-red-600 hover:bg-red-50 disabled:opacity-50"
+ className="inline-flex items-center gap-1.5 rounded-xl border border-red-200 bg-white px-4 py-2 text-sm font-bold text-red-600 hover:bg-red-50 disabled:opacity-50"
>
- β οΈ Tandai gagal
+
+ Tandai gagal
>
)}
diff --git a/features/review/components/organizer-reviews-list.tsx b/features/review/components/organizer-reviews-list.tsx
index 7755885..ca0e189 100644
--- a/features/review/components/organizer-reviews-list.tsx
+++ b/features/review/components/organizer-reviews-list.tsx
@@ -1,5 +1,6 @@
import Link from "next/link";
import Image from "next/image";
+import { Star } from "lucide-react";
import type { OrganizerReviewItem } from "@/server/services/review.service";
interface OrganizerReviewsListProps {
@@ -62,11 +63,22 @@ export function OrganizerReviewsList({
>
{r.user.name}
-
- {"β
".repeat(r.rating)}
-
- {"β
".repeat(5 - r.rating)}
-
+
+ {[1, 2, 3, 4, 5].map((n) => (
+
+ ))}
diff --git a/features/trip/components/admin-cancel-trip-button.tsx b/features/trip/components/admin-cancel-trip-button.tsx
index b8d8e44..a07de5b 100644
--- a/features/trip/components/admin-cancel-trip-button.tsx
+++ b/features/trip/components/admin-cancel-trip-button.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
+import { CircleCheck } from "lucide-react";
import { adminCancelTripAction } from "@/features/trip/actions";
interface AdminCancelTripButtonProps {
@@ -42,7 +43,10 @@ export function AdminCancelTripButton({ tripId }: AdminCancelTripButtonProps) {
if (result) {
return (
-
β
Trip berhasil dibatalkan.
+
+
+ Trip berhasil dibatalkan.
+
β’ {result.refundCount} booking PAID β refund auto-dibuat
diff --git a/features/trip/components/create-trip-form.tsx b/features/trip/components/create-trip-form.tsx
index 47a7c61..4e16b8b 100644
--- a/features/trip/components/create-trip-form.tsx
+++ b/features/trip/components/create-trip-form.tsx
@@ -2,6 +2,14 @@
import { useMemo, useState } from "react";
import { useRouter } from "next/navigation";
+import {
+ ArrowLeft,
+ ArrowRight,
+ Check,
+ X,
+ CircleAlert,
+ Users,
+} from "lucide-react";
import { DateRangeField, TimeField } from "@/components/shared/date-picker";
import { createTripAction } from "@/features/trip/actions";
import { ImageUrlInput } from "@/features/trip/components/image-url-input";
@@ -367,9 +375,10 @@ export function CreateTripForm({ isVerifiedOrganizer }: CreateTripFormProps) {
type="button"
onClick={goBack}
disabled={step === 1 || loading}
- className="rounded-xl border border-neutral-200 bg-white px-4 py-2.5 text-sm font-semibold text-neutral-700 transition-colors hover:bg-neutral-50 disabled:cursor-not-allowed disabled:opacity-40"
+ className="inline-flex items-center gap-1 rounded-xl border border-neutral-200 bg-white px-4 py-2.5 text-sm font-semibold text-neutral-700 transition-colors hover:bg-neutral-50 disabled:cursor-not-allowed disabled:opacity-40"
>
- β Kembali
+
+ Kembali
{isLastStep ? (
@@ -388,9 +397,10 @@ export function CreateTripForm({ isVerifiedOrganizer }: CreateTripFormProps) {
- Lanjut β
+ Lanjut
+
)}
@@ -442,7 +452,11 @@ function Stepper({
: "cursor-not-allowed"
}`}
>
- {isCompleted ? "β" : s.id}
+ {isCompleted ? (
+
+ ) : (
+ s.id
+ )}
- β
+
@@ -1032,14 +1046,7 @@ function StepSchedule({
{blockedByVerification && (
-
- β οΈ Trip berbayar butuh verifikasi organizer terlebih dahulu.
+
+
+ Trip berbayar butuh verifikasi organizer terlebih dahulu.
)}
diff --git a/features/trip/components/image-gallery.tsx b/features/trip/components/image-gallery.tsx
index 4526600..6674a10 100644
--- a/features/trip/components/image-gallery.tsx
+++ b/features/trip/components/image-gallery.tsx
@@ -2,6 +2,7 @@
import Image from "next/image";
import { useState } from "react";
+import { Mountain } from "lucide-react";
interface TripImage {
id: string;
@@ -14,8 +15,13 @@ export function ImageGallery({ images }: { images: TripImage[] }) {
if (images.length === 0) {
return (
-
-
ποΈ
+
+
);
}
diff --git a/features/trip/components/image-url-input.tsx b/features/trip/components/image-url-input.tsx
index 7580cad..16e6d15 100644
--- a/features/trip/components/image-url-input.tsx
+++ b/features/trip/components/image-url-input.tsx
@@ -1,5 +1,6 @@
"use client";
+import { Plus, X } from "lucide-react";
import { LIMITS } from "@/lib/limits";
interface ImageUrlInputProps {
@@ -59,7 +60,7 @@ export function ImageUrlInput({ value, onChange }: ImageUrlInputProps) {
aria-label={`Hapus foto ${i + 1}`}
className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-neutral-200 text-neutral-400 hover:bg-red-50 hover:text-red-500"
>
- β
+
)}
@@ -71,7 +72,8 @@ export function ImageUrlInput({ value, onChange }: ImageUrlInputProps) {
onClick={addField}
className="mt-2 flex items-center gap-1 rounded-lg px-2 py-1 text-sm font-medium text-secondary-600 hover:bg-secondary-50"
>
- + Tambah foto
+
+ Tambah foto
)}
diff --git a/features/trip/components/join-trip-button.tsx b/features/trip/components/join-trip-button.tsx
index 839480b..35f36f2 100644
--- a/features/trip/components/join-trip-button.tsx
+++ b/features/trip/components/join-trip-button.tsx
@@ -143,7 +143,7 @@ export function JoinTripButton({
Kamu sudah{" "}
terkonfirmasi sebagai peserta
trip ini
- {isFree && β trip gratis, tidak ada pembayaran π }.
+ {isFree && β trip gratis, tidak ada pembayaran }.
)}
{needsPayment && (
diff --git a/features/trip/components/organizer-trust-panel.tsx b/features/trip/components/organizer-trust-panel.tsx
index 04fc909..c7befbe 100644
--- a/features/trip/components/organizer-trust-panel.tsx
+++ b/features/trip/components/organizer-trust-panel.tsx
@@ -1,4 +1,5 @@
import Image from "next/image";
+import { BadgeCheck, Star } from "lucide-react";
import type { OrganizerTrust } from "@/server/services/trust.service";
interface OrganizerTrustPanelProps {
@@ -13,7 +14,7 @@ export function OrganizerTrustPanel({
trust,
}: OrganizerTrustPanelProps) {
return (
-
+
Organizer & kepercayaan
@@ -42,7 +43,8 @@ export function OrganizerTrustPanel({
className="inline-flex items-center gap-1 rounded-full bg-primary-100 px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide text-primary-800 sm:text-xs"
title="Identitas organizer telah diverifikasi (KTP & rekening)"
>
- β
Verified Organizer
+
+ Verified Organizer
)}
{trust.isTripLeader && (
@@ -79,8 +81,20 @@ export function OrganizerTrustPanel({
Rating organizer
-
- {trust.avgRating != null ? `${trust.avgRating} β
` : "β"}
+
+ {trust.avgRating != null ? (
+ <>
+ {trust.avgRating}
+
+ >
+ ) : (
+ "β"
+ )}
{trust.reviewCount > 0 && (
diff --git a/features/trip/components/trip-card.tsx b/features/trip/components/trip-card.tsx
index c898316..e5c5bf6 100644
--- a/features/trip/components/trip-card.tsx
+++ b/features/trip/components/trip-card.tsx
@@ -1,5 +1,12 @@
import Image from "next/image";
import Link from "next/link";
+import {
+ MapPin,
+ CalendarDays,
+ UserRound,
+ BadgeCheck,
+ Sparkles,
+} from "lucide-react";
import { formatRupiah } from "@/lib/utils";
import { formatTripCalendarDateRangeLong } from "@/lib/trip-dates";
import { categoryMeta } from "@/lib/activity-category";
@@ -132,21 +139,38 @@ export function TripCard({
- π {location}
+
+ {location}
- π
{" "}
- {formatTripCalendarDateRangeLong(date, endDate)}
+
+ {formatTripCalendarDateRangeLong(date, endDate)}
- π€ {" "}
+
{organizerName}
{isVerifiedOrganizer && (
- β
Verified
+
+ Verified
)}
{isSmallGroup && (
@@ -193,10 +217,11 @@ export function TripCard({
)}
{overlapCount > 0 && (
- β¨ {overlapCount} peserta sama minat
+
+ {overlapCount} peserta sama minat
)}
diff --git a/features/trip/components/trip-filter.tsx b/features/trip/components/trip-filter.tsx
index 286f70d..36d8af2 100644
--- a/features/trip/components/trip-filter.tsx
+++ b/features/trip/components/trip-filter.tsx
@@ -2,6 +2,7 @@
import { useRouter, useSearchParams } from "next/navigation";
import { useState } from "react";
+import { Search } from "lucide-react";
import { DateRangeField } from "@/components/shared/date-picker";
import {
formatLocalCalendarYmd,
@@ -263,18 +264,7 @@ export function TripFilter() {