HEX
Server: LiteSpeed
System: Linux server315.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User: globfdxw (6114)
PHP: 8.1.34
Disabled: NONE
Upload Files
File: /home/globfdxw/diasporameetsafrica.com/wp-content/plugins/extendify/src/QuickEdit/state/undo.js
// Entries are shaped like the save endpoint's request body so replay is just
// save(entry). Cap protects localStorage size.
import { __, sprintf } from '@wordpress/i18n';
import {
	save,
	saveProduct,
	saveSiteIdentity,
	saveWpFormsField,
	saveWpNavigationItem,
} from '../lib/api';
import { track } from '../lib/insights';

const STORAGE_KEY = 'extendify-quick-edit-undo-stack-v1';
const MAX_DEPTH = 5;
const ANNOUNCE_KEY = 'extendify-quick-edit-undo-announce';

const loadStack = () => {
	try {
		const raw = window.localStorage.getItem(STORAGE_KEY);
		const arr = raw ? JSON.parse(raw) : [];
		return Array.isArray(arr) ? arr : [];
	} catch (_) {
		return [];
	}
};

const saveStack = (stack) => {
	try {
		window.localStorage.setItem(STORAGE_KEY, JSON.stringify(stack));
	} catch (_) {
		// quota / private mode
	}
};

export const pushUndo = (entry) => {
	if (!entry) return;
	const kind = entry.kind || (entry.rawBlock ? 'block' : 'patches');
	const stack = loadStack();
	stack.push({ ...entry, kind, ts: Date.now() });
	while (stack.length > MAX_DEPTH) stack.shift();
	saveStack(stack);
};

const popUndo = () => {
	const stack = loadStack();
	const entry = stack.pop();
	saveStack(stack);
	return entry;
};

export const getStackDepth = () => loadStack().length;

// Returns false on empty stack so callers can show feedback.
export const performUndo = () => {
	const entry = popUndo();
	if (!entry) return false;
	// Site identity lives in wp_options, not post_content; route to its own endpoint.
	let promise;
	if (entry.identityReplay) {
		promise = saveSiteIdentity(entry.beforeValues || {});
	} else if (entry.productReplay) {
		// Routes through WCProductController; price entries carry { regular, sale }.
		promise = saveProduct({
			productId: entry.productId,
			field: entry.field,
			value: entry.beforeValue,
		});
	} else if (entry.navReplay) {
		// Routes through wp-navigation; ref-based nav items live in their own CPT.
		promise = saveWpNavigationItem({
			navPostId: entry.navPostId,
			itemIndex: entry.itemIndex,
			blockType: entry.blockType,
			patches: entry.patches,
		});
	} else if (entry.wpformsReplay) {
		// WPForms fields live in the form's serialized JSON, not post_content;
		// replay through the shallow-merge changes-bag the forward save used.
		promise = saveWpFormsField({
			formId: entry.formId,
			fieldId: entry.fieldId,
			changes: entry.changes,
		});
	} else {
		const { kind: _kind, ts: _ts, ...payload } = entry;
		promise = save(payload);
	}
	promise
		.then(() => {
			track('undo', { kind: entry.kind });
			// aria-live announcement survives the reload via sessionStorage.
			try {
				window.sessionStorage.setItem(
					ANNOUNCE_KEY,
					__('Reverted last change.', 'extendify-local'),
				);
			} catch (_) {
				// quota / private mode
			}
			window.location.reload();
		})
		.catch((err) => {
			track('undo_failed', { kind: entry.kind });
			window.alert(
				sprintf(
					// translators: %s is the underlying error message.
					__('Undo failed: %s', 'extendify-local'),
					err?.message || __('unknown error', 'extendify-local'),
				),
			);
		});
	return true;
};

export const ANNOUNCE_STORAGE_KEY = ANNOUNCE_KEY;