Maison > Article > interface Web > Méga-marché
Ceci est une soumission pour le Wix Studio Challenge.
Pourquoi suivre des méthodes dépassées alors que l'IA transforme le paysage commercial ? J'ai créé ce e-commerce car aujourd'hui l'IA est la tendance des entreprises. Mega Mart est une plate-forme qui offre non seulement une grande variété de produits, mais améliore également l'UI/UX grâce à des fonctionnalités avancées réalisées dans Wix Studio.
J'ai développé des options de recherche avancées par l'IA pour résoudre le problème de la découverte de produits inefficace, dans le but de créer une expérience d'achat plus intuitive et agréable pour les utilisateurs.
Avez-vous déjà vu quelqu'un porter un t-shirt que vous aimez mais vous ne vouliez pas lui demander la marque ? Avec Mega Market, prenez simplement une photo et téléchargez-la sur notre plateforme ; nous le rechercherons dans notre base de données de produits.
Pourquoi aller au centre commercial quand vous pouvez rechercher le produit que vous souhaitez comme vous le demanderiez à un employé de magasin ? écrivez simplement votre requête en langage naturel et nous vous montrerons des exemples des produits que vous recherchez. Par exemple, essayez de taper J'ai besoin d'une veste d'hiver pour femme ou Je voudrais un smartphone noir avec appareil photo.
La meilleure partie est que le site ne nécessite pas d'abonnement Wix pour terminer le processus de paiement car il est entièrement construit à l'aide d'éléments Wix et d'API Velo.
Chez Mega Mart, vous avez la possibilité d'acheter des produits avec ou sans compte.
La création d'un compte offre plusieurs avantages :
Comme mentionné précédemment, vous pouvez rechercher des produits en téléchargeant des images depuis votre appareil, en utilisant l'IA ou en parcourant tous les articles pour sélectionner celui que vous aimez le plus.
Avant de finaliser votre commande, assurez-vous d'avoir ajouté tous les produits souhaités à votre panier. Ajustez la quantité des articles si nécessaire ou supprimez les erreurs. De plus, vérifiez votre total et la date de livraison estimée.
Si vous êtes connecté, vos informations personnelles seront automatiquement renseignées. Vous pouvez choisir l'une de vos adresses précédemment enregistrées ou en saisir une nouvelle, qui sera ajoutée à votre compte pour les prochaines commandes.
Entrez les informations de votre carte de crédit ou de débit, puis cliquez sur le dernier bouton pour finaliser le paiement.
Vous serez redirigé vers la page de commande, où vous pourrez consulter les détails de votre achat et son statut : s'il est en cours de traitement, en transit pour livraison ou déjà livré. Vous recevrez également un email de confirmation de votre commande.
Qui veut mémoriser ses mots de passe de nos jours ? Chez Mega Mart, vous n'avez pas à vous en soucier ; chaque fois que vous souhaitez vous connecter à votre compte, vous recevrez un code à un chiffre par e-mail, SMS ou appel.
Qui n'aime pas être récompensé pour ses achats ? Chaque fois que vous achetez chez Mega Mart, vous recevrez 1 % de remise en argent, que vous pourrez utiliser pour payer de futures commandes.
Avez-vous déjà trouvé un produit que vous aimez mais que vous n’êtes pas encore prêt à acheter ? Chez Mega Mart, vous pouvez l'enregistrer dans votre liste de souhaits pour un prochain achat.
Vous n'avez pas besoin de basculer entre les pages pour voir l'état de votre envoi. Depuis la page de commande, vous pouvez facilement vérifier si elle est en cours, en transit ou déjà livrée.
Vous êtes-vous déjà demandé si un site Web pouvait être tout aussi fluide sur votre ordinateur, votre tablette ou votre téléphone ? Chez Mega Mart, notre site est entièrement réactif sur tous les appareils.
Curieuse de savoir à quel point faire du shopping peut être pratique ? Chez Mega Mart, vos adresses sont enregistrées pour de futurs achats et vous pouvez les gérer facilement depuis la page de votre compte.
Alors que de nombreux sites de commerce électronique nécessitent la création d'un compte pour faire des achats, chez Mega Mart, vous pouvez acheter en tant qu'invité. Cependant, n'oubliez pas tous les avantages dont vous pouvez bénéficier en tant que client fréquent de Mega Mart.
L'utilisation de Wix Studio m'a aidé à accélérer le développement du frontend, en réduisant considérablement le temps tout en garantissant une conception entièrement réactive sur tous les appareils. JavaScript joue un rôle important dans l'amélioration de l'interaction de l'utilisateur avec les éléments de Wix Studio, permettant ainsi des fonctionnalités dynamiques de manière transparente. De plus, notre site utilise des mesures de sécurité robustes, notamment la sécurité des bases de données, des méthodes Web et du routeur, pour protéger les données des utilisateurs et garantir une expérience de navigation sécurisée.
Avant de découvrir comment j'ai créé Mega Mart, il est important de dire que je n'ai installé aucune application du Wix Market. Alors que j'utilisais Wix Stores pour enregistrer des produits dans le panier, puis les récupérer dans certaines pages, j'ai choisi de créer entièrement les pages de produits, le panier et les pages de paiement à l'aide de Wix Elements.
Avis de non-responsabilité
Puisqu'il s'agit d'une démo pour le concours, je n'ai enregistré que 29 produits dans la base de données. Pour tirer le meilleur parti des méthodes de reconnaissance de produits d'images IA et de recherche IA, veuillez d'abord vous familiariser avec les produits disponibles dans le magasin. Par exemple, la recherche d'une imprimante ou d'un marteau peut ne pas donner de résultats, car ces éléments ne figurent pas dans la base de données de démonstration. Cependant, si ce projet était étendu à de grandes entreprises comme Home Depot ou Walmart, qui ont des milliers de produits dans leurs bases de données, les fonctionnalités de l'IA effectueraient des recherches complètes et fourniraient un plus large éventail de résultats.
Curieux de voir ce que Mega Mart peut apporter à votre expérience de magasinage ? Cliquez pour explorer et découvrir les possibilités.
Allons-y !
Développer ce site de commerce électronique n'a pas été facile, surtout compte tenu du calendrier serré, mais je suis fier de l'avoir construit avec toutes ses fonctionnalités en seulement 2 semaines.
La première page que j'ai développée était la page d'accueil, où j'avais pour objectif d'incorporer des fonctionnalités couramment trouvées sur d'autres sites de commerce électronique, telles que la présentation des best-sellers, des nouveautés et la mise en évidence des avantages des achats en magasin.
Vous trouverez ci-dessous un exemple de la façon dont j'ai récupéré les données sur les meilleures ventes et les produits les plus récents dans le code.
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}`) }) })
Comme vous pouvez le voir, le code inclut également une logique pour détecter si l'utilisateur navigue sur un appareil mobile ou non. En vue mobile, les répéteurs sont affichés sur deux colonnes, tandis qu'en modes tablette et ordinateur, ils sont disposés sur une seule ligne avec cinq colonnes.
Je pense que les pages d'inscription et de connexion doivent avoir une interface UI/UX intuitive. Si l'un ou l'autre des processus est difficile ou frustrant pour les utilisateurs, ils peuvent quitter le site, entraînant une perte de vente.
Pour éviter cela, Mega Mart utilise un système sans mot de passe. Chaque fois que vous souhaitez vous connecter, un code à usage unique sera envoyé par SMS, appel ou e-mail, éliminant ainsi le besoin de mémoriser plusieurs mots de passe.
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() })
Ce code gère le processus d'inscription lorsque vous cliquez sur le bouton. Si la zone de saisie du code de vérification est visible et que la saisie du code de vérification est valide, il vérifie l'e-mail ou le numéro de téléphone de l'utilisateur avec le code de vérification fourni. Si l'une ou l'autre des vérifications réussit, il tente d'enregistrer l'utilisateur, puis applique un jeton de session pour l'authentification. Si la vérification échoue, un message d'erreur s'affiche.
Si la boîte n'est pas visible, elle envoie les codes de vérification à l'e-mail et au téléphone de l'utilisateur, puis met à jour l'interface utilisateur pour permettre à l'utilisateur de terminer l'inscription.
Envoi du code de vérification à l'utilisateur
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() } })
Il vérifie d'abord l'existence de l'email ou du numéro de téléphone saisi.
Selon le bouton cliqué, il envoie un code de vérification par e-mail, SMS ou appel. Ensuite, il étend la saisie du code de vérification pour que l'utilisateur puisse écrire le code reçu.
Si la vérification échoue, un message d'erreur approprié s'affiche. Enfin, l'image de chargement est masquée et les boutons sont réactivés.
Vérification du code de vérification
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() } }
Il vérifie le code fourni en fonction du type de vérification (e-mail ou téléphone). Si la vérification réussit, elle tente de connecter l'utilisateur et d'appliquer le jeton de session pour l'authentification.
Que l'utilisateur se connecte ou s'enregistre, après un processus réussi, il sera redirigé vers la dernière page visitée.
import { authentication } from "wix-members" import wixLocationFrontend from 'wix-location-frontend' authentication.onLogin(() => { wixLocationFrontend.to(wixLocationFrontend.query.redirect) })
Afin de permettre aux utilisateurs de rechercher des produits à partir de n'importe quelle page, j'ai ajouté la barre de recherche dans une lightbox.
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 } );
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!