I have an SPA in vanilla JS, using classes and modules.
The main idea is creating visits of customers and render them. When I fill in the form, data are sent to the server in JSON, after successful fetch, a visit card is created in the #content section.
The rendered card has two options: edit and delete. I made deletion without problems, I send DELETE, then just remove() the element onclick.
But I have some difficulties when editing the card.
I wrote the code to pop up modal form when click on the Edit button, and this form is filled with the card's data, so that the user can change them, click on Submit and send PUT to the server. The response is successful.
This is the edit form submit
edit(id) {
const readData = document.querySelector('.form-edit');
readData.addEventListener('submit', (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const data = Array.from(formData.entries()).reduce((memo, pair) => ({
...memo,
[pair[0]]: pair[1],
}), {});
editCard(data, id)
.then((response) => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong');
}
})
document.querySelector(".closeBtnEdit").click();
});
}
What I want, is to change the info of existing card in DOM after submitting the edited data.
This is the code of card rendering:
render(parent){
this.elem.fullName.textContent = this.fullName;
this.elem.purpose.textContent = `Purpose of the visit: ${this.purpose}`;
this.elem.desc.textContent = `Description: ${this.desc}`;
this.elem.priority.textContent = `Priority: ${this.priority}`;
this.elem.date.textContent = `Visit Date: ${this.date}`;
this.elem.delBtn.textContent = `Delete`;
this.elem.editBtn.textContent = `Edit`;
}
Edit card API:
function editCard(newCard, cardId) {
return fetch(`${API}/${cardId}`,{
method: "PUT",
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newCard)
})
}
Related
I want to upgrade my simple Stripe one-page checkout to use the new Payment Element that unifies a lot of different payment methods under one component. By simple I mean, the customer chooses between a few variants of one product, provides needed info and submits the order. Collect money, send emails, fulfil the order etc. Just vanilla HTML/CSS/JS and a bit of PHP. Using Payment Intents API to process the payments, was on Charges API before.
I love the premise of this unified element so I decided to give it a go. It turns out I have trouble understanding what to do with both stripe.confirmPayment method and return_url parameter.
I guess the return_url should be my checkout page? Also, is there a way to redirect without hard refresh? Ideally, I would be able to do some server-side stuff before redirect happens, but it seems that stripe.confirmPayment automatically redirects if resolved successfully.
Here is my code. I am a designer btw, so guess I am missing something obvious as always.
// init Stripe elements
fetch('/config.php', {
method: 'get',
headers: {
'Content-Type': 'application/json'
}
})
.then((response) => {
return response.json();
})
.then((response) => {
return setupElements(response.publishableKey)
})
var setupElements = function (publishableKey) {
stripe = Stripe(publishableKey);
// create payment intent to setup payment element
fetch('/setup-elements.php', {
method: 'POST',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(order)
})
.then(function (response) {
return response.json()
})
.then(function (data) {
const appearance = {
theme: 'none',
labels: 'floating',
// etc.....
};
elements = stripe.elements({
clientSecret: data.clientSecret,
fonts: [{
cssSrc: 'https://use.typekit.net/hly2qug.css'
}, ],
appearance
});
const paymentElement = elements.create("payment", {
fields: {
billingDetails: {
email: 'never',
address: {
line1: 'never',
city: 'never',
state: 'never',
country: 'never',
postalCode: 'never'
}
}
}
});
paymentElement.mount("#payment-element");
})
}
form.addEventListener('submit', function (e) {
e.preventDefault();
var isFormValid = validate.validateAll(form);
if (isFormValid.length < 1) {
loading(true);
collectFormInfo();
confirmPayment();
}
})
var confirmPayment = function () {
stripe.confirmPayment({
elements,
confirmParams: {
return_url: 'checkout-page?',
payment_method_data: {
billing_details: {
email: order.customer.email,
address: {
line1: order.delivery.address,
city: order.delivery.city,
state: order.delivery.state,
country: order.delivery.country,
postal_code: order.delivery.postcode
}
}
}
}
})
.then(function (result) {
// This is where I get stuck. How to do stuff after
// payment is confirmed
// and not get redirected immediately? If
//redirected, where to and is it
// possible to do so asynchronously?
if (result.error.type === "card_error" || result.error.type === "validation_error") {
showMessage(result.error.message);
} else {
// get client secret
const clientSecret = new URLSearchParams(window.location.search).get(
"payment_intent_client_secret"
);
// bail if no client secret
if (!clientSecret) {
return;
} else {
stripe.retrievePaymentIntent(clientSecret).then(function (response) {
switch (response.paymentIntent.status) {
case "succeeded":
showMessage("Payment succeeded!");
break;
case "processing":
showMessage("Your payment is processing.");
break;
case "requires_payment_method":
showMessage("Payment failed. Please try another payment method.");
break;
default:
showMessage("Something went wrong.");
break;
}
});
}
}
})
}
Nudge in the right direction is all I need, at least I hope so
Yes the return_url should be your own page that Stripe will automatically redirect after your customer completed the Payment: Stripe Doc. 'checkout-page?' doesn't look like a valid URL. Normally you would want something like 'http://localhost:4242/success'
This action is done automatically on client and you can't intercept it. Any action you want to perform on server should be handled via webhook, at Step 6 "Handle post-payment events" at the same article above.
In a React project, I have pay() method. A wallet balance is shown with certain coins. When pay() is clicked data is updated in purchase data. Coins data is stored in sessionStorage, but, after refresh of page data is missing.
Payment method
const onPayment = async (coins, _id) => {
try {
await fetch(`${config.baseUrl}customers/purchaseproduct?content_id=${_id}&coins=${coins}&v=1.0`, {
method:'POST',
headers: {
'Content-Type': 'application/json',
'ApiKey': config.apiKey,
'Authorization':sessionStorage.getItem('tokenNew'),
'platform':'web'
},
}).then((data) => data.json()).then((data2) => {
const balanceUpdated = data2.data.purchase.coins_after_txn
console.log('new balance', balanceUpdated) //new balance: 49990
{/* Here coins data is updated only on click of pay() method later on page refresh sessionStorage
value is empty */}
sessionStorage.setItem('walletData', balanceUpdated)
})
}
catch({error}) {
toast.error(error)
}
}
As you can see 'coins' are the price of product whereas '_id' is the id of specific product in onPayment method. walletData is updated only on payment and when refreshed the page, data is empty.
Take an example, A product price is $90 when clicked on pay() method $90 is cut from wallet 'balanceUpdated' and then passed on to sessionStorage in 'walletData' which is shown at that instance i.e 4900 but when page is refreshed 'walletData' is empty.
How to store the new updated value in sessionStorage and will remain it even after refresh?
LoginNow file
const onSubmit = async (data) => {
try {
let newData = await fetch('customers/auth/login', {
method:'POST',
headers: {
'Content-Type': 'application/json',
'ApiKey': config.apiKey,
'Platform': 'web',
},
body: JSON.stringify(data)
});
newData = await newData.json();
if(newData.error == true) {
toast.error(newData.error_messages[0])
} else {
const tokenData = newData.data.token
const walletData = newData.data.coinsxp.coins
sessionStorage.setItem('tokenNew', tokenData);
sessionStorage.setItem('walletData', walletData);
}
}
catch({error}) {
toast.error(error)
}
}
The data is probably there in the sessionStorage, you just have to retrieve it and write it in memory, on startup.
Probably you want something like this (or the other way around, depending on which value you want to have precedence):
const walletData = newData.data.coinsxp.coins || sessionStorage.getItem('walletData');
Putting data in sessionstorage is not equivalent to making it persistent. Putting data in sessionStorage means that it will just stay in session storage, it doesn't mean that your app data will be updated automatically based on it. This is why every time you call setItem, you should also call getItem - otherwise you are just stashing stuff somewhere, without accessing it.
So right now I have a homepage, made by using html.
I want to add some divs, where I show the newest blogs I posted on my WIX page.
<div layout="row" layout-align="center center">
<md-card flex="60" class="pad-md md-body-1 border-1" md-colors="{"borderColor": "epprimary1-500", "color": "epsecondary6"}">
{{blog headline}}
Open Blog<md-icon>open_in_new</md-icon>
</md-card>
</div>
On the Wix platform, I know where they store the data in a so called dataset:
Now I need to know how to access these data from my other website.
I figured it out, finally!!
You can get the data you need via an http request.
Therefore, first of all, you need to add a javascript in your backend folder in Wix and name it "http-functions.js", delete it's content and add the folowing code.
Note: get_blogEntry() is method_functionName()
Blog/Posts is the DB I used, you can use any DB you have on wix.
import {ok, notFound, serverError} from 'wix-http-functions';
import wixData from 'wix-data';
export function get_blogEntry() {
let options = {
"headers": {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
}
};
// query a collection to find matching items
return wixData.query("Blog/Posts")
.find()
.then( (results) => {
// matching items were found
if(results.items.length > 0) {
let itemOne = results.items[0];
let itemTwo = results.items[1];
options.body = {
"blogOneTitle": itemOne.title,
"blogOneUrl": "https://etaplus.energy" + itemOne.postPageUrl,
"blogTwoTitle": itemTwo.title,
"blogTwoUrl": "https://etaplus.energy" + itemTwo.postPageUrl
}
return ok(options);
}
})
// something went wrong
.catch( (error) => {
options.body = {
"error": error
};
return serverError(options);
} );
}
After you added this code in your backend, then you can access the data via the following URL:
"https://YOURWEBSITEURL/_functions/blogEntryor whatever your function name is"
I am updating form data using api. So I created a form component that renders the data into the form. I have created a "device_detail" component. In this component I have added a "update" button which links to update_device_detail component. In my update_device_detail component I have a method handleUpdate:
handleUpdate(event) {
event.preventDefault()
const ied = this.props.match.params.id
if (this.validateMainForm()) {
let elements = this.state.element
let items = this.state.type_items
const data = {
id: items['id'],
name: items['name']
}
console.log('--------final-data before posting-------', data);
axios({
url: 'http://127.0.0.1:8000/api/foo/'+ied+'/update',
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
data: JSON.stringify(data)
})
.then(function(response) {
return response
})
alert('Device Updated Succesfully!!!')
this.setState({redirect: true})
}
}
I have set initial state of redirect: false .
In render() method I have made a condition statement:
if (this.state.redirect) {
return <Redirect to={`/device/${this.state.items.id}`} />
}
else {
return(
...)
}
Redirect is taking me to right page, but the updated data is not reflected on detail page. But when I press refresh button manually It gets reflected. Is there a way I can make to force refresh the page on which it is redirecting or is there any other way to achieve the same.
Asking for your help. I am beginner with Angular + RxJS, please don't blame me if this is easy task.
Idea is to submit form in which are many input fields and one of those is image upload.
When user click on submit button, first it needs to call POST /attachments service with added file to get it's token. When this service returns attachment's token, then need to use it in final service call where I am sending all form data.
Special case is, if user submit form, first service response with attachment's token and second one fails, then when user click one more time on submit button, shouldn't call /attachments service again, but just use previously got attachment's token and call form's POST service.
Is it possible with using some of RxJS operators or other features?
I know I can get it working with some ugly logic all around in my app, but I want to make it also beautiful too.
There is my first version of code for submit function.
public submitForm(finalData) {
const { attachment, ...data } = finalData;
return this.http
// at first get attachment's token
.post('/attachments', attachment)
.pipe(
switchMap((attachmentToken) => {
const formData = {
data,
attachment: attachmentToken
};
// submit form data
return this.http.post('/submitformdata', formData)
}),
);
}
You should store the attachment token and request based on it :
attachmentToken: string;
public submitForm(finalData) {
const { attachment, ...data } = finalData;
return !this.attachmentToken ? this.attachmentCall(attachment, data) : this.formDataCall(finalData);
}
attachementCall(attachment, data) {
this.http
// at first get attachment's token
.post('/attachments', attachment)
.pipe(
switchMap((attachmentToken) => {
const formData = {
data,
attachment: attachmentToken
};
this.attachmentToken = attachmentToken;
// submit form data
return this.formDataCall(formData);
}),
);
}
formDataCall() {
return this.http.post('/submitformdata', formData);
}