PageSourceSearch

https://saddleback.com/scripts/ServingOpps/Stores/CartStore.js?v=517cdeafa93af7720f65d0a6f449ca34186eeedc

js saddleback.com collected 2026-09-24 17:20:24 UTC 2,645 bytes, 89 lines download raw bytes

1// Single-source-of-truth cart for sign-ups, shared across the ServingOpps page,
2// the upcoming sign-up details page, and anything else that needs it.
3//
4// State is a Vue reactive array, so consumers that import `items` get automatic
5// reactivity without prop-drilling — mutating via the helpers below updates every
6// view bound to it.
7//
8// Persistence: every mutation is mirrored to localStorage under STORAGE_KEY.
9// On module load, the array hydrates from storage so the cart survives reloads
10// and navigation between sign-up pages.
11
12const { reactive, watch } = Vue;
13
14const STORAGE_KEY = 'saddleback.signups.cart';
15
16function loadFromStorage() {
17  try {
18    const raw = localStorage.getItem(STORAGE_KEY);
19    if (!raw) return [];
20    const parsed = JSON.parse(raw);
21    return Array.isArray(parsed) ? parsed : [];
22  } catch (err) {
23    console.warn('[CartStore] Failed to parse cart from localStorage; starting empty.', err);
24    return [];
25  }
26}
27
28function saveToStorage(snapshot) {
29  try {
30    localStorage.setItem(STORAGE_KEY, JSON.stringify(snapshot));
31  } catch (err) {
32    // Storage may be full or disabled (private mode, etc.). Cart still works in-memory.
33    console.warn('[CartStore] Failed to save cart to localStorage.', err);
34  }
35}
36
37// Composite key — id + locationId + scheduleId uniquely identifies a sign-up.
38// Same key the map drawer and list item already use for `isInCart` / `isSignedUp`.
39function oppKey(opp) {
40  const id = opp?.id ?? 0;
41  const locationId = opp?.location?.id ?? 0;
42  const scheduleId = opp?.schedules?.[0]?.id ?? 0;
43  return `${id}-${locationId}-${scheduleId}`;
44}
45
46const items = reactive(loadFromStorage());
47
48// Persist whenever the array shape changes (push / splice / replace).
49// `deep: true` also catches mutations inside individual entries — overkill for
50// our usage (we only push/splice) but cheap and future-proof.
51watch(
52  items,
53  (snapshot) => saveToStorage(snapshot),
54  { deep: true }
55);
56
57function isInCart(opp) {
58  if (!opp) return false;
59  const key = oppKey(opp);
60  return items.some((item) => oppKey(item) === key);
61}
62
63function addItem(opp) {
64  if (!opp || isInCart(opp)) return false;
65  items.push(opp);
66  return true;
67}
68
69function removeItem(opp) {
70  if (!opp) return false;
71  const key = oppKey(opp);
72  const idx = items.findIndex((item) => oppKey(item) === key);
73  if (idx === -1) return false;
74  items.splice(idx, 1);
75  return true;
76}
77
78function clearCart() {
79  items.splice(0, items.length);
80}
81
82export default {
83  items,
84  oppKey,
85  isInCart,
86  addItem,
87  removeItem,
88  clearCart,
89};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.