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 45x 45x 45x 45x 45x 1x 42x 2x 4x 2x 2x 2x 2x 4x 102x 4x 102x 1x 94x 27x 67x 67x 66x 1x 1x 6x 6x 6x 6x 6x 6x 95x 95x 90x 5x 5x 1x 4x | 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;
}
|