Skip to content

Commit 568c849

Browse files
committed
Update toolkit from Keystone 2.0.0
1 parent 2d72f7d commit 568c849

10 files changed

Lines changed: 12025 additions & 394 deletions

File tree

package-lock.json

Lines changed: 11424 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
{
22
"name": "keystone",
3-
"type": "commonjs",
4-
"version": "1.3.0",
3+
"version": "2.0.0",
54
"scripts": {
65
"dev": "npm-run-all --parallel vite_dev shopify_dev",
7-
"pull": "shopify theme pull --nodelete --store brickspacetestingstore.myshopify.com",
8-
"shopify_dev": "shopify theme dev --store brickspacetestingstore.myshopify.com",
6+
"pull": "shopify theme pull --nodelete --store high-variant-combined-testing-store.myshopify.com",
7+
"shopify_dev": "shopify theme dev --store high-variant-combined-testing-store.myshopify.com",
98
"vite_dev": "vite dev",
109
"test": "vitest",
1110
"coverage": "vitest run --coverage",
@@ -31,18 +30,18 @@
3130
"prettier": "^3.1.0",
3231
"prettier-plugin-tailwindcss": "^0.6.8",
3332
"tailwindcss": "^3.4.13",
34-
"vite": "^4.2.0",
35-
"vite-plugin-shopify": "^2.0.2",
33+
"vite": "^5.0.0",
34+
"vite-plugin-shopify": "^3.1.0",
3635
"vitest": "^0.29.7"
3736
},
3837
"dependencies": {
39-
"@alpinejs/focus": "^3.12.0",
40-
"@alpinejs/intersect": "^3.12.0",
41-
"@alpinejs/persist": "^3.12.0",
42-
"alpinejs": "^3.12.0",
43-
"instant.page": "5.1.1"
38+
"@alpinejs/focus": "^3.14.9",
39+
"@alpinejs/intersect": "^3.14.9",
40+
"@alpinejs/persist": "^3.14.9",
41+
"alpinejs": "^3.14.9",
42+
"instant.page": "5.2.0"
4443
},
4544
"config": {
46-
"store": "brickspacetestingstore.myshopify.com"
45+
"store": "high-variant-combined-testing-store.myshopify.com"
4746
}
4847
}

src/entrypoints/styles.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ html {
5151

5252
/* - strikethrough */
5353
.strikethrough {
54-
@apply line-through decoration-[#00000050] decoration-2;
54+
@apply !line-through decoration-[#00000050] decoration-2;
5555
}
5656

5757
/* - reset line-height */

src/ts/cart/cart.ts

Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,8 @@ export const cart = {
2828
try {
2929
const response = await fetch(`${window.Shopify.routes.root}cart.js`, {
3030
method: "GET",
31-
headers: {
32-
"Content-Type": "application/json",
33-
},
31+
credentials: "same-origin",
32+
cache: "no-store",
3433
});
3534

3635
if (!response.ok) {
@@ -39,14 +38,13 @@ export const cart = {
3938

4039
const data = await response.json();
4140

42-
// Shopify properties
43-
this.cart.items = data.items;
41+
// Shopify properties - ensure complete replacement for reactivity
42+
this.cart.items = [...data.items];
4443
this.cart.item_count = data.item_count;
4544
this.cart.total_price = data.total_price;
4645
this.cart.original_total_price = data.original_total_price;
4746
this.cart.total_discount = data.total_discount;
48-
this.cart.cart_level_discount_applications =
49-
data.cart_level_discount_applications;
47+
this.cart.cart_level_discount_applications = data.cart_level_discount_applications;
5048

5149
// Progress bar calculation
5250
let calcTotal;
@@ -77,6 +75,16 @@ export const cart = {
7775
// Optimize upsell handling - batch DOM operations
7876
this.handleUpsells();
7977

78+
// Ensure quantity inputs reflect authoritative cart quantities after DOM updates
79+
// Small timeout allows Alpine to re-render before syncing inputs
80+
setTimeout(() => {
81+
try {
82+
this.resetQuantityInputs();
83+
} catch (e) {
84+
// no-op
85+
}
86+
}, 10);
87+
8088
// Set cart behavior based on screen width
8189
let cart_behavior;
8290
if (window.innerWidth < 768) {
@@ -237,7 +245,15 @@ export const cart = {
237245
else {
238246
this.error_message = data.description;
239247
this.error_alert = true;
240-
this.cart_loading = false;
248+
249+
// When there's a stock limitation error, Shopify still updates the cart
250+
// with the available quantity, so we need to refresh the cart data
251+
this.updateCart(false, false);
252+
253+
// Force update of quantity input fields to reflect actual cart quantities
254+
setTimeout(() => {
255+
this.resetQuantityInputs();
256+
}, 200);
241257
}
242258
} catch (error: any) {
243259
console.error("Error:", error);
@@ -326,7 +342,15 @@ export const cart = {
326342
else {
327343
this.error_message = data.description;
328344
this.error_alert = true;
329-
this.cart_loading = false;
345+
346+
// Update cart to reflect the actual quantities that were added
347+
// This ensures the UI shows the correct quantities after a stock limitation error
348+
this.updateCart(false, false);
349+
350+
// Force update of quantity input fields to reflect actual cart quantities
351+
setTimeout(() => {
352+
this.resetQuantityInputs();
353+
}, 200);
330354
}
331355
})
332356
.catch((error) => {
@@ -453,7 +477,15 @@ export const cart = {
453477
else {
454478
this.error_message = data.description;
455479
this.error_alert = true;
456-
this.cart_loading = false;
480+
481+
// Update cart to reflect the actual quantities that were added
482+
// This ensures the UI shows the correct quantities after a stock limitation error
483+
this.updateCart(false, false);
484+
485+
// Force update of quantity input fields to reflect actual cart quantities
486+
setTimeout(() => {
487+
this.resetQuantityInputs();
488+
}, 200);
457489
}
458490
} catch (error) {
459491
console.error("Error:", error);
@@ -508,7 +540,15 @@ export const cart = {
508540
else {
509541
this.error_message = data.description;
510542
this.error_alert = true;
511-
this.cart_loading = false;
543+
544+
// Update cart to reflect the actual quantities that were added
545+
// This ensures the UI shows the correct quantities after a stock limitation error
546+
this.updateCart(false, false);
547+
548+
// Force update of quantity input fields to reflect actual cart quantities
549+
setTimeout(() => {
550+
this.resetQuantityInputs();
551+
}, 200);
512552
}
513553
})
514554
.catch((error) => {
@@ -683,4 +723,32 @@ export const cart = {
683723
this._memoizedSummary = null;
684724
this._memoizedGroupedItems = null;
685725
},
726+
727+
// Reset quantity input fields to match actual cart quantities
728+
// This is used when cart quantities are corrected due to stock limitations
729+
resetQuantityInputs() {
730+
// Find all quantity input fields and update them to match cart data
731+
const quantityInputs = document.querySelectorAll('input[type="number"][x-model*="quantity"]');
732+
quantityInputs.forEach((element: Element) => {
733+
const input = element as HTMLInputElement;
734+
// Get the cart item key from the input name or other attributes
735+
const name = input.getAttribute('name') || input.getAttribute(':name') || '';
736+
if (name.includes('cart-')) {
737+
// Extract key from name like 'cart-12345:abcdef-quantity'
738+
const keyMatch = name.match(/cart-([^-]+)-quantity/);
739+
if (keyMatch) {
740+
const key = keyMatch[1];
741+
// Find the corresponding cart item
742+
const cartItem = this.cart.items.find((item: any) => item.key.toString() === key);
743+
if (cartItem && input.value !== cartItem.quantity.toString()) {
744+
// Update the input value to match the actual cart quantity
745+
input.value = cartItem.quantity.toString();
746+
// Trigger input event to update Alpine.js binding
747+
input.dispatchEvent(new Event('input', { bubbles: true }));
748+
}
749+
}
750+
}
751+
});
752+
},
753+
686754
};

src/ts/collections/collections.ts

Lines changed: 108 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -55,35 +55,19 @@ export const collections = {
5555
},
5656

5757
// Check if next page is avaible and inject more products
58-
async fetchAndRenderNextPage() {
58+
async fetchAndRenderTableRows(product_handle: string, total_pages: number, current_page: number, section_id: string, inject_before: string) {
59+
5960
// Show loading
6061
this.pagination_loading = true;
6162

62-
// Get filter data
63-
const filter = document.getElementById(
64-
"js-desktopFilter",
65-
) as HTMLFormElement;
66-
6763
// Get pagination count
68-
const pageUrl = `&page=${this.pagination_current_page + 1}`;
69-
70-
// Get search parameter
71-
const searchUrl = new URL(location.href).searchParams.get("q")
72-
? `&q=${new URL(location.href).searchParams.get("q")}`
73-
: "";
64+
const pageUrl = `&page=${current_page}`;
7465

7566
// Build fetch url
76-
let fetchUrl = `${window.location.pathname}?section_id=${this.pagination_section}${pageUrl}${searchUrl}`;
77-
78-
// If filter exists, add filter data to fetch url
79-
if (filter) {
80-
const filterData = new FormData(filter);
81-
const filterUrl = this.buildUrlFilter(filterData);
82-
fetchUrl += filterUrl;
83-
}
67+
let fetchUrl = `${window.Shopify.routes.root}products/${product_handle}?section_id=${section_id}${pageUrl}`;
8468

8569
// Check if new page is available
86-
if (this.pagination_current_page < this.pagination_total_pages) {
70+
if (current_page <= total_pages) {
8771
// Get data from Shopify
8872
try {
8973
const response = await fetch(fetchUrl);
@@ -94,24 +78,27 @@ export const collections = {
9478
tempElement.innerHTML = data;
9579

9680
// Find the results within the fetched data
97-
const fetchedElement = tempElement.querySelector("#js-results");
81+
const fetchedElement = tempElement.querySelector(".js-results");
9882

9983
// If results are found, append its innerHTML to the existing element on the page
10084
if (fetchedElement) {
101-
const resultsElement = document.getElementById("js-results");
102-
if (resultsElement) {
103-
resultsElement.insertAdjacentHTML(
85+
const injectSpot = document.querySelector(inject_before);
86+
if (injectSpot) {
87+
injectSpot.insertAdjacentHTML(
10488
"beforeend",
10589
fetchedElement.innerHTML,
10690
);
10791
}
10892
}
10993

110-
// Update next page url
111-
this.pagination_current_page += 1;
94+
if (current_page >= total_pages) {
95+
this.pagination_load_more_button = false;
96+
}
11297

11398
// Reset loading
11499
this.loadImages();
100+
101+
// Reset loading
115102
this.pagination_loading = false;
116103
} catch (error) {
117104
console.error("Error:", error);
@@ -124,6 +111,100 @@ export const collections = {
124111
this.pagination_loading = false;
125112
}
126113
},
114+
115+
// Check if next page is avaible and inject more products
116+
async fetchAndRenderPage (direction: "next" | "previous") {
117+
// Prevent browser from scrolling down
118+
history.scrollRestoration = "manual";
119+
120+
// Show loading
121+
this.pagination_loading = true;
122+
123+
// Update URL to show updated page number
124+
if (direction === "next") {
125+
let url = new URL(window.location.href);
126+
url.searchParams.set("page", this.pagination_current_page + 1);
127+
window.history.pushState({}, "", url.toString());
128+
}
129+
130+
// Get filter data
131+
const filter = document.getElementById("js-desktopFilter") as HTMLFormElement;
132+
133+
// Get pagination count
134+
const pageUrl = `&page=${direction === "next" ? this.pagination_current_page + 1 : this.pagination_current_page - 1}`;
135+
136+
// Get search parameter
137+
const searchUrl = new URL(location.href).searchParams.get("q") ? `&q=${new URL(location.href).searchParams.get("q")}` : '';
138+
139+
// Build fetch url
140+
let fetchUrl = `${window.location.pathname}?section_id=${this.pagination_section}${pageUrl}${searchUrl}`;
141+
142+
// If filter exists, add filter data to fetch url
143+
if (filter) {
144+
const filterData = new FormData(filter);
145+
const filterUrl = this.buildUrlFilter(filterData);
146+
fetchUrl += filterUrl;
147+
}
148+
149+
// Check if new page is available
150+
if (this.pagination_current_page < this.pagination_total_pages ||
151+
direction === "previous") {
152+
153+
// Get data from Shopify
154+
try {
155+
const response = await fetch(fetchUrl);
156+
const data = await response.text();
157+
158+
// Create a new HTML element and set its innerHTML to the fetched data
159+
const tempElement = document.createElement("div");
160+
tempElement.innerHTML = data;
161+
162+
// Find the results within the fetched data
163+
const fetchedElement = tempElement.querySelector("#js-results");
164+
165+
// If results are found, append its innerHTML to the existing element on the page
166+
if (fetchedElement) {
167+
const resultsElement = document.getElementById("js-results");
168+
if (resultsElement) {
169+
if (direction === "next") {
170+
resultsElement.insertAdjacentHTML(
171+
"beforeend",
172+
fetchedElement.innerHTML,
173+
);
174+
} else {
175+
resultsElement.insertAdjacentHTML(
176+
"afterbegin",
177+
fetchedElement.innerHTML,
178+
);
179+
}
180+
}
181+
}
182+
183+
// Update next page url
184+
// Update next page url
185+
if (direction === "next") {
186+
this.pagination_current_page += 1;
187+
this.pagination_pages_loaded += 1;
188+
} else {
189+
this.pagination_current_page -= 1;
190+
}
191+
192+
// Reset loading
193+
// this.loadImages();
194+
this.pagination_loading = false;
195+
}
196+
197+
catch (error) {
198+
console.error("Error:", error);
199+
this.pagination_loading = false;
200+
}
201+
}
202+
203+
// If last page, stop loading
204+
else {
205+
this.pagination_loading = false;
206+
}
207+
},
127208

128209
// Load quick add with section render
129210
async fetchAndRenderQuickGallery(product_handle: string) {

src/ts/globals/globals.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export const globals = {
5050
error_message: app.error_message, // {string} Error message
5151

5252
// Pagination
53+
pagination_pages_loaded: app.pagination_pages_loaded, // {number} To track number of pages loaded
5354
pagination_loading: app.pagination_loading, // {boolean} To show loading state in pagination
5455
pagination_total_pages: app.pagination_total_pages, // {number} Total number of pages for the current collection
5556
pagination_current_page: app.pagination_current_page, // {number} Current page number in pagination

src/ts/models.interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export interface AppInterface {
3030
cart_drawer_style: string;
3131
error_alert: boolean;
3232
error_message: string;
33+
pagination_pages_loaded: number;
3334
pagination_loading: boolean;
3435
pagination_total_pages: number;
3536
pagination_current_page: number;

0 commit comments

Comments
 (0)