Files
BarangaySystem/resources/js/utils/RequestData.js
2026-06-06 18:43:00 +08:00

134 lines
3.8 KiB
JavaScript

// resources/js/utils/RequestData.js
import { useHashKeyCache } from '../composables/useHashKeyCache.js';
/**
* Modern implementation of the RequestData pattern.
* Supports method chaining and integration with HashKeyCache.
*/
export class RequestData {
constructor(withHashCheck = false) {
this._url = '';
this._type = 'GET';
this._data = null;
this._success = null;
this._error = null;
this._fromVarCache = false;
this._withHashCheck = withHashCheck;
this._hashCache = useHashKeyCache();
}
/** Set the request URL */
url(u) {
this._url = u;
return this;
}
/** Set the HTTP method (GET, POST, etc.) */
type(t) {
this._type = t.toUpperCase();
return this;
}
/** Set the request payload */
data(d) {
this._data = d;
return this;
}
/** Set the success callback */
success(callback) {
this._success = callback;
return this;
}
/** Set the error callback */
error(callback) {
this._error = callback;
return this;
}
/** Enable or disable cache-first behavior */
fromVarCache(bool) {
this._fromVarCache = bool;
return this;
}
/** Execute the request */
async go() {
if (!this._url) {
console.error('[RequestData] URL is missing');
return;
}
// 1. Check HashKey/Payload in URL first if applicable
const urlMatch = this._hashCache.parseHashUrl(this._url);
if (urlMatch.type !== 'none' && urlMatch.data) {
if (this._success) this._success(urlMatch.data, urlMatch.value);
return;
}
// 2. Check Var Cache (in-memory) if requested
if (this._fromVarCache) {
const cachedData = this._hashCache.getHashData(this._url);
if (cachedData) {
if (this._success) this._success(cachedData);
// Revalidate in background (Stale-While-Revalidate pattern)
this._fetchFromServer(true);
return;
}
}
// 3. Perform network request
return this._fetchFromServer();
}
/** Internal fetch implementation */
async _fetchFromServer(background = false) {
try {
const options = {
method: this._type,
headers: {
'Accept': 'application/json',
}
};
if (this._data && (this._type === 'POST' || this._type === 'PUT')) {
options.headers['Content-Type'] = 'application/json';
options.body = JSON.stringify(this._data);
}
const response = await fetch(this._url, options);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const result = await response.json();
// Update cache
if (this._fromVarCache) {
this._hashCache.setHashData(this._url, result);
}
// If background revalidation found non-identical data, you might want to call success again
// or use Pinia to update the UI reactively.
if (this._success) {
// For simplicity, we call success again if it's a background fetch
// but usually you want a way to avoid jitter if data is the same.
this._success(result);
}
return result;
} catch (err) {
if (!background && this._error) {
this._error(err);
}
if (background) {
console.warn('[RequestData] Background revalidation failed:', err);
}
}
}
}
/** Wrapper function for easier instantiation */
export function request(withHashCheck = false) {
return new RequestData(withHashCheck);
}