I am developing an app for BigCommerce, which i have to inject a Script into Order Confirmation page.
In the script, I want to read the current order detail, so i try this
<script>
function getOrderDetail(orderId) {
return fetch("/api/storefront/order/" + orderId, {
credentials: "include",
}).then(function (response) {
return response.json();
});
}
let ORDER_ID=123;
getOrderDetail(ORDER_ID).then(data=>{
// do this ,do that,
})
</script>
I don't find any docs related to get current Order_ID, I have inspected the HTML code and tried
function getOrderId() {
const orderIdRegex = /\s+orderId:\s'(\d+)',/;
return document.body.innerHTML.match(orderIdRegex)[1];
}
I know the code may break if there is a change in UI.
In Shopify, there is a global variable window.Shopify,
I am wondering if there is a better solution, or something similar to Shopify.
Update with correct answer
Thanks #MattCoy
<script>
function getOrderDetail(){
return fetch("/api/storefront/order/{{checkout.order.id}}", {
credentials: "include",
}).then(function (response) {
return response.json();
});
}
getOrderDetail().then(data=>{
// do this ,do that,
})
</script>
If this is a script in the Script Manager, you should have access to all the Stencil theme objects via Handlebars. In this case, try {{checkout.order.id}}.
Related
I want to check if the user is logged in when they visit the route /login and, if so, redirect them to /. The same happens vice versa if they are not logged in as well.
I want to put something like:
export async function load() {
const res = await fetch("[endpoint]", {
headers: {
"Authorization": `Bearer ${localStorage.jwt}`
},
credentials: "include"
});
const json = await res.json();
return {
logged_in: json.logged_in
};
}
in my +page.js (or +page.server.js?) but this doesn't work as it says localStorage is undefined.
How should I go about doing this?
LocaleStorage in Sveltekit is a bit tricky, but there are ways around it, like checking to see if your code is being executed on the client's browser, like so:
import { browser } from '$app/env'
export async function load(){
if (browser) {
// Do stuff here
...
}
...
}
A solution that's worked for me is chucking this code into the <script context="module"> of a base __layout.svelte that every layout inherits from.
For instance, you could have a __layout.svelte that consists of nothing more than this code. Building off of what Stephane pointed out, if you don't want to use cookies (e.g. a jwt token with a very limited lifespan) you could use session storage;
<script context="module">
export async function load({ fetch, session }) {
const res = await fetch("[endpoint]", {
headers: {
"Authorization": `Bearer ${session.jwt}`
},
credentials: "include"
});
const json = await res.json();
return {
logged_in: json.logged_in
};
}
</script>
<slot />
(You can read more about load() here)
And then have other layouts that inherit this layout by having a layout like __layout-auth#default.svelte. You can read more about named layouts here.
I have a strapi backend platform with a Vue front end. I'm trying to display content on the front page, but I'm having an issue.
It's calling in the data no problem and displays it in the console.log when I put one in. However, in the Vue data, the array remains empty so it won't display the data at all. Is there something I'm missing in my script on the page I want it to display? Below is the specific script code.
Again, the return within the try/catch actually shows the data. It's the return in the Vue data that doesn't want to populate
<script>
import Vue from "vue";
export default {
name: "whatsNew",
async beforeRouteEnter(to, from, next) {
try {
var WhatsNew = await Vue.$whatsNewService.findOne(to.params.id);
return next((vm) => {
vm.WhatsNew = WhatsNew;
console.log(WhatsNew.title);
});
} catch (err) {
console.log(err);
next(false);
}
},
data() {
return {
whatsNew: [],
};
},
};
</script>
For this instance, everything was right aside from a major gaffe...capitlization of whatsNew in the return. WhatsNew solved it
Im using nuxt and vuex. In vuex im getting data:
actions: {
get_posts(ctx) {
axios.get("http://vengdef.com/wp-json/wp/v2/posts").then(post => {
let posts = post.data;
if (!posts.length) return;
let medias_list = "";
posts.forEach(md => {
medias_list += md.featured_media + ","
});
medias_list = medias_list.slice(0, -1);
let author_list = "";
posts.forEach(md => {
author_list += md.author + ","
});
author_list = author_list.slice(0, -1);
axios.all([
axios.get("http://vengdef.com/wp-json/wp/v2/media?include=" + medias_list),
axios.get("http://vengdef.com/wp-json/wp/v2/users?include=" + author_list),
axios.get("http://vengdef.com/wp-json/wp/v2/categories"),
]).then(axios.spread((medias, authors, categories) => {
ctx.commit("set_postlist", {medias, authors, categories} );
})).catch((err) => {
console.log(err)
});
})
}
},
In vuex state i have dynamic postlist from exaple below.
How i can use it in Nuxt?
In nuxt i know async fetch and asyncData.
async fetch () {
this.$store.dispatch("posts/get_posts");
}
Thats not working.
How i can say to nuxt, wait loading page, before vuex actions loading all data?
As you already mentioned there are:
fetch hook
asyncData
And differences are well described here
The reason why your code is not working might be in your store action.
It should return a promise, try to add return before axios get method ->
get_posts(ctx) {
return axios.get(...
// ...
And then, on your page:
async fetch () {
await this.$store.dispatch("posts/get_posts");
}
Also, in comment above you're saying that you dont want to commit data in store:
...load page only after vuex, i dont need to pass data in vuex
But you do it with this line:
ctx.commit("set_postlist", {medias, authors, categories} );
if you dont want to keep data in store, just replace line above with:
return Promise.resolve({ medias, authors, categories })
and get it on your page:
async fetch () {
this.posts = await this.$store.dispatch("posts/get_posts");
// now you can use posts in template
}
Misread the actual question, hence the update
With Nuxt, you can either use asyncData(), the syntax will change a bit tho and the render will be totally blocked until all the calls are done.
Or use a combo of fetch() and some skeletons to make a smooth transition (aka not blocking the render), or a loader with the $fetchState.pending helper.
More info can be found here: https://nuxtjs.org/docs/2.x/features/data-fetching#the-fetch-hook
Older (irrelevant) answer
If you want to pass a param to your Vuex action, you can call it like this
async fetch () {
await this.$store.dispatch('posts/get_posts', variableHere)
}
In Vuex, access it like
get_posts(ctx, variableHere) {
That you can then use down below.
PS: try to use async/await everywhere.
PS2: also, you can destructure the context directly with something like this
get_posts({ commit }, variableHere) {
...
commit('set_postlist', {medias, authors, categories})
}
I am trying to fetch products by 'SKU', which is only possible using Admin API. I need to inject a JavaScript code snippet into theme.liquid file. Can I achieve this via JavaScript only? So far my code looks something like this:
<script>
const query = `{
productVariants(first: 1, query: "sku:<SKU>") {
edges {
node {
id
price
product {
title
description
featuredImage {
id
originalSrc
}
}
}
}
}
}`;
const STOREFRONT_ACCESS_TOKEN = 'xxxxxxxxxx';
const GRAPHQL_URL = 'https://<my-store>.myshopify.com/admin/api/2021-01/graphql.json';
const GRAPHQL_BODY = {
'method': 'POST',
'headers': {
'X-Shopify-Storefront-Access-Token': STOREFRONT_ACCESS_TOKEN,
'Content-Type': 'application/json',
},
'body': JSON.stringify({ query })
}
fetch(GRAPHQL_URL, GRAPHQL_BODY)
.then(res => res.json())
.then(data => {
console.log(data);
})
.catch((error) => {
console.log(error);
});
</script>
I am not very well familiar with Shopify and Shopify's APIs(Storefront, Admin). I tried every possible way but reached dead end. I would really appreciate if someone can redirect me to right resources. Thank you!
Your code looks loosely like the code from the docs here: https://shopify.dev/tutorials/authenticate-with-oauth
Two issues, really:
in this line:
'X-Shopify-Storefront-Access-Token': STOREFRONT_ACCESS_TOKEN,
you need be using a token which you get after you request it from
https://{shop}.myshopify.com/admin/oauth/access_token
the bigger issue, though, is:
to do so only through the theme code, you would ultimately have to expose your secret keys via the front end code, which is going to be a security risk. The technically correct way to use the Admin API would either be to set up a server that runs an embedded app and store those keys in a .env file there.
I've seen this elsewhere in other questions, but haven't seen a solution. I'm trying to make a simple GDPR cookie notification that closes on click, using a button. I'm in Universal mode, meaning mounted() isn't available, so I'm trying to set cookies through Vuex. However, the click event I have bound to the button in my component isn't firing.
Edit: After building a codesandbox version of my app, which worked as it should, I went through and hacked up my Nuxt app until I found what was causing the problem. As it turns out, it was my middleware, and more specifically, the fact that I was using the fs-extra library to read JSON files. Still not clear on why this is happening, so any suggestions are welcome. The code below includes my middleware.
components/CookieNotice.vue
<template>
<div v-if="cookie != true" class="cookie_notice_wrap">
<div class="cookie_notice">
<p class="notice_message">This site uses cookies for analytics purposes.</p>
<button #click.prevent="dismissNotification" class="notice_dismiss">Close</button>
</div></div>
</template>
<script>
import { mapGetters } from "vuex";
export default {
name: "CookieNotice",
methods: {
dismissNotification: function(e) {
console.log("we clicked?");
document.querySelector(".cookie_notice_wrap").classList.add("hidden_click");
this.store.dispatch("cookieStateChange", true);
}
},
computed: {
...mapGetters(["cookie"]),
}
}
</script>
Actions from store/index.js
export const actions = {
async getPosts({ state, commit, dispatch }) {
if (state.posts.length) {
return
}
try {
await axios.get("/api/json-access");
}
catch (err) {
console.log(err);
}
},
nuxtServerInit({ state, commit, dispatch }, { req }) {
dispatch("getPosts");
const seen = this.$cookies.get("cookie_notice_seen");
if (!seen) {
dispatch("cookieStateChange", false);
}
},
cookieStateChange({state, commit, dispatch}, bool) {
// this does set the cookie correctly, unsure if it will work the same when bound to the button click
commit("updateCookie", bool);
this.$cookies.set("cookie_notice_seen", bool, {
path: "/",
maxAge: 60 * 60 * 24 * 7
});
}
}
~/middleware/api/json-access.js:
const fse = require('fs-extra');
import axios from 'axios';
const storeLocation = "middleware/full_site.json";
export default async function({ store, route, redirect }) {
const exists = await fse.pathExists(storeLocation);
let posts;
if (!exists) {
await fse.ensureFile(storeLocation);
posts = await postsFromWP();
fse.writeJSON(storeLocation, posts);
}
else {
try {
posts = await fse.readJSON(storeLocation);
}
catch (err) {
console.log(err);
}
}
store.commit("updatePosts", posts);
}
async function postsFromWP() {
const url = ".../example/json/file.json";
const config = { headers: { "Accept": "application/json" }};
let posts = await axios.get(url, config);
posts = posts.data
.filter(el => el.status === "publish")
.map(({ id, slug, title, excerpt, date, tags, content }) => ({
id, slug, title, excerpt, date, tags, content
}));
return posts;
}
I had the middleware configured in nuxt.config.js via routes -> middleware before, but currently have it set to go through serverMiddleware instead, for testing. I also added the action that triggers getting the posts, in case that's also part of it. This has definitely hit on a limit of my Nuxt/Vue understanding - I have no idea why this could be happening, so any wisdom is much appreciated.
If you wind up dealing with something similar, fs or fs-extra are your culprits. You can't use file operations on the client side, which is when these middleware actions are happening (I think). The cookie notice only fully worked when I removed the fs-extra import at the very top of the middleware file.