Last active
April 30, 2026 14:58
-
-
Save iiic/258708a2c40365194b5ac4903a2d1475 to your computer and use it in GitHub Desktop.
nový cart-discount.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * revize 3 - minimum změn oproti produkci | |
| * | |
| * oproti produkci tam nejsou ty problémy s nutným refreshováním stránky či nepřidáním věcí do košíku při zadání kódu | |
| * taktéž oproti produkci nevypisuje chvilkově tu chybu po zadání kódu (než se košík přenačte) | |
| * není nutné podmínkově rozlišovat prohlížeče, chová se ve všech stejně | |
| * | |
| * ale oproti revizi 2 zase má stejný problém jako produkce, že to bere PATCHcokoliv, PATCHPOROTA, PATCHE CELÁ ZEMĚ a tak | |
| * | |
| */ | |
| import { Component } from '@theme/component'; | |
| import { morphSection } from '@theme/section-renderer'; | |
| import { DiscountUpdateEvent } from '@theme/events'; | |
| import { fetchConfig } from '@theme/utilities'; | |
| import { cartPerformance } from '@theme/performance'; | |
| /** | |
| * A custom element that applies a discount to the cart. | |
| * | |
| * @typedef {Object} CartDiscountComponentRefs | |
| * @property {HTMLElement} cartDiscountError - The error element. | |
| * @property {HTMLElement} cartDiscountErrorDiscountCode - The discount code error element. | |
| * @property {HTMLElement} cartDiscountErrorShipping - The shipping error element. | |
| */ | |
| /** | |
| * @extends {Component<CartDiscountComponentRefs>} | |
| */ | |
| class CartDiscount extends Component { | |
| requiredRefs = ['cartDiscountError', 'cartDiscountErrorDiscountCode', 'cartDiscountErrorShipping']; | |
| /** @type {AbortController | null} */ | |
| #activeFetch = null; | |
| #createAbortController() { | |
| if (this.#activeFetch) { | |
| this.#activeFetch.abort(); | |
| } | |
| const abortController = new AbortController(); | |
| this.#activeFetch = abortController; | |
| return abortController; | |
| } | |
| /** | |
| * Handles updates to the cart note. | |
| * @param {SubmitEvent} event - The submit event on our form. | |
| */ | |
| applyDiscount = async (event) => { | |
| const { cartDiscountError, cartDiscountErrorDiscountCode, cartDiscountErrorShipping } = this.refs; | |
| event.preventDefault(); | |
| event.stopPropagation(); | |
| const form = event.target; | |
| if (!(form instanceof HTMLFormElement)) return; | |
| const discountCode = form.querySelector('input[name="discount"]'); | |
| if (!(discountCode instanceof HTMLInputElement) || typeof this.dataset.sectionId !== 'string') return; | |
| const discountCodeValue = discountCode.value; | |
| const abortController = this.#createAbortController(); | |
| try { | |
| const existingDiscounts = this.#existingDiscounts(); | |
| if (existingDiscounts.includes(discountCodeValue)) return; | |
| cartDiscountError.classList.add('hidden'); | |
| cartDiscountErrorDiscountCode.classList.add('hidden'); | |
| cartDiscountErrorShipping.classList.add('hidden'); | |
| const config = fetchConfig('json', { | |
| body: JSON.stringify({ | |
| discount: [...existingDiscounts, discountCodeValue].join(','), | |
| sections: [this.dataset.sectionId], | |
| }), | |
| }); | |
| const response = await fetch(Theme.routes.cart_update_url, { | |
| ...config, | |
| signal: abortController.signal, | |
| }); | |
| /** @type {Object} */ | |
| const data = await response.json(); | |
| if ( discountCodeValue.startsWith( "PATCH" ) ) { | |
| console.log( "Detekoval jsem PATCH" ); | |
| const variantId = '57580469584197'; // ID dárku | |
| // 2. Zkontrolovat, jestli produkt už v košíku je | |
| const existingItem = data.items.find( item => item.variant_id == variantId ); | |
| const conflictItem = data.items.find( item => ( item.variant_id == '56990918050117' || item.variant_id == '57698293973317' ) ); //kontrola na přítomnost dvoubalení | |
| const solutionItem = data.items.find( item => item.variant_id == '57411253272901' ); //kontrola na přítomnost kompenzačního předmětu | |
| /** @type {{ items: Array }} */ | |
| const addIntoCartList = { items: [] }; | |
| if ( conflictItem && !solutionItem ) { //řeší problém s dvoubalením a dárkem, pokud je dvoubalení a není možné použít kód, tak to přidá prázdný předmět do košíku | |
| addIntoCartList.items.push( { // prázdný item přidán! | |
| id: 57411253272901, | |
| quantity: 1 | |
| } ); | |
| console.log( 'prázdný item přidán!' ); | |
| } | |
| if ( existingItem ) { | |
| console.log( 'Produkt už je v košíku, množství:', existingItem.quantity ); | |
| // Nedělejte nic, nebo aktualizujte množství | |
| } else { | |
| /** @type {{ code: string; applicable: boolean; }} */ | |
| const currentDiscount = data.discount_codes.find( item => item.code == discountCodeValue ); | |
| currentDiscount.applicable = true; // nastavím uživatelem zadaný kód jako platný (tedy nevypisuje se chybová hláška o špatném kódu) | |
| existingDiscounts.push( discountCodeValue ); // přidám kód do seznamu už použitých slevových kódů (prevence opakovaného vložení toho samého kódu) | |
| addIntoCartList.items.push( { // Přidat produkt | |
| id: variantId, | |
| quantity: 1 | |
| } ); | |
| console.log( 'Dárek přidán!' ); | |
| } | |
| if ( addIntoCartList.items.length ) { // je něco na přidání do košíku? | |
| await fetch( '/cart/add.js', { // hromadné vložení předmětu (předmětů) do košíku, s čekáním na dokončení (!) // @todo : může vracet chybovou hlášku typu "out of stock" pokud dojdou přidávané předměty a tak, odchytit vypsat | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify( addIntoCartList ) | |
| } ); | |
| } | |
| } | |
| if ( | |
| data.discount_codes.find((/** @type {{ code: string; applicable: boolean; }} */ discount) => { | |
| return discount.code === discountCodeValue && discount.applicable === false; | |
| }) | |
| ) { | |
| discountCode.value = ''; | |
| this.#handleDiscountError('discount_code'); | |
| return; | |
| } | |
| const newHtml = data.sections[this.dataset.sectionId]; | |
| const parsedHtml = new DOMParser().parseFromString(newHtml, 'text/html'); | |
| const section = parsedHtml.getElementById(`shopify-section-${this.dataset.sectionId}`); | |
| const discountCodes = section?.querySelectorAll('.cart-discount__pill') || []; | |
| if (section) { | |
| const codes = Array.from(discountCodes) | |
| .map((element) => (element instanceof HTMLLIElement ? element.dataset.discountCode : null)) | |
| .filter(Boolean); | |
| // Before morphing, we need to check if the shipping discount is applicable in the UI | |
| // we check the liquid logic compared to the cart payload to assess whether we leveraged | |
| // a valid shipping discount code. | |
| if ( | |
| codes.length === existingDiscounts.length && | |
| codes.every((/** @type {string} */ code) => existingDiscounts.includes(code)) && | |
| data.discount_codes.find((/** @type {{ code: string; applicable: boolean; }} */ discount) => { | |
| return discount.code === discountCodeValue && discount.applicable === true; | |
| }) | |
| ) { | |
| this.#handleDiscountError('shipping'); | |
| discountCode.value = ''; | |
| return; | |
| } | |
| } | |
| document.dispatchEvent(new DiscountUpdateEvent(data, this.id)); | |
| morphSection(this.dataset.sectionId, newHtml); | |
| } catch (error) { | |
| } finally { | |
| this.#activeFetch = null; | |
| cartPerformance.measureFromEvent('discount-update:user-action', event); | |
| } | |
| }; | |
| /** | |
| * Handles removing a discount from the cart. | |
| * @param {MouseEvent | KeyboardEvent} event - The mouse or keyboard event in our pill. | |
| */ | |
| removeDiscount = async (event) => { | |
| event.preventDefault(); | |
| event.stopPropagation(); | |
| if ( | |
| (event instanceof KeyboardEvent && event.key !== 'Enter') || | |
| !(event instanceof MouseEvent) || | |
| !(event.target instanceof HTMLElement) || | |
| typeof this.dataset.sectionId !== 'string' | |
| ) { | |
| return; | |
| } | |
| const pill = event.target.closest('.cart-discount__pill'); | |
| if (!(pill instanceof HTMLLIElement)) return; | |
| const discountCode = pill.dataset.discountCode; | |
| if (!discountCode) return; | |
| const existingDiscounts = this.#existingDiscounts(); | |
| const index = existingDiscounts.indexOf(discountCode); | |
| if (index === -1) return; | |
| existingDiscounts.splice(index, 1); | |
| const abortController = this.#createAbortController(); | |
| try { | |
| const config = fetchConfig('json', { | |
| body: JSON.stringify({ discount: existingDiscounts.join(','), sections: [this.dataset.sectionId] }), | |
| }); | |
| const response = await fetch(Theme.routes.cart_update_url, { | |
| ...config, | |
| signal: abortController.signal, | |
| }); | |
| const data = await response.json(); | |
| document.dispatchEvent(new DiscountUpdateEvent(data, this.id)); | |
| morphSection(this.dataset.sectionId, data.sections[this.dataset.sectionId]); | |
| } catch (error) { | |
| } finally { | |
| this.#activeFetch = null; | |
| } | |
| }; | |
| /** | |
| * Handles the discount error. | |
| * | |
| * @param {'discount_code' | 'shipping'} type - The type of discount error. | |
| */ | |
| #handleDiscountError(type) { | |
| const { cartDiscountError, cartDiscountErrorDiscountCode, cartDiscountErrorShipping } = this.refs; | |
| const target = type === 'discount_code' ? cartDiscountErrorDiscountCode : cartDiscountErrorShipping; | |
| cartDiscountError.classList.remove('hidden'); | |
| target.classList.remove('hidden'); | |
| } | |
| /** | |
| * Returns an array of existing discount codes. | |
| * @returns {string[]} | |
| */ | |
| #existingDiscounts() { | |
| /** @type {string[]} */ | |
| const discountCodes = []; | |
| const discountPills = this.querySelectorAll('.cart-discount__pill'); | |
| for (const pill of discountPills) { | |
| if (pill instanceof HTMLLIElement && typeof pill.dataset.discountCode === 'string') { | |
| discountCodes.push(pill.dataset.discountCode); | |
| } | |
| } | |
| return discountCodes; | |
| } | |
| } | |
| if (!customElements.get('cart-discount-component')) { | |
| customElements.define('cart-discount-component', CartDiscount); | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
nový script:
je možné použít libovolné kódy, není nutný PATCH prefix a přesto není možné je vyčíst ze zdrojákuty slevové kódy jsou zde https://gist.github.com/iiic/258708a2c40365194b5ac4903a2d1475#file-cart-discount-js-L39 udává se hash, sha256(libovolnýText) kde libovolnýText je slevový kód, udělá to libovolný online nástroj či AIčko, sha256 nějakého textu vychází vždy stejně a není možné vrátit otisk zpět na text (pokud by to bylo možné, tak Bitcoin jako celek je v prdeli), dají se najít hashe kratšího textu čistě vložením do googlu (třeba) b6f8d434a847fb0f0c1a8d9b936b8ca952e224f205a55f4ba9b2c20f88fdc9e7