88 * Update campaign fields. All fields are optional.
99 *
1010 * Body:
11- * - name? : string — Campaign name (non-empty)
12- * - bonusCreditAmount? : number — Bonus credits in dollars (> 0)
13- * - isActive? : boolean — Enable/disable the campaign
14- * - code? : string | null — Redeemable code (min 6 chars, auto-uppercased, null to remove)
15- * - utmSource? : string | null — UTM source match (null = wildcard)
16- * - utmMedium? : string | null — UTM medium match (null = wildcard)
17- * - utmCampaign? : string | null — UTM campaign match (null = wildcard)
18- * - utmContent? : string | null — UTM content match (null = wildcard)
11+ * - name: string (non-empty) - Campaign name
12+ * - bonusCreditAmount: number (> 0) - Bonus credits in dollars
13+ * - isActive: boolean - Enable/disable the campaign
14+ * - code: string | null (min 6 chars, auto-uppercased, null to remove) - Redeemable code
15+ * - utmSource: string | null - UTM source match (null = wildcard)
16+ * - utmMedium: string | null - UTM medium match (null = wildcard)
17+ * - utmCampaign: string | null - UTM campaign match (null = wildcard)
18+ * - utmContent: string | null - UTM content match (null = wildcard)
1919 */
2020
2121import { db } from '@sim/db'
2222import { referralCampaigns } from '@sim/db/schema'
2323import { createLogger } from '@sim/logger'
2424import { eq } from 'drizzle-orm'
25+ import { getBaseUrl } from '@/lib/core/utils/urls'
2526import { withAdminAuthParams } from '@/app/api/v1/admin/middleware'
2627import {
2728 badRequestResponse ,
2829 internalErrorResponse ,
2930 notFoundResponse ,
3031 singleResponse ,
3132} from '@/app/api/v1/admin/responses'
33+ import { toAdminReferralCampaign } from '@/app/api/v1/admin/types'
3234
33- const logger = createLogger ( 'AdminReferralCampaign ' )
35+ const logger = createLogger ( 'AdminReferralCampaignDetailAPI ' )
3436
3537interface RouteParams {
3638 id : string
3739}
3840
39- export const GET = withAdminAuthParams < RouteParams > ( async ( _request , context ) => {
41+ export const GET = withAdminAuthParams < RouteParams > ( async ( _ , context ) => {
4042 try {
41- const { id } = await context . params
43+ const { id : campaignId } = await context . params
4244
4345 const [ campaign ] = await db
4446 . select ( )
4547 . from ( referralCampaigns )
46- . where ( eq ( referralCampaigns . id , id ) )
48+ . where ( eq ( referralCampaigns . id , campaignId ) )
4749 . limit ( 1 )
4850
4951 if ( ! campaign ) {
5052 return notFoundResponse ( 'Campaign' )
5153 }
5254
53- return singleResponse ( campaign )
55+ logger . info ( `Admin API: Retrieved referral campaign ${ campaignId } ` )
56+
57+ return singleResponse ( toAdminReferralCampaign ( campaign , getBaseUrl ( ) ) )
5458 } catch ( error ) {
55- logger . error ( 'Failed to get referral campaign' , { error } )
59+ logger . error ( 'Admin API: Failed to get referral campaign' , { error } )
5660 return internalErrorResponse ( 'Failed to get referral campaign' )
5761 }
5862} )
5963
6064export const PATCH = withAdminAuthParams < RouteParams > ( async ( request , context ) => {
6165 try {
62- const { id } = await context . params
66+ const { id : campaignId } = await context . params
6367 const body = await request . json ( )
6468
6569 const [ existing ] = await db
6670 . select ( )
6771 . from ( referralCampaigns )
68- . where ( eq ( referralCampaigns . id , id ) )
72+ . where ( eq ( referralCampaigns . id , campaignId ) )
6973 . limit ( 1 )
7074
7175 if ( ! existing ) {
7276 return notFoundResponse ( 'Campaign' )
7377 }
7478
75- const updates : Record < string , unknown > = { updatedAt : new Date ( ) }
79+ const updateData : Record < string , unknown > = { updatedAt : new Date ( ) }
7680
7781 if ( body . name !== undefined ) {
78- if ( typeof body . name !== 'string' || ! body . name ) {
82+ if ( typeof body . name !== 'string' || body . name . trim ( ) . length === 0 ) {
7983 return badRequestResponse ( 'name must be a non-empty string' )
8084 }
81- updates . name = body . name
85+ updateData . name = body . name . trim ( )
8286 }
8387
8488 if ( body . bonusCreditAmount !== undefined ) {
@@ -89,14 +93,14 @@ export const PATCH = withAdminAuthParams<RouteParams>(async (request, context) =
8993 ) {
9094 return badRequestResponse ( 'bonusCreditAmount must be a positive number' )
9195 }
92- updates . bonusCreditAmount = body . bonusCreditAmount . toString ( )
96+ updateData . bonusCreditAmount = body . bonusCreditAmount . toString ( )
9397 }
9498
9599 if ( body . isActive !== undefined ) {
96100 if ( typeof body . isActive !== 'boolean' ) {
97101 return badRequestResponse ( 'isActive must be a boolean' )
98102 }
99- updates . isActive = body . isActive
103+ updateData . isActive = body . isActive
100104 }
101105
102106 if ( body . code !== undefined ) {
@@ -108,29 +112,31 @@ export const PATCH = withAdminAuthParams<RouteParams>(async (request, context) =
108112 return badRequestResponse ( 'code must be at least 6 characters' )
109113 }
110114 }
111- updates . code = body . code ? body . code . trim ( ) . toUpperCase ( ) : null
115+ updateData . code = body . code ? body . code . trim ( ) . toUpperCase ( ) : null
112116 }
113117
114118 for ( const field of [ 'utmSource' , 'utmMedium' , 'utmCampaign' , 'utmContent' ] as const ) {
115119 if ( body [ field ] !== undefined ) {
116120 if ( body [ field ] !== null && typeof body [ field ] !== 'string' ) {
117121 return badRequestResponse ( `${ field } must be a string or null` )
118122 }
119- updates [ field ] = body [ field ]
123+ updateData [ field ] = body [ field ] || null
120124 }
121125 }
122126
123127 const [ updated ] = await db
124128 . update ( referralCampaigns )
125- . set ( updates )
126- . where ( eq ( referralCampaigns . id , id ) )
129+ . set ( updateData )
130+ . where ( eq ( referralCampaigns . id , campaignId ) )
127131 . returning ( )
128132
129- logger . info ( 'Updated referral campaign' , { id, updates } )
133+ logger . info ( `Admin API: Updated referral campaign ${ campaignId } ` , {
134+ fields : Object . keys ( updateData ) . filter ( ( k ) => k !== 'updatedAt' ) ,
135+ } )
130136
131- return singleResponse ( updated )
137+ return singleResponse ( toAdminReferralCampaign ( updated , getBaseUrl ( ) ) )
132138 } catch ( error ) {
133- logger . error ( 'Failed to update referral campaign' , { error } )
139+ logger . error ( 'Admin API: Failed to update referral campaign' , { error } )
134140 return internalErrorResponse ( 'Failed to update referral campaign' )
135141 }
136142} )
0 commit comments