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 29x 29x 29x 29x 29x 1x 26x 2x 4x 2x 2x 2x 2x 4x 79x 3x 79x 1x 71x 11x 60x 60x 59x 1x 1x 5x 5x 5x 5x 5x 5x 72x 72x 68x 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;
}
|