create-shopify-firebase-app 2.0.6 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Settings page logic
3
3
  * Load, edit, and save app settings via the API.
4
- * Shows/hides the App Bridge <ui-save-bar> when the form is dirty.
4
+ * Uses Polaris Web Components + data-save-bar for native save/discard UX.
5
5
  */
6
6
 
7
7
  (function () {
@@ -9,161 +9,94 @@
9
9
 
10
10
  // ── State ───────────────────────────────────────────────────────
11
11
  var savedSettings = {};
12
- var isDirty = false;
13
- var isSaving = false;
14
12
 
15
13
  // ── Init ────────────────────────────────────────────────────────
16
14
  document.addEventListener("DOMContentLoaded", function () {
15
+ if (typeof apiFetch !== "function") {
16
+ var loading = document.getElementById("settings-loading");
17
+ if (loading) {
18
+ loading.innerHTML =
19
+ '<s-banner tone="critical"><s-text><s-text fontWeight="semibold">App failed to initialize</s-text> Core scripts did not load. Please refresh the page.</s-text></s-banner>';
20
+ }
21
+ return;
22
+ }
17
23
  loadSettings();
18
- setupSaveBar();
24
+ setupForm();
19
25
  });
20
26
 
21
- // ── Save bar wiring ─────────────────────────────────────────────
22
- function setupSaveBar() {
23
- var saveBar = document.getElementById("save-bar");
24
- var saveBtn = document.getElementById("save-btn");
25
- var discardBtn = document.getElementById("discard-btn");
26
-
27
- if (saveBtn) {
28
- saveBtn.addEventListener("click", function () {
29
- saveSettings();
30
- });
31
- }
32
-
33
- if (discardBtn) {
34
- discardBtn.addEventListener("click", function () {
35
- discardChanges();
36
- });
37
- }
27
+ // ── Form wiring (data-save-bar handles save/discard bar) ────────
28
+ function setupForm() {
29
+ var form = document.getElementById("settings-form");
30
+
31
+ // Submit = Save
32
+ form.addEventListener("submit", async function (e) {
33
+ e.preventDefault();
34
+ await saveSettings();
35
+ });
36
+
37
+ // Reset = Discard
38
+ form.addEventListener("reset", function () {
39
+ populateForm(savedSettings);
40
+ showToast("Changes discarded");
41
+ });
38
42
  }
39
43
 
40
44
  // ── Load settings ──────────────────────────────────────────────
41
45
  async function loadSettings() {
42
- var container = document.getElementById("settings-container");
46
+ var loading = document.getElementById("settings-loading");
47
+ var content = document.getElementById("settings-content");
43
48
 
44
49
  try {
45
50
  var data = await apiFetch("/api/settings");
46
51
  savedSettings = data.settings || data || {};
47
- renderForm(container, savedSettings);
52
+ populateForm(savedSettings);
53
+
54
+ // Hide loading, show content
55
+ if (loading) loading.style.display = "none";
56
+ content.style.display = "";
48
57
  } catch (err) {
49
- // If 404 or no settings yet, render empty form
58
+ // If 404 or no settings yet, show empty form
50
59
  if (err.message && err.message.indexOf("404") !== -1) {
51
60
  savedSettings = {};
52
- renderForm(container, savedSettings);
61
+ populateForm(savedSettings);
62
+ if (loading) loading.style.display = "none";
63
+ content.style.display = "";
53
64
  } else {
54
- container.innerHTML =
55
- '<div class="banner banner-critical">' +
56
- '<div class="banner-icon">&#9888;</div>' +
57
- '<div class="banner-content">' +
58
- "<p><strong>Could not load settings</strong></p>" +
59
- "<p>" + escapeHtml(err.message) + "</p>" +
60
- "</div></div>" +
61
- '<button class="btn mt-4" onclick="location.reload()">Retry</button>';
65
+ if (loading) {
66
+ loading.innerHTML =
67
+ '<s-banner tone="critical">' +
68
+ "<s-text>" +
69
+ "<s-text fontWeight=\"semibold\">Could not load settings</s-text> " +
70
+ escapeHtml(err.message) +
71
+ "</s-text></s-banner>" +
72
+ '<s-box paddingBlockStart="base"><s-button onclick="location.reload()">Retry</s-button></s-box>';
73
+ }
62
74
  }
63
75
  }
64
76
  }
65
77
 
66
- // ── Render form ─────────────────────────────────────────────────
67
- function renderForm(container, settings) {
68
- var html = "";
69
-
70
- // General settings card
71
- html += '<div class="card">';
72
- html += '<h2>General</h2>';
73
- html += '<p class="mb-4">Configure basic app settings.</p>';
74
-
75
- // Greeting message
76
- html += '<div class="form-group">';
77
- html += '<label for="setting-greeting">Store greeting message</label>';
78
- html += '<input type="text" class="form-input" id="setting-greeting" placeholder="Welcome to our store!" value="' + escapeAttr(settings.greeting || "") + '">';
79
- html += '<p class="form-hint">Displayed to customers when they visit your app.</p>';
80
- html += "</div>";
81
-
82
- // Theme select
83
- html += '<div class="form-group">';
84
- html += '<label for="setting-theme">Theme</label>';
85
- html += '<select class="form-select" id="setting-theme">';
86
- html += '<option value="auto"' + (settings.theme === "auto" ? " selected" : "") + '>Auto (System)</option>';
87
- html += '<option value="light"' + (settings.theme === "light" ? " selected" : "") + ">Light</option>";
88
- html += '<option value="dark"' + (settings.theme === "dark" ? " selected" : "") + ">Dark</option>";
89
- html += "</select>";
90
- html += '<p class="form-hint">Choose the visual theme for your app interface.</p>';
91
- html += "</div>";
92
-
93
- html += "</div>"; // end card
94
-
95
- // Notifications card
96
- html += '<div class="card">';
97
- html += '<h2>Notifications</h2>';
98
- html += '<p class="mb-4">Manage email and push notification preferences.</p>';
99
-
100
- // Enable notifications checkbox
101
- html += '<div class="form-group">';
102
- html += '<label class="form-checkbox">';
103
- html += '<input type="checkbox" id="setting-notifications"' + (settings.notifications ? " checked" : "") + ">";
104
- html += "<span>Enable email notifications</span>";
105
- html += "</label>";
106
- html += '<p class="form-hint" style="margin-left: 26px;">Receive email alerts for new orders and important events.</p>';
107
- html += "</div>";
108
-
109
- // Order notifications checkbox
110
- html += '<div class="form-group">';
111
- html += '<label class="form-checkbox">';
112
- html += '<input type="checkbox" id="setting-order-alerts"' + (settings.orderAlerts ? " checked" : "") + ">";
113
- html += "<span>Order alert notifications</span>";
114
- html += "</label>";
115
- html += '<p class="form-hint" style="margin-left: 26px;">Get notified when a new order is placed.</p>';
116
- html += "</div>";
117
-
118
- html += "</div>"; // end card
119
-
120
- // Advanced card
121
- html += '<div class="card">';
122
- html += '<h2>Advanced</h2>';
123
- html += '<p class="mb-4">Advanced customization options.</p>';
124
-
125
- // Custom CSS textarea
126
- html += '<div class="form-group">';
127
- html += '<label for="setting-css">Custom CSS</label>';
128
- html += '<textarea class="form-textarea" id="setting-css" rows="6" placeholder="/* Add custom styles here */">' + escapeHtml(settings.customCss || "") + "</textarea>";
129
- html += '<p class="form-hint">Add custom CSS to override default styles. Use with caution.</p>';
130
- html += "</div>";
131
-
132
- html += "</div>"; // end card
133
-
134
- // Save button (visible below form too)
135
- html += '<div class="flex justify-end gap-3 mb-8">';
136
- html += '<button class="btn" onclick="discardChanges()">Discard</button>';
137
- html += '<button class="btn btn-primary" id="save-button" onclick="saveSettings()">Save settings</button>';
138
- html += "</div>";
139
-
140
- container.innerHTML = html;
141
-
142
- // Attach change listeners for dirty tracking
143
- var inputs = container.querySelectorAll("input, select, textarea");
144
- for (var i = 0; i < inputs.length; i++) {
145
- inputs[i].addEventListener("input", markDirty);
146
- inputs[i].addEventListener("change", markDirty);
147
- }
78
+ // ── Populate form fields ────────────────────────────────────────
79
+ function populateForm(settings) {
80
+ setFieldValue("setting-greeting", settings.greeting || "");
81
+ setFieldValue("setting-theme", settings.theme || "auto");
82
+ setFieldValue("setting-css", settings.customCss || "");
83
+ setSwitch("setting-notifications", !!settings.notifications);
84
+ setSwitch("setting-order-alerts", !!settings.orderAlerts);
148
85
  }
149
86
 
150
- // ── Dirty state management ──────────────────────────────────────
151
- function markDirty() {
152
- if (isDirty) return;
153
- isDirty = true;
154
-
155
- var saveBar = document.getElementById("save-bar");
156
- if (saveBar && saveBar.show) {
157
- saveBar.show();
158
- }
87
+ function setFieldValue(id, value) {
88
+ var el = document.getElementById(id);
89
+ if (el) el.value = value;
159
90
  }
160
91
 
161
- function clearDirty() {
162
- isDirty = false;
163
-
164
- var saveBar = document.getElementById("save-bar");
165
- if (saveBar && saveBar.hide) {
166
- saveBar.hide();
92
+ function setSwitch(id, checked) {
93
+ var el = document.getElementById(id);
94
+ if (!el) return;
95
+ el.checked = checked;
96
+ if (checked) {
97
+ el.setAttribute("checked", "");
98
+ } else {
99
+ el.removeAttribute("checked");
167
100
  }
168
101
  }
169
102
 
@@ -185,20 +118,11 @@
185
118
 
186
119
  function getChecked(id) {
187
120
  var el = document.getElementById(id);
188
- return el ? el.checked : false;
121
+ return el ? el.hasAttribute("checked") || el.checked : false;
189
122
  }
190
123
 
191
124
  // ── Save settings ──────────────────────────────────────────────
192
- window.saveSettings = async function () {
193
- if (isSaving) return;
194
- isSaving = true;
195
-
196
- var saveButton = document.getElementById("save-button");
197
- if (saveButton) {
198
- saveButton.classList.add("btn-loading");
199
- saveButton.disabled = true;
200
- }
201
-
125
+ async function saveSettings() {
202
126
  try {
203
127
  var values = collectFormValues();
204
128
 
@@ -208,34 +132,12 @@
208
132
  });
209
133
 
210
134
  savedSettings = values;
211
- clearDirty();
212
135
  showToast("Settings saved successfully");
213
136
  } catch (err) {
214
137
  showToast("Failed to save: " + err.message, true);
215
- } finally {
216
- isSaving = false;
217
- if (saveButton) {
218
- saveButton.classList.remove("btn-loading");
219
- saveButton.disabled = false;
220
- }
221
138
  }
222
- };
223
-
224
- // ── Discard changes ─────────────────────────────────────────────
225
- window.discardChanges = function () {
226
- var container = document.getElementById("settings-container");
227
- renderForm(container, savedSettings);
228
- clearDirty();
229
- showToast("Changes discarded");
230
- };
231
-
232
- // ── Helpers ─────────────────────────────────────────────────────
233
- function escapeAttr(str) {
234
- return String(str)
235
- .replace(/&/g, "&amp;")
236
- .replace(/"/g, "&quot;")
237
- .replace(/'/g, "&#39;")
238
- .replace(/</g, "&lt;")
239
- .replace(/>/g, "&gt;");
240
139
  }
140
+
141
+ // Expose for direct calls
142
+ window.saveSettings = saveSettings;
241
143
  })();