├── resources ├── views │ ├── cart │ │ ├── queries │ │ │ ├── cart.graphql │ │ │ ├── partials │ │ │ │ └── customizable-options.graphql │ │ │ └── fragments │ │ │ │ └── product.graphql │ │ ├── coupon.blade.php │ │ ├── coupon │ │ │ ├── list.blade.php │ │ │ └── add.blade.php │ │ └── item │ │ │ ├── remove.blade.php │ │ │ └── quantity.blade.php │ ├── components │ │ ├── input │ │ │ ├── input.blade.php │ │ │ ├── swatch │ │ │ │ ├── text.blade.php │ │ │ │ └── visual.blade.php │ │ │ ├── select │ │ │ │ ├── country.blade.php │ │ │ │ └── region.blade.php │ │ │ └── password │ │ │ │ └── password.blade.php │ │ ├── summary.blade.php │ │ ├── button │ │ │ ├── toggle.blade.php │ │ │ ├── base.blade.php │ │ │ ├── cart.blade.php │ │ │ └── tag.blade.php │ │ ├── breadcrumbs.blade.php │ │ ├── autocomplete │ │ │ ├── title.blade.php │ │ │ └── magnifying-glass.blade.php │ │ ├── highlight.blade.php │ │ ├── no-image.blade.php │ │ ├── recaptcha.blade.php │ │ ├── breadcrumb.blade.php │ │ ├── accordion │ │ │ └── filter.blade.php │ │ ├── cookie-notice.blade.php │ │ └── slideover │ │ │ └── global.blade.php │ ├── layouts │ │ ├── config.blade.php │ │ ├── partials │ │ │ ├── footer │ │ │ │ ├── copyright.blade.php │ │ │ │ └── social.blade.php │ │ │ ├── head │ │ │ │ └── hreflang.blade.php │ │ │ ├── header │ │ │ │ └── autocomplete │ │ │ │ │ ├── results.blade.php │ │ │ │ │ ├── all-results.blade.php │ │ │ │ │ └── categories.blade.php │ │ │ ├── global-slideover.blade.php │ │ │ └── footer.blade.php │ │ └── checkout │ │ │ ├── footer.blade.php │ │ │ └── header.blade.php │ ├── widget │ │ ├── link.blade.php │ │ ├── productlist.blade.php │ │ └── recently-viewed.blade.php │ ├── listing │ │ └── partials │ │ │ ├── filter │ │ │ ├── selected │ │ │ │ ├── swatch.blade.php │ │ │ │ └── boolean.blade.php │ │ │ └── search.blade.php │ │ │ ├── toolbar │ │ │ ├── stats.blade.php │ │ │ ├── pages.blade.php │ │ │ └── sorting.blade.php │ │ │ ├── toolbar.blade.php │ │ │ ├── no-products.blade.php │ │ │ └── item │ │ │ ├── super-attributes.blade.php │ │ │ ├── addtocart.blade.php │ │ │ └── super-attributes │ │ │ ├── drop-down.blade.php │ │ │ ├── text-swatch.blade.php │ │ │ └── visual-swatch.blade.php │ ├── checkout │ │ ├── pages │ │ │ ├── success.blade.php │ │ │ └── login.blade.php │ │ ├── queries │ │ │ ├── fragments │ │ │ │ ├── order.graphql │ │ │ │ └── item.graphql │ │ │ ├── setGuestEmailOnCart.graphql │ │ │ ├── setPaymentMethodOnCart.graphql │ │ │ ├── setShippingMethodsOnCart.graphql │ │ │ ├── placeOrder.graphql │ │ │ ├── setExistingShippingAddressesOnCart.graphql │ │ │ └── setExistingBillingAddressOnCart.graphql │ │ ├── steps │ │ │ └── place-order.blade.php │ │ └── partials │ │ │ └── progressbar.blade.php │ ├── product │ │ └── partials │ │ │ ├── widget.blade.php │ │ │ ├── quantity.blade.php │ │ │ ├── options.blade.php │ │ │ ├── options │ │ │ ├── field.blade.php │ │ │ ├── area.blade.php │ │ │ ├── multiple.blade.php │ │ │ ├── radio.blade.php │ │ │ ├── checkbox.blade.php │ │ │ ├── drop-down.blade.php │ │ │ └── file.blade.php │ │ │ ├── breadcrumbs.blade.php │ │ │ ├── images.blade.php │ │ │ ├── super-attributes.blade.php │ │ │ ├── opengraph.blade.php │ │ │ ├── microdata.blade.php │ │ │ ├── super-attributes │ │ │ ├── drop-down.blade.php │ │ │ ├── text-swatch.blade.php │ │ │ └── visual-swatch.blade.php │ │ │ └── gallery │ │ │ ├── popup.blade.php │ │ │ └── thumbnails │ │ │ └── show-more.blade.php │ ├── category │ │ └── partials │ │ │ └── breadcrumbs.blade.php │ ├── page │ │ └── overview.blade.php │ ├── errors │ │ └── 404.blade.php │ ├── customer │ │ └── queries │ │ │ └── customer.graphql │ └── search │ │ └── overview.blade.php ├── js │ ├── app.js │ ├── components │ │ ├── Checkout │ │ │ └── Checkout.vue │ │ ├── User │ │ │ └── User.vue │ │ ├── GlobalSlideoverInstance.vue │ │ ├── GlobalSlideover.vue │ │ ├── Notifications │ │ │ └── Notifications.vue │ │ ├── Elements │ │ │ └── Toggler.vue │ │ ├── VueTurboFrame.vue │ │ └── Recursion.vue │ ├── cookies.js │ ├── polyfills.js │ ├── fetch │ │ └── graphqlbundle.js │ ├── turbolinks.js │ ├── stores │ │ ├── useInstantsearchMiddlewares.js │ │ ├── useFetches.js │ │ └── useSearchHistory.js │ ├── polyfills │ │ └── requestIdleCallback.js │ └── jwt.js ├── payment-icons │ ├── banktransfer.svg │ ├── checkmo.svg │ ├── purchaseorder.svg │ ├── free.svg │ ├── default.svg │ └── cashondelivery.svg └── svg │ ├── x.svg │ ├── github.svg │ ├── slack.svg │ └── loading.svg ├── .github ├── CODEOWNERS ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── translations.yml │ ├── prettier.yml │ ├── duster-fix-blame.yml │ └── changelog.yml ├── .gitattributes ├── config ├── rapidez.php └── rapidez │ ├── attribute-models.php │ ├── jwt.php │ ├── healthcheck.php │ └── system.php ├── tformat.json ├── postcss.config.js ├── .prettierignore ├── src ├── Exceptions │ ├── DecryptionException.php │ └── StoreNotFoundException.php ├── Models │ ├── AttributeDecimal.php │ ├── AttributeDatetime.php │ ├── AttributeModels │ │ ├── AttributeModel.php │ │ └── ArrayBackend.php │ ├── AttributeInt.php │ ├── CustomerGroup.php │ ├── AttributeText.php │ ├── AttributeVarchar.php │ ├── SearchSynonym.php │ ├── ReportEvent.php │ ├── ProductSuperLink.php │ ├── QuoteIdMask.php │ ├── Review.php │ ├── SalesOrderAddress.php │ ├── Scopes │ │ ├── Product │ │ │ ├── SupportedScope.php │ │ │ ├── EnabledScope.php │ │ │ └── ForCurrentWebsiteScope.php │ │ ├── IsActiveScope.php │ │ └── ForCurrentStoreScope.php │ ├── OauthToken.php │ ├── CheckoutAgreement.php │ ├── CategoryProduct.php │ ├── ProductOptionPrice.php │ ├── ProductOptionTitle.php │ ├── Traits │ │ ├── HasToArrayData.php │ │ └── HasEventyGlobalScopeFilter.php │ ├── ProductOptionTypePrice.php │ ├── ProductOptionTypeTitle.php │ ├── ProductTierPrice.php │ ├── ProductImageValue.php │ ├── Page.php │ ├── SalesOrderItem.php │ ├── Rewrite.php │ ├── AttributeOption.php │ ├── QuoteItem.php │ ├── Widget.php │ ├── SearchQuery.php │ ├── ReviewSummary.php │ ├── OptionValue.php │ ├── Block.php │ ├── SalesOrderPayment.php │ ├── ProductImage.php │ └── SuperAttribute.php ├── ViewComponents │ └── PlaceholderComponent.php ├── ContentVariables │ ├── Store.php │ └── Media.php ├── Events │ ├── IndexAfterEvent.php │ ├── IndexBeforeEvent.php │ └── ProductViewEvent.php ├── Widgets │ ├── ViewOnly.php │ ├── Block.php │ ├── ProductList.php │ ├── PageLink.php │ └── ProductAndCategoryLink.php ├── Http │ ├── Middleware │ │ ├── CheckStoreCode.php │ │ ├── Uncacheable.php │ │ ├── VerifyAdminToken.php │ │ ├── DetermineAndSetShop.php │ │ ├── AuthenticateHealthCheck.php │ │ └── ConfigForTesting.php │ └── Controllers │ │ ├── PageController.php │ │ ├── Fallback │ │ ├── LegacyFallbackController.php │ │ ├── CmsPageController.php │ │ └── UrlRewriteController.php │ │ ├── HealthcheckController.php │ │ ├── OrderController.php │ │ ├── CategoryController.php │ │ ├── CheckoutSuccessController.php │ │ ├── CheckoutController.php │ │ ├── GetSignedCheckoutController.php │ │ └── SignedCheckoutController.php ├── Casts │ ├── DecodeHtmlEntities.php │ ├── CommaSeparatedToArray.php │ ├── CommaSeparatedToIntegerArray.php │ └── Multiselect.php ├── Listeners │ ├── ReportProductView.php │ ├── UpdateLatestIndexDate.php │ └── Healthcheck │ │ ├── Base.php │ │ └── ModelsHealthcheck.php ├── Commands │ └── ValidateCommand.php └── Facades │ └── Rapidez.php ├── tests ├── playwright │ ├── general.spec.js-snapshots │ │ ├── cookie-1-chromium-linux.png │ │ ├── cookie-1-firefox-linux.png │ │ ├── cookie-1-webkit-linux.png │ │ ├── cookie-1-Mobile-Chrome-linux.png │ │ └── cookie-1-Mobile-Safari-linux.png │ ├── homepage.spec.js-snapshots │ │ ├── homepage-1-chromium-linux.png │ │ ├── homepage-1-firefox-linux.png │ │ ├── homepage-1-webkit-linux.png │ │ ├── homepage-1-Mobile-Chrome-linux.png │ │ └── homepage-1-Mobile-Safari-linux.png │ ├── search.spec.js-snapshots │ │ ├── autocomplete-1-chromium-linux.png │ │ ├── autocomplete-1-firefox-linux.png │ │ ├── autocomplete-1-webkit-linux.png │ │ ├── search-page-1-chromium-linux.png │ │ ├── search-page-1-firefox-linux.png │ │ ├── search-page-1-webkit-linux.png │ │ ├── autocomplete-1-Mobile-Chrome-linux.png │ │ ├── autocomplete-1-Mobile-Safari-linux.png │ │ ├── search-page-1-Mobile-Chrome-linux.png │ │ └── search-page-1-Mobile-Safari-linux.png │ ├── cart.spec.js-snapshots │ │ ├── add-product-simple-1-chromium-linux.png │ │ ├── add-product-simple-1-firefox-linux.png │ │ ├── add-product-simple-1-webkit-linux.png │ │ ├── add-product-simple-1-Mobile-Chrome-linux.png │ │ └── add-product-simple-1-Mobile-Safari-linux.png │ ├── category.spec.js-snapshots │ │ ├── category-filter-1-chromium-linux.png │ │ ├── category-filter-1-firefox-linux.png │ │ ├── category-filter-1-webkit-linux.png │ │ ├── category-filter-1-Mobile-Chrome-linux.png │ │ ├── category-filter-1-Mobile-Safari-linux.png │ │ ├── category-pagination-1-chromium-linux.png │ │ ├── category-pagination-1-firefox-linux.png │ │ ├── category-pagination-1-webkit-linux.png │ │ ├── category-pagination-1-Mobile-Chrome-linux.png │ │ ├── category-pagination-1-Mobile-Safari-linux.png │ │ ├── category-with-simple-products-1-chromium-linux.png │ │ ├── category-with-simple-products-1-firefox-linux.png │ │ ├── category-with-simple-products-1-webkit-linux.png │ │ ├── category-with-configurable-products-1-chromium-linux.png │ │ ├── category-with-configurable-products-1-firefox-linux.png │ │ ├── category-with-configurable-products-1-webkit-linux.png │ │ ├── category-with-simple-products-1-Mobile-Chrome-linux.png │ │ ├── category-with-simple-products-1-Mobile-Safari-linux.png │ │ ├── category-with-configurable-products-1-Mobile-Chrome-linux.png │ │ └── category-with-configurable-products-1-Mobile-Safari-linux.png │ ├── checkout.spec.js-snapshots │ │ ├── default---as-guest-1-webkit-linux.png │ │ ├── default---as-guest-2-webkit-linux.png │ │ ├── default---as-guest-3-webkit-linux.png │ │ ├── default---as-user-1-firefox-linux.png │ │ ├── default---as-user-1-webkit-linux.png │ │ ├── default---as-user-2-webkit-linux.png │ │ ├── default---as-user-3-firefox-linux.png │ │ ├── default---as-user-3-webkit-linux.png │ │ ├── onestep---as-guest-1-webkit-linux.png │ │ ├── onestep---as-user-1-webkit-linux.png │ │ ├── onestep---as-user-2-webkit-linux.png │ │ ├── default---as-guest-1-chromium-linux.png │ │ ├── default---as-guest-1-firefox-linux.png │ │ ├── default---as-guest-2-chromium-linux.png │ │ ├── default---as-guest-2-firefox-linux.png │ │ ├── default---as-guest-3-chromium-linux.png │ │ ├── default---as-guest-3-firefox-linux.png │ │ ├── default---as-guest-4-chromium-linux.png │ │ ├── default---as-guest-4-firefox-linux.png │ │ ├── default---as-guest-4-webkit-linux.png │ │ ├── default---as-user-1-chromium-linux.png │ │ ├── default---as-user-2-chromium-linux.png │ │ ├── default---as-user-2-firefox-linux.png │ │ ├── default---as-user-3-chromium-linux.png │ │ ├── onestep---as-guest-1-chromium-linux.png │ │ ├── onestep---as-guest-1-firefox-linux.png │ │ ├── onestep---as-guest-2-chromium-linux.png │ │ ├── onestep---as-guest-2-firefox-linux.png │ │ ├── onestep---as-guest-2-webkit-linux.png │ │ ├── onestep---as-guest-3-chromium-linux.png │ │ ├── onestep---as-guest-3-firefox-linux.png │ │ ├── onestep---as-guest-3-webkit-linux.png │ │ ├── onestep---as-user-1-chromium-linux.png │ │ ├── onestep---as-user-1-firefox-linux.png │ │ ├── onestep---as-user-2-chromium-linux.png │ │ ├── onestep---as-user-2-firefox-linux.png │ │ ├── default---as-guest-1-Mobile-Chrome-linux.png │ │ ├── default---as-guest-1-Mobile-Safari-linux.png │ │ ├── default---as-guest-2-Mobile-Chrome-linux.png │ │ ├── default---as-guest-2-Mobile-Safari-linux.png │ │ ├── default---as-guest-3-Mobile-Chrome-linux.png │ │ ├── default---as-guest-3-Mobile-Safari-linux.png │ │ ├── default---as-guest-4-Mobile-Chrome-linux.png │ │ ├── default---as-guest-4-Mobile-Safari-linux.png │ │ ├── default---as-user-1-Mobile-Chrome-linux.png │ │ ├── default---as-user-1-Mobile-Safari-linux.png │ │ ├── default---as-user-2-Mobile-Chrome-linux.png │ │ ├── default---as-user-2-Mobile-Safari-linux.png │ │ ├── default---as-user-3-Mobile-Chrome-linux.png │ │ ├── default---as-user-3-Mobile-Safari-linux.png │ │ ├── onestep---as-guest-1-Mobile-Chrome-linux.png │ │ ├── onestep---as-guest-1-Mobile-Safari-linux.png │ │ ├── onestep---as-guest-2-Mobile-Chrome-linux.png │ │ ├── onestep---as-guest-2-Mobile-Safari-linux.png │ │ ├── onestep---as-guest-3-Mobile-Chrome-linux.png │ │ ├── onestep---as-guest-3-Mobile-Safari-linux.png │ │ ├── onestep---as-user-1-Mobile-Chrome-linux.png │ │ ├── onestep---as-user-1-Mobile-Safari-linux.png │ │ ├── onestep---as-user-2-Mobile-Chrome-linux.png │ │ └── onestep---as-user-2-Mobile-Safari-linux.png │ ├── product.spec.js-snapshots │ │ ├── product-grouped-1-chromium-linux.png │ │ ├── product-grouped-1-firefox-linux.png │ │ ├── product-grouped-1-webkit-linux.png │ │ ├── product-simple-1-chromium-linux.png │ │ ├── product-simple-1-firefox-linux.png │ │ ├── product-simple-1-webkit-linux.png │ │ ├── product-configurable-1-chromium-linux.png │ │ ├── product-configurable-1-firefox-linux.png │ │ ├── product-configurable-1-webkit-linux.png │ │ ├── product-grouped-1-Mobile-Chrome-linux.png │ │ ├── product-grouped-1-Mobile-Safari-linux.png │ │ ├── product-simple-1-Mobile-Chrome-linux.png │ │ ├── product-simple-1-Mobile-Safari-linux.png │ │ ├── product-special-price-1-chromium-linux.png │ │ ├── product-special-price-1-firefox-linux.png │ │ ├── product-special-price-1-webkit-linux.png │ │ ├── product-configurable-1-Mobile-Chrome-linux.png │ │ ├── product-configurable-1-Mobile-Safari-linux.png │ │ ├── product-special-price-1-Mobile-Chrome-linux.png │ │ └── product-special-price-1-Mobile-Safari-linux.png │ ├── pages │ │ ├── AccountPage.js │ │ ├── CartPage.js │ │ └── ProductPage.js │ ├── homepage.spec.js │ ├── .env.testing │ ├── search.spec.js │ ├── product.spec.js │ └── general.spec.js └── Feature │ └── ConfigTest.php ├── phpstan.neon ├── .gitignore ├── README.md ├── .prettierrc.js ├── .php-cs-fixer.dist.php ├── vite.config.js ├── routes └── magento-redirects.php └── .editorconfig /resources/views/cart/queries/cart.graphql: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @royduin @indykoning 2 | -------------------------------------------------------------------------------- /resources/js/app.js: -------------------------------------------------------------------------------- 1 | import './package.js' 2 | -------------------------------------------------------------------------------- /resources/js/components/Checkout/Checkout.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | tests/playwright/**/*.png filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /config/rapidez.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tformat.json: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "tighten", 3 | "disabled": ["SpaceAfterBladeDirectives"] 4 | } 5 | -------------------------------------------------------------------------------- /resources/views/layouts/config.blade.php: -------------------------------------------------------------------------------- 1 | window.config = { ...window.config ?? {}, ...@json($config) }; 2 | -------------------------------------------------------------------------------- /resources/views/widget/link.blade.php: -------------------------------------------------------------------------------- 1 | {{ $anchorText }} 2 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /resources/views/cart/queries/partials/customizable-options.graphql: -------------------------------------------------------------------------------- 1 | customizable_options { 2 | label 3 | values { 4 | label 5 | value 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /resources/js/cookies.js: -------------------------------------------------------------------------------- 1 | import VueCookies from 'vue-cookies' 2 | 3 | document.addEventListener('vue:loaded', function (event) { 4 | event.detail.vue.use(VueCookies) 5 | }) 6 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /public 2 | /vendor 3 | .github 4 | .git 5 | **/*.php 6 | !**/*.blade.php 7 | /resources/views/*.graphql 8 | /resources/views/**/*.graphql 9 | CHANGELOG.md 10 | -------------------------------------------------------------------------------- /resources/js/polyfills.js: -------------------------------------------------------------------------------- 1 | import './polyfills/emit' 2 | 3 | if (!window.requestIdleCallback || !window.cancelIdleCallback) { 4 | import('./polyfills/requestIdleCallback') 5 | } 6 | -------------------------------------------------------------------------------- /resources/views/listing/partials/filter/selected/swatch.blade.php: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /config/rapidez/attribute-models.php: -------------------------------------------------------------------------------- 1 | Rapidez\Core\Models\AttributeModels\ArrayBackend::class, 5 | ]; 6 | -------------------------------------------------------------------------------- /resources/views/layouts/partials/footer/copyright.blade.php: -------------------------------------------------------------------------------- 1 |

2 | © {{ date('Y') }} {{ config('app.name') }}. @lang('All rights reserved.') 3 |

4 | -------------------------------------------------------------------------------- /src/Exceptions/DecryptionException.php: -------------------------------------------------------------------------------- 1 | 'float']; 8 | } 9 | -------------------------------------------------------------------------------- /resources/js/fetch/graphqlbundle.js: -------------------------------------------------------------------------------- 1 | import { print } from 'graphql' 2 | import { gql } from 'graphql-tag' 3 | import combineQuery from 'graphql-combine-query' 4 | 5 | export { print, combineQuery, gql } 6 | -------------------------------------------------------------------------------- /resources/views/widget/productlist.blade.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/Models/AttributeDatetime.php: -------------------------------------------------------------------------------- 1 | 'datetime']; 8 | } 9 | -------------------------------------------------------------------------------- /src/Exceptions/StoreNotFoundException.php: -------------------------------------------------------------------------------- 1 | twMerge('flex flex-col gap-y-1.5 w-full *:flex *:gap-1 *:flex-wrap first:*:*:flex-1 *:*:flex *:*:flex-col *:*:gap-0.5') }}> 2 | {{ $slot }} 3 | -------------------------------------------------------------------------------- /src/Models/AttributeModels/AttributeModel.php: -------------------------------------------------------------------------------- 1 | $url) 3 | 4 | @endforeach 5 | @endpush 6 | -------------------------------------------------------------------------------- /tests/playwright/category.spec.js-snapshots/category-pagination-1-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:13124fada4aa14553976e52bac968ad5f49f29f8ab8859fdc08fa3a4b742f751 3 | size 134678 4 | -------------------------------------------------------------------------------- /tests/playwright/category.spec.js-snapshots/category-pagination-1-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:becbbfb8e0b7169723c1629b730fec3ae142ddd984a1232acde2c47d9dd20ca0 3 | size 144967 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/default---as-guest-1-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:7bf2322328a373c6dc53ed5c65ebcb4bb33e194756386ab9179eb90337305698 3 | size 16313 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/default---as-guest-1-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:f08516f5301e34d7f4e74faf345fff1a6ade49eb266a4bb5d20eecfe529865ad 3 | size 18333 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/default---as-guest-2-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:d009b998abaa9c62841ce3887284fc18fef41ddc78e5307193951cda2cd1a9b1 3 | size 67862 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/default---as-guest-2-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:6b199fd6eebc0b67a853d22cbf6ae9e89a3dd044948ff25ca64845f27214915f 3 | size 75366 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/default---as-guest-3-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:0adcc2bd58fe3a6f2d2acf5edecdc6477247f8b77eff3c21b90c5c8cf9ace147 3 | size 45623 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/default---as-guest-3-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:05d86c0f5a76ae36f462b53e0047dd8b0d20b99a7d750556a3522503f922fbd5 3 | size 51185 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/default---as-guest-4-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:daa208dcbbd85f6d42520b5921d415666b946843ac926c220c1168db0acb65d5 3 | size 119503 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/default---as-guest-4-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:e31b548941472a6cb153c76afc491a1b50339b5bd5269bbc24c24795d7ff7013 3 | size 128993 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/default---as-user-1-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:5441da80aaf8b4022a2f8c28b86dbbed04d45014176d9479dc1c4668f23edebf 3 | size 26307 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/default---as-user-1-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:316e721aec5e0f1d12021c4e1ed77de41e2a7f632914e72b64b3fdfdb2edfa7e 3 | size 29865 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/default---as-user-2-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:04328e7d9eed2515d1ef52a788ac6da972cfa52e62e4e6a676512c8d4f2482eb 3 | size 70259 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/default---as-user-2-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:ac7ad891a586199906e985387fdc8f9e5a849ff37275f92bc5522c688adf6caa 3 | size 78274 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/default---as-user-3-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:9a0450fac8f93eabb7c28e7b1e721036b4c4f730c2692aa069c4b78122b3fa42 3 | size 17712 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/default---as-user-3-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:d97d1618791351cfa1a555b29c19b2350860e82d2a81b0dd287b497dbdb6df4c 3 | size 21038 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/onestep---as-guest-1-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:0030d2a51b0163eb3c73e43d35ef341b25c64a3893800a0eb2e823a8174c7da6 3 | size 77244 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/onestep---as-guest-1-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:23b715d7083e018d7e9d88f6aa92dd1c2837a5042813ca91e8367d2c16c14f06 3 | size 85643 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/onestep---as-guest-2-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:720e3665f334317fbe8917a555b3efb72c99177e7760300ad4a1c38d98b88a2a 3 | size 99346 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/onestep---as-guest-2-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:be3b55a23341a6f849c96a1361f00b86a08c941b367b3448742d1b4ab508071a 3 | size 111354 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/onestep---as-guest-3-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:daa208dcbbd85f6d42520b5921d415666b946843ac926c220c1168db0acb65d5 3 | size 119503 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/onestep---as-guest-3-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:e31b548941472a6cb153c76afc491a1b50339b5bd5269bbc24c24795d7ff7013 3 | size 128993 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/onestep---as-user-1-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:363f349f80081f7bc5478d3a71f142d00846a4f8986e864c2ea8fd1a7cbbe2d8 3 | size 87881 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/onestep---as-user-1-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:cd30c18e575b01f95ea259a43eb77502a3cfdda0d3e5186825073d470d051a65 3 | size 97904 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/onestep---as-user-2-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:ee8e2ac67b99eafe688cf15cda80b1ef5b370eea5fbbd284c55b001f9ae72c4a 3 | size 78526 4 | -------------------------------------------------------------------------------- /tests/playwright/checkout.spec.js-snapshots/onestep---as-user-2-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:e3489b6a0a1df221071129c0e5e55e1e1fb1e05152458c0b7ac5755f7a36b3a8 3 | size 88915 4 | -------------------------------------------------------------------------------- /tests/playwright/product.spec.js-snapshots/product-configurable-1-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:3cdb07fbdd831a55152d5d935760c809af974e5e469ecc7db05aa5dee08776c8 3 | size 257426 4 | -------------------------------------------------------------------------------- /tests/playwright/product.spec.js-snapshots/product-configurable-1-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:34aa1de2b2ae6ed41452906ffe4407d95ae164cdb6236e47d1f73df04574430f 3 | size 276401 4 | -------------------------------------------------------------------------------- /tests/playwright/product.spec.js-snapshots/product-special-price-1-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:944770aa72df05adf424622b10ada2431c086d527f7900dd24ab277fcf61b9e3 3 | size 199449 4 | -------------------------------------------------------------------------------- /tests/playwright/product.spec.js-snapshots/product-special-price-1-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:7ea7531048ff06acb3ab2e01233e70ec925d48c2390e38d7271459413bb9d352 3 | size 214103 4 | -------------------------------------------------------------------------------- /tests/playwright/category.spec.js-snapshots/category-with-simple-products-1-chromium-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:843f898c9d34524a402b0301aa0d9d938401590e83331f4214c9e536af86ebab 3 | size 459347 4 | -------------------------------------------------------------------------------- /tests/playwright/category.spec.js-snapshots/category-with-simple-products-1-firefox-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:2ad4c60aeed6bdea67f06f0dd04cbe50239bfb136939887c08117bb94b1ecfa5 3 | size 627946 4 | -------------------------------------------------------------------------------- /tests/playwright/category.spec.js-snapshots/category-with-simple-products-1-webkit-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:0886848320b5a07055f77c908409f934677208a61839bc921e79c4cbc0387d3f 3 | size 511758 4 | -------------------------------------------------------------------------------- /tests/playwright/category.spec.js-snapshots/category-with-configurable-products-1-chromium-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:09fce0100e411c2b07d0fe519620c4f56ed65115d9febe3c7bba0524523d2cf9 3 | size 587347 4 | -------------------------------------------------------------------------------- /tests/playwright/category.spec.js-snapshots/category-with-configurable-products-1-firefox-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:5a5376e327d4bd17a3a02ae61ec0b616ece494e02db161ec98da5d38e414f47b 3 | size 870745 4 | -------------------------------------------------------------------------------- /tests/playwright/category.spec.js-snapshots/category-with-configurable-products-1-webkit-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:6cb7fea38d85b2e23c1f4d44f93c28cac520619d64a6f809ab19672f1c473692 3 | size 662704 4 | -------------------------------------------------------------------------------- /tests/playwright/category.spec.js-snapshots/category-with-simple-products-1-Mobile-Chrome-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:b3d2c3afe8d56bc2c89d81539c06d42da428b802e7ce664c770521f18b93e8db 3 | size 382891 4 | -------------------------------------------------------------------------------- /tests/playwright/category.spec.js-snapshots/category-with-simple-products-1-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:09a60719b9e5f3bb631e5116cb0016aed1e209628029609a2c12fcc9fc1e29db 3 | size 418104 4 | -------------------------------------------------------------------------------- /config/rapidez/jwt.php: -------------------------------------------------------------------------------- 1 | Services > Magento Web API > JWT Authentication` 5 | 'signed_with' => \Lcobucci\JWT\Signer\Hmac\Sha256::class, 6 | ]; 7 | -------------------------------------------------------------------------------- /src/Models/AttributeInt.php: -------------------------------------------------------------------------------- 1 | merge(['class' => 'text-sm border bg-white min-h-0 p-2 rounded-md cursor-pointer mr-2 hover:border-active']) }}> 2 | {{ $slot }} 3 | -------------------------------------------------------------------------------- /src/Models/AttributeText.php: -------------------------------------------------------------------------------- 1 | 2 | @lang('Home') 3 | {{ $slot }} 4 | 5 | -------------------------------------------------------------------------------- /src/Models/AttributeVarchar.php: -------------------------------------------------------------------------------- 1 | twMerge('text-muted text-xs font-semibold pb-2 px-5') }}> 3 | {{ $slot }} 4 | 5 | -------------------------------------------------------------------------------- /resources/views/listing/partials/filter/selected/boolean.blade.php: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /resources/views/components/highlight.blade.php: -------------------------------------------------------------------------------- 1 | @props(['attribute', 'item' => 'item']) 2 | 3 | 7 | -------------------------------------------------------------------------------- /src/ViewComponents/PlaceholderComponent.php: -------------------------------------------------------------------------------- 1 | null, 6 | 'allowed_ips' => [ 7 | '127.0.0.1/8', 8 | ...explode(',', env('HEALTHCHECK_ALLOWED_IPS', '')), 9 | ], 10 | ]; 11 | -------------------------------------------------------------------------------- /resources/views/product/partials/widget.blade.php: -------------------------------------------------------------------------------- 1 |
2 | @widget( 3 | 'content', 4 | ['all_products', $product->type_id.'_products'], 5 | ['catalog_product_view', 'catalog_product_view_type_'.$product->type_id], 6 | $product->entity_id 7 | ) 8 |
9 | -------------------------------------------------------------------------------- /src/ContentVariables/Store.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | @lang('Apply coupon code') 4 | 5 | 6 | @include('rapidez::cart.coupon.add') 7 | @include('rapidez::cart.coupon.list') 8 | 9 | -------------------------------------------------------------------------------- /src/ContentVariables/Media.php: -------------------------------------------------------------------------------- 1 | twMerge('relative inline-flex items-center justify-center transition font-medium text-base rounded min-h-12 py-1.5 px-5 disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer gap-x-1.5') }}> 2 | {{ $slot }} 3 | -------------------------------------------------------------------------------- /resources/views/listing/partials/toolbar/stats.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | -------------------------------------------------------------------------------- /resources/views/listing/partials/toolbar.blade.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | @include('rapidez::listing.partials.toolbar.stats') 4 |
5 | @include('rapidez::listing.partials.toolbar.pages') 6 | @include('rapidez::listing.partials.toolbar.sorting') 7 |
8 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | includes: 2 | - ./vendor/larastan/larastan/extension.neon 3 | 4 | parameters: 5 | paths: 6 | - src/ 7 | - tests/ 8 | - routes/ 9 | ignoreErrors: 10 | - '#^Result of static method TorMorten\\Eventy\\Events::#' 11 | - "#Access to an undefined property#" 12 | level: 1 13 | -------------------------------------------------------------------------------- /resources/views/checkout/queries/fragments/order.graphql: -------------------------------------------------------------------------------- 1 | @use('\TorMorten\Eventy\Facades\Eventy') 2 | 3 | fragment order on Order { 4 | order_number 5 | # Still used by PSPs 6 | @foreach(array_unique(Eventy::filter('checkout.queries.order.data', []), SORT_REGULAR) as $attribute) 7 | {{ $attribute }} 8 | @endforeach 9 | } 10 | -------------------------------------------------------------------------------- /src/Events/IndexAfterEvent.php: -------------------------------------------------------------------------------- 1 | context = $context; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Events/IndexBeforeEvent.php: -------------------------------------------------------------------------------- 1 | context = $context; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.phpunit.cache 2 | /node_modules 3 | /public 4 | /vendor 5 | .phpunit.result.cache 6 | composer.lock 7 | yarn.lock 8 | phpunit.xml 9 | stats.html 10 | 11 | # Playwright 12 | .env 13 | node_modules/ 14 | /test-results/ 15 | /playwright-report/ 16 | /blob-report/ 17 | /playwright/.cache/ 18 | /tests/playwright/**/*-darwin.png 19 | /lighthouse 20 | -------------------------------------------------------------------------------- /resources/views/checkout/queries/setGuestEmailOnCart.graphql: -------------------------------------------------------------------------------- 1 | mutation setGuestEmailOnCart ( 2 | $cart_id: String!, 3 | $email: String!, 4 | ) { 5 | setGuestEmailOnCart(input: { 6 | cart_id: $cart_id, 7 | email: $email 8 | }) { 9 | cart { ...cart } 10 | } 11 | } 12 | 13 | @include('rapidez::cart.queries.fragments.cart') 14 | -------------------------------------------------------------------------------- /resources/views/components/no-image.blade.php: -------------------------------------------------------------------------------- 1 | merge(['class' => 'w-full']) }}> 2 | 3 | @lang('Sorry! No image') 4 | 5 | -------------------------------------------------------------------------------- /resources/js/turbolinks.js: -------------------------------------------------------------------------------- 1 | import * as Turbo from '@hotwired/turbo' 2 | 3 | Turbo.config.drive.progressBarDelay = 5 4 | 5 | document.addEventListener('turbo:before-visit', function (e) { 6 | if (typeof history.state.turbo === 'undefined') { 7 | // Trigger turbo to add the state. 8 | Turbo?.navigator?.history?.replace(window.location) 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /resources/views/components/recaptcha.blade.php: -------------------------------------------------------------------------------- 1 | @props(['location']) 2 | 3 | @if (Rapidez::config('recaptcha_frontend/type_for/'.$location) == 'recaptcha_v3' && $key = Rapidez::config('recaptcha_frontend/type_recaptcha_v3/public_key', null, true)) 4 | @push('head') 5 | 6 | @endpush 7 | @endif 8 | -------------------------------------------------------------------------------- /src/Models/ProductSuperLink.php: -------------------------------------------------------------------------------- 1 | 2 | {{ $slot }} 3 | class('opacity-0 size-0 absolute') }}> 4 | 5 | -------------------------------------------------------------------------------- /resources/views/widget/recently-viewed.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | -------------------------------------------------------------------------------- /src/Models/AttributeModels/ArrayBackend.php: -------------------------------------------------------------------------------- 1 | 7 | @for ($i = $product->qty_increments; $i <= $product->qty_increments * 10; $i += $product->qty_increments) 8 | 9 | @endfor 10 | 11 | -------------------------------------------------------------------------------- /resources/views/components/autocomplete/magnifying-glass.blade.php: -------------------------------------------------------------------------------- 1 | {{-- This is the search icon in the autocomplete --}} 2 |
twMerge('transition-colors duration-300 rounded-lg bg-primary text-primary-text absolute right-1 inset-y-1 w-11 pointer-events-none flex items-center justify-center z-header-autocomplete-button') }}> 3 | 4 |
5 | -------------------------------------------------------------------------------- /resources/payment-icons/banktransfer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/views/listing/partials/no-products.blade.php: -------------------------------------------------------------------------------- 1 |
2 |

3 | @lang('There are currently no products in this category.') 4 |

5 | 6 | 7 | @lang('Go to home') 8 | 9 |
10 | -------------------------------------------------------------------------------- /resources/views/product/partials/options.blade.php: -------------------------------------------------------------------------------- 1 | @if ($product->options->isNotEmpty()) 2 |
3 | @foreach ($product->options->sortBy('sort_order') as $option) 4 |
5 | @include('rapidez::product.partials.options.' . str_replace('_', '-', $option->type)) 6 |
7 | @endforeach 8 |
9 | @endif 10 | -------------------------------------------------------------------------------- /src/Models/QuoteIdMask.php: -------------------------------------------------------------------------------- 1 | belongsTo(config('rapidez.models.quote'), 'entity_id', 'quote_id'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Models/Review.php: -------------------------------------------------------------------------------- 1 | merge([ 2 | 'type' => 'submit', 3 | 'class' => 'relative', 4 | 'data-testid' => 'add-to-cart', 5 | ]) }} 6 | v-bind:class="{'button-loading': addToCart.adding}" 7 | > 8 | 9 | @lang('Add to cart') 10 | 11 | -------------------------------------------------------------------------------- /resources/js/stores/useInstantsearchMiddlewares.js: -------------------------------------------------------------------------------- 1 | export let instantsearchMiddlewares = [] 2 | 3 | export async function addInstantsearchMiddleware(middlewareFn) { 4 | instantsearchMiddlewares.push(middlewareFn) 5 | } 6 | 7 | export async function removeInstantsearchMiddleware(middlewareFn) { 8 | instantsearchMiddlewares = instantsearchMiddlewares.filter((registeredMiddleware) => registeredMiddleware !== middlewareFn) 9 | } 10 | -------------------------------------------------------------------------------- /src/Models/SalesOrderAddress.php: -------------------------------------------------------------------------------- 1 | belongsTo(config('rapidez.models.sales_order'), 'parent_id'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Widgets/ViewOnly.php: -------------------------------------------------------------------------------- 1 | options = $options; 12 | } 13 | 14 | public function render(string $view): string 15 | { 16 | return view($view, [ 17 | 'options' => $this->options, 18 | ])->render(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Http/Middleware/CheckStoreCode.php: -------------------------------------------------------------------------------- 1 | where('type_id', '<>', 'bundle'); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /resources/views/layouts/checkout/footer.blade.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |
6 | @include('rapidez::layouts.partials.footer.copyright') 7 |
8 |
9 |
10 |
11 | -------------------------------------------------------------------------------- /resources/views/product/partials/options/field.blade.php: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /tests/playwright/pages/AccountPage.js: -------------------------------------------------------------------------------- 1 | import { expect } from '@playwright/test' 2 | 3 | export class AccountPage { 4 | constructor(page) { 5 | this.page = page 6 | } 7 | 8 | async logout() { 9 | await this.page.goto('/') 10 | await this.page.getByTestId('account-menu').click() 11 | await this.page.getByTestId('logout').click() 12 | await this.page.waitForLoadState('networkidle') 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /resources/svg/x.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/views/product/partials/options/area.blade.php: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /src/Models/OauthToken.php: -------------------------------------------------------------------------------- 1 | where('revoked', 0); 16 | }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Casts/DecodeHtmlEntities.php: -------------------------------------------------------------------------------- 1 | product = $product; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /resources/payment-icons/checkmo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Http/Controllers/PageController.php: -------------------------------------------------------------------------------- 1 | view('rapidez::page.overview', compact('page')); 12 | 13 | return $response 14 | ->setEtag(md5($response->getContent() ?? '')) 15 | ->setLastModified($page->update_time); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /resources/js/components/User/User.vue: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /src/Casts/CommaSeparatedToArray.php: -------------------------------------------------------------------------------- 1 | whereAttribute('status', Product::STATUS_ENABLED); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /resources/views/category/partials/breadcrumbs.blade.php: -------------------------------------------------------------------------------- 1 | 2 | @foreach ($category->parentcategories as $parentcategory) 3 | 8 | {{ $parentcategory->name }} 9 | 10 | @endforeach 11 | 12 | -------------------------------------------------------------------------------- /resources/views/product/partials/breadcrumbs.blade.php: -------------------------------------------------------------------------------- 1 | 2 | @foreach ($product->breadcrumb_categories as $category) 3 | 4 | {{ $category->name }} 5 | 6 | @endforeach 7 | {{ $product->name }} 8 | 9 | -------------------------------------------------------------------------------- /resources/views/checkout/queries/setShippingMethodsOnCart.graphql: -------------------------------------------------------------------------------- 1 | mutation ( 2 | $cart_id: String!, 3 | $carrier_code: String!, 4 | $method_code: String!, 5 | ) { 6 | setShippingMethodsOnCart(input: { 7 | cart_id: $cart_id, 8 | shipping_methods: [{ 9 | carrier_code: $carrier_code 10 | method_code: $method_code 11 | }] 12 | }) { 13 | cart { ...cart } 14 | } 15 | } 16 | 17 | @include('rapidez::cart.queries.fragments.cart') 18 | -------------------------------------------------------------------------------- /resources/payment-icons/purchaseorder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Listeners/ReportProductView.php: -------------------------------------------------------------------------------- 1 | product->views()->create(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Casts/CommaSeparatedToIntegerArray.php: -------------------------------------------------------------------------------- 1 | $fields) 2 | @includeIf('rapidez::layouts.partials.header.autocomplete.' . $key) 3 | @endforeach 4 | @includeWhen(config('rapidez.frontend.autocomplete.additionals.products') === null,'rapidez::layouts.partials.header.autocomplete.products') 5 | @include('rapidez::layouts.partials.header.autocomplete.all-results') 6 | @include('rapidez::layouts.partials.header.autocomplete.no-results') 7 | -------------------------------------------------------------------------------- /src/Http/Controllers/Fallback/LegacyFallbackController.php: -------------------------------------------------------------------------------- 1 | { 5 | var start = Date.now() 6 | callback({ 7 | didTimeout: false, 8 | timeRemaining: () => Math.max(0, 50 - (Date.now() - start)), 9 | }) 10 | }, 1) 11 | } 12 | 13 | window.cancelIdleCallback = 14 | window.cancelIdleCallback || 15 | function (id) { 16 | clearTimeout(id) 17 | } 18 | -------------------------------------------------------------------------------- /resources/views/product/partials/images.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | @include('rapidez::product.partials.gallery.slider') 6 | @include('rapidez::product.partials.gallery.thumbnails') 7 |
8 | 9 | @include('rapidez::product.partials.gallery.popup') 10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /src/Http/Middleware/VerifyAdminToken.php: -------------------------------------------------------------------------------- 1 | token !== $token, 401); 19 | 20 | return $next($request); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Models/CategoryProduct.php: -------------------------------------------------------------------------------- 1 | belongsTo(config('rapidez.models.category'), 'category_id', 'entity_id'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /resources/views/checkout/queries/setExistingBillingAddressOnCart.graphql: -------------------------------------------------------------------------------- 1 | mutation setExistingBillingAddressOnCart ( 2 | $cart_id: String!, 3 | $customer_address_id: Int, 4 | $same_as_shipping: Boolean 5 | ) { 6 | setBillingAddressOnCart(input: { 7 | cart_id: $cart_id, 8 | billing_address: { 9 | customer_address_id: $customer_address_id, 10 | same_as_shipping: $same_as_shipping, 11 | } 12 | }) { 13 | cart { ...cart } 14 | } 15 | } 16 | 17 | @include('rapidez::cart.queries.fragments.cart') 18 | -------------------------------------------------------------------------------- /src/Models/ProductOptionPrice.php: -------------------------------------------------------------------------------- 1 | belongsTo(config('rapidez.models.store')); 16 | } 17 | 18 | public function option() 19 | { 20 | return $this->belongsTo(config('rapidez.models.product_option'), 'option_id'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Models/ProductOptionTitle.php: -------------------------------------------------------------------------------- 1 | belongsTo(config('rapidez.models.store')); 16 | } 17 | 18 | public function option() 19 | { 20 | return $this->belongsTo(config('rapidez.models.product_option'), 'option_id'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /resources/views/layouts/partials/header/autocomplete/all-results.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | -------------------------------------------------------------------------------- /src/Http/Controllers/HealthcheckController.php: -------------------------------------------------------------------------------- 1 | ! $healthy, true); 14 | $result['healthy'] = $isHealthy; 15 | 16 | return response($result, $isHealthy ? 200 : 503); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Models/Traits/HasToArrayData.php: -------------------------------------------------------------------------------- 1 | filter(fn ($function) => str_ends_with($function, 'ToArrayData')) 13 | ->map(fn ($function) => $this->{$function}()) 14 | ->toArray(), 15 | ), 16 | parent::toArray() 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rapidez Core 2 | 3 | See: https://github.com/rapidez/rapidez 4 | 5 | ## Running the tests 6 | 7 | ### Unit and feature tests 8 | 9 | Just run `./vendor/bin/phpunit` 10 | 11 | ### Browser tests 12 | 13 | - Make sure Rapidez is working in your browser 14 | - Run the tests with `yarn playwright test` 15 | - Alternatively, run the tests from a UI with `yarn playwright test --ui` 16 | - Update the screenshots with `yarn playwright test --update-snapshots` 17 | 18 | ## License 19 | 20 | GNU General Public License v3. Please see [License File](LICENSE) for more information. 21 | -------------------------------------------------------------------------------- /resources/views/product/partials/super-attributes.blade.php: -------------------------------------------------------------------------------- 1 | @foreach ($product->superAttributes ?: [] as $superAttributeId => $superAttribute) 2 | @php($swatchType = $superAttribute->additional_data['swatch_input_type'] ?? null) 3 | @if ($swatchType === 'visual') 4 | @include('rapidez::product.partials.super-attributes.visual-swatch') 5 | @elseif ($swatchType === 'text') 6 | @include('rapidez::product.partials.super-attributes.text-swatch') 7 | @else 8 | @include('rapidez::product.partials.super-attributes.drop-down') 9 | @endif 10 | @endforeach 11 | -------------------------------------------------------------------------------- /resources/js/components/GlobalSlideoverInstance.vue: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /tests/playwright/homepage.spec.js: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { BasePage } from './pages/BasePage' 3 | 4 | test('homepage', BasePage.tags, async ({ page }, testInfo) => { 5 | await page.goto('/') 6 | await new BasePage(page).screenshot('fullpage-footer') 7 | }) 8 | 9 | test('wcag', BasePage.tags, async ({ page }, testInfo) => { 10 | await page.goto('/') 11 | await new BasePage(page).wcag(testInfo, 'page-has-heading-one') 12 | }) 13 | 14 | test('lighthouse', BasePage.tags, async ({ page }) => { 15 | await new BasePage(page).lighthouse('/') 16 | }) 17 | -------------------------------------------------------------------------------- /src/Http/Controllers/Fallback/CmsPageController.php: -------------------------------------------------------------------------------- 1 | path() == '/' ? 'home' : $request->path())->first()) { 13 | $pageController = config('rapidez.routing.controllers.page'); 14 | 15 | return (new $pageController)->show($page); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Models/Scopes/Product/ForCurrentWebsiteScope.php: -------------------------------------------------------------------------------- 1 | leftJoin('catalog_product_website', 'catalog_product_website.product_id', '=', $model->getQualifiedKeyName()); 14 | $builder->where('website_id', config('rapidez.website')); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Models/ProductOptionTypePrice.php: -------------------------------------------------------------------------------- 1 | belongsTo(config('rapidez.models.store')); 16 | } 17 | 18 | public function value() 19 | { 20 | return $this->belongsTo(config('rapidez.models.product_option_type_value'), 'option_type_id'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Models/ProductOptionTypeTitle.php: -------------------------------------------------------------------------------- 1 | belongsTo(config('rapidez.models.store')); 16 | } 17 | 18 | public function value() 19 | { 20 | return $this->belongsTo(config('rapidez.models.product_option_type_value'), 'option_type_id'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Models/Scopes/IsActiveScope.php: -------------------------------------------------------------------------------- 1 | column = $column; 16 | } 17 | 18 | public function apply(Builder $builder, Model $model) 19 | { 20 | $builder->where($builder->getQuery()->from . '.' . $this->column, 1); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /resources/views/checkout/steps/place-order.blade.php: -------------------------------------------------------------------------------- 1 | 10 |
11 | 12 | @lang('Place order') 13 | 14 |
15 |
16 | -------------------------------------------------------------------------------- /src/Http/Controllers/OrderController.php: -------------------------------------------------------------------------------- 1 | bearerToken(), 401); 12 | 13 | $salesOrder = config('rapidez.models.sales_order')::with('sales_order_addresses', 'sales_order_items.product', 'sales_order_payments') 14 | ->whereQuoteIdOrCustomerToken($request->bearerToken()) 15 | ->latest() 16 | ->firstOrFail(); 17 | 18 | return $salesOrder; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /resources/views/components/button/tag.blade.php: -------------------------------------------------------------------------------- 1 | @props(['tag' => 'button', 'disableWhenLoading' => true, 'loader' => false]) 2 | 3 | @php 4 | $tag = $attributes->hasAny('href', ':href', 'v-bind:href') ? 'a' : $tag; 5 | $tag = $attributes->has('for') ? 'label' : $tag; 6 | @endphp 7 | 8 | merge([ 12 | ':disabled' => $attributes->has('href') || $attributes->has(':href') || !$disableWhenLoading ? null : '$root.loading', 13 | ]) }} 14 | > 15 | {{ $slot }} 16 | 17 | -------------------------------------------------------------------------------- /resources/views/components/input/select/country.blade.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 7 | 8 |
9 |
10 | -------------------------------------------------------------------------------- /resources/views/layouts/partials/global-slideover.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | -------------------------------------------------------------------------------- /src/Models/ProductTierPrice.php: -------------------------------------------------------------------------------- 1 | belongsTo( 21 | config('rapidez.models.product'), 22 | 'entity_id' 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /resources/views/product/partials/options/multiple.blade.php: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /resources/views/listing/partials/item/super-attributes.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 5 | 8 | 11 |
12 | -------------------------------------------------------------------------------- /resources/payment-icons/free.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/views/page/overview.blade.php: -------------------------------------------------------------------------------- 1 | @extends('rapidez::layouts.app') 2 | 3 | @section('title', $page->meta_title ?: $page->title) 4 | @section('description', $page->meta_description) 5 | 6 | @section('content') 7 |
8 | @if ($page->identifier != 'home' && $page->content_heading) 9 |

{{ $page->content_heading }}

10 | @endif 11 | @includeIf('pages.' . $page->identifier) 12 | @if ($page->content) 13 |
14 | @content($page->content) 15 |
16 | @endif 17 |
18 | @endsection 19 | -------------------------------------------------------------------------------- /src/Widgets/Block.php: -------------------------------------------------------------------------------- 1 | blockId = is_object($vars) ? $vars->block_id : json_decode($vars)->block_id; 14 | } 15 | 16 | public function render() 17 | { 18 | $blockModel = config('rapidez.models.block'); 19 | $block = new $blockModel; 20 | 21 | return Rapidez::content($blockModel::where($block->getQualifiedKeyName(), $this->blockId)->orWhere($block->qualifyColumn('identifier'), $this->blockId)->first()->content); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /resources/views/layouts/partials/footer/social.blade.php: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /src/Models/ProductImageValue.php: -------------------------------------------------------------------------------- 1 | belongsTo(config('rapidez.models.product_image'), 'value_id'); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // "wrapAttributes": "force-expand-multiline", 3 | sortTailwindcssClasses: true, 4 | sortHtmlAttributes: 'code-guide', 5 | noPhpSyntaxCheck: true, 6 | semi: false, 7 | singleQuote: true, 8 | overrides: [ 9 | { 10 | files: ['tailwind.config.js'], 11 | options: { 12 | quoteProps: 'preserve', 13 | }, 14 | }, 15 | // Disabled for now as it messes with attributes and directives 16 | // { 17 | // "files": ["*.blade.php"], 18 | // "options": { 19 | // "parser": "blade" 20 | // } 21 | // } 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /resources/payment-icons/default.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | setFinder(PhpCsFixer::getFinder()) 11 | ->setUsingCache(false) 12 | ->registerCustomFixers([ 13 | new CustomControllerOrderFixer(), 14 | new CustomOrderedClassElementsFixer(), 15 | new CustomPhpUnitOrderFixer(), 16 | ]) 17 | ->setRules([ 18 | 'Tighten/custom_controller_order' => true, 19 | 'Tighten/custom_phpunit_order' => true, 20 | ]); 21 | -------------------------------------------------------------------------------- /resources/payment-icons/cashondelivery.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/svg/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/Http/Middleware/DetermineAndSetShop.php: -------------------------------------------------------------------------------- 1 | has('_store') && ! app()->isProduction() 15 | ? $request->get('_store') 16 | : $request->server('MAGE_RUN_CODE'); 17 | 18 | $store = Rapidez::getStore($storeCode ?: config('rapidez.store')); 19 | 20 | Rapidez::setStore($store); 21 | 22 | return $next($request); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /resources/views/cart/queries/fragments/product.graphql: -------------------------------------------------------------------------------- 1 | fragment product on ProductInterface { 2 | @foreach(collect([ 3 | 'id', 4 | 'sku', 5 | 'name', 6 | 'type_id', 7 | 'url_key', 8 | 'url_suffix', 9 | ])->merge(config('rapidez.frontend.cart_attributes'))->unique() as $attribute) 10 | {{ $attribute }} 11 | @endforeach 12 | image { 13 | url 14 | } 15 | crosssell_products { 16 | id 17 | } 18 | @if (Rapidez::checkCompadreVersion('0.0.1')) 19 | stock_item { 20 | in_stock 21 | max_sale_qty 22 | min_sale_qty 23 | qty_increments 24 | } 25 | @endif 26 | } 27 | -------------------------------------------------------------------------------- /resources/js/components/GlobalSlideover.vue: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /src/Models/Page.php: -------------------------------------------------------------------------------- 1 | 'datetime', 20 | self::CREATED_AT => 'datetime', 21 | ]; 22 | 23 | protected static function booting() 24 | { 25 | static::addGlobalScope(new IsActiveScope); 26 | static::addGlobalScope(new ForCurrentStoreScope); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Http/Controllers/CategoryController.php: -------------------------------------------------------------------------------- 1 | $category->only('entity_id')]); 13 | session(['latest_category_path' => $category->path]); 14 | 15 | $response = response()->view('rapidez::category.overview', compact('category')); 16 | 17 | return $response 18 | ->setEtag(md5($response->getContent() ?? '')) 19 | ->setLastModified($category->updated_at); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /resources/views/listing/partials/item/addtocart.blade.php: -------------------------------------------------------------------------------- 1 |
2 |

3 | @lang('Sorry! This product is currently out of stock.') 4 |

5 |
6 | @includeWhen(Rapidez::config('catalog/frontend/show_swatches_in_product_list'), 'rapidez::listing.partials.item.super-attributes') 7 | 8 |
9 | 10 | 11 | @if (App::providerIsLoaded('Rapidez\Wishlist\WishlistServiceProvider')) 12 | @include('rapidez::wishlist.button') 13 | @endif 14 |
15 |
16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Models/SalesOrderItem.php: -------------------------------------------------------------------------------- 1 | 'collection', 15 | ]; 16 | 17 | public function sales_order(): BelongsTo 18 | { 19 | return $this->belongsTo(config('rapidez.models.sales_order'), 'order_id'); 20 | } 21 | 22 | public function product(): BelongsTo 23 | { 24 | return $this->belongsTo(config('rapidez.models.product'), 'sku', 'sku')->selectAttributes(config('rapidez.frontend.cart_attributes')); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/Feature/ConfigTest.php: -------------------------------------------------------------------------------- 1 | 'rapidez/test/value_null', 17 | 'value' => null, 18 | ]); 19 | 20 | $this->assertNull(Rapidez::config('rapidez/test/value_null', 'default')); 21 | $this->assertEquals('default', Rapidez::config('rapidez/test/nonexistent_value', 'default')); 22 | 23 | $test->delete(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /resources/js/stores/useFetches.js: -------------------------------------------------------------------------------- 1 | import { computed, ref } from 'vue' 2 | import { until } from '@vueuse/core' 3 | 4 | export let fetches = ref([]) 5 | 6 | export const fetchCount = computed(() => { 7 | return fetches.value.length 8 | }) 9 | 10 | export async function addFetch(promise) { 11 | fetches.value.push(promise) 12 | 13 | promise.finally((...args) => { 14 | removeFetch(promise) 15 | 16 | return args 17 | }) 18 | 19 | return promise 20 | } 21 | 22 | export async function removeFetch(promise) { 23 | fetches.value = fetches.value.filter((fetch) => fetch !== promise) 24 | 25 | return fetches 26 | } 27 | 28 | export async function allSettled(options = null) { 29 | await until(fetchCount).toBe(0, options) 30 | } 31 | -------------------------------------------------------------------------------- /src/Listeners/UpdateLatestIndexDate.php: -------------------------------------------------------------------------------- 1 | put( 15 | '/.last-index', 16 | // With this we're just making sure the comparison 17 | // is done within the same timezone in MySQL. 18 | DB::scalar('SELECT NOW()') 19 | ); 20 | } 21 | 22 | public static function register() 23 | { 24 | Event::listen(IndexAfterEvent::class, static::class); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import { defineConfig } from 'vite' 3 | import laravel from 'laravel-vite-plugin' 4 | import vue from '@vitejs/plugin-vue' 5 | import { visualizer } from 'rollup-plugin-visualizer' 6 | 7 | export default defineConfig({ 8 | plugins: [ 9 | laravel({ 10 | input: ['resources/css/app.css', 'resources/js/app.js'], 11 | refresh: true, 12 | }), 13 | vue(), 14 | visualizer(), 15 | ], 16 | resolve: { 17 | preserveSymlinks: true, 18 | alias: { 19 | '@': path.resolve(__dirname, './resources/js'), 20 | Vendor: path.resolve(__dirname, './vendor'), 21 | vue: 'vue/dist/vue.esm-bundler.js', 22 | }, 23 | }, 24 | }) 25 | -------------------------------------------------------------------------------- /resources/views/components/breadcrumb.blade.php: -------------------------------------------------------------------------------- 1 | @props(['url', 'position', 'active' => false]) 2 | 3 |
  • 4 | @if (!$active) 5 | merge(['class' => 'text-sm hover:underline', 'href' => url($url), 'itemprop' => 'item']) }}> 6 | {{ $slot }} 7 | 8 | 9 | 10 | @else 11 | {{ $slot }} 12 | 13 | @endif 14 |
  • 15 | -------------------------------------------------------------------------------- /src/Models/Rewrite.php: -------------------------------------------------------------------------------- 1 | where('store_id', config('rapidez.store')); 18 | }); 19 | } 20 | 21 | public function store(): HasOne 22 | { 23 | return $this->hasOne( 24 | config('rapidez.models.store'), 25 | 'store_id', 26 | 'store_id', 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /resources/views/errors/404.blade.php: -------------------------------------------------------------------------------- 1 | @extends('rapidez::layouts.app') 2 | @php 3 | $page = config('rapidez.models.page')::firstWhere('identifier', 'no-route'); 4 | @endphp 5 | 6 | @section('title', $page->meta_title ?: $page->title) 7 | @section('description', $page->meta_description) 8 | 9 | @push('head') 10 | 15 | @endpush 16 | 17 | @section('content') 18 |
    19 |

    {{ $page->content_heading }}

    20 |
    21 | @content($page->content) 22 |
    23 |
    24 | @endsection 25 | -------------------------------------------------------------------------------- /resources/views/components/input/password/password.blade.php: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 | 10 | @if (!$attributes['disabled'] ?? false) 11 |
    12 | 13 | 14 |
    15 | @endif 16 |
    17 |
    18 |
    19 | -------------------------------------------------------------------------------- /resources/views/cart/coupon/list.blade.php: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /.github/workflows/translations.yml: -------------------------------------------------------------------------------- 1 | name: Check translations 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - '*.x' 8 | pull_request: 9 | 10 | jobs: 11 | translations: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v2 17 | - name: Setup PHP 18 | uses: shivammathur/setup-php@v2 19 | with: 20 | php-version: '8.3' 21 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick 22 | coverage: none 23 | - name: Install dependencies 24 | run: composer install --prefer-dist --no-interaction 25 | - name: Check translations 26 | uses: rapidez/laravel-translation-checker@master 27 | -------------------------------------------------------------------------------- /src/Models/AttributeOption.php: -------------------------------------------------------------------------------- 1 | leftJoin('eav_attribute_option_value', function (JoinClause $join) use ($builder) { 18 | $join->on($builder->qualifyColumn('option_id'), '=', 'eav_attribute_option_value.option_id') 19 | ->whereIn('store_id', [0, config('rapidez.store')]); 20 | }); 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /resources/views/listing/partials/toolbar/pages.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | -------------------------------------------------------------------------------- /tests/playwright/pages/CartPage.js: -------------------------------------------------------------------------------- 1 | import { expect } from '@playwright/test' 2 | 3 | export class CartPage { 4 | constructor(page) { 5 | this.page = page 6 | } 7 | 8 | async gotoCart() { 9 | await this.page.goto('/cart') 10 | await this.page.waitForLoadState('networkidle') 11 | } 12 | 13 | cartItem() { 14 | return this.page.getByTestId('cart-item') 15 | } 16 | 17 | cartItemQty() { 18 | return this.cartItem().getByTestId('qty') 19 | } 20 | 21 | async firstItemIs(product) { 22 | await this.gotoCart() 23 | await expect(this.cartItem()).toContainText(product.name) 24 | } 25 | 26 | async firstItemQtyIs(qty) { 27 | await this.gotoCart() 28 | await expect(this.cartItemQty()).toHaveValue(qty.toString()) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /resources/views/listing/partials/toolbar/sorting.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | -------------------------------------------------------------------------------- /src/Casts/Multiselect.php: -------------------------------------------------------------------------------- 1 | 2 | import notification from './Notification.vue' 3 | document.addEventListener('vue:loaded', function (event) { 4 | event.detail.vue.component('notification', notification) 5 | }) 6 | export default { 7 | components: { 8 | notification: notification, 9 | }, 10 | data: () => ({ 11 | notifications: [], 12 | }), 13 | render() { 14 | return this.$slots.default(this) 15 | }, 16 | mounted() { 17 | window.$on('notification-message', (message, type, params, link) => { 18 | this.notifications.push({ 19 | message: message, 20 | type: type, 21 | params: params, 22 | link: link, 23 | show: true, 24 | }) 25 | }) 26 | }, 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/Models/QuoteItem.php: -------------------------------------------------------------------------------- 1 | belongsTo(config('rapidez.models.store')); 14 | } 15 | 16 | public function quote() 17 | { 18 | return $this->belongsTo(config('rapidez.models.quote')); 19 | } 20 | 21 | public function parent() 22 | { 23 | return $this->belongsTo(self::class, 'parent_item_id'); 24 | } 25 | 26 | public function children() 27 | { 28 | return $this->hasMany(self::class, 'parent_item_id'); 29 | } 30 | 31 | public function options() 32 | { 33 | return $this->hasMany(config('rapidez.models.quote_item_option'), 'item_id'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.github/workflows/prettier.yml: -------------------------------------------------------------------------------- 1 | name: Prettier 2 | 3 | on: 4 | push: 5 | workflow_run: 6 | workflows: ["Duster"] 7 | types: 8 | - completed 9 | 10 | jobs: 11 | prettier: 12 | runs-on: ubuntu-latest 13 | 14 | permissions: 15 | contents: write 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | with: 20 | ref: ${{ github.head_ref }} 21 | token: ${{ secrets.RAPIDEZ_ACTIONS_ACCOUNT_PAT }} 22 | 23 | - name: Run install 24 | uses: borales/actions-yarn@v4 25 | with: 26 | cmd: install 27 | 28 | - name: "Prettier Fix" 29 | uses: creyD/prettier_action@v4.3 30 | with: 31 | prettier_options: --write . 32 | commit_message: "Apply fixes from Prettier" 33 | prettier_plugins: "prettier-plugin-tailwindcss @shufo/prettier-plugin-blade" 34 | -------------------------------------------------------------------------------- /resources/js/stores/useSearchHistory.js: -------------------------------------------------------------------------------- 1 | import { useLocalStorage } from '@vueuse/core' 2 | 3 | /** 4 | * @typedef {Object} SearchHistory 5 | * { 6 | * [query: string]: { 7 | * count: number, 8 | * lastSearched: string, 9 | * hits: number, 10 | * } 11 | */ 12 | export const searchHistory = useLocalStorage('search_history', {}) 13 | 14 | export const addQuery = (query, metadata = {}) => { 15 | query = query.toLowerCase() 16 | searchHistory.value[query] = { 17 | ...searchHistory.value[query], 18 | count: (searchHistory.value[query]?.count || 0) + 1, 19 | lastSearched: new Date().toISOString(), 20 | ...metadata, 21 | } 22 | } 23 | 24 | export const removeQuery = (query) => { 25 | if (searchHistory.value[query]) { 26 | delete searchHistory.value[query] 27 | } 28 | } 29 | 30 | export default () => searchHistory 31 | -------------------------------------------------------------------------------- /src/Widgets/ProductList.php: -------------------------------------------------------------------------------- 1 | conditions ?? Rapidez::fancyMagentoSyntaxDecoder($options->conditions_encoded)); 15 | $this->condition = $conditions->first(function ($condition) { 16 | return $condition->type == 'Magento\CatalogWidget\Model\Rule\Condition\Product'; 17 | }); 18 | $this->options = $options; 19 | } 20 | 21 | public function render() 22 | { 23 | return view('rapidez::widget.productlist', [ 24 | 'options' => $this->options, 25 | 'condition' => $this->condition, 26 | ])->render(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.github/workflows/duster-fix-blame.yml: -------------------------------------------------------------------------------- 1 | name: Duster 2 | 3 | # Commits made in here will not trigger any workflows 4 | # Checkout Duster's documentation for a workaround 5 | 6 | on: 7 | push: 8 | 9 | jobs: 10 | duster: 11 | runs-on: ubuntu-latest 12 | 13 | permissions: 14 | contents: write 15 | 16 | steps: 17 | - uses: actions/checkout@v3 18 | with: 19 | ref: ${{ github.head_ref }} 20 | token: ${{ secrets.RAPIDEZ_ACTIONS_ACCOUNT_PAT }} 21 | 22 | - name: "Duster Fix" 23 | uses: tighten/duster-action@v2 24 | with: 25 | args: fix -vvv 26 | 27 | - uses: stefanzweifel/git-auto-commit-action@v4 28 | id: auto_commit_action 29 | with: 30 | commit_message: Apply fixes from Duster 31 | commit_user_name: GitHub Action 32 | commit_user_email: actions@github.com 33 | -------------------------------------------------------------------------------- /resources/views/cart/item/remove.blade.php: -------------------------------------------------------------------------------- 1 | 9 | 18 | 19 | -------------------------------------------------------------------------------- /resources/views/product/partials/opengraph.blade.php: -------------------------------------------------------------------------------- 1 | @push('head') 2 | 3 | 4 | @if ($product->meta_description) 5 | 6 | @endif 7 | 8 | @isset($product->images[0]) 9 | 10 | @endisset 11 | 12 | 13 | 14 | 15 | @endpush 16 | -------------------------------------------------------------------------------- /tests/playwright/pages/ProductPage.js: -------------------------------------------------------------------------------- 1 | export class ProductPage { 2 | constructor(page) { 3 | this.page = page 4 | } 5 | 6 | async goto(url) { 7 | await this.page.goto(url) 8 | return await this.page.evaluate(() => window.config.product) 9 | } 10 | 11 | async addToCart(url, qty = 1) { 12 | const product = await this.goto(url) 13 | 14 | if (qty > 1) { 15 | await this.page.waitForTimeout(100) 16 | await this.page.getByTestId('qty').fill('') 17 | await this.page.waitForTimeout(100) 18 | await this.page.getByTestId('qty').pressSequentially(qty.toString()) 19 | } 20 | 21 | await this.page.getByTestId('add-to-cart').click() 22 | await this.page.waitForTimeout(100) 23 | await this.page.waitForLoadState('networkidle') 24 | 25 | return product 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /resources/views/listing/partials/item/super-attributes/drop-down.blade.php: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /resources/js/components/Elements/Toggler.vue: -------------------------------------------------------------------------------- 1 | 39 | -------------------------------------------------------------------------------- /src/Listeners/Healthcheck/Base.php: -------------------------------------------------------------------------------- 1 | true, 13 | 'messages' => [ 14 | // [ 15 | // 'type' => 'error', 16 | // 'value' => ''. 17 | // ], 18 | // [ 19 | // 'type' => 'warn', 20 | // 'value' => ''. 21 | // ], 22 | // [ 23 | // 'type' => 'info', 24 | // 'value' => ''. 25 | // ], 26 | ], 27 | ]; 28 | } 29 | 30 | public static function register() 31 | { 32 | Event::listen('rapidez:health-check', static::class); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Models/Traits/HasEventyGlobalScopeFilter.php: -------------------------------------------------------------------------------- 1 | withGlobalScope($scope, new $scope); 27 | } 28 | 29 | return $query; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Models/Widget.php: -------------------------------------------------------------------------------- 1 | 'object', 15 | ]; 16 | 17 | protected static function booting() 18 | { 19 | static::addGlobalScope('with-all-info', function (Builder $builder) { 20 | $builder->join('widget_instance_page', 'widget_instance_page.instance_id', '=', 'widget_instance.instance_id'); 21 | }); 22 | 23 | static::addGlobalScope('for-current-store', function (Builder $builder) { 24 | $builder->whereRaw('FIND_IN_SET(?, store_ids)', 0) 25 | ->orWhereRaw('FIND_IN_SET(?, store_ids)', config('rapidez.store')); 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Widgets/PageLink.php: -------------------------------------------------------------------------------- 1 | find($vars->page_id); 19 | 20 | $this->url = $page->identifier ?? '/'; 21 | $this->anchorText = $vars->anchor_text ?? $page->title ?? 'link'; 22 | $this->title = $vars->title ?? $page->title ?? ''; 23 | } 24 | 25 | public function render() 26 | { 27 | return view('rapidez::widget.link', [ 28 | 'title' => $this->title, 29 | 'url' => $this->url, 30 | 'anchorText' => $this->anchorText, 31 | ]); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /routes/magento-redirects.php: -------------------------------------------------------------------------------- 1 | group(function () { 6 | // Magento_Catalog 7 | Route::get('catalog/category/view/id/{categoryId}', [config('rapidez.routing.controllers.category'), 'show'])->whereNumber('categoryId'); 8 | Route::get('catalog/product/view/id/{productId}', [config('rapidez.routing.controllers.product'), 'show'])->whereNumber('productId'); 9 | Route::get('catalog/product/view/id/{productId}/{any?}', function ($productId) { 10 | return redirect('catalog/product/view/id/' . $productId, 301); 11 | })->where('any', '.*'); 12 | 13 | // Magento_CatalogSearch 14 | Route::get('catalogsearch/result', function () { 15 | return redirect('/search?q=' . request()->get('q'), 301); 16 | }); 17 | 18 | // Magento_Checkout 19 | Route::permanentRedirect('checkout/cart', '/cart'); 20 | }); 21 | -------------------------------------------------------------------------------- /resources/views/product/partials/options/radio.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ $option->title }} 4 | 5 |
    6 | @if (!$option->is_require) 7 | 8 | @lang('No selection') 9 | 10 | @endif 11 | @foreach ($option->values as $value) 12 | 13 | {{ $value->title }} {{ $value->price_label }} 14 | 15 | @endforeach 16 |
    17 |
    18 | -------------------------------------------------------------------------------- /src/Http/Controllers/CheckoutSuccessController.php: -------------------------------------------------------------------------------- 1 | withCookie(cookie('mask', null, 0)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Http/Controllers/CheckoutController.php: -------------------------------------------------------------------------------- 1 | user()) { 18 | $step = $checkoutSteps[array_search($step, $checkoutSteps) + 1]; 19 | } 20 | 21 | abort_if(! in_array($step, $checkoutSteps), 404); 22 | 23 | return view('rapidez::checkout.pages.' . $step, [ 24 | 'checkoutSteps' => $checkoutSteps, 25 | 'currentStep' => $step, 26 | 'currentStepKey' => array_search($step, $checkoutSteps), 27 | ]); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Http/Middleware/AuthenticateHealthCheck.php: -------------------------------------------------------------------------------- 1 | ip(), config('rapidez.healthcheck.allowed_ips', ['127.0.0.1/8'])); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /resources/views/product/partials/options/checkbox.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ $option->title }} 4 | 5 |
    6 | @foreach ($option->values as $value) 7 | 14 | {{ $value->title }} {{ $value->price_label }} 15 | 16 | @endforeach 17 |
    18 |
    19 | -------------------------------------------------------------------------------- /resources/js/jwt.js: -------------------------------------------------------------------------------- 1 | export const isJwt = function (token) { 2 | return !!token.match(/^(?:[\w-]*\.){2}[\w-]*$/) 3 | } 4 | 5 | // NOTE: we do not and can not validate the token, never assume this is truth. 6 | export const decode = function (token) { 7 | if (!isJwt(token)) { 8 | return null 9 | } 10 | const base64Url = token.split('.')[1] 11 | const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/') 12 | const jsonPayload = decodeURIComponent( 13 | window 14 | .atob(base64) 15 | .split('') 16 | .map(function (c) { 17 | return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2) 18 | }) 19 | .join(''), 20 | ) 21 | 22 | let jwt = JSON.parse(jsonPayload) 23 | jwt.expDate = new Date(jwt.exp * 1000) 24 | jwt.isExpired = () => this.expDate < new Date() 25 | 26 | return jwt 27 | } 28 | 29 | export default { isJwt: isJwt, decode: decode } 30 | -------------------------------------------------------------------------------- /src/Listeners/Healthcheck/ModelsHealthcheck.php: -------------------------------------------------------------------------------- 1 | true, 13 | 'messages' => [], 14 | ]; 15 | $classesWithIncorrectParent = collect(config('rapidez.models'))->filter(fn ($model) => ! is_subclass_of($model, Model::class)); 16 | 17 | if (! $classesWithIncorrectParent->count()) { 18 | return $response; 19 | } 20 | 21 | $response['messages'][] = [ 22 | 'type' => 'warn', 23 | 'value' => __('Models should extend :rapidezModel, the following dont: :models', ['rapidezModel' => Model::class, 'models' => PHP_EOL . '- ' . $classesWithIncorrectParent->implode(PHP_EOL . '- ')]), 24 | ]; 25 | 26 | return $response; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /resources/views/layouts/partials/footer.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | @lang('This website uses cookies') 4 | @lang('Accept cookies') 5 | 6 |
    7 |
    8 |
    9 | @include('rapidez::layouts.partials.footer.navigation') 10 | @includeWhen(Rapidez::config('newsletter/general/active'), 'rapidez::layouts.partials.footer.newsletter') 11 |
    12 |
    13 | @include('rapidez::layouts.partials.footer.social') 14 |
    15 | @include('rapidez::layouts.partials.footer.copyright') 16 |
    17 |
    18 |
    19 |
    20 | -------------------------------------------------------------------------------- /src/Models/SearchQuery.php: -------------------------------------------------------------------------------- 1 | $query->where('store_id', config('rapidez.store'))); 22 | static::addGlobalScope(new IsActiveScope); 23 | } 24 | 25 | protected function makeAllSearchableUsing(Builder $query) 26 | { 27 | return $query 28 | ->where(fn ($subQuery) => $subQuery 29 | ->where('num_results', '>', 0) 30 | ->orWhereNotNull('redirect') 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /resources/js/components/VueTurboFrame.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 36 | -------------------------------------------------------------------------------- /resources/views/customer/queries/customer.graphql: -------------------------------------------------------------------------------- 1 | addresses { 2 | city 3 | company 4 | country_code 5 | default_billing 6 | default_shipping 7 | extension_attributes { 8 | attribute_code 9 | value 10 | } 11 | fax 12 | firstname 13 | id 14 | lastname 15 | middlename 16 | postcode 17 | prefix 18 | region { 19 | region 20 | region_code 21 | region_id 22 | } 23 | region_id 24 | street 25 | suffix 26 | telephone 27 | vat_id 28 | } 29 | created_at 30 | id 31 | date_of_birth 32 | default_billing 33 | default_shipping 34 | email 35 | firstname 36 | gender 37 | is_subscribed 38 | lastname 39 | middlename 40 | prefix 41 | suffix 42 | taxvat 43 | custom_attributes { 44 | code 45 | ... on AttributeValue { 46 | value 47 | } 48 | ... on AttributeSelectedOptions { 49 | selected_options { 50 | label 51 | value 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /resources/views/product/partials/microdata.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @foreach ($product->images as $image) 5 | 6 | @endforeach 7 | 8 |
    9 | 10 | 11 | 12 | 13 | @if ($product->special_to_date && $product->special_to_date > now()->toDateTimeString()) 14 | 15 | @endif 16 |
    17 | -------------------------------------------------------------------------------- /resources/views/components/input/swatch/visual.blade.php: -------------------------------------------------------------------------------- 1 | @props(['color' => null, 'vBindColor' => $attributes['v-bind:color'] ?? null]) 2 | 3 | 16 | -------------------------------------------------------------------------------- /src/Commands/ValidateCommand.php: -------------------------------------------------------------------------------- 1 | call('cache:clear'); 18 | $result = array_merge_recursive(...Event::dispatch('rapidez:health-check')); 19 | $isHealthy = Arr::first($result['healthy'], fn ($healthy) => ! $healthy, true); 20 | 21 | foreach ($result['messages'] as $message) { 22 | (match ($message['type']) { 23 | 'error' => $this->error(...), 24 | 'warn' => $this->warn(...), 25 | default => $this->info(...), 26 | })($message['value']); 27 | } 28 | 29 | return (int) ! $isHealthy; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/playwright/.env.testing: -------------------------------------------------------------------------------- 1 | APP_NAME="Rapidez" 2 | APP_URL=http://localhost:8000 3 | MAGENTO_URL=http://localhost:1234 4 | CRYPT_KEY=5AM3SD5SkwT8iwIxL6L1q8XQhzK3wk51 5 | 6 | APP_ENV=testing 7 | APP_KEY=AckfSECXIvnK5r28GVIWUAxmbBSjTsmF 8 | APP_DEBUG=true 9 | VITE_DEBUG=false 10 | 11 | DB_CONNECTION=mysql 12 | DB_HOST=127.0.0.1 13 | DB_PORT=3307 14 | DB_DATABASE=magento 15 | DB_USERNAME=magento 16 | DB_PASSWORD=password 17 | 18 | ELASTICSEARCH_HOST=http://localhost:9200 19 | ELASTICSEARCH_URL=http://localhost:9200 20 | SCOUT_PREFIX=rapidez 21 | 22 | APP_MAINTENANCE_STORE=file 23 | 24 | CACHE_STORE=file 25 | QUEUE_CONNECTION=sync 26 | SESSION_DRIVER=file 27 | 28 | PRODUCT_URL_SIMPLE=/wayfarer-messenger-bag.html 29 | PRODUCT_URL_CONFIGURABLE=/stellar-solar-jacket.html 30 | PRODUCT_URL_GROUPED=/set-of-sprite-yoga-straps.html 31 | PRODUCT_URL_SPECIAL_PRICE=/savvy-shoulder-tote.html 32 | 33 | CATEGORY_URL_SIMPLE=/gear/bags.html 34 | CATEGORY_URL_CONFIGURABLE=/women/tops-women.html 35 | CATEGORY_FILTER_LABEL=Gym 36 | -------------------------------------------------------------------------------- /resources/svg/slack.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /resources/views/cart/coupon/add.blade.php: -------------------------------------------------------------------------------- 1 | 10 |
    11 | 18 | 19 | @lang('Apply') 20 | 21 | 22 |
    23 | -------------------------------------------------------------------------------- /src/Facades/Rapidez.php: -------------------------------------------------------------------------------- 1 | $builder 19 | ->where('entity_type', 1) 20 | ); 21 | 22 | static::addGlobalScope('store', fn (Builder $builder) => $builder 23 | ->where('store_id', config('rapidez.store')) 24 | ); 25 | } 26 | 27 | public function product(): BelongsTo 28 | { 29 | return $this->belongsTo( 30 | config('rapidez.models.product', \Rapidez\Core\Models\Product::class), 31 | 'entity_pk_value' 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /resources/views/listing/partials/item/super-attributes/text-swatch.blade.php: -------------------------------------------------------------------------------- 1 |
    2 | 3 | @{{ superAttribute.frontend_label }} 4 | 5 | 6 |
      7 |
    • 8 | 18 | @{{ option.label }} 19 | 20 |
    • 21 |
    22 |
    23 | -------------------------------------------------------------------------------- /src/Models/OptionValue.php: -------------------------------------------------------------------------------- 1 | tags('attributes')->get($cacheKey, []); 17 | 18 | if (! isset($cache[$optionId])) { 19 | $cache[$optionId] = html_entity_decode(self::where('option_id', $optionId) 20 | ->whereIn('store_id', [config('rapidez.store'), 0]) 21 | ->orderByDesc('store_id') 22 | ->first('value') 23 | ->value ?? false); 24 | Cache::store('rapidez:multi')->tags('attributes')->forever($cacheKey, $cache); 25 | } 26 | 27 | return $cache[$optionId]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 4 8 | end_of_line = lf 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | # Unofficial config, support depends on the application reading the file. 13 | # https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#supported-by-a-limited-number-of-editors 14 | # https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#ideas-for-domain-specific-properties 15 | max_line_length = off 16 | quote_type = single 17 | spaces_around_operators = true 18 | spaces_around_brackets = none 19 | 20 | # https://en.wikipedia.org/wiki/Indent_style 21 | indent_brace_style = K&R 22 | 23 | [*.md] 24 | trim_trailing_whitespace = false 25 | 26 | [*.{yml,yaml}] 27 | indent_style = space 28 | indent_size = 2 29 | 30 | [*.{blade.php,html}] 31 | max_line_length = 400 32 | 33 | [*.{js,vue}] 34 | max_line_length = 140 35 | -------------------------------------------------------------------------------- /.github/workflows/changelog.yml: -------------------------------------------------------------------------------- 1 | name: "Update Changelog" 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: [ published, edited, deleted ] 7 | 8 | jobs: 9 | generate: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v3 15 | with: 16 | ref: ${{ github.event.release.target_commitish }} 17 | token: ${{ secrets.RAPIDEZ_ACTIONS_ACCOUNT_PAT }} 18 | 19 | - name: Generate changelog 20 | uses: justbetter/generate-changelogs-action@main 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | with: 24 | repository: ${{ github.repository }} 25 | sha: ${{ github.head_ref || github.ref_name }} 26 | 27 | - name: Commit CHANGELOG 28 | uses: stefanzweifel/git-auto-commit-action@v4 29 | with: 30 | branch: ${{ github.event.release.target_commitish }} 31 | commit_message: Update CHANGELOG 32 | file_pattern: CHANGELOG.md 33 | -------------------------------------------------------------------------------- /resources/views/components/accordion/filter.blade.php: -------------------------------------------------------------------------------- 1 | @slots(['content', 'label', 'icon']) 2 | @props(['canToggleShowMore' => false]) 3 | 4 | 5 | 6 | @slotdefault('label') 7 | @{{ filter?.name?.replace('_', ' ') }} 8 | @endslotdefault 9 | 10 | 11 | 12 | {{ $content }} 13 | 14 | @if ($canToggleShowMore) 15 | 27 | @endif 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Models/Block.php: -------------------------------------------------------------------------------- 1 | first('content'))->content ?: false; 27 | }); 28 | 29 | return empty($replace) ? $block : strtr($block, $replace); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Models/SalesOrderPayment.php: -------------------------------------------------------------------------------- 1 | 'collection', 15 | ]; 16 | 17 | protected $hidden = [ 18 | 'cc_debug_request_body', 19 | 'cc_secure_verify', 20 | 'cc_approval', 21 | 'cc_last_4', 22 | 'cc_status_description', 23 | 'cc_debug_response_serialized', 24 | 'cc_ss_start_month', 25 | 'cc_cid_status', 26 | 'cc_owner', 27 | 'cc_exp_year', 28 | 'cc_exp_month', 29 | 'cc_debug_response_body', 30 | 'cc_number_enc', 31 | 'cc_trans_id', 32 | 'echeck_type', 33 | ]; 34 | 35 | public function sales_order() 36 | { 37 | return $this->belongsTo(config('rapidez.models.sales_order'), 'parent_id'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /resources/views/product/partials/options/drop-down.blade.php: -------------------------------------------------------------------------------- 1 | 31 | -------------------------------------------------------------------------------- /src/Http/Controllers/GetSignedCheckoutController.php: -------------------------------------------------------------------------------- 1 | validate([ 21 | 'mask' => 'required', 22 | 'token' => 'nullable', 23 | ]); 24 | $cachekey = (string) Str::uuid(); 25 | Cache::store(config('rapidez.standalone_checkout.cache_store'))->put('checkout-' . $cachekey, $data, static::URL_TIMEOUT); 26 | 27 | return ['url' => URL::signedRoute('signed-checkout', ['key' => $cachekey], static::URL_TIMEOUT)]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /resources/views/product/partials/super-attributes/drop-down.blade.php: -------------------------------------------------------------------------------- 1 | 25 | -------------------------------------------------------------------------------- /resources/views/checkout/pages/login.blade.php: -------------------------------------------------------------------------------- 1 | @extends('rapidez::layouts.app') 2 | 3 | @section('title', __('Checkout')) 4 | 5 | @section('robots', 'NOINDEX,NOFOLLOW') 6 | 7 | @section('content') 8 |
    9 | @include('rapidez::checkout.partials.progressbar') 10 |
    21 | @include('rapidez::checkout.steps.login') 22 | 23 | 24 | @lang('Next') 25 | 26 |
    27 |
    28 | @endsection 29 | -------------------------------------------------------------------------------- /src/Models/ProductImage.php: -------------------------------------------------------------------------------- 1 | $query 21 | ->where($query->qualifyColumn('disabled'), 0) 22 | ->whereHas( 23 | 'productImageValue', 24 | fn ($query) => $query 25 | ->where($query->qualifyColumn('disabled'), 0) 26 | ) 27 | ); 28 | } 29 | 30 | public function productImageValue(): BelongsTo 31 | { 32 | return $this->belongsTo(config('rapidez.models.product_image_value'), 'value_id', 'value_id'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /resources/views/cart/item/quantity.blade.php: -------------------------------------------------------------------------------- 1 | 9 |
    10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Http/Middleware/ConfigForTesting.php: -------------------------------------------------------------------------------- 1 | session()->get('config', []); 14 | 15 | if ($request->has('checkout')) { 16 | if ($request->get('checkout') === 'onestep') { 17 | Arr::set($sessionConfig, 'rapidez.frontend.checkout_steps', ['onestep']); 18 | } else { 19 | Arr::forget($sessionConfig, 'rapidez.frontend.checkout_steps'); 20 | } 21 | $request->session()->put('config', $sessionConfig); 22 | } 23 | 24 | $config = config(); 25 | 26 | foreach ($sessionConfig as $key => $values) { 27 | $config->set($key, array_merge_recursive( 28 | $values ?? [], $config->get($key, []) 29 | )); 30 | } 31 | 32 | return $next($request); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Http/Controllers/Fallback/UrlRewriteController.php: -------------------------------------------------------------------------------- 1 | path())) { 13 | return; 14 | } 15 | 16 | if ($rewrite->redirect_type !== 0) { 17 | return redirect($rewrite->target_path, $rewrite->redirect_type ?: 302); 18 | } 19 | 20 | if ($rewrite->entity_type == 'category') { 21 | $categoryController = config('rapidez.routing.controllers.category'); 22 | 23 | return (new $categoryController)->show($rewrite->entity_id); 24 | } 25 | 26 | if ($rewrite->entity_type == 'product') { 27 | $productController = config('rapidez.routing.controllers.product'); 28 | 29 | return (new $productController)->show($rewrite->entity_id); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Widgets/ProductAndCategoryLink.php: -------------------------------------------------------------------------------- 1 | id_path = collect(explode('/', $vars->id_path))->take(2)->implode('/'); 16 | $type = str($vars->id_path)->before('/')->value(); 17 | $id = str($vars->id_path)->after('/'); 18 | 19 | $this->url = match ($type) { 20 | 'category' => $id->prepend('catalog/category/view/id/'), 21 | 'product' => $id->prepend('catalog/product/view/id/'), 22 | }; 23 | 24 | $this->title = $vars->title ?? $type ?: ''; 25 | $this->anchorText = $vars->anchor_text ?? $type ?: 'link'; 26 | } 27 | 28 | public function render() 29 | { 30 | return view('rapidez::widget.link', [ 31 | 'title' => $this->title, 32 | 'url' => $this->url, 33 | 'anchorText' => $this->anchorText, 34 | ]); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /resources/js/components/Recursion.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 41 | -------------------------------------------------------------------------------- /resources/views/checkout/queries/fragments/item.graphql: -------------------------------------------------------------------------------- 1 | fragment orderItem on OrderItemInterface { 2 | id 3 | quantity_ordered 4 | status 5 | product_name 6 | product_sku 7 | product_type 8 | product_url_key 9 | product_sale_price { 10 | currency 11 | value 12 | } 13 | product { 14 | ...product 15 | } 16 | discounts { 17 | amount { 18 | currency 19 | value 20 | } 21 | label 22 | } 23 | entered_options { 24 | label 25 | value 26 | } 27 | selected_options { 28 | label 29 | value 30 | } 31 | gift_message { 32 | from 33 | message 34 | to 35 | } 36 | quantity_canceled 37 | quantity_invoiced 38 | quantity_ordered 39 | quantity_refunded 40 | quantity_returned 41 | quantity_shipped 42 | ... on DownloadableOrderItem { 43 | downloadable_links { 44 | title 45 | sort_order 46 | } 47 | } 48 | } 49 | 50 | @include('rapidez::cart.queries.fragments.product') 51 | -------------------------------------------------------------------------------- /resources/views/product/partials/super-attributes/text-swatch.blade.php: -------------------------------------------------------------------------------- 1 |
    2 | 3 | {{ $superAttribute->frontend_label }} 4 | 5 | 6 |
      7 | @foreach ($product->superAttributeValues[$superAttribute->attribute_code] as $option) 8 |
    • 9 | 19 | {{ $option->label }} 20 | 21 |
    • 22 | @endforeach 23 |
    24 |
    25 | -------------------------------------------------------------------------------- /config/rapidez/system.php: -------------------------------------------------------------------------------- 1 | env('STORE', 1), 6 | 7 | // Elasticsearch url. 8 | 'es_url' => env('ELASTICSEARCH_URL', 'http://localhost:9200'), 9 | 10 | // Get Magento url from Database 11 | 'magento_url_from_db' => env('GET_MAGENTO_URL_FROM_DATABASE', false), 12 | 13 | // Media url. 14 | 'media_url' => env('MEDIA_URL', env('MAGENTO_URL') . '/media'), 15 | 16 | // Magento url. 17 | 'magento_url' => env('MAGENTO_URL'), 18 | 19 | // Magento crypt key. 20 | 'crypt_key' => env('CRYPT_KEY'), 21 | 22 | // With this token you can run commands from an url. 23 | 'admin_token' => env('RAPIDEZ_TOKEN', env('APP_KEY')), 24 | 25 | // Should the stock qty be exposed and indexed within Elasticsearch? 26 | 'expose_stock' => false, 27 | 28 | 'standalone_checkout' => [ 29 | // What cache store should be used to store temporary standalone checkout credentials 30 | 'cache_store' => env('STANDALONE_CHECKOUT_CACHE_STORE', config('cache.default')), 31 | ], 32 | ]; 33 | -------------------------------------------------------------------------------- /src/Models/Scopes/ForCurrentStoreScope.php: -------------------------------------------------------------------------------- 1 | joinTable = $joinTable; 17 | } 18 | 19 | public function apply(Builder $builder, Model $model) 20 | { 21 | $currentTable = $builder->getQuery()->from; 22 | $joinTable = $this->joinTable ?: $currentTable . '_store'; 23 | $primaryKey = $model->getKeyName(); 24 | 25 | $storeQuery = DB::table($joinTable) 26 | ->where($builder->qualifyColumn($primaryKey), DB::raw($joinTable . '.' . $primaryKey)) 27 | ->whereIn('store_id', [0, config('rapidez.store')]) 28 | ->orderByDesc('store_id') 29 | ->limit(1); 30 | 31 | $builder->joinLateral($storeQuery, $joinTable); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /resources/views/components/cookie-notice.blade.php: -------------------------------------------------------------------------------- 1 | @if (!App::runningUnitTests() || request()->has('show-cookie-notice')) 2 | 12 | 13 |
    14 |
    15 |
    16 | {{ $slot }} 17 |
    18 |
    19 | 20 | {{ $button ?? __('Accept cookies') }} 21 | 22 |
    23 |
    24 |
    25 | @endif 26 | -------------------------------------------------------------------------------- /tests/playwright/search.spec.js: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { ProductPage } from './pages/ProductPage' 3 | import { BasePage } from './pages/BasePage' 4 | 5 | test('search page', BasePage.tags, async ({ page }) => { 6 | const product = await new ProductPage(page).goto(process.env.PRODUCT_URL_SIMPLE) 7 | await page.goto('/search?q=' + product.name) 8 | await page.waitForLoadState('networkidle') 9 | await expect(page.getByTestId('listing-item').first()).toContainText(product.name) 10 | await new BasePage(page).screenshot() 11 | }) 12 | 13 | test('autocomplete', BasePage.tags, async ({ page }) => { 14 | const product = await new ProductPage(page).goto(process.env.PRODUCT_URL_SIMPLE) 15 | await page.goto('/') 16 | await page.getByTestId('autocomplete-input').click() 17 | await page.waitForLoadState('networkidle') 18 | await page.getByTestId('autocomplete-input').fill(product.name) 19 | await page.waitForLoadState('networkidle') 20 | await expect(page.getByTestId('autocomplete-item').first()).toContainText(product.name) 21 | await new BasePage(page).screenshot() 22 | }) 23 | -------------------------------------------------------------------------------- /resources/svg/loading.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/views/listing/partials/item/super-attributes/visual-swatch.blade.php: -------------------------------------------------------------------------------- 1 |
    2 | 3 | @{{ superAttribute.frontend_label }} 4 | 5 | 6 |
      7 |
    • 8 | 19 | @{{ option.label }} 20 | 21 |
    • 22 |
    23 |
    24 | -------------------------------------------------------------------------------- /resources/views/product/partials/gallery/popup.blade.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | {{ $product->name }} 9 |
    10 | 11 |
    12 |
    13 | 16 | 19 |
    20 | -------------------------------------------------------------------------------- /resources/views/search/overview.blade.php: -------------------------------------------------------------------------------- 1 | @extends('rapidez::layouts.app') 2 | 3 | @section('robots', 'NOINDEX,NOFOLLOW') 4 | 5 | @pushOnce('head', 'search-overview') 6 | @vite(vite_filename_paths(['StateResults.vue'])) 7 | @endPushOnce 8 | 9 | @section('content') 10 |
    11 | 12 | 13 | 14 | 24 | 25 | 26 | 27 |
    28 | @endsection 29 | -------------------------------------------------------------------------------- /src/Models/SuperAttribute.php: -------------------------------------------------------------------------------- 1 | 'json', 15 | ]; 16 | 17 | public static function boot() 18 | { 19 | parent::boot(); 20 | 21 | static::addGlobalScope('attribute', function (Builder $builder) { 22 | $builder 23 | ->leftJoin('eav_attribute', $builder->qualifyColumn('attribute_id'), '=', 'eav_attribute.attribute_id') 24 | ->leftJoin('catalog_eav_attribute', $builder->qualifyColumn('attribute_id'), '=', 'catalog_eav_attribute.attribute_id'); 25 | }); 26 | } 27 | 28 | /** 29 | * @deprecated please use attribute_code 30 | */ 31 | protected function code(): Attribute 32 | { 33 | return Attribute::get( 34 | fn (): string => $this->attribute_code 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/views/listing/partials/filter/search.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /resources/views/layouts/checkout/header.blade.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 25 |
    26 |
    -------------------------------------------------------------------------------- /resources/views/components/input/select/region.blade.php: -------------------------------------------------------------------------------- 1 | @props(['country']) 2 | 10 |
    11 | 22 |
    23 |
    24 | -------------------------------------------------------------------------------- /resources/views/product/partials/gallery/thumbnails/show-more.blade.php: -------------------------------------------------------------------------------- 1 | {{-- This component shows an overlay on the last shown thumbnail if there are more thumbnails after it. --}} 2 | 3 |
    !(count($selectedChild->images) - $imageId - 1), 5 | 'v-if' => 'images.length - ' . $imageId . ' - 1', 6 | ])> 7 | 25 |
    26 | -------------------------------------------------------------------------------- /resources/views/components/slideover/global.blade.php: -------------------------------------------------------------------------------- 1 | {{-- 2 | This is a wrapper for the global slideover. Use this as much as possible to reduce the amount of html elements in the DOM. 3 | Standard usage may look like this: 4 | ``` 5 | 6 | 7 | Click me 8 | 9 |
    10 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 11 |
    12 |
    13 | ``` 14 | --}} 15 | 16 | @props(['title', 'position' => 'left']) 17 | @slots(['label']) 18 | 19 | 20 |
    21 | 24 | 29 |
    30 |
    31 | -------------------------------------------------------------------------------- /resources/views/product/partials/options/file.blade.php: -------------------------------------------------------------------------------- 1 | @if (Rapidez::checkCompadreVersion('0.0.1')) 2 | 15 | @if ($option->file_extension) 16 |

    @lang('Compatible file extensions to upload'): {{ $option->file_extension }}

    17 | @endif 18 | @if ($option->image_size_x) 19 |

    @lang('Maximum image width'): {{ $option->image_size_x }}

    20 | @endif 21 | @if ($option->image_size_y) 22 |

    @lang('Maximum image height'): {{ $option->image_size_y }}

    23 | @endif 24 | @else 25 | @php(Log::error('File upload customizable option is being used, for now you will need to install rapidez/magento2-compadre')) 26 | @endif 27 | -------------------------------------------------------------------------------- /src/Http/Controllers/SignedCheckoutController.php: -------------------------------------------------------------------------------- 1 | hasValidSignature() || ! $cache->has('checkout-' . $request->get('key'))) { 15 | return redirect(config('rapidez.magento_url'), 301); 16 | } 17 | 18 | $data = $cache->get('checkout-' . $request->get('key')); 19 | $cache->forget('checkout-' . $request->get('key')); 20 | 21 | $response = redirect()->to('checkout', 301); 22 | 23 | if (! Quote::whereQuoteIdOrCustomerToken($data['mask'] ?? $data['token'])->exists()) { 24 | return redirect(config('rapidez.magento_url'), 301); 25 | } 26 | 27 | $response->withCookie('mask', $data['mask'] ?? null, 525949, null, null, null, false); 28 | $response->withCookie('token', $data['token'] ?? null, 525949, null, null, null, false); 29 | 30 | return $response; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /resources/views/checkout/partials/progressbar.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 22 | -------------------------------------------------------------------------------- /tests/playwright/product.spec.js: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { BasePage } from './pages/BasePage' 3 | 4 | test('product simple', BasePage.tags, async ({ page }) => { 5 | await page.goto(process.env.PRODUCT_URL_SIMPLE) 6 | await new BasePage(page).screenshot('fullpage-footer') 7 | }) 8 | 9 | test('product configurable', BasePage.tags, async ({ page }) => { 10 | await page.goto(process.env.PRODUCT_URL_CONFIGURABLE) 11 | await new BasePage(page).screenshot('fullpage-footer') 12 | }) 13 | 14 | test('product grouped', BasePage.tags, async ({ page }) => { 15 | await page.goto(process.env.PRODUCT_URL_GROUPED) 16 | await new BasePage(page).screenshot('fullpage-footer') 17 | }) 18 | 19 | test('product special price', BasePage.tags, async ({ page }) => { 20 | await page.goto(process.env.PRODUCT_URL_SPECIAL_PRICE) 21 | await new BasePage(page).screenshot('fullpage-footer') 22 | }) 23 | 24 | test('wcag', BasePage.tags, async ({ page }, testInfo) => { 25 | await page.goto(process.env.PRODUCT_URL_SIMPLE) 26 | await new BasePage(page).wcag(testInfo) 27 | }) 28 | 29 | test('lighthouse', BasePage.tags, async ({ page }) => { 30 | await new BasePage(page).lighthouse(process.env.PRODUCT_URL_SIMPLE) 31 | }) 32 | -------------------------------------------------------------------------------- /tests/playwright/general.spec.js: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test' 2 | import { BasePage } from './pages/BasePage' 3 | 4 | test('cookie', BasePage.tags, async ({ page }) => { 5 | const acceptCookiesButton = page.getByTestId('accept-cookies') 6 | 7 | await page.goto('/?show-cookie-notice') 8 | await new BasePage(page).screenshot() 9 | await acceptCookiesButton.click() 10 | await expect(acceptCookiesButton).not.toBeVisible() 11 | 12 | const cookieNotice = await page.evaluate(() => { 13 | return window.localStorage.getItem('cookie-notice') 14 | }) 15 | 16 | await expect(cookieNotice).not.toBeNull() 17 | }) 18 | 19 | test('newsletter', BasePage.tags, async ({ page }) => { 20 | const email = `wayne+${Date.now()}@enterprises.com` 21 | 22 | await page.goto('/') 23 | await new BasePage(page).scrolldown() 24 | 25 | await page.getByTestId('newsletter-email').fill(email) 26 | await page.getByTestId('newsletter-submit').click() 27 | await expect(page.getByTestId('newsletter-success')).toBeVisible() 28 | 29 | await page.getByTestId('newsletter-email').fill(email) 30 | await page.getByTestId('newsletter-submit').click() 31 | await expect(page.getByTestId('newsletter-error')).toBeVisible() 32 | }) 33 | -------------------------------------------------------------------------------- /resources/views/layouts/partials/header/autocomplete/categories.blade.php: -------------------------------------------------------------------------------- 1 | 2 | @if ($size = Arr::get($fields, 'size')) 3 | 4 | @endif 5 | 6 |
    7 | 8 | @lang('Categories') 9 | 10 | 21 |
    22 |
    23 |
    24 | -------------------------------------------------------------------------------- /resources/views/product/partials/super-attributes/visual-swatch.blade.php: -------------------------------------------------------------------------------- 1 |
    2 | 3 | {{ $superAttribute->frontend_label }} 4 | 5 | 6 |
      7 | @foreach ($product->superAttributeValues[$superAttribute->attribute_code] as $option) 8 |
    • 9 | 20 | {{ $option->label }} 21 | 22 |
    • 23 | @endforeach 24 |
    25 |
    26 | --------------------------------------------------------------------------------