{"version":3,"file":"product_service-86901b8a.js","sources":["../../../app/javascript/plugins/shoelace.js","../../../app/javascript/plugins/shopify_app_bridge.ts","../../../app/javascript/services/product_variant_service.ts","../../../app/javascript/services/shopping_cart_service.ts","../../../app/javascript/stores/shopping_cart.ts","../../../app/javascript/stores/user_session.ts","../../../app/javascript/services/api_service.ts","../../../app/javascript/services/configuration_service.ts","../../../app/javascript/stores/admin/configuration.ts","../../../app/javascript/views/application/not_found.vue","../../../app/javascript/services/style_service.ts","../../../app/javascript/services/product_service.ts"],"sourcesContent":["import '@shoelace-style/shoelace/dist/themes/light.css'\nimport '@shoelace-style/shoelace/dist/components/alert/alert.js'\nimport '@shoelace-style/shoelace/dist/components/input/input.js'\nimport '@shoelace-style/shoelace/dist/components/select/select.js'\nimport '@shoelace-style/shoelace/dist/components/option/option.js'\nimport '@shoelace-style/shoelace/dist/components/badge/badge.js'\nimport '@shoelace-style/shoelace/dist/components/dialog/dialog.js'\nimport '@shoelace-style/shoelace/dist/components/icon/icon.js'\nimport '@shoelace-style/shoelace/dist/components/textarea/textarea.js'\nimport '@shoelace-style/shoelace/dist/components/skeleton/skeleton.js'\nimport '@shoelace-style/shoelace/dist/components/tab/tab.js'\nimport '@shoelace-style/shoelace/dist/components/tab-group/tab-group.js'\nimport '@shoelace-style/shoelace/dist/components/tab-panel/tab-panel.js'\nimport '@shoelace-style/shoelace/dist/components/button/button.js'\nimport '@shoelace-style/shoelace/dist/components/checkbox/checkbox.js'\nimport '@shoelace-style/shoelace/dist/components/spinner/spinner.js'\nimport '@shoelace-style/shoelace/dist/components/switch/switch.js'\nimport '@shoelace-style/shoelace/dist/components/tooltip/tooltip.js'\nimport '@shoelace-style/shoelace/dist/components/button-group/button-group.js'\nimport '@shoelace-style/shoelace/dist/components/menu-item/menu-item.js'\nimport '@shoelace-style/shoelace/dist/components/radio/radio.js'\nimport '@shoelace-style/shoelace/dist/components/radio-group/radio-group.js'\nimport '@shoelace-style/shoelace/dist/components/color-picker/color-picker.js'\n\nimport { setBasePath } from '@shoelace-style/shoelace/dist/utilities/base-path'\n\nsetBasePath('/shoelace')\n","export enum RedirectTarget {\n App,\n Admin,\n Remote\n}\n\nexport function useShopifyAppBridge() {\n const AppBridge = window['app-bridge']\n\n if (!AppBridge) {\n return\n }\n\n function sessionToken(host: string): Promise {\n const shopifyApp = initializeShopifyApp(host)\n return AppBridge.utilities.getSessionToken(shopifyApp)\n }\n\n function redirect(\n host: string,\n url: string,\n target: RedirectTarget = RedirectTarget.App,\n newWindow: boolean = false\n ) {\n const shopifyApp = initializeShopifyApp(host)\n const redirect = AppBridge.actions.Redirect.create(shopifyApp)\n if (target === RedirectTarget.Remote) {\n return redirect.dispatch(getRedirectActionTarget(target), { url: url, newContext: newWindow })\n } else {\n return redirect.dispatch(getRedirectActionTarget(target), { path: url, newContext: newWindow })\n }\n }\n\n // private functions\n\n function initializeShopifyApp(host: string) {\n const bridgeConfig = {\n apiKey: import.meta.env.VITE_SHOPIFY_CLIENT_ID,\n host: host\n }\n const shopifyApp = AppBridge.createApp(bridgeConfig)\n return shopifyApp\n }\n\n function getRedirectActionTarget(target: RedirectTarget) {\n switch (target) {\n case RedirectTarget.App:\n return AppBridge.actions.Redirect.Action.APP\n case RedirectTarget.Admin:\n return AppBridge.actions.Redirect.Action.ADMIN_PATH\n case RedirectTarget.Remote:\n return AppBridge.actions.Redirect.Action.REMOTE\n }\n }\n\n return { sessionToken, redirect }\n}\n","import ApiService from './api_service'\n\nexport default {\n async preview(id: number | string): Promise<{ preview_url: string }> {\n const response = await ApiService.get(`/product-variants/${id}/preview`)\n return response.data\n }\n}\n","import { UserSession } from '@/stores/user_session'\nimport { ShoppingCartLineItem } from '@/types'\n\nimport ApiService from './api_service'\n\nexport default {\n async quote(lineItems: ShoppingCartLineItem[]) {\n const response = await ApiService.post(\n `/cart/quote`,\n {\n line_items: lineItems,\n currency: UserSession().currentCurrency.code\n },\n { withCredentials: true }\n )\n return response.data\n },\n\n async checkout(lineItems: ShoppingCartLineItem[], locale: string = 'en') {\n const response = await ApiService.post(`/cart/checkout`, {\n line_items: lineItems,\n locale: locale,\n currency: UserSession().currentCurrency.code\n })\n return response.data\n }\n}\n","import { useStorage } from '@vueuse/core'\nimport { defineStore } from 'pinia'\nimport { ref } from 'vue'\n\nimport ProductVariantService from '@/services/product_variant_service'\nimport ShoppingCartService from '@/services/shopping_cart_service'\nimport { ShoppingCartLineItem } from '@/types'\n\nconst STORE_NAME = 'shoppingCart'\n\nexport const useShoppingCart = defineStore(STORE_NAME, () => {\n const state = ref(\n useStorage(STORE_NAME, {\n lineItems: [],\n shipping: '',\n quoting: false\n } as any)\n )\n\n function setLineItems(updatedLineItems: ShoppingCartLineItem[]) {\n state.value.lineItems = updatedLineItems\n quote()\n }\n\n function checkPreviews(lineItemsToCheck: ShoppingCartLineItem[] = state.value.lineItems) {\n lineItemsToCheck.forEach(async (lineItem) => {\n let previewUrl = (await ProductVariantService.preview(lineItem.product_variant_id)).preview_url\n\n if (previewUrl) {\n lineItem.preview = previewUrl\n }\n })\n\n const itemsWithoutPreview = state.value.lineItems.filter((lineItem: ShoppingCartLineItem) => {\n return !lineItem.preview\n })\n\n if (itemsWithoutPreview.length > 0) {\n setTimeout(() => checkPreviews(itemsWithoutPreview), 3000)\n }\n }\n\n function addLineItem(lineItem: ShoppingCartLineItem) {\n state.value.lineItems.push(lineItem)\n quote()\n }\n\n function addLineItems(lineItemsToAdd: ShoppingCartLineItem[]) {\n lineItemsToAdd.forEach((lineItemToAdd) => {\n const existingLineItem = state.value.lineItems.find(\n (lineItem) => lineItem.product_variant_id === lineItemToAdd.product_variant_id\n )\n if (existingLineItem) {\n existingLineItem.quantity += lineItemToAdd.quantity\n } else {\n state.value.lineItems.push(lineItemToAdd)\n }\n })\n quote()\n }\n\n function removeLineItems(lineItemsToRemove: ShoppingCartLineItem[]) {\n state.value.lineItems = state.value.lineItems.filter(\n (lineItem: ShoppingCartLineItem) =>\n lineItemsToRemove\n .map((itemToRemove) => itemToRemove.product_variant_id)\n .includes(lineItem.product_variant_id) == false\n )\n quote()\n }\n\n function clear() {\n state.value.lineItems = []\n }\n\n function updateQuantity(lineItem: ShoppingCartLineItem, quantity: number) {\n if (quantity <= 0) {\n removeLineItems([lineItem])\n } else {\n const existingLineItem = state.value.lineItems.find(\n (existingLineItem) => existingLineItem.product_variant_id === lineItem.product_variant_id\n )\n if (existingLineItem) {\n existingLineItem.quantity = quantity\n }\n quote()\n }\n }\n\n async function quote() {\n state.value.quoting = true\n const response = await ShoppingCartService.quote(state.value.lineItems)\n state.value.lineItems = response.line_items\n state.value.shipping = response.shipping\n state.value.quoting = false\n }\n\n function lineItems(): ShoppingCartLineItem[] {\n return state.value.lineItems\n }\n\n function totalQuantity(): number {\n return state.value.lineItems.reduce((total, lineItem) => total + lineItem.quantity, 0)\n }\n\n function shipping() {\n return state.value.shipping\n }\n\n function quoting(): boolean {\n return state.value.quoting\n }\n\n return {\n lineItems,\n totalQuantity,\n shipping,\n quoting,\n setLineItems,\n addLineItem,\n addLineItems,\n removeLineItems,\n checkPreviews,\n clear,\n quote,\n updateQuantity\n }\n})\n","import { defineStore } from 'pinia'\nimport { ref } from 'vue'\nimport { useCookies } from 'vue3-cookies'\n\nimport { useShoppingCart } from '@/stores/shopping_cart'\nimport { Session, ShopifyShop, User } from '@/types'\n\nexport const UserSession = defineStore('userSession', () => {\n const { cookies } = useCookies()\n const shoppingCart = useShoppingCart()\n const currentUser = ref({} as User)\n const currentShopifyShop = ref({} as ShopifyShop)\n const shopifyHost = ref('')\n const currentCurrency = ref(\n cookies.get('currency') || ({ code: 'eur', symbol: '€', name: 'Euro', symbol_position: 'before' } as any)\n )\n\n function setShopifyHost(host: string) {\n shopifyHost.value = host\n }\n\n function setCurrentSession(session: Session) {\n currentUser.value = session.user\n }\n\n function setCurrentUser(user: User) {\n currentUser.value = user\n }\n\n function setCurrentCurrency(currency: any) {\n currentCurrency.value = currency\n cookies.set('currency', currency)\n shoppingCart.quote()\n }\n\n function setCurrentLocale(locale: string) {\n cookies.set('locale', locale)\n }\n\n function setCurrentShopifyShop(shopifyShop: ShopifyShop) {\n currentShopifyShop.value = shopifyShop\n }\n\n function initializeCurrency(_country: string) {\n if (cookies.get('currency')) {\n return\n }\n\n currentCurrency.value = { code: 'eur', symbol: '€', name: 'Euro', symbol_position: 'before' }\n }\n\n return {\n currentUser,\n currentCurrency,\n shopifyHost,\n currentShopifyShop,\n initializeCurrency,\n setCurrentSession,\n setCurrentCurrency,\n setCurrentLocale,\n setCurrentUser,\n setCurrentShopifyShop,\n setShopifyHost\n }\n})\n","import Axios from 'axios'\n\nimport { useShopifyAppBridge } from '@/plugins/shopify_app_bridge'\nimport { UserSession } from '@/stores/user_session'\n\nconst ApiService = Axios.create({\n baseURL: import.meta.env.VITE_API_URL\n})\n\nconst appBridge = useShopifyAppBridge()\n\nApiService.defaults.headers.common['X-CSRF-Token'] = document\n .querySelector('meta[name=\"csrf-token\"]')\n .getAttribute('content')\n\nApiService.interceptors.response.use(\n (response) => {\n return response\n },\n (error) => {\n return Promise.reject(error)\n }\n)\n\nApiService.interceptors.request.use(\n async (config) => {\n const host = UserSession().shopifyHost\n\n if (!appBridge) return config\n const sessionToken = await appBridge.sessionToken(host)\n\n config.headers = {\n 'sessionToken': sessionToken\n }\n return config\n },\n (error) => {\n return Promise.reject(error)\n }\n)\n\nexport default ApiService\n","import Axios from 'axios'\n\nexport default {\n async get() {\n const response = await Axios.create({\n baseURL: 'https://api.printplus.app',\n headers: {\n 'X-CSRF-Token': document.querySelector('meta[name=\"csrf-token\"]').getAttribute('content')\n }\n }).get(`/configuration`)\n return response.data\n }\n}\n","import { defineStore } from 'pinia'\n\nimport ConfigurationService from '@/services/configuration_service'\nimport { UserSession } from '@/stores/user_session'\n\nexport const Configuration = defineStore('configuration', {\n state: () => {\n // TODO: initialize if needed?\n return {\n countries: [],\n shippingCountries: [],\n shippingPrices: [],\n currencyExchangeRates: {},\n styleCategories: [],\n styleQualityLevels: [],\n styleGenders: [],\n designAreas: [],\n shopifyShopId: null,\n ipCountry: null\n }\n },\n\n actions: {\n async initialize() {\n const response = await ConfigurationService.get()\n this.countries = response.data.countries\n this.shippingCountries = response.data.shipping_countries\n this.shippingPrices = response.data.shipping_prices\n this.currencyExchangeRates = response.data.currency_exchange_rates || {}\n this.styleCategories = response.data.style_categories\n this.styleQualityLevels = response.data.style_quality_levels\n this.styleGenders = response.data.style_genders\n this.designAreas = response.data.design_areas\n this.ipCountry = response.data.ip_country\n\n this.designAreasOrder = {}\n this.designAreas.forEach((da, index) => {\n this.designAreasOrder[da] = index\n })\n\n UserSession().initializeCurrency(this.ipCountry)\n },\n\n setShopifyShopId(shopifyShopId: string) {\n this.shopifyShopId = shopifyShopId\n },\n\n designAreaNaturalOrder(a, b) {\n if (!this.designAreasOrder) {\n return 0\n }\n return this.designAreasOrder[a.location] - this.designAreasOrder[b.location]\n }\n }\n})\n","\n\n\n","import { Configuration } from '@/stores/admin/configuration'\nimport { PaginatedCollection, Style, StyleCategory, StyleVariant } from '@/types'\n\nimport ApiService from './api_service'\n\nexport default {\n async index(query = {}): Promise> {\n const response = await ApiService.get('/admin/styles', { params: query })\n return response.data\n },\n\n async get(id: number | string): Promise