fix: replace silent json.Encode with error-logging pattern across all handlers
This commit is contained in:
@@ -105,7 +105,9 @@ func GetCustomServices(w http.ResponseWriter, r *http.Request) {
|
|||||||
if services == nil {
|
if services == nil {
|
||||||
services = []CustomService{}
|
services = []CustomService{}
|
||||||
}
|
}
|
||||||
_ = json.NewEncoder(w).Encode(services)
|
if err := json.NewEncoder(w).Encode(services); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,12 +194,14 @@ func GetCustomServices(w http.ResponseWriter, r *http.Request) {
|
|||||||
if services == nil {
|
if services == nil {
|
||||||
services = []CustomService{}
|
services = []CustomService{}
|
||||||
}
|
}
|
||||||
_ = json.NewEncoder(w).Encode(CustomServiceListResponse{
|
if err := json.NewEncoder(w).Encode(CustomServiceListResponse{
|
||||||
Services: services,
|
Services: services,
|
||||||
Total: total,
|
Total: total,
|
||||||
PerPage: perPage,
|
PerPage: perPage,
|
||||||
NextCursor: nextCursor,
|
NextCursor: nextCursor,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateCustomService(w http.ResponseWriter, r *http.Request) {
|
func CreateCustomService(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -266,7 +270,9 @@ func CreateCustomService(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
_ = json.NewEncoder(w).Encode(cs)
|
if err := json.NewEncoder(w).Encode(cs); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCustomService(w http.ResponseWriter, r *http.Request) {
|
func GetCustomService(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -306,7 +312,9 @@ func GetCustomService(w http.ResponseWriter, r *http.Request) {
|
|||||||
cs.LastUsedAt = &lastUsedAt.Time
|
cs.LastUsedAt = &lastUsedAt.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(cs)
|
if err := json.NewEncoder(w).Encode(cs); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateCustomService(w http.ResponseWriter, r *http.Request) {
|
func UpdateCustomService(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -407,7 +415,9 @@ func UpdateCustomService(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(map[string]string{"message": "Custom service updated"})
|
if err := json.NewEncoder(w).Encode(map[string]string{"message": "Custom service updated"}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func PromoteCustomService(w http.ResponseWriter, r *http.Request) {
|
func PromoteCustomService(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -496,11 +506,13 @@ func PromoteCustomService(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(map[string]string{
|
if err := json.NewEncoder(w).Encode(map[string]string{
|
||||||
"message": "Custom service promoted to regular service",
|
"message": "Custom service promoted to regular service",
|
||||||
"new_service_id": newServiceID,
|
"new_service_id": newServiceID,
|
||||||
"custom_service_id": id,
|
"custom_service_id": id,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteCustomService(w http.ResponseWriter, r *http.Request) {
|
func DeleteCustomService(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -551,7 +563,9 @@ func DeleteCustomService(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(map[string]string{"message": "Custom service deleted"})
|
if err := json.NewEncoder(w).Encode(map[string]string{"message": "Custom service deleted"}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinStrings(strs []string, sep string) string {
|
func joinStrings(strs []string, sep string) string {
|
||||||
|
|||||||
@@ -671,10 +671,12 @@ func DeleteDiscountCampaign(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"message": "Campaign deleted successfully",
|
"message": "Campaign deleted successfully",
|
||||||
"id": campaignID,
|
"id": campaignID,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCampaignStats handles GET /api/admin/discount-campaigns/{id}/stats
|
// GetCampaignStats handles GET /api/admin/discount-campaigns/{id}/stats
|
||||||
|
|||||||
@@ -75,7 +75,9 @@ func GetPatchTests(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(patchTests)
|
if err := json.NewEncoder(w).Encode(patchTests); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatePatchTest handles POST /api/admin/patch-tests
|
// CreatePatchTest handles POST /api/admin/patch-tests
|
||||||
@@ -122,7 +124,9 @@ func CreatePatchTest(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
_ = json.NewEncoder(w).Encode(map[string]string{"id": id})
|
if err := json.NewEncoder(w).Encode(map[string]string{"id": id}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePatchTest handles PUT /api/admin/patch-tests/{id}
|
// UpdatePatchTest handles PUT /api/admin/patch-tests/{id}
|
||||||
|
|||||||
@@ -69,7 +69,9 @@ func GetPublicBusinessInfo(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(info)
|
if err := json.NewEncoder(w).Encode(info); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetBusinessSettings(w http.ResponseWriter, r *http.Request) {
|
func GetBusinessSettings(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -91,7 +93,9 @@ func GetBusinessSettings(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(s)
|
if err := json.NewEncoder(w).Encode(s); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateBusinessSettingsRequest struct {
|
type UpdateBusinessSettingsRequest struct {
|
||||||
|
|||||||
@@ -458,10 +458,12 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(auth.AuthResponse{
|
if err := json.NewEncoder(w).Encode(auth.AuthResponse{
|
||||||
Token: tokenString,
|
Token: tokenString,
|
||||||
JTI: jti,
|
JTI: jti,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST /api/refresh-token (requires auth middleware)
|
// POST /api/refresh-token (requires auth middleware)
|
||||||
@@ -501,10 +503,12 @@ func RefreshTokenHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(auth.AuthResponse{
|
if err := json.NewEncoder(w).Encode(auth.AuthResponse{
|
||||||
Token: newToken,
|
Token: newToken,
|
||||||
JTI: jti,
|
JTI: jti,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST /api/logout (requires auth middleware)
|
// POST /api/logout (requires auth middleware)
|
||||||
@@ -522,7 +526,9 @@ func LogoutHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(map[string]bool{"success": true})
|
if err := json.NewEncoder(w).Encode(map[string]bool{"success": true}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type VerificationCodeRequest struct {
|
type VerificationCodeRequest struct {
|
||||||
@@ -562,7 +568,9 @@ func GenerateVerificationCodeHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
).Scan(&userID)
|
).Scan(&userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, pgx.ErrNoRows) {
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
_ = json.NewEncoder(w).Encode(VerificationResponse{Success: true, Message: "If the email exists, a verification code will be sent"})
|
if err := json.NewEncoder(w).Encode(VerificationResponse{Success: true, Message: "If the email exists, a verification code will be sent"}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("Failed to look up user: %v", err)
|
log.Printf("Failed to look up user: %v", err)
|
||||||
@@ -583,7 +591,9 @@ func GenerateVerificationCodeHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(VerificationResponse{Success: true, Message: "Verification code generated"})
|
if err := json.NewEncoder(w).Encode(VerificationResponse{Success: true, Message: "Verification code generated"}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func VerifyCodeHandler(w http.ResponseWriter, r *http.Request) {
|
func VerifyCodeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -679,7 +689,7 @@ func VerifyCodeHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(VerificationResponse{Success: true, Message: "Email verified successfully"})
|
if err := json.NewEncoder(w).Encode(VerificationResponse{Success: true, Message: "Email verified successfully"}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2006,7 +2006,9 @@ func CreateBookingHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_ = json.NewEncoder(w).Encode(existingBooking)
|
if err := json.NewEncoder(w).Encode(existingBooking); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// If err is sql.ErrNoRows, proceed with creation
|
// If err is sql.ErrNoRows, proceed with creation
|
||||||
@@ -3258,9 +3260,11 @@ func DeleteBookingHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
log.Printf("Refund processing failed for booking %s — cancellation aborted: %v", bookingID, calcErr)
|
log.Printf("Refund processing failed for booking %s — cancellation aborted: %v", bookingID, calcErr)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
_ = json.NewEncoder(w).Encode(map[string]string{
|
if err := json.NewEncoder(w).Encode(map[string]string{
|
||||||
"error": "Refund processing failed — cancellation aborted. Please try again or contact support.",
|
"error": "Refund processing failed — cancellation aborted. Please try again or contact support.",
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3352,7 +3356,9 @@ func DeleteBookingHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_ = json.NewEncoder(w).Encode(resp)
|
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3393,10 +3399,12 @@ func DeleteBookingHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"message": "Booking deleted successfully",
|
"message": "Booking deleted successfully",
|
||||||
"id": bookingID,
|
"id": bookingID,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET /api/bookings/{id}
|
// GET /api/bookings/{id}
|
||||||
|
|||||||
@@ -289,7 +289,9 @@ func AdminCancelBookingHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
resp["refund_failed"] = true
|
resp["refund_failed"] = true
|
||||||
resp["warning"] = "Booking was cancelled but refund processing failed — please process refund manually or retry"
|
resp["warning"] = "Booking was cancelled but refund processing failed — please process refund manually or retry"
|
||||||
}
|
}
|
||||||
_ = json.NewEncoder(w).Encode(resp)
|
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,7 +426,9 @@ if err := db.Conn.QueryRow(r.Context(), `SELECT COALESCE(SUM(amount), 0) FROM pa
|
|||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_ = json.NewEncoder(w).Encode(existingBooking)
|
if err := json.NewEncoder(w).Encode(existingBooking); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1567,10 +1571,12 @@ func RequestEditHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"auto_approved": true,
|
"auto_approved": true,
|
||||||
"edit_request": editReq,
|
"edit_request": editReq,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1667,7 +1673,9 @@ func RequestEditHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
_ = json.NewEncoder(w).Encode(editReq)
|
if err := json.NewEncoder(w).Encode(editReq); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdminListEditRequestsHandler returns all edit requests
|
// AdminListEditRequestsHandler returns all edit requests
|
||||||
@@ -1748,10 +1756,12 @@ func AdminListEditRequestsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"requests": requests,
|
"requests": requests,
|
||||||
"total": total,
|
"total": total,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdminApproveEditRequestHandler approves an edit request and updates the booking
|
// AdminApproveEditRequestHandler approves an edit request and updates the booking
|
||||||
@@ -2162,9 +2172,11 @@ func GetMyEditRequestHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
if errors.Is(err, pgx.ErrNoRows) {
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"edit_request": nil,
|
"edit_request": nil,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("Failed to get edit request for booking %s: %v", bookingID, err)
|
log.Printf("Failed to get edit request for booking %s: %v", bookingID, err)
|
||||||
@@ -2181,9 +2193,11 @@ func GetMyEditRequestHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"edit_request": enriched,
|
"edit_request": enriched,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMyEditRequestsHandler returns all pending edit requests for the current user across all bookings.
|
// GetMyEditRequestsHandler returns all pending edit requests for the current user across all bookings.
|
||||||
@@ -2245,9 +2259,11 @@ func GetMyEditRequestsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"edit_requests": enrichedRequests,
|
"edit_requests": enrichedRequests,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdminListAllEditRequestsHandler returns ALL pending edit requests across all bookings.
|
// AdminListAllEditRequestsHandler returns ALL pending edit requests across all bookings.
|
||||||
@@ -2302,9 +2318,11 @@ func AdminListAllEditRequestsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"edit_requests": enrichedRequests,
|
"edit_requests": enrichedRequests,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdminGetBookingEditRequestHandler returns the pending edit request for a specific booking.
|
// AdminGetBookingEditRequestHandler returns the pending edit request for a specific booking.
|
||||||
@@ -2352,9 +2370,11 @@ func AdminGetBookingEditRequestHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"edit_request": enriched,
|
"edit_request": enriched,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================================
|
// ========================================
|
||||||
|
|||||||
@@ -343,5 +343,7 @@ func ReserveSlotHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
_ = json.NewEncoder(w).Encode(response)
|
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -274,9 +274,11 @@ func AcknowledgeNotification(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(map[string]string{
|
if err := json.NewEncoder(w).Encode(map[string]string{
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AcknowledgePendingBookingNotification(tx any, ctx context.Context, bookingID string) error {
|
func AcknowledgePendingBookingNotification(tx any, ctx context.Context, bookingID string) error {
|
||||||
|
|||||||
@@ -332,7 +332,9 @@ func GetGiftCards(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
resp.TotalPages = totalPages
|
resp.TotalPages = totalPages
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(resp)
|
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateGiftCard(w http.ResponseWriter, r *http.Request) {
|
func CreateGiftCard(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -426,7 +428,9 @@ func CreateGiftCard(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
_ = json.NewEncoder(w).Encode(gc)
|
if err := json.NewEncoder(w).Encode(gc); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TopUpGiftCard(w http.ResponseWriter, r *http.Request) {
|
func TopUpGiftCard(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -542,7 +546,9 @@ func TopUpGiftCard(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(gc)
|
if err := json.NewEncoder(w).Encode(gc); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TransferGiftCard(w http.ResponseWriter, r *http.Request) {
|
func TransferGiftCard(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -654,7 +660,9 @@ func TransferGiftCard(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_ = json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
if err := json.NewEncoder(w).Encode(map[string]string{"status": "success"}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- User Handlers ---
|
// --- User Handlers ---
|
||||||
@@ -762,10 +770,12 @@ func RedeemGiftCard(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"status": "success",
|
"status": "success",
|
||||||
"amount_redeemed": amountRemaining,
|
"amount_redeemed": amountRemaining,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGiftCardBalance(w http.ResponseWriter, r *http.Request) {
|
func GetGiftCardBalance(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -780,7 +790,9 @@ func GetGiftCardBalance(w http.ResponseWriter, r *http.Request) {
|
|||||||
err := db.Conn.QueryRow(ctx, "SELECT balance FROM user_giftcard_balances WHERE user_id = $1", userID).Scan(&balance)
|
err := db.Conn.QueryRow(ctx, "SELECT balance FROM user_giftcard_balances WHERE user_id = $1", userID).Scan(&balance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, pgx.ErrNoRows) {
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
_ = json.NewEncoder(w).Encode(map[string]float64{"balance": 0.00})
|
if err := json.NewEncoder(w).Encode(map[string]float64{"balance": 0.00}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("Failed to query user balance: %v", err)
|
log.Printf("Failed to query user balance: %v", err)
|
||||||
@@ -788,7 +800,9 @@ func GetGiftCardBalance(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(map[string]float64{"balance": balance})
|
if err := json.NewEncoder(w).Encode(map[string]float64{"balance": balance}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserGiftCardBalanceAdmin Handler returns any user's balance for the admin.
|
// GetUserGiftCardBalanceAdmin Handler returns any user's balance for the admin.
|
||||||
@@ -806,7 +820,9 @@ func GetUserGiftCardBalanceAdmin(w http.ResponseWriter, r *http.Request) {
|
|||||||
err := db.Conn.QueryRow(ctx, "SELECT balance FROM user_giftcard_balances WHERE user_id = $1", userID).Scan(&balance)
|
err := db.Conn.QueryRow(ctx, "SELECT balance FROM user_giftcard_balances WHERE user_id = $1", userID).Scan(&balance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, pgx.ErrNoRows) {
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
_ = json.NewEncoder(w).Encode(map[string]float64{"balance": 0.00})
|
if err := json.NewEncoder(w).Encode(map[string]float64{"balance": 0.00}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("Failed to query user balance: %v", err)
|
log.Printf("Failed to query user balance: %v", err)
|
||||||
@@ -838,7 +854,9 @@ func GetUserGiftCardBalanceAdmin(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(map[string]float64{"balance": balance})
|
if err := json.NewEncoder(w).Encode(map[string]float64{"balance": balance}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuyGiftCard(w http.ResponseWriter, r *http.Request) {
|
func BuyGiftCard(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -880,7 +898,9 @@ func BuyGiftCard(w http.ResponseWriter, r *http.Request) {
|
|||||||
log.Printf("Failed to check idempotency: %v", err)
|
log.Printf("Failed to check idempotency: %v", err)
|
||||||
}
|
}
|
||||||
if existing != nil {
|
if existing != nil {
|
||||||
_ = json.NewEncoder(w).Encode(existing)
|
if err := json.NewEncoder(w).Encode(existing); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1107,11 +1127,13 @@ func BuyGiftCard(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"status": "success",
|
"status": "success",
|
||||||
"code": cardID,
|
"code": cardID,
|
||||||
"amount": amountPounds,
|
"amount": amountPounds,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Helpers ---
|
// --- Helpers ---
|
||||||
@@ -1179,10 +1201,12 @@ func GetExpiredBalances(w http.ResponseWriter, r *http.Request) {
|
|||||||
balances = []ExpiredBalance{}
|
balances = []ExpiredBalance{}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"expired_balances": balances,
|
"expired_balances": balances,
|
||||||
"total": len(balances),
|
"total": len(balances),
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClaimExpiredBalanceRequest struct {
|
type ClaimExpiredBalanceRequest struct {
|
||||||
@@ -1258,5 +1282,7 @@ func ClaimExpiredBalance(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_ = json.NewEncoder(w).Encode(map[string]string{"status": "claimed"})
|
if err := json.NewEncoder(w).Encode(map[string]string{"status": "claimed"}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,7 +130,9 @@ func GetDiscountPreviewHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
preview := calculateDiscountPreview(r.Context(), bookingID, userID)
|
preview := calculateDiscountPreview(r.Context(), bookingID, userID)
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(preview)
|
if err := json.NewEncoder(w).Encode(preview); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculateDiscountPreview runs the same queries as applyEligibleCampaignsAtPayment
|
// calculateDiscountPreview runs the same queries as applyEligibleCampaignsAtPayment
|
||||||
@@ -389,10 +391,12 @@ func CreateTerminalPayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err := tx.QueryRow(r.Context(), `
|
if err := tx.QueryRow(r.Context(), `
|
||||||
SELECT id, status FROM payments WHERE booking_id = $1 AND idempotency_key = $2
|
SELECT id, status FROM payments WHERE booking_id = $1 AND idempotency_key = $2
|
||||||
`, bookingID, idempotencyKey).Scan(&existingID, &existingStatus); err == nil {
|
`, bookingID, idempotencyKey).Scan(&existingID, &existingStatus); err == nil {
|
||||||
_ = json.NewEncoder(w).Encode(CheckoutResponse{
|
if err := json.NewEncoder(w).Encode(CheckoutResponse{
|
||||||
CheckoutID: existingID,
|
CheckoutID: existingID,
|
||||||
Status: existingStatus,
|
Status: existingStatus,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
} else if !errors.Is(err, pgx.ErrNoRows) {
|
} else if !errors.Is(err, pgx.ErrNoRows) {
|
||||||
log.Printf("Failed to check idempotency: %v", err)
|
log.Printf("Failed to check idempotency: %v", err)
|
||||||
@@ -531,10 +535,12 @@ func CreateTerminalPayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(CheckoutResponse{
|
if err := json.NewEncoder(w).Encode(CheckoutResponse{
|
||||||
CheckoutID: paymentID,
|
CheckoutID: paymentID,
|
||||||
Status: "COMPLETED",
|
Status: "COMPLETED",
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,10 +567,12 @@ func CreateTerminalPayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
log.Printf("Failed to check idempotency: %v", err)
|
log.Printf("Failed to check idempotency: %v", err)
|
||||||
}
|
}
|
||||||
if existingPayment != nil {
|
if existingPayment != nil {
|
||||||
_ = json.NewEncoder(w).Encode(CheckoutResponse{
|
if err := json.NewEncoder(w).Encode(CheckoutResponse{
|
||||||
CheckoutID: existingPayment.ID,
|
CheckoutID: existingPayment.ID,
|
||||||
Status: existingPayment.Status,
|
Status: existingPayment.Status,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -583,10 +591,12 @@ func CreateTerminalPayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(CheckoutResponse{
|
if err := json.NewEncoder(w).Encode(CheckoutResponse{
|
||||||
CheckoutID: checkout.ID,
|
CheckoutID: checkout.ID,
|
||||||
Status: checkout.Status,
|
Status: checkout.Status,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCheckoutStatus(w http.ResponseWriter, r *http.Request) {
|
func GetCheckoutStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -613,7 +623,9 @@ func GetCheckoutStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
paymentResult, err := SquareClient.GetCheckout(r.Context(), checkoutID)
|
paymentResult, err := SquareClient.GetCheckout(r.Context(), checkoutID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() == "checkout pending" {
|
if err.Error() == "checkout pending" {
|
||||||
_ = json.NewEncoder(w).Encode(PaymentStatusResponse{Status: "PENDING"})
|
if err := json.NewEncoder(w).Encode(PaymentStatusResponse{Status: "PENDING"}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("Failed to get checkout status: %v", err)
|
log.Printf("Failed to get checkout status: %v", err)
|
||||||
@@ -647,14 +659,16 @@ func GetCheckoutStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
WHERE booking_id = $1 AND idempotency_key = $2
|
WHERE booking_id = $1 AND idempotency_key = $2
|
||||||
`, bookingID, idempotencyKey).Scan(&existingID, &existingSquarePayID); err == nil {
|
`, bookingID, idempotencyKey).Scan(&existingID, &existingSquarePayID); err == nil {
|
||||||
if existingSquarePayID.Valid && existingSquarePayID.String == paymentResult.SquarePayID {
|
if existingSquarePayID.Valid && existingSquarePayID.String == paymentResult.SquarePayID {
|
||||||
_ = json.NewEncoder(w).Encode(PaymentStatusResponse{
|
if err := json.NewEncoder(w).Encode(PaymentStatusResponse{
|
||||||
Status: "COMPLETED",
|
Status: "COMPLETED",
|
||||||
PaymentID: existingID,
|
PaymentID: existingID,
|
||||||
Amount: paymentResult.Amount,
|
Amount: paymentResult.Amount,
|
||||||
CardBrand: paymentResult.CardBrand,
|
CardBrand: paymentResult.CardBrand,
|
||||||
CardLast4: paymentResult.CardLast4,
|
CardLast4: paymentResult.CardLast4,
|
||||||
ReceiptURL: paymentResult.ReceiptURL,
|
ReceiptURL: paymentResult.ReceiptURL,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if !errors.Is(err, pgx.ErrNoRows) {
|
} else if !errors.Is(err, pgx.ErrNoRows) {
|
||||||
@@ -688,14 +702,16 @@ func GetCheckoutStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(PaymentStatusResponse{
|
if err := json.NewEncoder(w).Encode(PaymentStatusResponse{
|
||||||
Status: "COMPLETED",
|
Status: "COMPLETED",
|
||||||
PaymentID: paymentID,
|
PaymentID: paymentID,
|
||||||
Amount: paymentResult.Amount,
|
Amount: paymentResult.Amount,
|
||||||
CardBrand: paymentResult.CardBrand,
|
CardBrand: paymentResult.CardBrand,
|
||||||
CardLast4: paymentResult.CardLast4,
|
CardLast4: paymentResult.CardLast4,
|
||||||
ReceiptURL: paymentResult.ReceiptURL,
|
ReceiptURL: paymentResult.ReceiptURL,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -876,14 +892,16 @@ func CreateBookingPayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
FROM payments
|
FROM payments
|
||||||
WHERE booking_id = $1 AND idempotency_key = $2
|
WHERE booking_id = $1 AND idempotency_key = $2
|
||||||
`, bookingID, req.IdempotencyKey).Scan(&existingID, &existingBookingID, &existingPaymentType, &existingStatus, &existingAmount, &existingCreatedAt); err == nil {
|
`, bookingID, req.IdempotencyKey).Scan(&existingID, &existingBookingID, &existingPaymentType, &existingStatus, &existingAmount, &existingCreatedAt); err == nil {
|
||||||
_ = json.NewEncoder(w).Encode(PaymentResponse{
|
if err := json.NewEncoder(w).Encode(PaymentResponse{
|
||||||
ID: existingID.String,
|
ID: existingID.String,
|
||||||
BookingID: existingBookingID.String,
|
BookingID: existingBookingID.String,
|
||||||
PaymentType: existingPaymentType.String,
|
PaymentType: existingPaymentType.String,
|
||||||
Status: existingStatus.String,
|
Status: existingStatus.String,
|
||||||
Amount: int64(existingAmount.Float64 * 100),
|
Amount: int64(existingAmount.Float64 * 100),
|
||||||
CreatedAt: existingCreatedAt.Time.Format(time.RFC3339),
|
CreatedAt: existingCreatedAt.Time.Format(time.RFC3339),
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
} else if !errors.Is(err, pgx.ErrNoRows) {
|
} else if !errors.Is(err, pgx.ErrNoRows) {
|
||||||
log.Printf("Failed to check idempotency: %v", err)
|
log.Printf("Failed to check idempotency: %v", err)
|
||||||
@@ -1073,7 +1091,7 @@ func CreateBookingPayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(PaymentResponse{
|
if err := json.NewEncoder(w).Encode(PaymentResponse{
|
||||||
ID: primaryPaymentID,
|
ID: primaryPaymentID,
|
||||||
BookingID: bookingID,
|
BookingID: bookingID,
|
||||||
PaymentType: req.PaymentType,
|
PaymentType: req.PaymentType,
|
||||||
@@ -1083,7 +1101,9 @@ func CreateBookingPayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
CardLast4: paymentResult.CardLast4,
|
CardLast4: paymentResult.CardLast4,
|
||||||
ReceiptURL: paymentResult.ReceiptURL,
|
ReceiptURL: paymentResult.ReceiptURL,
|
||||||
CreatedAt: clock.Now().Format(time.RFC3339),
|
CreatedAt: clock.Now().Format(time.RFC3339),
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// applyEligibleCampaignsAtPayment checks and applies any eligible discount
|
// applyEligibleCampaignsAtPayment checks and applies any eligible discount
|
||||||
@@ -1472,7 +1492,9 @@ func GetUserPaymentMethods(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(cards)
|
if err := json.NewEncoder(w).Encode(cards); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AdminGetUserPaymentMethods(w http.ResponseWriter, r *http.Request) {
|
func AdminGetUserPaymentMethods(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -1490,7 +1512,9 @@ func AdminGetUserPaymentMethods(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(cards)
|
if err := json.NewEncoder(w).Encode(cards); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeletePaymentMethod(w http.ResponseWriter, r *http.Request) {
|
func DeletePaymentMethod(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -1514,7 +1538,9 @@ func DeletePaymentMethod(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(map[string]string{"status": "deleted"})
|
if err := json.NewEncoder(w).Encode(map[string]string{"status": "deleted"}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreatePaymentMethodRequest struct {
|
type CreatePaymentMethodRequest struct {
|
||||||
@@ -1563,7 +1589,9 @@ func CreatePaymentMethod(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(card)
|
if err := json.NewEncoder(w).Encode(card); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func RefundPayment(w http.ResponseWriter, r *http.Request) {
|
func RefundPayment(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -1691,14 +1719,16 @@ func RefundPayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(RefundResponse{
|
if err := json.NewEncoder(w).Encode(RefundResponse{
|
||||||
ID: refundID,
|
ID: refundID,
|
||||||
PaymentID: paymentID,
|
PaymentID: paymentID,
|
||||||
Amount: req.Amount,
|
Amount: req.Amount,
|
||||||
Status: "completed",
|
Status: "completed",
|
||||||
Reason: req.Reason,
|
Reason: req.Reason,
|
||||||
CreatedAt: clock.Now().Format(time.RFC3339),
|
CreatedAt: clock.Now().Format(time.RFC3339),
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateTipPayment(w http.ResponseWriter, r *http.Request) {
|
func CreateTipPayment(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -1846,7 +1876,7 @@ func CreateTipPayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(PaymentResponse{
|
if err := json.NewEncoder(w).Encode(PaymentResponse{
|
||||||
ID: paymentID,
|
ID: paymentID,
|
||||||
BookingID: bookingID,
|
BookingID: bookingID,
|
||||||
PaymentType: "tip",
|
PaymentType: "tip",
|
||||||
@@ -1856,7 +1886,9 @@ func CreateTipPayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
CardLast4: paymentResult.CardLast4,
|
CardLast4: paymentResult.CardLast4,
|
||||||
ReceiptURL: paymentResult.ReceiptURL,
|
ReceiptURL: paymentResult.ReceiptURL,
|
||||||
CreatedAt: clock.Now().Format(time.RFC3339),
|
CreatedAt: clock.Now().Format(time.RFC3339),
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetBookingPaymentSummary(w http.ResponseWriter, r *http.Request) {
|
func GetBookingPaymentSummary(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -1921,7 +1953,7 @@ func GetBookingPaymentSummary(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(PaymentSummaryResponse{
|
if err := json.NewEncoder(w).Encode(PaymentSummaryResponse{
|
||||||
TotalAmount: int64(summary.TotalAmount * 100),
|
TotalAmount: int64(summary.TotalAmount * 100),
|
||||||
PaidAmount: int64(summary.PaidAmount * 100),
|
PaidAmount: int64(summary.PaidAmount * 100),
|
||||||
RefundedAmount: int64(summary.RefundedAmount * 100),
|
RefundedAmount: int64(summary.RefundedAmount * 100),
|
||||||
@@ -1930,7 +1962,9 @@ func GetBookingPaymentSummary(w http.ResponseWriter, r *http.Request) {
|
|||||||
TotalNetAmount: int64(summary.TotalNetAmount * 100),
|
TotalNetAmount: int64(summary.TotalNetAmount * 100),
|
||||||
Payments: payments,
|
Payments: payments,
|
||||||
Refunds: refunds,
|
Refunds: refunds,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PaymentLockDuration is the TTL for a payment-in-flight lock in minutes.
|
// PaymentLockDuration is the TTL for a payment-in-flight lock in minutes.
|
||||||
@@ -2025,11 +2059,13 @@ func AcquirePaymentLock(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"status": "locked",
|
"status": "locked",
|
||||||
"ttl_min": PaymentLockDuration,
|
"ttl_min": PaymentLockDuration,
|
||||||
"bookingID": bookingID,
|
"bookingID": bookingID,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReleasePaymentLock removes the PAYMENT_IN_FLIGHT time_blocker for a booking.
|
// ReleasePaymentLock removes the PAYMENT_IN_FLIGHT time_blocker for a booking.
|
||||||
|
|||||||
@@ -155,8 +155,10 @@ func ApplyLoyaltyRedemption(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"success": true,
|
"success": true,
|
||||||
"discount_amount": discountAmount,
|
"discount_amount": discountAmount,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,13 +98,15 @@ func CreateTillSale(w http.ResponseWriter, r *http.Request) {
|
|||||||
err := db.Conn.QueryRow(ctx, `SELECT id FROM till_sales WHERE idempotency_key = $1`, req.IdempotencyKey).Scan(&existingID)
|
err := db.Conn.QueryRow(ctx, `SELECT id FROM till_sales WHERE idempotency_key = $1`, req.IdempotencyKey).Scan(&existingID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Existing sale found — return it (idempotent)
|
// Existing sale found — return it (idempotent)
|
||||||
_ = json.NewEncoder(w).Encode(TillSaleResponse{
|
if err := json.NewEncoder(w).Encode(TillSaleResponse{
|
||||||
ID: existingID,
|
ID: existingID,
|
||||||
ItemType: req.ItemType,
|
ItemType: req.ItemType,
|
||||||
TotalAmount: req.Amount,
|
TotalAmount: req.Amount,
|
||||||
PaymentMethod: req.PaymentMethod,
|
PaymentMethod: req.PaymentMethod,
|
||||||
Status: "completed",
|
Status: "completed",
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -447,7 +449,7 @@ func CreateTillSale(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
_ = json.NewEncoder(w).Encode(TillSaleResponse{
|
if err := json.NewEncoder(w).Encode(TillSaleResponse{
|
||||||
ID: tillSaleID,
|
ID: tillSaleID,
|
||||||
ItemType: req.ItemType,
|
ItemType: req.ItemType,
|
||||||
ItemID: &giftCardID,
|
ItemID: &giftCardID,
|
||||||
@@ -455,7 +457,9 @@ func CreateTillSale(w http.ResponseWriter, r *http.Request) {
|
|||||||
PaymentMethod: req.PaymentMethod,
|
PaymentMethod: req.PaymentMethod,
|
||||||
Status: saleStatus,
|
Status: saleStatus,
|
||||||
CheckoutID: squareCheckoutID,
|
CheckoutID: squareCheckoutID,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTillCheckoutStatus(w http.ResponseWriter, r *http.Request) {
|
func GetTillCheckoutStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -482,16 +486,20 @@ func GetTillCheckoutStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if currentStatus == "completed" {
|
if currentStatus == "completed" {
|
||||||
_ = json.NewEncoder(w).Encode(PaymentStatusResponse{
|
if err := json.NewEncoder(w).Encode(PaymentStatusResponse{
|
||||||
Status: "COMPLETED",
|
Status: "COMPLETED",
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
paymentResult, err := SquareClient.GetCheckout(r.Context(), checkoutID)
|
paymentResult, err := SquareClient.GetCheckout(r.Context(), checkoutID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() == "checkout pending" {
|
if err.Error() == "checkout pending" {
|
||||||
_ = json.NewEncoder(w).Encode(PaymentStatusResponse{Status: "PENDING"})
|
if err := json.NewEncoder(w).Encode(PaymentStatusResponse{Status: "PENDING"}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("Failed to get checkout status: %v", err)
|
log.Printf("Failed to get checkout status: %v", err)
|
||||||
@@ -532,16 +540,20 @@ func GetTillCheckoutStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(PaymentStatusResponse{
|
if err := json.NewEncoder(w).Encode(PaymentStatusResponse{
|
||||||
Status: "COMPLETED",
|
Status: "COMPLETED",
|
||||||
PaymentID: tillSaleID,
|
PaymentID: tillSaleID,
|
||||||
Amount: paymentResult.Amount,
|
Amount: paymentResult.Amount,
|
||||||
CardBrand: paymentResult.CardBrand,
|
CardBrand: paymentResult.CardBrand,
|
||||||
CardLast4: paymentResult.CardLast4,
|
CardLast4: paymentResult.CardLast4,
|
||||||
ReceiptURL: paymentResult.ReceiptURL,
|
ReceiptURL: paymentResult.ReceiptURL,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(PaymentStatusResponse{Status: "PENDING"})
|
if err := json.NewEncoder(w).Encode(PaymentStatusResponse{Status: "PENDING"}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kovidgoyal/imaging"
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
|
"github.com/kovidgoyal/imaging"
|
||||||
)
|
)
|
||||||
|
|
||||||
const MaxInputLength = 256
|
const MaxInputLength = 256
|
||||||
@@ -381,10 +381,12 @@ func ListImages(w http.ResponseWriter, r *http.Request) {
|
|||||||
nextCursor = &cursor
|
nextCursor = &cursor
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(ImageListResponse{
|
if err := json.NewEncoder(w).Encode(ImageListResponse{
|
||||||
Images: images,
|
Images: images,
|
||||||
NextCursor: nextCursor,
|
NextCursor: nextCursor,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListTags(w http.ResponseWriter, r *http.Request) {
|
func ListTags(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -450,7 +452,9 @@ func ListTags(w http.ResponseWriter, r *http.Request) {
|
|||||||
tags = []Tag{}
|
tags = []Tag{}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(tags)
|
if err := json.NewEncoder(w).Encode(tags); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type FilterCategory struct {
|
type FilterCategory struct {
|
||||||
@@ -622,7 +626,9 @@ func ListFilters(w http.ResponseWriter, r *http.Request) {
|
|||||||
return sumI > sumJ
|
return sumI > sumJ
|
||||||
})
|
})
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(filters)
|
if err := json.NewEncoder(w).Encode(filters); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,7 +682,9 @@ func ListFilters(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
filters = uniqueFilters
|
filters = uniqueFilters
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(filters)
|
if err := json.NewEncoder(w).Encode(filters); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func UploadImage(w http.ResponseWriter, r *http.Request) {
|
func UploadImage(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -932,7 +940,7 @@ func UploadImage(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(Image{
|
if err := json.NewEncoder(w).Encode(Image{
|
||||||
ID: imgID,
|
ID: imgID,
|
||||||
URL: fullURLs.Avif,
|
URL: fullURLs.Avif,
|
||||||
ThumbnailURL: thumbURLs.Webp,
|
ThumbnailURL: thumbURLs.Webp,
|
||||||
@@ -940,7 +948,9 @@ func UploadImage(w http.ResponseWriter, r *http.Request) {
|
|||||||
Thumb: thumbURLs,
|
Thumb: thumbURLs,
|
||||||
TagNames: tags,
|
TagNames: tags,
|
||||||
CreatedAt: clock.Now(),
|
CreatedAt: clock.Now(),
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteImage(w http.ResponseWriter, r *http.Request) {
|
func DeleteImage(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -1139,5 +1149,7 @@ func GetImage(w http.ResponseWriter, r *http.Request) {
|
|||||||
img.Thumb.Jpg = thumbJpg.String
|
img.Thumb.Jpg = thumbJpg.String
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(img)
|
if err := json.NewEncoder(w).Encode(img); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,9 @@ func GetDefaultHours(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
_ = json.NewEncoder(w).Encode(hours)
|
if err := json.NewEncoder(w).Encode(hours); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateDefaultHours(w http.ResponseWriter, r *http.Request) {
|
func UpdateDefaultHours(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -294,7 +296,9 @@ func GetWorkingHours(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
_ = json.NewEncoder(w).Encode(results)
|
if err := json.NewEncoder(w).Encode(results); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// isValidTime15Min checks that a time string (HH:MM or HH:MM:SS) has minutes in {00, 15, 30, 45}.
|
// isValidTime15Min checks that a time string (HH:MM or HH:MM:SS) has minutes in {00, 15, 30, 45}.
|
||||||
@@ -610,7 +614,9 @@ func GetAvailableHours(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
_ = json.NewEncoder(w).Encode(results)
|
if err := json.NewEncoder(w).Encode(results); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalizeTime strips seconds from HH:MM:SS to HH:MM for consistent string
|
// normalizeTime strips seconds from HH:MM:SS to HH:MM for consistent string
|
||||||
|
|||||||
@@ -119,8 +119,9 @@ func ListExceptionalGroups(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := json.NewEncoder(w).Encode(groups); err != nil {
|
||||||
_ = json.NewEncoder(w).Encode(groups)
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Create Group with Hours and Applications (bulk) ---
|
// --- Create Group with Hours and Applications (bulk) ---
|
||||||
@@ -236,9 +237,10 @@ func CreateExceptionalGroup(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
_ = json.NewEncoder(w).Encode(g)
|
if err := json.NewEncoder(w).Encode(g); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Delete Group (cascades to hours and applications) ---
|
// --- Delete Group (cascades to hours and applications) ---
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"crussell/db"
|
|
||||||
"crussell/clock"
|
"crussell/clock"
|
||||||
|
"crussell/db"
|
||||||
"crussell/internal/validators"
|
"crussell/internal/validators"
|
||||||
"crussell/mw"
|
"crussell/mw"
|
||||||
|
|
||||||
@@ -113,7 +113,9 @@ func ListTimeBlockers(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
_ = json.NewEncoder(w).Encode(blockers)
|
if err := json.NewEncoder(w).Encode(blockers); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Create Time Blocker ---
|
// --- Create Time Blocker ---
|
||||||
@@ -180,7 +182,9 @@ func CreateTimeBlocker(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
_ = json.NewEncoder(w).Encode(blocker)
|
if err := json.NewEncoder(w).Encode(blocker); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Delete Time Blocker ---
|
// --- Delete Time Blocker ---
|
||||||
|
|||||||
@@ -90,10 +90,12 @@ func ToggleService(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"message": "Service toggled successfully",
|
"message": "Service toggled successfully",
|
||||||
"id": serviceID,
|
"id": serviceID,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST /api/admin/services
|
// POST /api/admin/services
|
||||||
@@ -252,10 +254,12 @@ func DeleteServiceHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"message": "Service deleted successfully",
|
"message": "Service deleted successfully",
|
||||||
"id": serviceID,
|
"id": serviceID,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServicesHandler returns all services from the database
|
// ServicesHandler returns all services from the database
|
||||||
|
|||||||
@@ -799,7 +799,9 @@ func GetTodayAppointmentsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
rows.Close()
|
rows.Close()
|
||||||
|
|
||||||
if len(raw) == 0 {
|
if len(raw) == 0 {
|
||||||
_ = json.NewEncoder(w).Encode(TodayAppointmentsResponse{Appointments: []TodayAppointment{}})
|
if err := json.NewEncoder(w).Encode(TodayAppointmentsResponse{Appointments: []TodayAppointment{}}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -144,7 +144,9 @@ func CreateGuestUserHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
// Note: We intentionally don't sync to CardDAV - guests don't need calendar contacts
|
// Note: We intentionally don't sync to CardDAV - guests don't need calendar contacts
|
||||||
|
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
_ = json.NewEncoder(w).Encode(CreateGuestUserResponse{ID: userID, Role: "guest"})
|
if err := json.NewEncoder(w).Encode(CreateGuestUserResponse{ID: userID, Role: "guest"}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET /api/check-email?email=...&firstName=...&lastName=...&phone=...
|
// GET /api/check-email?email=...&firstName=...&lastName=...&phone=...
|
||||||
@@ -199,7 +201,9 @@ func CheckEmailHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"suggestion": suggestion,
|
"suggestion": suggestion,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package user
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"crussell/db"
|
"crussell/db"
|
||||||
@@ -29,6 +30,7 @@ func GetLoyaltyHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := json.NewEncoder(w).Encode(loyalty); err != nil {
|
||||||
_ = json.NewEncoder(w).Encode(loyalty)
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,7 +170,9 @@ func GetProfileHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(user)
|
if err := json.NewEncoder(w).Encode(user); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUT /api/user/profile
|
// PUT /api/user/profile
|
||||||
@@ -815,7 +817,9 @@ func GetEligiblePatchTestServicesHandler(w http.ResponseWriter, r *http.Request)
|
|||||||
services = []ServiceForPatchTest{}
|
services = []ServiceForPatchTest{}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(services)
|
if err := json.NewEncoder(w).Encode(services); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type AddPatchTestRequest struct {
|
type AddPatchTestRequest struct {
|
||||||
@@ -940,7 +944,9 @@ func GetUserPatchTestsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(tests)
|
if err := json.NewEncoder(w).Encode(tests); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE /api/admin/users/{user_id}/patch-tests/{test_id}
|
// DELETE /api/admin/users/{user_id}/patch-tests/{test_id}
|
||||||
@@ -1096,7 +1102,9 @@ func UploadProfilePictureHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(UploadProfilePicResponse{URL: url})
|
if err := json.NewEncoder(w).Encode(UploadProfilePicResponse{URL: url}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func processProfileImage(data []byte) ([]byte, error) {
|
func processProfileImage(data []byte) ([]byte, error) {
|
||||||
@@ -1165,7 +1173,9 @@ func GetNotificationPreferencesHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(prefs)
|
if err := json.NewEncoder(w).Encode(prefs); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUT /api/user/notification-preferences
|
// PUT /api/user/notification-preferences
|
||||||
@@ -1258,5 +1268,7 @@ func GetContactInfoHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
contact.Role = "Owner / Beauty Specialist"
|
contact.Role = "Owner / Beauty Specialist"
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(contact)
|
if err := json.NewEncoder(w).Encode(contact); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -151,10 +151,12 @@ func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
} else {
|
} else {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
if err := json.NewEncoder(w).Encode(map[string]any{
|
||||||
"status": status,
|
"status": status,
|
||||||
"services": services,
|
"services": services,
|
||||||
})
|
}); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package mw
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -11,7 +12,9 @@ import (
|
|||||||
func RespondJSON(w http.ResponseWriter, status int, data any) {
|
func RespondJSON(w http.ResponseWriter, status int, data any) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
_ = json.NewEncoder(w).Encode(data)
|
if err := json.NewEncoder(w).Encode(data); err != nil {
|
||||||
|
log.Printf("Failed to encode JSON response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RespondError sends a JSON error response with the given status code and message.
|
// RespondError sends a JSON error response with the given status code and message.
|
||||||
@@ -19,6 +22,7 @@ func RespondJSON(w http.ResponseWriter, status int, data any) {
|
|||||||
func RespondError(w http.ResponseWriter, status int, msg string) {
|
func RespondError(w http.ResponseWriter, status int, msg string) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
_ = json.NewEncoder(w).Encode(map[string]string{"error": msg})
|
if err := json.NewEncoder(w).Encode(map[string]string{"error": msg}); err != nil {
|
||||||
|
log.Printf("Failed to encode error response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user