Skip to content

Commit 85c1e0a

Browse files
sumchatteringclaude
andcommitted
fix(#581): convert createdAt and expiresAt to Date objects in fromDict
The native bridge sends epoch milliseconds (number) for createdAt and expiresAt, but the previous code used setUTCMilliseconds which returns a number instead of a Date object. This caused runtime crashes when consumers tried to use createdAt as a Date. Replace with new Date() constructor to properly convert timestamps. Also removes the @ts-ignore workaround and provides a default for priorityLevel. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e69c305 commit 85c1e0a

2 files changed

Lines changed: 47 additions & 15 deletions

File tree

src/__tests__/IterableInApp.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,46 @@ describe('Iterable In App', () => {
178178
);
179179
});
180180

181+
test('fromDict_withCreatedAtAndExpiresAt_returnsDateObjects', () => {
182+
// GIVEN a message dict with numeric timestamps from the native bridge
183+
const createdAtMs = 1609459200000; // 2021-01-01T00:00:00.000Z
184+
const expiresAtMs = 1609545600000; // 2021-01-02T00:00:00.000Z
185+
const messageDict = {
186+
messageId: 'message1',
187+
campaignId: 1234,
188+
trigger: { type: IterableInAppTriggerType.immediate },
189+
createdAt: createdAtMs,
190+
expiresAt: expiresAtMs,
191+
priorityLevel: 300.5,
192+
};
193+
194+
// WHEN fromDict is called
195+
const message = IterableInAppMessage.fromDict(messageDict);
196+
197+
// THEN createdAt and expiresAt are Date objects with the correct values
198+
expect(message.createdAt).toBeInstanceOf(Date);
199+
expect(message.expiresAt).toBeInstanceOf(Date);
200+
expect(message.createdAt?.getTime()).toBe(createdAtMs);
201+
expect(message.expiresAt?.getTime()).toBe(expiresAtMs);
202+
});
203+
204+
test('fromDict_withoutCreatedAtAndExpiresAt_returnsUndefined', () => {
205+
// GIVEN a message dict without timestamps
206+
const messageDict = {
207+
messageId: 'message1',
208+
campaignId: 1234,
209+
trigger: { type: IterableInAppTriggerType.immediate },
210+
priorityLevel: 300.5,
211+
};
212+
213+
// WHEN fromDict is called
214+
const message = IterableInAppMessage.fromDict(messageDict);
215+
216+
// THEN createdAt and expiresAt are undefined
217+
expect(message.createdAt).toBeUndefined();
218+
expect(message.expiresAt).toBeUndefined();
219+
});
220+
181221
test('getMessages_noParams_returnsMessages', async () => {
182222
// GIVEN a list of in-app messages representing the local queue
183223
const messageDicts = [

src/inApp/classes/IterableInAppMessage.ts

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -175,16 +175,12 @@ export class IterableInAppMessage {
175175
const campaignId = dict.campaignId;
176176
const trigger = IterableInAppTrigger.fromDict(dict.trigger);
177177

178-
let createdAt = dict.createdAt;
179-
if (createdAt) {
180-
const dateObject = new Date(0);
181-
createdAt = dateObject.setUTCMilliseconds(createdAt);
182-
}
183-
let expiresAt = dict.expiresAt;
184-
if (expiresAt) {
185-
const dateObject = new Date(0);
186-
expiresAt = dateObject.setUTCMilliseconds(expiresAt);
187-
}
178+
const createdAt = dict.createdAt
179+
? new Date(dict.createdAt)
180+
: undefined;
181+
const expiresAt = dict.expiresAt
182+
? new Date(dict.expiresAt)
183+
: undefined;
188184
const saveToInbox = IterableUtil.readBoolean(dict, 'saveToInbox');
189185
const inboxMetadataDict = dict.inboxMetadata;
190186
let inboxMetadata: IterableInboxMetadata | undefined;
@@ -196,16 +192,12 @@ export class IterableInAppMessage {
196192
const customPayload = dict.customPayload;
197193
const read = IterableUtil.readBoolean(dict, 'read');
198194

199-
const priorityLevel = dict.priorityLevel;
195+
const priorityLevel = dict.priorityLevel ?? 0;
200196

201197
return new IterableInAppMessage(
202198
messageId,
203199
campaignId,
204200
trigger,
205-
// MOB-10426: Speak to the team about `IterableInAppMessage` requiring a date
206-
// object, but being passed a number in this case
207-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
208-
// @ts-ignore
209201
createdAt,
210202
expiresAt,
211203
saveToInbox,

0 commit comments

Comments
 (0)