Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
// Pure helpers for the one-time-token PIN entry. Kept free of React so the
|
|
// distribution/assembly logic can be unit-tested directly.
|
|
|
|
export const TOKEN_GROUPS = [4, 4, 4, 4, 4];
|
|
export const TOKEN_DIGIT_COUNT = TOKEN_GROUPS.reduce((sum, size) => sum + size, 0); // 20
|
|
|
|
export function onlyDigits(value: string): string {
|
|
return (value || '').replace(/\D+/g, '');
|
|
}
|
|
|
|
// Distribute typed/pasted digits across the fixed-width boxes starting at
|
|
// `startIndex`. Non-digits are ignored; overflow is dropped.
|
|
export function fillFrom(current: string[], startIndex: number, incoming: string): string[] {
|
|
const digits = onlyDigits(incoming);
|
|
const next = current.slice();
|
|
let cursor = startIndex;
|
|
for (const digit of digits) {
|
|
if (cursor >= TOKEN_DIGIT_COUNT) break;
|
|
next[cursor] = digit;
|
|
cursor += 1;
|
|
}
|
|
return next;
|
|
}
|
|
|
|
// The index of the first empty box at or after `from`, or the last box if full.
|
|
export function nextEmptyIndex(boxes: string[], from = 0): number {
|
|
for (let i = Math.max(0, from); i < TOKEN_DIGIT_COUNT; i += 1) {
|
|
if (!/\d/.test(boxes[i] || '')) return i;
|
|
}
|
|
return TOKEN_DIGIT_COUNT - 1;
|
|
}
|
|
|
|
// Join the boxes into the canonical 5x4 dashed token, e.g. 4817-2039-6152-...
|
|
export function assembleToken(boxes: string[]): string {
|
|
const digits = onlyDigits(boxes.join('')).slice(0, TOKEN_DIGIT_COUNT);
|
|
const groups: string[] = [];
|
|
let pos = 0;
|
|
for (const size of TOKEN_GROUPS) {
|
|
groups.push(digits.slice(pos, pos + size));
|
|
pos += size;
|
|
}
|
|
return groups.join('-');
|
|
}
|
|
|
|
export function isComplete(boxes: string[]): boolean {
|
|
return onlyDigits(boxes.join('')).length === TOKEN_DIGIT_COUNT;
|
|
}
|
|
|
|
export function emptyBoxes(): string[] {
|
|
return Array.from({ length: TOKEN_DIGIT_COUNT }, () => '');
|
|
}
|