Skip to content

Commit fd35d07

Browse files
committed
stop manual status from auto-reverting to a previous claim
1 parent e78ad0f commit fd35d07

3 files changed

Lines changed: 57 additions & 15 deletions

File tree

ee/packages/presence/src/Presence.spec.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,12 @@ describe('Presence class', () => {
111111
statusExpiresAt: expiresAt,
112112
});
113113

114-
expect(updatePresenceMock).toHaveBeenCalledWith('u1', expect.objectContaining({ statusExpiresAt: expiresAt }), undefined, undefined);
114+
expect(updatePresenceMock).toHaveBeenCalledWith(
115+
'u1',
116+
expect.objectContaining({ statusExpiresAt: expiresAt }),
117+
expect.arrayContaining(['previousState']),
118+
undefined,
119+
);
115120
});
116121
});
117122

ee/packages/presence/src/lib/presenceEngine.spec.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,15 +163,47 @@ describe('processPresence', () => {
163163
expect(result.values).toStrictEqual({});
164164
});
165165

166-
test('should apply higher priority over external and save external as previousState', () => {
166+
test('should apply manual over external without stashing the displaced claim', () => {
167167
const result = processPresence(
168168
user({ statusSource: 'external', statusDefault: UserStatus.BUSY, statusText: 'In a meeting' }),
169169
[session()],
170170
{ type: 'setActive', newState: { statusDefault: UserStatus.BUSY, statusText: 'Focusing', statusSource: 'manual' } },
171171
);
172172
expect(result.values.statusSource).toBe('manual');
173173
expect(result.values.statusText).toBe('Focusing');
174-
expect(result.values.previousState).toMatchObject({ statusSource: 'external', statusText: 'In a meeting' });
174+
expect(result.values.previousState).toBeUndefined();
175+
expect(result.clear).toContain('previousState');
176+
});
177+
178+
test('should drop a queued previousState when a manual claim wins', () => {
179+
const result = processPresence(
180+
user({
181+
statusSource: 'external',
182+
statusDefault: UserStatus.BUSY,
183+
statusText: 'In a meeting',
184+
previousState: { statusDefault: UserStatus.AWAY, statusText: 'Lunch', statusSource: 'manual' },
185+
}),
186+
[session()],
187+
{ type: 'setActive', newState: { statusDefault: UserStatus.BUSY, statusText: 'Focusing', statusSource: 'manual' } },
188+
);
189+
expect(result.values.statusSource).toBe('manual');
190+
expect(result.values.previousState).toBeUndefined();
191+
expect(result.clear).toContain('previousState');
192+
});
193+
194+
test('should clear a queued previousState when overwriting a same-source manual claim', () => {
195+
const result = processPresence(
196+
user({
197+
statusSource: 'manual',
198+
statusDefault: UserStatus.BUSY,
199+
statusText: 'Focusing',
200+
previousState: { statusDefault: UserStatus.AWAY, statusText: 'Lunch', statusSource: 'external' },
201+
}),
202+
[session()],
203+
{ type: 'setActive', newState: { statusDefault: UserStatus.AWAY, statusText: 'Heads down', statusSource: 'manual' } },
204+
);
205+
expect(result.values.statusText).toBe('Heads down');
206+
expect(result.clear).toContain('previousState');
175207
});
176208
});
177209

ee/packages/presence/src/lib/presenceEngine.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,21 @@ function resolveIntent(
9595
const currentPriority = user.statusSource ? PRIORITY[user.statusSource] : NO_PRIORITY;
9696
const newPriority = newState.statusSource ? PRIORITY[newState.statusSource] : NO_PRIORITY;
9797

98-
// higher priority -> save current as previous and apply new
98+
// a manual claim is the user's explicit intent: when it wins it doesn't stash the
99+
// displaced claim and clears any queued one, so it never gets auto-reverted.
100+
const isManual = newState.statusSource === 'manual';
101+
102+
// higher priority -> apply new; stash displaced claim unless the new claim is manual
99103
if (newPriority < currentPriority) {
100-
const previousState = user.statusSource
101-
? {
102-
statusDefault: currentStatusDefault,
103-
statusText: user.statusText ?? '',
104-
statusSource: user.statusSource,
105-
statusExpiresAt: user.statusExpiresAt,
106-
}
107-
: undefined;
104+
const previousState =
105+
!isManual && user.statusSource
106+
? {
107+
statusDefault: currentStatusDefault,
108+
statusText: user.statusText ?? '',
109+
statusSource: user.statusSource,
110+
statusExpiresAt: user.statusExpiresAt,
111+
}
112+
: undefined;
108113

109114
return {
110115
set: {
@@ -114,11 +119,11 @@ function resolveIntent(
114119
...(newState.statusExpiresAt && { statusExpiresAt: newState.statusExpiresAt }),
115120
...(previousState && { previousState }),
116121
},
117-
unset: fieldsToUnset(newState),
122+
unset: fieldsToUnset(newState, isManual ? ['previousState'] : []),
118123
};
119124
}
120125

121-
// same priority -> overwrite and keep previous
126+
// same priority -> overwrite; manual also drops any queued previous
122127
if (newPriority === currentPriority) {
123128
return {
124129
set: {
@@ -127,7 +132,7 @@ function resolveIntent(
127132
...(newState.statusText != null && { statusText: newState.statusText }),
128133
...(newState.statusExpiresAt && { statusExpiresAt: newState.statusExpiresAt }),
129134
},
130-
unset: fieldsToUnset(newState),
135+
unset: fieldsToUnset(newState, isManual ? ['previousState'] : []),
131136
};
132137
}
133138

0 commit comments

Comments
 (0)