/** Service for coupon-related API calls */ import { supabase } from '@/supabase' import type { Coupon } from '@/types' export interface CouponFilters { category?: string is_active?: boolean active_only?: boolean } export const couponsService = { /** Get all coupons with optional filters */ async getAllCoupons(filters?: CouponFilters): Promise { let query = supabase.from('coupons').select('*, business:businesses(*)') if (filters?.category) query = query.eq('category', filters.category) if (filters?.is_active !== undefined) query = query.eq('is_active', filters.is_active) if (filters?.active_only !== undefined && filters.active_only) { query = query.eq('is_active', true) } const { data, error } = await query if (error) throw new Error(error.message) return data as Coupon[] }, /** Get a single coupon by ID */ async getCouponById(id: string): Promise { const { data, error } = await supabase.from('coupons').select('*, business:businesses(*)').eq('id', id).single() if (error) throw new Error(error.message) return data as Coupon }, /** Create a new coupon */ async createCoupon(coupon: Omit): Promise { // Prevent sending nested business properties over insert const { business, business_name, business_address, business_phone, created_at, updated_at, id, ...payload } = coupon as any const { data, error } = await supabase.from('coupons').insert([payload]).select().single() if (error) throw new Error(error.message) return data as Coupon }, /** Update an existing coupon */ async updateCoupon(id: string, coupon: Partial): Promise { const { business, business_name, business_address, business_phone, created_at, updated_at, id: _id, ...payload } = coupon as any const { data, error } = await supabase.from('coupons').update(payload).eq('id', id).select().single() if (error) throw new Error(error.message) return data as Coupon }, /** Delete a coupon */ async deleteCoupon(id: string): Promise { const { error } = await supabase.from('coupons').delete().eq('id', id) if (error) throw new Error(error.message) }, /** Claim a coupon */ async claimCoupon(id: string): Promise { const { data: userData, error: userError } = await supabase.auth.getUser() if (userError || !userData?.user) throw new Error('User not logged in.') const claimPayload = { user_id: userData.user.id, coupon_id: id, status: 'claimed', redemption_code: Math.random().toString(36).substring(2, 8).toUpperCase() } const { data, error } = await supabase.from('user_coupons').insert([claimPayload]).select().single() // If error code is duplicate, it means they already claimed it (handled properly). if (error) throw error return data }, /** Get current user's claimed coupons */ async getMyCoupons(): Promise { const { data: userData } = await supabase.auth.getUser() if (!userData || !userData.user) return [] const { data, error } = await supabase .from('user_coupons') .select('*, coupon:coupons(*, business:businesses(*))') .eq('user_id', userData.user.id) if (error) throw new Error(error.message) return data || [] }, /** Validate a coupon by code (merchants/drivers only) */ async validateCoupon(code: string): Promise { const { data, error } = await supabase .from('user_coupons') .update({ status: 'redeemed', redeemed_at: new Date().toISOString() }) .eq('redemption_code', code) .select() .single() if (error) throw new Error(error.message) if (!data) throw new Error('Invalid code or already redeemed.') return data } }