mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 09:01:03 -08:00
fix(parental-lock): let a repeated refusal shake for its full time
Each refusal started a 400ms timeout that cleared the shared shake state. A second refusal inside that window, for example on the other field, had its shake cut short by the first timer. Starting a shake now cancels the previous timer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2677b7afaf
commit
9d1f3d34fc
2 files changed
+34
-1
No files matched your search
+24
@@ -198,6 +198,30 @@ describe('ParentalLockPinDialogComponent', () => {
|
||||
expect(dialog.close).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('lets a second refusal shake for its full time', async () => {
|
||||
const { component } = await openDialog({ mode: 'set' });
|
||||
jest.useFakeTimers();
|
||||
try {
|
||||
component.onPinInput('24');
|
||||
await component.submit();
|
||||
expect(component.shake()).toBe('pin');
|
||||
|
||||
jest.advanceTimersByTime(300);
|
||||
component.onPinInput('2468');
|
||||
component.onConfirmationInput('2469');
|
||||
await component.submit();
|
||||
expect(component.shake()).toBe('confirmation');
|
||||
|
||||
// The first refusal's timer must not end the second shake.
|
||||
jest.advanceTimersByTime(150);
|
||||
expect(component.shake()).toBe('confirmation');
|
||||
jest.advanceTimersByTime(250);
|
||||
expect(component.shake()).toBeNull();
|
||||
} finally {
|
||||
jest.useRealTimers();
|
||||
}
|
||||
});
|
||||
|
||||
it('refuses a too-short PIN on Enter with an error on the PIN field', async () => {
|
||||
const dialog = await openDialog({ mode: 'set' });
|
||||
const pin = () =>
|
||||
|
||||
+10
-1
@@ -96,6 +96,7 @@ export class ParentalLockPinDialogComponent {
|
||||
private readonly throttle =
|
||||
this.data.throttle ?? createParentalLockPinThrottle();
|
||||
private cooldownTimer: number | null = null;
|
||||
private shakeTimer: number | null = null;
|
||||
|
||||
readonly isSetMode = computed(() => this.data.mode === 'set');
|
||||
readonly titleKey = computed(
|
||||
@@ -252,8 +253,16 @@ export class ParentalLockPinDialogComponent {
|
||||
}
|
||||
|
||||
private shakeField(field: PinDialogField): void {
|
||||
// A refusal inside the previous one's 400ms shakes for its own
|
||||
// full time; the earlier timer would otherwise end it early.
|
||||
if (this.shakeTimer !== null) {
|
||||
window.clearTimeout(this.shakeTimer);
|
||||
}
|
||||
this.shake.set(field);
|
||||
window.setTimeout(() => this.shake.set(null), 400);
|
||||
this.shakeTimer = window.setTimeout(() => {
|
||||
this.shakeTimer = null;
|
||||
this.shake.set(null);
|
||||
}, 400);
|
||||
}
|
||||
|
||||
private startCooldown(until: number): void {
|
||||
|
||||
Reference in new issue
Block a user