[feat](client): make delivery durable with an offline check-in and ack queue
The server ledger is cleared by an explicit ack, never by the check-in response, so a dismissal that cannot reach the service must be persisted and retried or the device rings again later. Add a durable pending-ack queue (404 means the alert ended: settled, drop it), map the 409 ERR_ALARM_TRIGGERED_OFFLINE check-in into a normal trigger for the same takeover, and make a 404 an ending rather than a missed alarm. This also carries the expiry/endings state the screens render.
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
export {};
|
||||
|
||||
/**
|
||||
* Dismiss must silence the phone locally, first, without the owner.
|
||||
*
|
||||
* Source contract: JSX/native playback can't be executed headlessly here, so we
|
||||
* pin the order the code depends on — `stopAlarm()` before any server call or
|
||||
* event clearing in the acknowledge path — and that playback has no timer that
|
||||
* could silence it "by itself".
|
||||
*/
|
||||
declare const __dirname: string;
|
||||
const fs: { readFileSync(p: string, enc: string): string } = jest.requireActual('fs');
|
||||
const path: { join(...parts: string[]): string } = jest.requireActual('path');
|
||||
|
||||
const screen = fs.readFileSync(
|
||||
path.join(__dirname, '..', 'src', 'screens', 'LiveAlarmScreen.tsx'),
|
||||
'utf8',
|
||||
);
|
||||
const nativeTs = fs.readFileSync(
|
||||
path.join(__dirname, '..', 'src', 'services', 'alarmNative.ts'),
|
||||
'utf8',
|
||||
);
|
||||
|
||||
describe('local dismiss contract', () => {
|
||||
it('silences first and only then drops the live event', () => {
|
||||
const ackAt = screen.indexOf('const ack = useCallback');
|
||||
expect(ackAt).toBeGreaterThan(-1);
|
||||
const ack = screen.slice(ackAt, ackAt + 900);
|
||||
expect(ack.indexOf('await stopAlarm()')).toBeGreaterThan(-1);
|
||||
expect(ack.indexOf('await stopAlarm()')).toBeLessThan(ack.indexOf('clearLiveEvent()'));
|
||||
});
|
||||
|
||||
it('stops both audio and vibration through the native bridge', () => {
|
||||
expect(nativeTs).toContain('stopAlarm');
|
||||
expect(nativeTs).toContain('AlarmModule');
|
||||
});
|
||||
|
||||
it('does not schedule its own auto-stop in JS', () => {
|
||||
expect(screen).not.toMatch(/autoStop/i);
|
||||
// The 1 s interval is the displayed count-up only; it must not stop audio.
|
||||
const countUp = screen.slice(screen.indexOf('The count-up ticks'), screen.indexOf('The count-up ticks') + 300);
|
||||
expect(countUp).toContain('setInterval');
|
||||
expect(countUp).not.toContain('stopAlarm');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user