4-digit auto-submit PIN + operator name in audit logs
Login: fixed-length 4-digit PIN that auto-submits on the 4th digit (no submit button to scroll to on small iPhone screens) and clears on a wrong PIN. Compact, vertically-centered keypad so it fits without scrolling. Operator tracking: after PIN auth, staff enter their name (new /operator screen, persisted per device). The name is sent as X-Operator on every authed request and recorded on each check-in/undo/ice audit entry (new Operator column), so logs show who did what. Shown in the scanner header and the admin audit view. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
336d2a5c83
commit
0e8fe3bb9a
11 changed files with 311 additions and 102 deletions
|
|
@ -2,6 +2,7 @@ import { Platform } from "react-native";
|
|||
|
||||
// Token persistence: localStorage on web, SecureStore on native.
|
||||
const KEY = "campscan.token";
|
||||
const OPERATOR_KEY = "campscan.operator";
|
||||
|
||||
export async function saveToken(token: string): Promise<void> {
|
||||
if (Platform.OS === "web") {
|
||||
|
|
@ -40,3 +41,44 @@ export async function clearToken(): Promise<void> {
|
|||
const SecureStore = await import("expo-secure-store");
|
||||
await SecureStore.deleteItemAsync(KEY);
|
||||
}
|
||||
|
||||
// Operator (gate staff) name — plain persistence, not sensitive. Kept in
|
||||
// localStorage on both platforms for simplicity (SecureStore is overkill here;
|
||||
// on native we still use localStorage-less AsyncStorage-free approach below).
|
||||
export async function saveOperator(name: string): Promise<void> {
|
||||
if (Platform.OS === "web") {
|
||||
try {
|
||||
window.localStorage.setItem(OPERATOR_KEY, name);
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
return;
|
||||
}
|
||||
const SecureStore = await import("expo-secure-store");
|
||||
await SecureStore.setItemAsync(OPERATOR_KEY, name);
|
||||
}
|
||||
|
||||
export async function loadOperator(): Promise<string | null> {
|
||||
if (Platform.OS === "web") {
|
||||
try {
|
||||
return window.localStorage.getItem(OPERATOR_KEY);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
const SecureStore = await import("expo-secure-store");
|
||||
return SecureStore.getItemAsync(OPERATOR_KEY);
|
||||
}
|
||||
|
||||
export async function clearOperator(): Promise<void> {
|
||||
if (Platform.OS === "web") {
|
||||
try {
|
||||
window.localStorage.removeItem(OPERATOR_KEY);
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
return;
|
||||
}
|
||||
const SecureStore = await import("expo-secure-store");
|
||||
await SecureStore.deleteItemAsync(OPERATOR_KEY);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue