尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗A production-quality, premium web application for discovering events and buying tickets in Haiti. Built with Next.js 14, TypeScript, Tailwind CSS, and Firebase, featuring an Eventbrite/Posh-like premium experience with advanced animations, modern UI components, and comprehensive features.
Tikèm/
├── app/ # Next.js App Router
│ ├── page.tsx # Premium home page with carousel
│ ├── loading.tsx # App-wide loading skeleton
│ ├── dashboard/ # Attendee dashboard
│ ├── discover/ # Discover page with advanced search
│ ├── events/[id]/ # Event detail pages
│ ├── favorites/ # Favorites page with empty state
│ ├── tickets/ # My tickets page
│ ├── organizer/ # Organizer features
│ │ ├── page.tsx # Organizer dashboard
│ │ ├── events/ # Event management
│ │ ├── analytics/ # Analytics with charts
│ │ └── scan/ # QR code scanner
│ ├── auth/ # Authentication pages
│ └── api/ # API routes
├── components/ # React components
│ ├── ui/ # Base UI components (10)
│ ├── charts/ # Chart components
│ ├── EventCard.tsx # Premium event card
│ ├── AdvancedSearch.tsx # Advanced search component
│ ├── EmptyState.tsx # Empty state component
│ ├── Confetti.tsx # Confetti animation
│ └── SuccessCelebration.tsx # Success modal
├── lib/ # Utilities and helpers
├── types/ # TypeScript types
├── public/ # Static assets
└── tailwind.config.ts # Premium design system
loading.tsx)Clone the repository
git clone <repository-url>
cd Tikèm
Install dependencies
npm install
Set up environment variables
cp .env.example .env.local
Fill in your credentials in .env.local (see FIREBASE_SETUP.md for detailed guide)
Set up Firebase
Follow the instructions in FIREBASE_SETUP.md:
Run development server
npm run dev
Open in browser Navigate to http://localhost:3000
See FIREBASE_SETUP.md for comprehensive Firebase setup instructions including:
Also see SETUP.md for:
Tikèm/
├── app/ # Next.js app router pages
│ ├── api/ # API routes
│ │ ├── create-checkout-session/ # Stripe checkout
│ │ └── webhooks/ # Payment webhooks
│ ├── events/ # Event browsing & details
│ ├── tickets/ # User ticket management
│ ├── favorites/ # Favorite events
│ ├── organizer/ # Organizer dashboard
│ │ ├── events/ # Event management
│ │ ├── analytics/ # Sales analytics
│ │ ├── settings/ # Payment settings
│ │ ├── scan/ # Ticket scanning
│ │ └── promo-codes/ # Discount codes
│ └── profile/ # User profile
├── components/ # Reusable React components
│ ├── ImageUpload.tsx # Image upload widget
│ └── Navbar.tsx # Navigation
├── lib/ # Utility libraries
│ ├── firebase/ # Firebase client utilities
│ ├── firebase-db/ # Firebase Firestore wrapper (Supabase-compatible API)
│ ├── email.ts # Email service (Resend)
│ ├── whatsapp.ts # WhatsApp service (Twilio)
│ ├── qrcode.ts # QR code generation
│ └── demo.ts # Demo mode utilities
├── .env.example # Environment variables template
├── FIREBASE_SETUP.md # Firebase setup guide
├── SETUP.md # Integration setup guide
└── README.md # This file
Required variables (see .env.example):
# Firebase (Required)
NEXT_PUBLIC_FIREBASE_API_KEY=
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=
NEXT_PUBLIC_FIREBASE_PROJECT_ID=
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
NEXT_PUBLIC_FIREBASE_APP_ID=
# Firebase Admin SDK (Required for server-side)
FIREBASE_ADMIN_PROJECT_ID=
FIREBASE_ADMIN_CLIENT_EMAIL=
FIREBASE_ADMIN_PRIVATE_KEY=
# Stripe (required for payments)
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=
# Resend (required for emails)
RESEND_API_KEY=
# Twilio WhatsApp (optional)
TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=
TWILIO_WHATSAPP_NUMBER=
# MonCash (optional, for Haiti payments)
MONCASH_CLIENT_ID=
MONCASH_SECRET_KEY=
MONCASH_MODE=
Use test card numbers:
Set NEXT_PUBLIC_DEMO_MODE=true to enable demo mode with:
Push to GitHub
git push origin main
Import to Vercel
Configure Webhooks
Contributions are welcome! Please:
MIT License - see LICENSE file for details
For setup help or questions:
Built with:
The platform uses Firebase (Firestore) as its primary database with a Supabase-compatible API wrapper for easier migration and development. This means:
Tikèm - Experience Haiti's Best Events 🇭🇹
5. **Run the development server**
```bash
npm run dev
Open your browser
Navigate to http://localhost:3000
Tikèm/
├── app/ # Next.js App Router pages
│ ├── auth/ # Authentication pages
│ ├── events/ # Event pages
│ ├── tickets/ # Ticket pages
│ ├── organizer/ # Organizer dashboard
│ └── page.tsx # Home page
├── components/ # Reusable React components
├── config/ # Configuration files
├── lib/ # Utility functions
├── types/ # TypeScript type definitions
├── supabase/ # Supabase configuration
└── public/ # Static assets
Tikèm is designed with multi-tenancy in mind for future expansion to HaitiPass and HaitiEvents brands.
Built with ❤️ for Haiti 🇭🇹
Real-time and segmented notifications are supported via a progressive enhancement layer:
public/sw.js) handles push events, offline caching, and notification action clicks.POST /api/push/subscribe, POST /api/push/unsubscribe, POST /api/push/send, POST /api/push/test.reminders, promotions, updates for targeted sends.userId enabling user-specific targeting.Navigate to /settings/notifications to adjust topics and manage your subscription.
The page renders components/settings/NotificationPreferences.tsx providing:
localStorage key: eh_push_topics)Add VAPID keys to .env.local:
NEXT_PUBLIC_VAPID_PUBLIC_KEY=your_public_key
VAPID_PRIVATE_KEY=your_private_key
# Optional but recommended for managed tests
PUSH_TEST_SECRET=your_random_secret
Generate with the web-push library or existing tooling.
NEXT_PUBLIC_VAPID_PUBLIC_KEYVAPID_PRIVATE_KEYPUSH_TEST_SECRET (any long random string; enables secure remote tests)
Redeploy after saving./settings/notifications to subscribe. Use the Send Test button for an end-to-end check (it issues a POST to /api/push/test).https://<your-app>.vercel.app/api/push/test?secret=<PUSH_TEST_SECRET>.curl "https://tikem.co/api/push/test?secret=$PUSH_TEST_SECRET"
Successful responses include sent and pruned arrays. A 401 Invalid secret error means the query parameter or Vercel env is incorrect; 404 No valid subscriptions means nobody is currently subscribed on that environment./api/push/send body:{ "title": "Promo", "body": "New discount!", "topics": ["promotions"] }
Omit topics to broadcast to all.
/api/push/send-user body:{ "userId": "uid_abc123", "title": "Reminder", "body": "Event starting soon", "url": "/tickets" }
Applies per-user rate limit (default: 20 notifications/hour) and prunes expired endpoints.
/api/push/test (no body) for system validation.All send/test/user endpoints append a document to pushDispatchLogs with:
{
"kind": "topic|user|test",
"topics": ["promotions"], // topic only
"userId": "uid_abc123", // user only
"title": "Promo",
"body": "New discount!",
"url": "/tickets",
"sentCount": 3,
"successCount": 3,
"pruned": ["endpoint1"],
"timestamp": "2025-11-29T02:15:00.000Z"
}
Use this collection for future analytics (CTR, failure rates, topic adoption).
| Symptom | Likely Cause | Fix |
|---|---|---|
| Test notification returns 404 "No valid subscriptions" | Existing subscription stored without encryption keys | Disable then re-enable push (updates keys) |
| Notifications not received after enabling | Browser permission still "default" or service worker not active | Refresh page; ensure HTTPS + granted permission |
| Some endpoints pruned immediately | Stale or invalidated subscription | Re-subscribe; keys rotate automatically |
| Rate limit error (429) on user send | Exceeded 20 targeted sends/hour for user | Wait for window reset or lower volume |
If upgrading from earlier implementation (before key extraction fix), users must re-enable notifications to populate keys.p256dh and keys.auth for web-push encryption.
Endpoint: POST /api/push/send-user
Body example:
{ "userId": "uid_abc123", "title": "Ticket Update", "body": "Your ticket was transferred", "url": "/tickets" }
Behavior:
userId matches.20/hour) via pushRateLimits collection.pushDispatchLogs with counts & pruned list.Helper (client/server): sendUserNotification(userId, title?, body?, url?, data?) in lib/push.ts.
Each send (topic or user) can be extended to log to pushDispatchLogs:
{
"kind": "user", // or "topic"
"userId": "uid_abc123", // optional for topic
"title": "Ticket Update",
"sentCount": 2,
"successCount": 2,
"pruned": [],
"timestamp": "2025-11-29T03:12:45.000Z"
}
resetAt).{ error: 'Rate limit exceeded', limit: 20 }.