feat: loyalty/discount system with milestone campaigns, auto-redemption, and admin UI
- Database: loyalty_redemptions, discount_campaigns, booking_discounts tables - Backend: auto-create pending redemption at 10 stamps, apply discounts at completion - Backend: discount_eligible flag on booking creation (user + admin flows) - Backend: campaign CRUD handlers (GET/POST/PUT/DELETE + stats) - Backend: milestone campaigns (per-user, global, anniversary) - Frontend: customer account page shows 'card full' status at 10 stamps - Frontend: admin discounts page with campaign management UI - Frontend: TypeScript types for all discount entities - Tests: 9 integration tests covering loyalty, campaigns, milestones, edge cases
This commit is contained in:
@@ -21,6 +21,7 @@ import (
|
||||
"crussell/mw"
|
||||
|
||||
authHandlers "crussell/handlers/auth"
|
||||
"crussell/handlers/admin"
|
||||
"crussell/handlers/bookings"
|
||||
"crussell/handlers/notifications"
|
||||
"crussell/handlers/portfolio"
|
||||
@@ -270,6 +271,14 @@ r.Route("/admin/users", func(r chi.Router) {
|
||||
r.Post("/", scheduling.CreateTimeBlocker)
|
||||
r.Delete("/{id}", scheduling.DeleteTimeBlocker)
|
||||
})
|
||||
|
||||
r.Route("/admin/discount-campaigns", func(r chi.Router) {
|
||||
r.Get("/", admin.GetDiscountCampaigns)
|
||||
r.Post("/", admin.CreateDiscountCampaign)
|
||||
r.Put("/{id}", admin.UpdateDiscountCampaign)
|
||||
r.Delete("/{id}", admin.DeleteDiscountCampaign)
|
||||
r.Get("/{id}/stats", admin.GetCampaignStats)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user