NeonClary's picture
Deploy brand mark, logo palette, goal-aware starters, and carousel fit.
ffcad5d verified
Raw
History Blame Contribute Delete
2.1 kB
/**
* Server persistence helpers for Workspace + Documents (phd-canvas API).
* Failures are soft — callers keep localStorage as a fallback cache.
*/
const apiBase = () => process.env.REACT_APP_API_URL || '';
const authHeaders = (token) => ({
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
});
export async function fetchCanvas(authToken) {
if (!authToken) return null;
try {
const resp = await fetch(`${apiBase()}/api/phd-canvas`, {
headers: authHeaders(authToken),
});
if (!resp.ok) return null;
return await resp.json();
} catch {
return null;
}
}
export async function saveWorkspace(authToken, workspace) {
if (!authToken) return false;
try {
const resp = await fetch(`${apiBase()}/api/phd-canvas/workspace`, {
method: 'PUT',
headers: authHeaders(authToken),
body: JSON.stringify({
layout: workspace.layout || [],
states: workspace.states || {},
view: workspace.view ?? undefined,
task_statuses: workspace.task_statuses ?? undefined,
}),
});
return resp.ok;
} catch {
return false;
}
}
export async function saveDeliverables(authToken, store) {
if (!authToken) return false;
try {
const resp = await fetch(`${apiBase()}/api/phd-canvas/deliverables`, {
method: 'PUT',
headers: authHeaders(authToken),
body: JSON.stringify({
activeProjectId: store.activeProjectId ?? null,
projects: store.projects || {},
}),
});
return resp.ok;
} catch {
return false;
}
}
/** Simple debounce — returns a cancelable scheduler. */
export function debounce(fn, ms = 800) {
let t = null;
const wrapped = (...args) => {
if (t) clearTimeout(t);
t = setTimeout(() => {
t = null;
fn(...args);
}, ms);
};
wrapped.cancel = () => {
if (t) clearTimeout(t);
t = null;
};
wrapped.flush = (...args) => {
if (t) clearTimeout(t);
t = null;
fn(...args);
};
return wrapped;
}