persistence.js Data adapter
Three functions that wrap localStorage. The simplest module in the project. All logic for what to save lives in PlannerContext — this module only handles the serialization/deserialization.
Parent
Called by
PlannerContext.jsx (loadSaved on mount, saveState on every change, clearState on reset)
Exported functions
loadSaved() → SavedState | null
Reads plan index and active plan from localStorage. Reads the active plan's data JSON. Returns a fully parsed object, or null if nothing is saved (first visit).
Returns: SavedState object with placements, cohort, major selections, etc. — or null
saveState(persist: boolean, obj: PlanState) → void
If
persist = true, serializes obj to JSON and writes it to ncp-plan-data-{activePlanId}. If persist = false, writes nothing (user has disabled auto-save). Also updates ncp-plan-index with the current plan's lastSaved timestamp.clearState() → void
Removes all Nu-Map keys from localStorage. Called when the user clicks "Reset plan." Removes
ncp-plan-index, ncp-active-plan, and all ncp-plan-data-* keys.localStorage key reference
| Key | Contents | Lifetime |
|---|---|---|
ncp-plan-index | [{id, name, lastSaved}] | Until clearState() |
ncp-active-plan | Plan ID string | Until clearState() |
ncp-plan-data-{id} | Full plan JSON (see below) | Until plan deleted or clearState() |
ncp-theme | Theme name string | Permanent (not cleared by reset) |
ncp-zoom | Number | Permanent |
ncp-ent-sem/year | Cohort settings | Permanent |
ncp-grad-sem/year | Cohort settings | Permanent |
ncp-starred | string[] of courseIds | Permanent |
ncp-sticky-courses | boolean | Permanent |
ncp-collapse-other-credits | boolean (default true) | Permanent |
ncp-show-cont-logo | boolean (default true) — show company logo on co-op/internship continuation rows | Permanent |
ncp-seen-disclaimer | boolean | Permanent |
ncp-state-v2 | Legacy full state (old system) | Migrated on load |
Plan JSON structure
{
"version": 1,
"exported": "2026-04-04T12:00:00Z",
"entSem": "fall", "entYear": 2026,
"gradSem": "spring", "gradYear": 2031,
"placements": { "CS3500": "fall2027", "CS2810": "spring2028" },
"workPl": { "coop-1234": { "semId": "sumA2028", "duration": 6, "company": "Microsoft", "companyDomain": "microsoft.com", "subline": "SWE Intern" } },
"internPl": {},
"semOrders": { "fall2027": ["CS3500", "CS1800"] },
"shOverrides": { "CS1234": 3 },
"bonusSH": { "fall2026": 8 },
"major": "2024/computer-information-science/computer_science_bscs",
"conc": null,
"minor1": null, "minor2": null,
"placedOut": ["CS1200"],
"substitutions": [{ "from": "ENGW3302", "to": "ENGW3315" }]
}