Is there any way to set customer object in shopify themes when user logs in? - shopify

In my Shopify theme, I'm creating a login form where when a user logs in, the customer object should be populated and it should know that the specific user is logged in so that I can use the customer object's properties anywhere in my project.
I want that following customer becomes true:
{%- if customer -%}
What I've done is used email to log inside account, first it check if email present then log inside, then it uses admin api to store the customer object inside another object. But I want that instead my customer object that is present in liquid should be updated that this user is logged inside.
<div id="login-container">
<form id="login-form">
<div>
<label for="email">Email:</label>
<input type="email" id="email" required>
</div>
<button type="submit" id="signInBtn">Login</button>
</form>
</div>
const email = localStorage.getItem("email");
const loginContainer = document.getElementById("login-container");
// form functionality
const form = document.getElementById("login-form");
form.addEventListener("submit", (e) => {
e.preventDefault();
var customerEmail = document.getElementById("email").value;
fetch('/admin/customers/search.json?email=' + customerEmail)
.then(function(response) {
return response.json();
})
.then(function(data) {
if (data.customers.length > 0) {
var customer = data.customers[0];
localStorage.setItem('customer', JSON.stringify(customer));
} else {
alert("User not found");
}
})
.catch(function(error) {
console.error('An error occurred:', error);
});
});

Related

Computed Property + Show/Hide DIV

I am not a vue.JS programmer, but have been asked to jump in and make a few changes to an existing app. I am trying to use a computed property to show/hide a DIV.
The problem is the computed property is not being called after the form POST (I put a console.log statement inside the computed method to verify it's not even being called). The findLoginProvider method is invoked successfully and the localStorage items are set... but the DIV is not hidden.
Like I said, I am not a vue.JS programmer and cannot figure out why this isn't working... this is a simplified example of the real page. I really want computed properties to work because I have multiple DIV's to show/hide based on a few computed properties (so manually settings the visibility of a specific DIV is not desired)
HTML:
<div v-if="showFindLoginProvider" :class="{'disabled': isLoading}">
<form #submit.prevent="findLoginProvider" method="POST">
<div>
<label class="block text-gray-700">Email Address</label>
<input
type="email"
name="email"
v-model="email"
placeholder="Enter Email Address"
autofocus
autocomplete
required
/>
</div>
<button type="submit">Continue</button>
</form>
</div>
Methods:
findLoginProvider() {
this.isLoading = true;
UserService
.getLoginProvider(this.email)
.then((response) => {
if (response?.status === 200) {
localStorage.setItem("login_email", this.email);
localStorage.setItem("login_provider", JSON.stringify(response.data));
} else {
this.isError = "Error retrieving login provider";
}});
this.isLoading = false;
},
Computed:
showFindLoginProvider() {
console.log("showFindLoginProvider")
return !this.isLoggedIn && (!this.hasLoginEmail || !this.hasLoginProvider);
},
According to the docs
A computed property will only re-evaluate when some of its reactive dependencies have changed
By saying that in your fnc findLoginProvider you need to change reactive variable to fire showFindLoginProvider run
findLoginProvider() {
this.isLoading = true;
UserService
.getLoginProvider(this.email)
.then((response) => {
if (response?.status === 200) {
// will tell computed to run
this.isLoggedIn = true
// rest of your code
} else {
this.isError = "Error retrieving login provider";
}
});
this.isLoading = false;
},

How do I dynamically render an array from an api call in Vue?

I'm trying to make an autocomplete dropdown menu in vue and can't get the api response to render on the page. I'm making an api call on every keystroke in the input. You can see in the handleOnChange method that I'm trying to set the response to the results variable that is binding to the list above.
When I console log the results right after I make the api call AND set it to the data binding variable it logs as if everything is working fine. However, it does not render the actual data on the screen.
Here is my code
<template>
<div>
<input type="text" value="" v-model="address" placeholder="Start typing an address..." #input="methods.handleOnChange(address)"/>
<ul v-if="results.length !== 0">
<li v-for="result in results">
{{ result.streetLine || ""}}
</li>
</ul>
<p v-model="results">
{{results}}
</p>
</div>
</template>
<script>
const SmartyStreetsSDK = require("smartystreets-javascript-sdk");
const SmartyStreetsCore = SmartyStreetsSDK.core;
const Lookup = SmartyStreetsSDK.usAutocompletePro.Lookup;
const credentials = new SmartyStreetsCore.SharedCredentials([website-key]);
const clientBuilder = new SmartyStreetsCore.ClientBuilder(credentials).withLicenses(["us-autocomplete-pro-cloud"]).withBaseUrl("https://us-autocomplete-pro.api.smartystreets.me/lookup");
const client = clientBuilder.buildUsAutocompleteProClient();
export default {
name: 'Autocomplete',
data () {
return {
address: "",
results: [{streetLine: "testing"}],
methods: {
handleOnChange: function(address) {
//TODO: need to be able to access "results" from in here
console.log("this: ", this);
if (address) {
const lookup = new Lookup(address);
client.send(lookup).then((response) => {
console.log(response.result);
this.results = response.result;
console.log("databinding: ", this.results);
}).catch(console.log)
}
}
}
}
}
}
</script>
Vue.set()
As discussed in the comments, Vue.set was able to do it.
See documentation: https://v2.vuejs.org/v2/api/#Vue-set
Arguments are:
{Object | Array} target
{string | number} propertyName/index
{any} value
It replaces the value at target[propertyName/index] with value and forces reactivity on the value(s).
In your case it should be this instead of this.results = response.result;:
Vue.set(this, "results", response.result);

Login form briefly reappears when user logs in -- what is causing this?

I have a login screen that briefly flashes after the user logs in. This doesn't happen all the time, but it's annoying. I am having trouble figuring out what is causing this and so I thought I'd ask the great people of stackoverflow to see if they have any tips on how to fix or troubleshoot. Thanks!
Here's my issue (as shown in screenshots with some code below):
User logs in:
User sees spinner as his credentials are authenticated:
User sees login screen flash briefly again before router redirects him to the requested content.
Here is code for the Login.vue page:
<template>
<div class="col-lg-6">
<template v-if="isLoading">
<spinner key="spinner"></spinner>
</template>
<template v-else>
<div key="form">
<h1>Login</h1>
<aside class="alert alert-danger" v-if="error">
{{ error }}
</aside>
<form #submit.prevent="handlerLogin">
<div class="form-group">
<label for="exampleInputEmail1">Email address</label>
<input type="email" class="form-control" id="exampleInputEmail1" v-model="formData.email" />
</div>
<div class="form-group">
<label for="exampleInputPassword1">Password</label>
<input type="password" class="form-control" id="exampleInputPassword1" v-model="formData.password" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</template>
</div>
</template>
<script>
export default {
name: 'Login',
data() {
return {
isLoading: false,
formData: {
email: null,
password: null
}
}
},
computed: {
error() {
return this.$store.state.error
}
},
methods: {
async handlerLogin() {
this.isLoading = true
try {
const payload = {
email: this.formData.email,
password: this.formData.password
}
await this.$store.dispatch('logInUser', payload)
console.log('ready to fetch user profile')
await this.$store.dispatch('fetchUserProfile')
this.$router.replace('photos')
} catch (error) {
console.log(error)
} finally {
this.isLoading = false
}
}
}
}
</script>
And here is the logInUser action code from Vuex store:
async logInUser({ commit }, payload) {
commit('CLEAR_ERROR')
try {
const user = await auth.signInWithEmailAndPassword(payload.email, payload.password)
commit('SET_CURRENT_USER', user.user)
} catch (error) {
commit('SET_ERROR', error)
}
}
I think the mistake you are making is that you expect this.$router.replace to be blocking, which it is not. (docs) As such, the this.isLoading = false from finally is called immediately after. Sometimes Vue manages to re-render your component before the router finishes transitioning to the new view, and sometimes it does not.
You can create a third state that simply checks if the user is logged in and displays an appropriate message. Keep in mind that if the user gets on the log-in page when logged in, this needs to do something sensible as well. An other option is to move this.isLoading = false to the catch, but keep in mind that if navigation fails, for example due to a (global) route guard, your component is loading eternally without clear feedback what happened. A third option would be to make this.$router.replace blocking by wrapping it in a Promise or something:
await new Promise((resolve, reject) => {
this.$router.replace('photos', resolve, reject)
})

not able to add user input into a rest api using store

This is my mainpage where I have a form which I want to integrate with an API so that I can save my data there:
<div>
<span>userId</span> <input type="text" v-model="info.userId">
</div>
<br>
<div>
<span>id</span> <input type="text" v-model="info.id">
</div>
<br>
<div>
<span>title</span> <input type="text" v-model="info.title">
</div>
<br>
<div>
<span>body</span> <input type="text" v-model="info.body" >
</div>
<br>
<input type="submit" #click="addtoAPI">
This is mainpage.js code where i have declared the the object named "info" which will hold all the fileds of my form and there is also the "addtoAPI" method which basically access the store's action
data(){
return{
info:{
userId:'',
id:'',
title:'',
body:''
}
}
},
methods:{
addtoAPI(){
this.$store.dispatch('addtoapi',this.info)
}
This is my store.js code where I have added an action named addtoapi which basically stores data in respective fields
actions: {
addtoapi :({commit},info) =>{
let newuser={
userId:this.info.userId,
id:this.info.id,
title:this.info.title,
body:this.info.body
}
console.log(newuser);
axios.post('https://jsonplaceholder.typicode.com/posts/',newuser)
.then((response) =>{
console.log(response);
})
.catch((error) => {
console.log(error);
})
}
}
Now when I am running this I am getting this error please help me with this because I have already added userId.
store.js?adc6:50 Uncaught TypeError: Cannot read property 'userId' of undefined
at Store.addtoapi (store.js?adc6:50)
at Array.wrappedActionHandler (vuex.esm.js?358c:704)
at Store.dispatch (vuex.esm.js?358c:426)
at Store.boundDispatch [as dispatch] (vuex.esm.js?358c:332)
at VueComponent.addtoAPI (Mainpage.js?4af6:45)
at invoker (vue.esm.js?efeb:2027)
at HTMLInputElement.fn._withTask.fn._withTask (vue.esm.js?efeb:1826)
In your store's actions you've made a mistake, you're trying to access to property info of this (that's why it throw an error with undefined) :
let newuser= {
userId:this.info.userId,
id:this.info.id,
title:this.info.title,
body:this.info.body
}
Need to be replaced by this:
let newuser = {
userId: info.userId,
id: info.id,
title: info.title,
body: info.body
}

worklight j_security_check not found

I'm using Worklight Studio Plugin 6.0.
I am trying to get FormBasedAuthentication working. When I run and deploy my worklight project, the app login page is presented successfully. However when I click on the login button, an error is thrown on the server console:
[ERROR ] FWLSE0048E: Unhandled exception caught: SRVE0190E: File not found: /apps/services/j_security_check [project DojoTest]
SRVE0190E: File not found: /apps/services/j_security_check
This directory doesn't exist in the project. I've tried creating another project but it doesn't add the missing folder.
Any advise is appreciated. Thank you in advance.
<div id=BorderDiv>
<div class=imageDiv id="imageDiv">
<center style="color:#66FF66">
Test
</center>
</div>
<fieldset id="loginFieldSet">
<legend>Login:</legend>
<div data-dojo-type="dojox/mobile/FormLayout"
data-dojo-props="columns:'auto'">
<div>
<label>User name*: </label> <input id="username" type=text
data-dojo-type="dojox.mobile.TextBox" size="50"
placeholder="Enter Username" name="username" required></input>
</div>
<div>
<label>Password*: </label> <input id="password" type=password
name="pass" placeholder="Enter Password" size="50"
data-dojo-type="dojox.mobile.TextBox" required> </input>
</div>
</div>
<div>
<center>
<input type="button" class="formButton" id="AuthSubmitButton" value="Login" /> <input type="button" class="formButton" id="AuthCancelButton" value="Cancel" />
</center>
</div>
<!-- <button data-dojo-type="dojox.mobile.Button" onclick="login()">Login</button>-->
</fieldset>
</div>
//Create the challenge object
var challengeHandler = WL.Client.createChallengeHandler("SampleAppRealm");
/*
* Read the response of the challenge. The default login form
* that the server returns contains a j_security_check string.
* If the challenge handler detects it in the response, return true
*
*/
challengeHandler.isCustomResponse = function(response) {
if (!response || response.responseText === null) {
return false;
}
var indicatorIdx = response.responseText.search('j_security_check');
if (indicatorIdx >= 0) {
return true;
}
return false;
};
//Hanlde the Challenege. In our case, we do nothing!
challengeHandler.handleChallenge = function(response) {
//do nothing
};
//Bind the login button to collect the username and the password
$('#AuthSubmitButton').bind('click', function () {
var reqURL = 'j_security_check';
var options = {};
options.parameters = {
j_username : $('#username').val(),
j_password : $('#password').val()
};
options.headers = {};
challengeHandler.submitLoginForm(reqURL, options, challengeHandler.submitLoginFormCallback);
});
$('#AuthCancelButton').bind('click', function () {
alert("Cancel Clicked");
sampleAppRealmChallengeHandler.submitFailure();
});
challengeHandler.submitLoginFormCallback = function(response) {
var isLoginFormResponse = challengeHandler.isCustomResponse(response);
if (isLoginFormResponse){
challengeHandler.handleChallenge(response);
} else {
login();
$('#password').val('');
$('#username').val('');
challengeHandler.submitSuccess();
}
};
function login(){
require([ "dojo/dom", "dijit/registry" ], function(dom, registry) {
var username = dom.byId("username");
var password = dom.byId("password");
alert("username= " + username.value + " AND password = "
+ password.value);
try {
registry.byId("mainMenuView").performTransition("myAcctView", 1,
"slide");
WL.Logger.debug("Moved to My Account view");
} catch (e) {
WL.Logger.debug("Error Caught: " + e);
}
});
}
In form-based authentication it is expected from the server to send a login form in response to a connect attempt (you are not required to display the HTML sent by the server, it's just the response that matters mostly).
Basically, if your app's first screen is the login form and you click some login button and this button does a login attempt, it will first the first time, because only in the first time will the server get a request from the app and the response to that request would be the challenge - the login form.
So you need to make sure that you first connect to the server using WL.Client.connect and only then allow the user to do any login attempts (can be a login button). This is the usual scenario why the above error is given.
Note also that this is not a resource that exists in your Worklight project; it's a resource that exists on the server. This is why you cannot find it.
Please review the authentication concepts and form-based tutorial (and its sample) user documentation: http://www-01.ibm.com/support/knowledgecenter/SSZH4A_6.0.0/com.ibm.worklight.getstart.doc/start/c_gettingstarted.html?cp=SSNJXP