Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | 2x 6x 30x 30x 30x 30x 30x 1x 27x 2x 4x 2x 2x 2x 2x 4x 82x 3x 82x 1x 74x 12x 62x 62x 61x 1x 1x 5x 5x 5x 5x 5x 5x 75x 75x 71x 4x 4x 1x 3x | import { AppointmentHash } from "@/types/AppointmentHashTypes";
import { LocalStorageUiData } from "@/types/LocalStorageAppointmentData";
import {
LOCALSTORAGE_PARAM_APPOINTMENT_DATA,
SESSIONSTORAGE_PARAM_APPOINTMENT_AUTH_HASH,
} from "@/utils/Constants";
/** UI localStorage is only valid for login resume within this window. */
export const LOCALSTORAGE_UI_TTL_MS = 30 * 60 * 1000;
export function encodeAppointmentAuthHash(
processId: string,
authKey: string
): string {
return btoa(JSON.stringify({ id: processId, authKey }));
}
export function parseAppointmentHash(hash: string): AppointmentHash | null {
try {
// Add missing base64 padding if needed (padding may be stripped from URL)
const padding = (4 - (hash.length % 4)) % 4;
const paddedHash = padding > 0 ? hash + "=".repeat(padding) : hash;
const appointmentData = JSON.parse(window.atob(paddedHash));
if (
appointmentData.id == undefined ||
appointmentData.authKey == undefined
) {
return null;
}
return appointmentData;
} catch {
return null;
}
}
/**
* Store credentials for the OAuth hop: sessionStorage survives IdP redirect
* (URL fragment does not); replaceState avoids firing hashchange before leave.
*/
export function setAppointmentAuthHashForLogin(
processId: string | undefined,
authKey: string | undefined
): void {
if (!processId || !authKey) {
return;
}
const encoded = encodeAppointmentAuthHash(processId, authKey);
sessionStorage.setItem(SESSIONSTORAGE_PARAM_APPOINTMENT_AUTH_HASH, encoded);
history.replaceState(null, "", `#/appointment/${encoded}`);
}
export function saveUiToLocalStorage(uiData: LocalStorageUiData): void {
localStorage.setItem(
LOCALSTORAGE_PARAM_APPOINTMENT_DATA,
JSON.stringify(uiData)
);
}
export function clearAppointmentLocalStorage(): void {
if (localStorage.getItem(LOCALSTORAGE_PARAM_APPOINTMENT_DATA)) {
localStorage.removeItem(LOCALSTORAGE_PARAM_APPOINTMENT_DATA);
}
}
export function clearAppointmentAuthHashSession(): void {
if (sessionStorage.getItem(SESSIONSTORAGE_PARAM_APPOINTMENT_AUTH_HASH)) {
sessionStorage.removeItem(SESSIONSTORAGE_PARAM_APPOINTMENT_AUTH_HASH);
}
}
/**
* Prefer hash from the URL/prop; else restore from the short-lived session bridge.
*/
export function resolveAppointmentAuthHash(
appointmentHashFromProps?: string | null
): string | undefined {
if (appointmentHashFromProps) {
return appointmentHashFromProps;
}
const pendingHash = sessionStorage.getItem(
SESSIONSTORAGE_PARAM_APPOINTMENT_AUTH_HASH
);
if (!pendingHash) {
return undefined;
}
history.replaceState(null, "", `#/appointment/${pendingHash}`);
return pendingHash;
}
export function parseUiLocalStorage(data: string): LocalStorageUiData | null {
try {
const raw = JSON.parse(data) as {
timestamp?: number;
currentView?: number;
selectedServiceId?: string;
selectedProviderId?: string;
selectedServiceMap?: Record<string, number>;
selectedTimeslot?: number;
selectedService?: { id?: string };
selectedProvider?: { id?: string };
};
const selectedServiceId = raw.selectedServiceId ?? raw.selectedService?.id;
const selectedProviderId =
raw.selectedProviderId ?? raw.selectedProvider?.id;
Iif (
raw.timestamp == undefined ||
raw.currentView == undefined ||
selectedServiceId == undefined ||
selectedProviderId == undefined
) {
return null;
}
// Persist IDs only — never restore legacy full objects / credentials / PII.
return {
timestamp: raw.timestamp,
currentView: raw.currentView,
selectedServiceId: String(selectedServiceId),
selectedServiceMap: raw.selectedServiceMap ?? {},
selectedProviderId: String(selectedProviderId),
selectedTimeslot: raw.selectedTimeslot ?? 0,
};
} catch {
return null;
}
}
export function getFreshLocalStorageUiData(
nowMs: number = Date.now()
): LocalStorageUiData | null {
const raw = localStorage.getItem(LOCALSTORAGE_PARAM_APPOINTMENT_DATA);
if (!raw) {
return null;
}
const parsed = parseUiLocalStorage(raw);
if (!parsed || nowMs - parsed.timestamp >= LOCALSTORAGE_UI_TTL_MS) {
return null;
}
return parsed;
}
|