这是 Wix Studio 挑战赛的提交内容。
当人工智能正在改变商业格局时,为什么还要遵循过时的方法?我创建这个电子商务是因为现在人工智能是公司的趋势。 Mega Mart 是一个不仅提供各种商品的平台,还通过 Wix Studio 中的高级功能增强了 UI/UX。
我开发了高级人工智能搜索选项来解决产品发现效率低下的问题,目标是为用户创造更直观和愉快的购物体验。
你有没有见过有人穿着你喜欢的T恤但不想问他们是什么牌子的?通过 Mega Market,只需拍照并将其上传到我们的平台;我们将在我们的产品数据库中搜索它。
当你可以像向商店员工询问一样搜索你想要的产品时,为什么还要去商场呢?只需用自然语言写下您的查询,我们就会向您展示您正在寻找的产品的示例。例如,尝试输入“我需要一件女士冬季夹克”或“我想要一部带摄像头的黑色智能手机”。
最好的部分是该网站不需要 Wix 订阅来完成结帐过程因为它完全使用 Wix 元素和 Velo API 构建。
在 Mega Mart,您可以选择使用或不使用帐户购买产品。
创建帐户有多种好处:
如前所述,您可以通过从设备上传图片、使用人工智能来搜索产品,或浏览所有商品以选择您最喜欢的商品。
结账之前,请确保您已将所有想要的产品添加到您的购物车。 根据需要调整物品的数量或删除任何错误。此外,请检查您的总交货日期和预计交货日期。
如果您登录,您的个人信息将自动填写。您可以选择之前保存的地址之一或输入一个新地址,该新地址将添加到您的帐户以供将来订购。
输入您的信用卡或借记卡信息,然后单击最后按钮完成结账。
您将被重定向到订单页面,您可以在其中查看购买的详细信息及其状态:是否正在处理、正在运送或已运送。您还将收到订单确认电子邮件。
现在谁想记住密码?在Mega Mart,您不必担心它们;每次您想要登录帐户时,您都会通过电子邮件、短信或电话收到一次性数字代码。
谁不喜欢购物获得奖励呢?每次在Mega Mart购物,您将获得1%返现,您可以用它来支付以后的订单。
曾经找到过您喜欢的产品,但还没有准备好购买吗?在 Mega Mart,您可以将其保存到您的愿望清单以供将来购买。
您无需切换页面即可查看货件状态。从订单页面,您可以轻松查看订单是否正在处理中、运输中或已交付。
有没有想过网站在您的计算机、平板电脑或手机上是否也能同样流畅?在 Mega Mart,我们的网站在所有设备上都能完全响应。
想知道购物有多方便吗?在 Mega Mart,您的地址会被保存以供将来购买,并且您可以从帐户页面轻松管理它们。
虽然许多电子商务网站需要创建帐户才能购物,但在 Mega Mart,您可以以访客身份购买。但是,请记住作为 Mega Mart 的常客可以享受的所有好处。
利用 Wix Studio 帮助我加速了前端开发,显着减少了时间,同时确保了跨所有设备的完全响应式设计。 JavaScript 在增强用户与 Wix Studio 元素的交互、无缝实现动态功能方面发挥着重要作用。此外,我们的网站采用了强大的安全措施,包括数据库、网络方法和路由器的安全性,以保护用户数据并确保安全的浏览体验。
在深入了解我如何创建 Mega Mart 之前,需要先说明的是,我没有安装 Wix Market 中的任何应用程序。虽然我使用 Wix Stores 将产品保存到购物车,然后在某些页面中检索它们,但我选择使用 Wix Elements 完全从头开始构建产品页面、购物车和结账页面。
免责声明
由于这是比赛的演示,我在数据库中只保存了 29 个产品。为了充分利用人工智能图像产品识别和人工智能搜索方法,请首先熟悉商店中的可用产品。例如,搜索打印机或锤子可能不会产生结果,因为这些项目不在演示数据库中。然而,如果这个项目扩大到像家得宝或沃尔玛这样的数据库中拥有数千种产品的大公司,人工智能功能将执行全面的搜索并提供更广泛的结果。
想知道 Mega Mart 能为您带来什么购物体验吗?点击探索并发现可能性。
走吧!
开发这个电子商务网站并不容易,特别是考虑到时间紧迫,但我很自豪能够在短短 2 周内构建其所有功能。
我开发的第一个页面是主页,我的目标是整合其他电子商务网站中常见的功能,例如展示畅销商品、新品以及强调在商店购物的好处。
下面是我如何在代码中检索畅销产品和最新产品数据的示例。
import wixData from 'wix-data'; import wixWindowFrontend from 'wix-window-frontend'; import wixLocationFrontend from 'wix-location-frontend'; const limit = wixWindowFrontend.formFactor === "Mobile" ? 6 : 5 const bestSellers = (await wixData.query("Products").descending("rating").limit(limit).find()).items $w('#repeater2').data = bestSellers $w('#repeater2').onItemReady(($item, itemData, index)=>{ $item('#imageX9').src = itemData.imageUrl[0].src $item('#imageX9').alt = itemData.name $item('#text12').text = itemData.name $item('#text13').text = "$" + itemData.price $item('#box15').onClick(() => { wixLocationFrontend.to(`/product/${itemData._id}`) }) }) const newProucts = (await wixData.query("Products").descending("_createdDate").limit(limit).find()).items $w('#repeater3').data = newProucts $w('#repeater3').onItemReady(($item, itemData, index)=>{ $item('#imageX10').src = itemData.imageUrl[0].src $item('#imageX10').alt = itemData.name $item('#text15').text = itemData.name $item('#text14').text = "$" + itemData.price $item('#box19').onClick(() => { wixLocationFrontend.to(`/product/${itemData._id}`) }) })
如您所见,代码还包含检测用户是否在移动设备上浏览的逻辑。在移动设备视图中,中继器显示为两列,而在平板电脑和电脑模式下,它们排列成单行五列。
我认为注册和登录页面应该有一个直观的 UI/UX 界面。如果任一流程对用户来说很困难或令人沮丧,他们可能会离开网站,从而导致销售损失。
为了防止这种情况,Mega Mart 使用无密码系统。每次您想要登录时,都会通过短信、电话或电子邮件发送一次性代码,无需记住多个密码。
import { verify, sendVerification } from "backend/twilio.web" import { register } from "backend/members.web" $w('#button1').onClick(async () => { $w('#imageX9').show() $w('#button1').disable() if ($w('#box37').isVisible) { if ($w('#input5').valid) { $w('#text35').collapse() const verifyEmailResponse = await verify($w('#input3').value, $w('#input5').value) const verifyPhoneResponse = await verify($w('#input4').value, $w('#input5').value) if (verifyEmailResponse || verifyPhoneResponse) { try { const sessionToken = await register($w('#input1').value, $w('#input2').value, $w('#input3').value, $w('#input4').value) await authentication.applySessionToken(sessionToken) } catch (error) { $w('#text35').text = "Error registering: " + new Error(error).message $w('#text35').expand() } } else { $w('#text35').text = "Wrong verification code." $w('#text35').expand() } } } else { const sendEmailResponse = await sendVerification("email", $w('#input3').value) const sendSMSResponse = await sendVerification("sms", $w('#input4').value) if (sendEmailResponse && sendSMSResponse) { $w('#input1,#input2,#box36').collapse() $w('#box37').expand() $w('#button1').label = "Register" $w('#text37').hide() } } $w('#imageX9').hide() $w('#button1').enable() })
此代码处理单击按钮时的注册过程。如果验证码输入框可见并且输入的验证码有效,则会使用提供的验证码验证用户的电子邮件或电话号码。如果任一验证成功,它会尝试注册用户,然后应用会话令牌进行身份验证。如果验证失败,则会显示错误消息。
如果该框不可见,它会向用户的电子邮件和电话发送验证码,然后更新 UI 以允许用户完成注册。
发送验证码给用户
import { sendVerification } from "backend/twilio.web" import { verifyEmailOrPhoneNumber} from "backend/members.web" $w('#button2,#button3').onClick(async (rest) => { if ($w('#input7').valid || $w('#input8').valid) { $w('#imageX10').show() $w('#text34').collapse() $w('#button2,#button3').disable() let toSearch = $w('#input7').isVisible ? $w('#input7').value : $w('#input8').value if (!(await verifyEmailOrPhoneNumber(toSearch))) { $w('#text34').text = "There isn't an account with that email or phone number." $w('#text34').expand() } else { switch (rest.target) { case $w('#button2'): let response = false if ($w('#input7').isVisible) { response = await sendVerification("email", $w('#input7').value) verificationTypeAtLogin = "email" $w('#text31').text = "Please check you email. It may be at junk mails." } else { response = await sendVerification("sms", $w('#input8').value) verificationTypeAtLogin = "sms" $w('#text31').text = "Please check you SMS." } if (response) { $w('#text33,#box41,#box47').collapse() $w('#box46,#box48').expand() $w('#text36').hide() } else { $w('#text34').text = "We couldn't send the verification code. Try using another method." $w('#text34').expand() } break; case $w('#button3'): verificationTypeAtLogin = "call" $w('#text31').text = "You will receive a phone call in a few moments." if (await sendVerification("call", $w('#input8').value)) { $w('#text33,#box41,#box47').collapse() $w('#box46,#box48').expand() $w('#text36').hide() } else { $w('#text34').text = "We couldn't send the verification code. Try using another method." $w('#text34').expand() } break; } } $w('#imageX10').hide() $w('#button2,#button3').enable() } })
它首先验证输入的电子邮件或电话号码是否存在。
根据单击的按钮,它会通过电子邮件、短信或电话发送验证码。然后扩展验证码输入,供用户写入接收到的代码。
如果验证失败,则会显示相应的错误消息。最后,加载图像被隐藏,按钮被重新启用。
正在验证验证码
import { verify } from "backend/twilio.web" import { login } from "backend/members.web" if ($w('#input9').valid) { $w('#imageX11').show() $w('#text34').collapse() $w('#button4').disable() let verifyResponse = false if (verificationTypeAtLogin === "email") verifyResponse = await verify($w('#input7').value, $w('#input9').value) else verifyResponse = await verify($w('#input8').value, $w('#input9').value) if (verifyResponse) { try { const sessionToken = await login(verificationTypeAtLogin === "email" ? $w('#input7').value : "", verificationTypeAtLogin !== "email" ? $w('#input8').value : "") await authentication.applySessionToken(sessionToken) } catch (error) { $w('#text34').text = "Error registering: " + new Error(error).message $w('#text34').expand() $w('#imageX11').hide() $w('#button4').enable() } } else { $w('#text34').text = "Wrong verification code." $w('#text34').expand() $w('#imageX11').hide() $w('#button4').enable() } }
它根据验证类型(电子邮件或电话)验证提供的代码。如果验证成功,它会尝试让用户登录并应用会话令牌进行身份验证。
无论用户是登录还是注册,成功后都会被重定向到上次访问的页面。
import { authentication } from "wix-members" import wixLocationFrontend from 'wix-location-frontend' authentication.onLogin(() => { wixLocationFrontend.to(wixLocationFrontend.query.redirect) })
为了让用户可以从任何页面搜索产品,我在灯箱内添加了搜索栏。
First check what search type the user selected.
import wixWindowFrontend from 'wix-window-frontend'; $w('#imageX7').hide() $w('#button2,#input1,#searchByImage,#searchByAI').enable() const type = wixWindowFrontend.lightbox.getContext() let instructions = "" switch (type) { case "text": $w('#searchByTextMobile').show("fade", { duration: 500 }) instructions = "Enter keywords or product names into the search bar." break; case "image": $w('#searchByImage').show("fade", { duration: 500 }) instructions = "Upload an image of the product you are looking for." break; case "AI": $w('#searchByAI').show("fade", { duration: 500 }) instructions = "Type your query in natural language (e.g., 'I need a winter jacket for women')." break; } $w('#text21').text = `Search by ${type}` $w('#text22').text = instructions
By image
import { getImageLabels } from "backend/googleVision.web" $w('#searchByImage').onChange(async () => { $w('#searchByImage').disable() $w('#imageX7').show() const file = await $w('#searchByImage').uploadFiles() const labels = await getImageLabels(file[0].fileUrl) sendTo("tags", labels) })
First, the image is uploaded to the Media Manager to obtain its URL. Then, the URL is sent to Google Vision to identify tags related to the image.
By AI
$w('#searchByAI').onKeyPress(async (rest) => { if ($w('#searchByAI').valid && rest.key === "Enter") { $w('#searchByAI').disable() $w('#imageX7').show() const labels = await getTextLabels($w('#searchByAI').value) sendTo("tags", labels) } })
If the user presses Enter, the input text is tokenized to extract nouns.
Once one of the methods is completed, the user is redirected to the search router page with the queries included in the URL.
import wixLocationFrontend from 'wix-location-frontend'; function sendTo(type = "", value = []) { wixLocationFrontend.to(`/search?type=${type}&value=${JSON.stringify(value)}`) }
This is a Wix Router page that helped me show the different types of search, and also the wishlist of the products the user saved.
import wixWindowFrontend from 'wix-window-frontend'; import { cart } from "wix-stores-frontend"; let originalItem = wixWindowFrontend.getRouterData() let items = wixWindowFrontend.getRouterData() initRepeater(items) $w('#repeater1').onItemReady(async ($item, itemData, index) => { $item('#imageX9').src = itemData.imageUrl[0].src $item('#text12').text = itemData.name $item('#text13').text = "$" + itemData.price $item('#ratingsDisplay1').rating = itemData.rating $item('#button1').onClick(async () => { const product = [{ productId: itemData._id, quantity: 1, }] await cart.addProducts(product) await showAlert("add") }) $item('#box38').onClick(() => { wixLocationFrontend.to(`/product/${itemData._id}`) }) if (authentication.loggedIn()) { const userID = await currentMember.getMember({ fieldsets: ["FULL"] }) const item = await wixData.query("Wishlist").eq("product", itemData._id).eq("_owner", userID._id).find() if (item.totalCount === 0) $item('#button2').expand() else { itemData.wishList = item.items[0]._id $item('#button3').expand() } } else $item('#button2').expand() $item('#button2').onClick(async () => { if (authentication.loggedIn()) { const itemWishlist = await wixData.insert("Wishlist", { product: itemData._id }) itemData.wishList = itemWishlist._id await showAlert("save") $item('#button2').collapse().then(() => { $item('#button3').expand() }) } else wixWindowFrontend.openLightbox("loginToWishlist") }) $item('#button3').onClick(async () => { await wixData.remove("Wishlist", itemData.wishList) await showAlert("remove") $item('#button3').collapse().then(() => { $item('#button2').expand() }) }) }) function initRepeater(items = [], changeFilter = true) { $w('#repeater1').data = items if ($w('#repeater1').data.length === 0) { if (wixLocationFrontend.query.type === "wishlist") { $w('#text27').text = "You haven't add any item to your wishlist. Add your first product!" } else { $w('#text27').text = "Try searching with another method or include more details if you are using AI." } $w('#section5').collapse() $w('#section6').expand() } else { const htmlLinks = items[0].tags.slice(0, 5).map(word => `<span style="font-size: 10px;"><a href="/search?type=tags&value=[%22${word}%22]">${word}</a></span>`).join(' - '); $w('#text22').html = htmlLinks $w('#section6').collapse() $w('#section5').expand() $w('#switch1').checked = false if (changeFilter) { const maxPrice = sortByPrice(items, "desc")[0] $w('#slider1').max = maxPrice.price $w('#slider2').max = maxPrice.price $w('#slider2').value = maxPrice.price } } }
As you can see, this includes the import { cart } from "wix-stores-frontend" statement, which allows the product to be added to the cart when the user clicks the button inside the repeater.
$w('#switch1').onChange(() => { $w('#repeater1').data = [] items = sortByPrice(items, $w('#switch1').checked ? "desc" : "asc") $w('#repeater1').data = items }) function sortByPrice(products = [{}], order = 'asc') { return products.sort((a, b) => { if (order === 'asc') { return a.price - b.price; } else if (order === 'desc') { return b.price - a.price; } else { throw new Error("Order must be either 'asc' or 'desc'"); } }); }
$w('#slider1,#slider2').onChange(() => { items = filterByPriceRange(originalItem, $w('#slider1').value, $w('#slider2').value) initRepeater(items, false) }) function filterByPriceRange(products, minPrice, maxPrice) { return products.filter(product => product.price >= minPrice && product.price <= maxPrice); }
Since searching for new products redirects the user to the same page /search and only changes the URL queries, I needed to handle this with wixLocationFrontend.onChange() to update the repeater items.
This is also a router page /product/${productID} that fetches product information from the backend and displays it using wixWindowFrontend.getRouterData().
import wixWindowFrontend from 'wix-window-frontend'; const product = wixWindowFrontend.getRouterData() $w('#gallery1').items = product.imageUrl $w('#features').text = product.features $w('#title').text = product.name $w('#brand').text = product.brand $w('#color').text = product.color $w('#price').text = String(product.price) $w('#description').text = product.description $w('#ratings').rating = product.rating $w('#stock').text = `${product.stock} available`
Since you can add the product to your cart from here, with the option to set a quantity, I used the following code to achieve this.
import { cart } from "wix-stores-frontend" $w('#addCart').onClick(async () => { const productToSave = [{ productId: product._id, quantity: Number($w('#inputQuantity').value), }] await cart.addProducts(productToSave) await showAlert("add") }) $w('#quantityLess,#quantityMore').onClick((rest) => { let value = Number($w('#inputQuantity').value) switch (rest.target) { case $w('#quantityLess'): if (value > 1) value-- break; case $w('#quantityMore'): value++ break; } $w('#inputQuantity').value = String(value) })
Also having the option to add the product to the wishlist or delete it.
$w('#addWishList').onClick(async () => { if (authentication.loggedIn()) { await wixData.insert("Wishlist", { product: product._id }) await showAlert("save") $w('#addWishList').collapse().then(() => { $w('#deleteWishlist').expand() }) } else wixWindowFrontend.openLightbox("loginToWishlist") }) $w('#deleteWishlist').onClick(async () => { await wixData.remove("Wishlist", product.wishList) await showAlert("remove") $w('#deleteWishlist').collapse().then(() => { $w('#addWishList').expand() }) })
Need to review your cart? This page allows you to check if you have added the desired quantities of the products you want to buy and also lets you delete any items if needed.
import { cart } from "wix-stores-frontend" $w('#repeater1').onItemReady(($item, itemData, index) => { $item('#quantityLess,#quantityMore').onClick(async (rest) => { $item('#quantityLess,#quantityMore,#button3').disable() let value = Number($item('#inputQuantity').value) switch (rest.target) { case $item('#quantityLess'): if (value > 1) value-- break; case $item('#quantityMore'): value++ break; } $item('#inputQuantity').value = String(value) $item('#text22').text = `$${(itemData.price * value).toFixed(2)}` const updadedCart = await cart.updateLineItemQuantity(Number(itemData._id), value) $item('#quantityLess,#quantityMore,#button3').enable() $w('#text25').text = `Total: $${updadedCart.totals.total.toFixed(2)}` }) $item('#button3').onClick(async () => { $item('#quantityLess,#quantityMore,#button3').disable() await cart.removeProduct(Number(itemData._id)) await initCart() }) })
Clicking the buttons #quantityLess and #quantityMore triggers an event to edit the product quantity. Clicking the #button3 removes the product from the cart.
This is the final step for purchasing at Mega Market.
If the user is a Site Member, it retrieves their saved addresses and accumulated cashback from their account.
import { authentication, currentMember } from "wix-members-frontend" if (authentication.loggedIn()) { $w('#text25').collapse() const user = await currentMember.getMember({ fieldsets: ["FULL"] }) $w('#input1').value = user.contactDetails.firstName $w('#input2').value = user.contactDetails.lastName $w('#input3').value = user.loginEmail $w('#input4').value = user.contactDetails.phones[0] const addresses = await getUserAdderess(user._id) if (addresses.length === 0) { $w('#dropdown1').options = [{ value: "No addresses founded", label: "No addresses founded" }] $w('#dropdown1').value = "No addresses founded" $w('#dropdown1').disable() } else { const addressesOptions = addresses.map(address => ({ label: `${address.addressLine} ${address.state}, ${address.country}`, value: JSON.stringify(address) })); $w('#dropdown1').options = addressesOptions } const totalCashback = await getTotalCashback(user._id) if (totalCashback === 0) { $w('#switch1').disable() $w('#switch1').checked = false $w('#text28').text = `You will earn $${Number(currentCart.totals.total * 0.01).toFixed(2)} in cashback with this order.` } else { cashback = totalCashback > currentCart.totals.total ? currentCart.totals.total : totalCashback; $w('#switch1').enable() $w('#text28').text = `Use my cashback: $${Number(cashback).toFixed(2)}` } }
It also validates that the card number of the user is a Master Card, Visa or AMEX.
$w('#input10').onCustomValidation((value, reject) => { const cardsInfo = { "Unknown": { "image": "https://static.wixstatic.com/media/4c0a11_600a3b93f607463296a7c9149268800e~mv2.gif", "regex": /^\d+$/, "length": 16 }, "Master Credit": { "image": "https://www.mercadopago.com/org-img/MP3/API/logos/master.gif", "regex": , "length": 16 }, "Visa Credit": { "image": "https://www.mercadopago.com/org-img/MP3/API/logos/visa.gif", "regex": , "length": 16 }, "AMEX": { "image": "https://www.mercadopago.com/org-img/MP3/API/logos/amex.gif", "regex": , "length": 15 }, "Visa Debit": { "image": "https://www.mercadopago.com/org-img/MP3/API/logos/debvisa.gif", "regex": , "length": 16 }, "Master Debit": { "image": "https://www.mercadopago.com/org-img/MP3/API/logos/debmaster.gif", "regex": , "length": 16 } } const cardCategory = identifyCardCategory(value) $w('#imageX8').src = cardsInfo[cardCategory].image $w('#input10').maxLength = cardsInfo[cardCategory].length if (!cardsInfo[cardCategory].regex.test(value)) { reject("Invalid card number") } }) function identifyCardCategory(cardNumber) { const patterns = { masterCredit: , visaCredit: , amex: , visaDebit: , masterDebit: }; if (patterns.masterCredit.test(cardNumber)) return "Master Credit"; if (patterns.visaCredit.test(cardNumber)) return "Visa Credit"; if (patterns.amex.test(cardNumber)) return "AMEX"; if (patterns.visaDebit.test(cardNumber)) return "Visa Debit"; if (patterns.masterDebit.test(cardNumber)) return "Master Debit"; return "Unknown"; }
After the user inputs all the required information, it's time to process the order.
$w('#button2').onClick(async () => { if ($w('#input1').valid && $w('#input2').valid && $w('#input3').valid && $w('#input4').valid && $w('#input5').valid && $w('#input6').valid && $w('#input7').valid && $w('#input8').valid && $w('#input9').valid && $w('#input10').valid && $w('#dropdown2').valid && $w('#dropdown3').valid && $w('#dropdown4').valid) { $w('TextInput,Dropdown').disable() $w('#box53').show() const productArray = currentCart.lineItems.map(item => ({ quantity: item.quantity, name: item.name, priceData: { price: item.price, }, mediaItem: { src: item.mediaItem.src } })); const insertedItem = await wixData.insert("Orders", { lineItems: productArray, totals: { subtotal: subTotal, total: total, }, shippingInfo: { shipmentDetails: { address: { city: $w('#dropdown4').value, country: $w('#dropdown2').value, addressLine: $w('#input5').value, postalCode: $w('#input6').value, subdivision: $w('#dropdown3').value, } } }, billingInfo: { address: { city: $w('#dropdown4').value, country: $w('#dropdown2').value, addressLine: $w('#input5').value, postalCode: $w('#input6').value, subdivision: $w('#dropdown3').value, }, lastName: $w('#input2').value, firstName: $w('#input1').value, email: $w('#input3').value, phone: $w('#input4').value }, cashback: $w('#switch1').checked }) for (let lineItem of currentCart.lineItems) { await cart.removeProduct(lineItem.id) } wixLocationFrontend.to(`/order/${insertedItem._id}`) } })
This wixData.insert() triggers a data hook that creates the order using wixStoresBackend.createOrder() which I'll talk of it later.
This page displays the order information passed though the wixWindowFrontend.getRouterData().
import wixWindowFrontend from 'wix-window-frontend'; const orderInfo = wixWindowFrontend.getRouterData() const contact = orderInfo.billingInfo const shipping = contact.address $w('#text21').text = `Order #${orderInfo.orderNumber}` $w('#text48').text = `Amount paid: $${orderInfo.totals.total}` $w('#text47').text = `Subtotal: $${Number(orderInfo.totals.subtotal).toFixed(2)} | Discounts: $${Number(orderInfo.totals.subtotal - orderInfo.totals.total).toFixed(2)}` $w('#text26').text = contact.firstName $w('#text27').text = contact.lastName $w('#text28').text = contact.phone $w('#text29').text = contact.email $w('#text30').text = shipping.addressLine $w('#text31').text = shipping.city $w('#text32').text = shipping.postalCode $w('#text33').text = `${shipping.subdivision}, ${shipping.country}`
API | Method | Location in Project |
---|---|---|
Wix Data | 1. query() 2. insert() 3. remove() 4. get() | 1. Home page 2. Search page 3. Checkout |
Wix Window Frontend | 1. formFactor 2. lightbox.getContext() 3. getRouterData() 4. openLightbox() | 1. Home page 2. Login 3. Search bar 4. Search page 5. Product page |
Wix Location Frontend | 1. to() 2. onChange() 3. query | 1. Home page 2. Login 3. Search bar 4. Search page 5. Cart page 6. Checkout 7. Order page |
{authentication} from Wix Members | 1. applySessionToken() 2. onLogin() | 1. Login 2. Checkout |
{ cart } from Wix Stores | 1. addProducts() | 1. Search page 2. Product page 3. Cart page 4. Checkout |
{currentMember} from Wix Members | 1. getMember() | 1. Product page 2. Checkout |
Wix Secrets | getSecret() | Backend |
Helped to get the countries, states of countries and cities of states.
import { Permissions, webMethod } from "wix-web-module"; export const getAllCountries = webMethod( Permissions.Anyone, async () => { const countries = await require('country-state-city').Country.getAllCountries(); const toReturn = countries.map(state => ({ label: state.name, value: state.isoCode })); return toReturn; } ); export const getStatesOfCountry = webMethod( Permissions.Anyone, async (country) => { const states = await require('country-state-city').State.getStatesOfCountry(country); const toReturn = states.map(state => ({ label: state.name, value: state.isoCode })); return toReturn; } ); export const getCitiesOfStates = webMethod( Permissions.Anyone, async (country, state) => { const states = await require('country-state-city').City.getCitiesOfState(country, state); const toReturn = states.map(state => ({ label: state.name, value: state.name })); return toReturn; } );
Reads the image and provides labels of what it identifies.
const vision = require('@google-cloud/vision'); export const getImageLabels = webMethod( Permissions.Anyone, async (imageUrl) => { const credentials = JSON.parse(await wixSecretsBackend.getSecret("googleVisionCredentials")) const client = new vision.ImageAnnotatorClient({ credentials }); try { const [result] = await client.labelDetection(getPublicURL(imageUrl)); const labels = result.labelAnnotations.map(label => label.description); const lowerCaseLabels = labels.map(element => element.toLowerCase()); return lowerCaseLabels; } catch (error) { console.error('Error detecting labels:', error); return [] } } );
Extracts the nouns from a text.
const nlp = require('compromise'); export const getTextLabels = webMethod( Permissions.Anyone, async (text) => { let doc = nlp(text); let categories = doc.match('#Noun').out('array'); const lowerCaseCategories = categories.map(element => element.toLowerCase()); return lowerCaseCategories } );
Used for sending the verification code via SMS, call or email and to verify the one-time digit code.
export const sendVerification = webMethod( Permissions.Anyone, async (type = "email" || "sms" || "call", to = "diego_deap@outlook.com") => { try { const { accountSid, authToken, service } = await auth() const client = twilio(accountSid, authToken); await client.verify.v2 .services(service) .verifications.create({ channel: type, to: to, }); return true } catch (error) { return false } } ); export const verify = webMethod( Permissions.Anyone, async (to = "", code = "") => { const { accountSid, authToken, service } = await auth() const client = twilio(accountSid, authToken); const verificationCheck = await client.verify.v2 .services(service) .verificationChecks.create({ code: code, to: to, }); const status = verificationCheck.status === "approved" ? true : false; return status } );
以上是超级市场的详细内容。更多信息请关注PHP中文网其他相关文章!