@@ -21,15 +21,15 @@ export class UpdateQueue {
2121 }
2222
2323 public updateUserId ( userId : string ) : void {
24- if ( ! this . updates ) {
24+ if ( this . updates ) {
2525 this . updates = {
26+ ...this . updates ,
2627 userId,
27- attributes : { } ,
2828 } ;
2929 } else {
3030 this . updates = {
31- ...this . updates ,
3231 userId,
32+ attributes : { } ,
3333 } ;
3434 }
3535 }
@@ -39,16 +39,16 @@ export class UpdateQueue {
3939 // Get userId from updates first, then fallback to config
4040 const userId = this . updates ?. userId ?? config . get ( ) . user . data . userId ?? "" ;
4141
42- if ( ! this . updates ) {
42+ if ( this . updates ) {
4343 this . updates = {
44+ ...this . updates ,
4445 userId,
45- attributes,
46+ attributes : { ... this . updates . attributes , ... attributes } ,
4647 } ;
4748 } else {
4849 this . updates = {
49- ...this . updates ,
5050 userId,
51- attributes : { ... this . updates . attributes , ... attributes } ,
51+ attributes,
5252 } ;
5353 }
5454 }
@@ -65,6 +65,81 @@ export class UpdateQueue {
6565 return ! this . updates ;
6666 }
6767
68+ private handleLanguageWithoutUserId (
69+ currentUpdates : Partial < TUpdates > & { attributes ?: TAttributes } ,
70+ config : RNConfig
71+ ) : Partial < TUpdates > & { attributes ?: TAttributes } {
72+ if ( ! currentUpdates . attributes ?. language ) {
73+ return currentUpdates ;
74+ }
75+
76+ // Update language in local config
77+ config . update ( {
78+ ...config . get ( ) ,
79+ user : {
80+ ...config . get ( ) . user ,
81+ data : {
82+ ...config . get ( ) . user . data ,
83+ language : currentUpdates . attributes . language ,
84+ } ,
85+ } ,
86+ } ) ;
87+
88+ logger . debug ( "Updated language successfully" ) ;
89+
90+ // Remove language from attributes
91+ const { language : _ , ...remainingAttributes } = currentUpdates . attributes ;
92+ return {
93+ ...currentUpdates ,
94+ attributes : remainingAttributes ,
95+ } ;
96+ }
97+
98+ private validateAttributesWithUserId (
99+ currentUpdates : Partial < TUpdates > & { attributes ?: TAttributes } ,
100+ effectiveUserId : string | null | undefined
101+ ) : void {
102+ const hasAttributes =
103+ Object . keys ( currentUpdates . attributes ?? { } ) . length > 0 ;
104+
105+ if ( hasAttributes && ! effectiveUserId ) {
106+ const errorMessage =
107+ "Formbricks can't set attributes without a userId! Please set a userId first with the setUserId function" ;
108+ logger . error ( errorMessage ) ;
109+ this . clearUpdates ( ) ;
110+ throw new Error ( errorMessage ) ;
111+ }
112+ }
113+
114+ private async sendUpdatesIfNeeded (
115+ effectiveUserId : string | null | undefined ,
116+ currentUpdates : Partial < TUpdates > & { attributes ?: TAttributes }
117+ ) : Promise < void > {
118+ if ( ! effectiveUserId ) {
119+ return ;
120+ }
121+
122+ const result = await sendUpdates ( {
123+ updates : {
124+ userId : effectiveUserId ,
125+ attributes : currentUpdates . attributes ?? { } ,
126+ } ,
127+ } ) ;
128+
129+ if ( result . ok ) {
130+ logger . debug ( "Updates sent successfully" ) ;
131+ } else {
132+ const err = result . error as {
133+ status ?: number ;
134+ code ?: string ;
135+ message ?: string ;
136+ } ;
137+ logger . error (
138+ `Failed to send updates: ${ err ?. message ?? "unknown error" } `
139+ ) ;
140+ }
141+ }
142+
68143 public async processUpdates ( ) : Promise < void > {
69144 if ( ! this . updates ) {
70145 return ;
@@ -80,66 +155,29 @@ export class UpdateQueue {
80155 let currentUpdates = { ...this . updates } ;
81156 const config = await RNConfig . getInstance ( ) ;
82157
83- if ( Object . keys ( currentUpdates ) . length > 0 ) {
84- // Get userId from either updates or config
85- const effectiveUserId =
86- currentUpdates . userId ?? config . get ( ) . user . data . userId ;
87- const isLanguageInUpdates = currentUpdates . attributes ?. language ;
88-
89- if ( ! effectiveUserId && isLanguageInUpdates ) {
90- // no user id set but the updates contain a language
91- // we need to set this language in the local config:
92- config . update ( {
93- ...config . get ( ) ,
94- user : {
95- ...config . get ( ) . user ,
96- data : {
97- ...config . get ( ) . user . data ,
98- language : currentUpdates . attributes ?. language ,
99- } ,
100- } ,
101- } ) ;
102-
103- logger . debug ( "Updated language successfully" ) ;
104-
105- const { language : _ , ...remainingAttributes } =
106- currentUpdates . attributes ?? { } ;
107-
108- // remove language from attributes
109- currentUpdates = {
110- ...currentUpdates ,
111- attributes : remainingAttributes ,
112- } ;
113- }
114-
115- if (
116- Object . keys ( currentUpdates . attributes ?? { } ) . length > 0 &&
117- ! effectiveUserId
118- ) {
119- const errorMessage =
120- "Formbricks can't set attributes without a userId! Please set a userId first with the setUserId function" ;
121- logger . error ( errorMessage ) ;
122- this . clearUpdates ( ) ;
123- throw new Error ( errorMessage ) ;
124- }
125-
126- // Only send updates if we have a userId (either from updates or local storage)
127- if ( effectiveUserId ) {
128- const result = await sendUpdates ( {
129- updates : {
130- userId : effectiveUserId ,
131- attributes : currentUpdates . attributes ?? { } ,
132- } ,
133- } ) ;
134-
135- if ( result . ok ) {
136- logger . debug ( "Updates sent successfully" ) ;
137- } else {
138- logger . error ( "Failed to send updates" ) ;
139- }
140- }
158+ if ( Object . keys ( currentUpdates ) . length === 0 ) {
159+ this . clearUpdates ( ) ;
160+ resolve ( ) ;
161+ return ;
141162 }
142163
164+ const effectiveUserId =
165+ currentUpdates . userId ?? config . get ( ) . user . data . userId ;
166+
167+ // Handle language updates without userId
168+ if ( ! effectiveUserId ) {
169+ currentUpdates = this . handleLanguageWithoutUserId (
170+ currentUpdates ,
171+ config
172+ ) ;
173+ }
174+
175+ // Validate attributes require userId
176+ this . validateAttributesWithUserId ( currentUpdates , effectiveUserId ) ;
177+
178+ // Send updates if we have a userId
179+ await this . sendUpdatesIfNeeded ( effectiveUserId , currentUpdates ) ;
180+
143181 this . clearUpdates ( ) ;
144182 resolve ( ) ;
145183 } catch ( error : unknown ) {
0 commit comments