Shopping Cart item list across frontend and backend - javascript

I'm working on an E-Commerce store using Node.JS, Stripe and HTML. I have the frontend JS file in which users add/remove/change the quantity of cart items which also affects a list with all the cart items to access later (Price SKUs and Quantity). A typical cart list would look like this:
["price_1LWgytARYjIsWfAV0lZI6mgW", "1", "price_1LWgytARYjIsWfAV0lZI6PXv", "3"]
To get the checkout in stripe, you need to provide Node.JS with the line items of the Price SKUs and Quantities. I am trying to access this cart items list in the backend. I have tried things such as local storage but it is undefined and null because it isn't running on the webpage.
Can anyone help me to access this list in the backend server? Thank you

Local storage is a feature that lets you store information client-side in the browser. An example is storing someone's preferred locale or timezone if you don't want a cookie/session server-side. So it's expected that your server-side code in Node.js will not have access to those values.
What you need to do instead is make a request to your server that will contain all the line items they have in their cart. In Javascript, this is usually done in two ways
You have your own form in HTML and you pass all the information in the form and submit it which redirects the whole page.
You write code using the Fetch API so that you can send your line items (usually as JSON) to your server and have it reply asynchronously.
In your case, the second option is usually best. You'll have a button that someone can click on when they are ready to pay. At that point, the code will take all your line_items and send them as a JSON array/hash to your server-side code.
It's important to note that the format of your line items right now doesn't really work well because you have an array alternating a Price id price_123 and then the quantity, and then another Price id, etc. making editing quite hard. Usually, you'd want to use an array of objects instead, which would be quite similar to what you would send to the Create Checkout Session API's line_items parameter. What you want to send should look more like this:
var cart = {
line_items: [
{
price: "price_ABC",
quantity: 1
},
{
price: "price_123",
quantity: 7
},
{
price: "price_XYZ",
quantity: 2
}
]
};
This format makes it a lot easier because you have a hash/object that is your cart. It has a line_items property that is an array array of line items. It contains 3 elements, and the first element's price is price_ABC and its quantity is 1 which will be a lot easier to parse and modify in Javascript both client-side and server-side.
Here's a basic example of how to send your cart variable/content to your server with fetch():
fetch(
"/checkout_session_creation",
{
method: "POST",
body: JSON.stringify(cart)
})
.then(function(response) {
return response.json();
})
.then(function(data) {
console.log("Got the response: ", data);
});
This will post to /checkout_session_creation though you have to put the route you are expecting there. It will sent the cart variable/content in the POST body as JSON. Then it expects a response back in JSON that you can parse.
The idea here is that after creating the Checkout Session in Node server-side, you will get the url property that you then need to return to your client. You then need to redirect client-side to that URL.
With all of that said, I'd highly recommend going through Stripe's official Checkout Quickstart end to end as they walk you through most of this.

Related

Redux - Remove object from store on http response error

Consider the following flow:
I have a page with a list of "products" and a modal to create a single "product". I open the modal, fill the form and submit the form.
At this point, I dispatch an action CREATING_PRODUCT, add the product to the store and send the http request to the server.
I close the modal and display the list of results with the new product.
Let's suppose I receive an error response from the server.
Desired behavior:
I would like to display an error, remove the project from the list, re-open the modal and display the form already filled.
Question
How can I find that project and remove it the list? I don't have an id (or a combination of unique properties) to find that project in the store. I don't see a clean way to link a request/response to that "product" object in the store.
Possible solution
The client adds a "requestId" into the project before adding it to the store. On response error, I dispatch a generic "CREATE_ERROR" and I remove the project with that requestId from the store.
Extra
Same problem with edit and delete. For example during a delete should I keep a reference to the deleted project with the requestId in the store, until the http request is successful?
I bet it is a problem with a common solution, but I can't find examples.
Thanks!
In general, your Redux store should be modeled somewhat like a relational database, in that every time you have a list of data models, each element of the list should have its own identifier. This helps a lot when dealing with more complex data schemes.
You should probably store your projects as an object, something like:
{
// ...other store properties
projects: {
"_0": { // ... project properties }
"_1": { // ... project properties }
// ...more projects...
},
}
This way, whenever you need to mess with an existing project, you can just reference its id and use projects[id] to access that project. This would also solve the edit and delete cases, as you could just pass the IDs around as handles.
I like this short piece on why your Redux store should be mostly flat and why data should always have identifiers very much. It also talks about using selectors to "hide" your IDs away, which may or may not be useful for you.
In your case, as you are getting IDs from a server, you could have an ID prefix which indicates unsaved values. So your projects object would become something like:
projects: {
"_0": { // ... }
"_1": { // ... }
"UNSAVED_2": { // ... }
}
This way, you could easily identify unsaved values and handle them when an error occurs, still get the benefits of generating temp IDs on the client-side in order to revert changes on error, and also warn your user if they try to leave your app while their data still hasn't been synchronized - just check if there are any "UNSAVED" IDs :)
When you get a response from the server, you could change the "UNSAVED_suffix" ID to an actual ID.

How to pass data between Django module/app functions without using database in asynchronous web service

I've got a web service under development that uses Django and Django Channels to send data across websockets to a remote application. The arrangement is asynchronous and I pass information between the 2 by sending JSON formatted commands across websockets and then receive replies back on the same websocket.
The problem I'm having is figuring out how to get the replies back to a Javascript call from a Django template that invokes a Python function to initiate the JSON websocket question. Since the command question & data reply happen in different Django areas and the originating Javascript/Python functions call does not have a blocking statement, the Q&A are basically disconnected and I can't figure out how to get the results back to the browser.
Right now, my idea is to use Django global variables or store the results in the Django models. I can get either to work, but I beleive the Django global variables would not scale beyond multiple workers from runserver or if the system was eventually spread across multiple servers.
But since the reply data is for different purposes (for example, list of users waiting in a remote lobby, current debugging levels in remote system, etc), the database option seems unworkable because the reply data is varying structure. That, plus the replies are temporal and don't need to be permanently stored in the database.
Here's some code showing the flow. I'm open to different implementation recommendations or a direct answer to the question of how to share information between the 2 Django functions.
In the template, for testing, I just have a button defined like this:
<button id="request_lobby">Request Lobby</button>
With a Javascript function. This function is incomplete as I've yet to do anything about the response (because I can't figure out how to connect it):
$("#request_lobby").click(function(){
$.ajax({
type: "POST",
url: "{% url 'test_panel_function' %}",
data: { csrfmiddlewaretoken: '{{ csrf_token }}', button:"request_lobby" },
success: function(response){
}
});
});
This is the Django/Python function in views.py . The return channel for the remote application is pre-stored in the database as srv.server_channel when the websocket is initially connected (not shown):
#login_required
def test_panel_function(request):
button = request.POST.get('button', '')
if button == "request_lobby" :
srv = Server.objects.get(server_key="1234567890")
json_res = []
json_res.append({"COMMAND": "REQUESTLOBBY"})
message = ({
"text": json.dumps(json_res)
})
Channel(srv.server_channel).send(message)
return HttpResponse(button)
Later, the remote application sends the reply back on the websocket and it's received by a Django Channels demultiplexer in routing.py :
class RemoteDemultiplexer(WebsocketDemultiplexer):
mapping = {
"gLOBBY" : "gLOBBY.receive",
}
http_user = True
slight_ordering = True
channel_routing = [
route_class(RemoteDemultiplexer, path=r"^/server/(?P<server_key>[a-zA-Z0-9]+)$"),
route("gLOBBY.receive" , command_LOBBY),
]
And the consumer.py :
#channel_session
def command_LOBBY(message):
skey = message.channel_session["server_key"]
for x in range(int(message.content['LOBBY'])):
logger.info("USERNAME: " + message.content[str(x)]["USERNAME"])
logger.info("LOBBY_ID: " + message.content[str(x)]["LOBBY_ID"])
logger.info("OWNER_ID: " + message.content[str(x)]["IPADDRESS"])
logger.info("DATETIME: " + message.content[str(x)]["DATETIME"])
So I need to figure out how to get the reply data in command_LOBBY to the Javascript/Python function call in test_panel_function
Current ideas, both of which seem bad and why I think I need to ask this question for SO:
1) Use Django global variables:
Define in globals.py:
global_async_result = {}
And include in all relevant Django modules:
from test.globals import global_async_result
In order to make this work, when I originate the initial command in test_panel_function to send to the remote application (the REQUESTLOBBY), I'll include a randomized key in the JSON message which would be round-tripped back to command_LOBBY and then global_async_result dictionary would be indexed with the randomized key.
In test_panel_function , I would wait in a loop checking a flag for the results to be ready in global_async_result and then retrieve them from the randomized key and delete the entry in global_async_result.
Then the reply can be given back to the Javascript in the Django template.
That all makes sense to me, but uses global variables (bad), and seems that it wouldn't scale as the web service is spread across servers.
2) Store replies in Django mySQL model.py table
I could create a table in models.py to hold the replies temporarily. Since Django doesn't allow for dynamic or temporary table creations on the fly, this would have to be a pre-defined table.
Also, because the websocket replies would be different formats for different questions, I could not know in advance all the fields ever needed and even if so, most fields would not be used for differing replies.
My workable idea here is to create the reply tables using a field for the randomized key (which is still routed back round-trip through the websocket) and another large field to just store the JSON reply entirely.
Then in test_panel_function which is blocking in a loop waiting for the results, pull the JSON from the table, delete the row, and decode. Then the reply can be given back to the Javascript in the Django template.
3) Use Django signals
Django has a signals capability, but the response function doesn't seem to be able to be embedded (like inside test_panel_function) and there seems to be no wait() function available for an arbitrary function to just wait for the signal. If this were available, it would be very helpful

get foreignId Data from the feed of a user [Stream Js]

hi i'm trying to implement getstream.io in my project.
i'm using https://github.com/GetStream/stream-js
as my server side script is in nodeJS.
i'm able to create a user in feed using
user1 = client.feed('user', 'dpz');
i'm creating activity for this user using using
activity ={
"actor":"user:1",
"message": "#flat_4_bfcaffca-c35f-11e5-8080-8001002e75f6",
"verb":"tweet",
"object":"tweet:4",
"foreign_id": "flat:4"
};
user1.addActivity(activity);
if i want to get all records of that user,
i use
user1.get()
.then(function(body) { console.log(JSON.stringify(body)); })
.catch(function(reason) { console.log(JSON.stringify(reason.error));});
i get result as :
{"duration":"19ms",
"next":"",
"results":[{
"actor":"user:1",
"foreign_id":"flat:4",
"id":"41231d40-ca5a-11e5-8080-800047dac62a",
"message":"#flat_4_bfcaffca-c35f-11e5-8080-8001002e75f6",
"object":"tweet:4",
"origin":null,
"target":null,
"time":"2016-02-03T09:41:09.335584",
"to":[],
"verb":"tweet"
}]
}
in your rest_ documentation
https://getstream.io/docs_rest/#feed_detail
you have specified
feed/(feed_slug)/(user_id)/(activity_id|foreign_id)/
to delete an activity for if the foreign key matches criteria.
in your nodejs code
user1.removeActivity({foreignId: 'flat:4'})
line works to remove the feed for that user where foreign key is flat:4
user1.get({foreignId: 'flat:4'})
does not work
can you please help if i want to get feeds with the foreignId as 'flat:4'
is there any way for such ?
please help as i'm stuck on this point only.
The feed/(feed_slug)/(user_id)/(activity_id|foreign_id)/ endpoint is only for DELETE requests. At this present is not possible to retrieve activities by its foreign_id. That field can only be used to perform cascaded deletion and/or to define the uniqueness of your data.
Looking at the code that you added, it seems like to use references to feeds as the value for foreign_ids, if that's the case then you are probably using this field in a weird/wrong way and you should create a new question on SO to ask help with the integration of your data.

Trello API: how to get board ids of an organisation or member

I am working on a Trello sync bot based off of the GitHub one here : https://github.com/fiatjaf/trello-cardsync and I am working on the coffeescript files. I have looked on the API and I think I know what I need I just don't know how to write it exactly and I can't find any examples of it especially in coffeescript (or javascript).
I would like to be able to search through an organisations boards or a members boards and then pick out certain board IDs so I get just a list of board IDs to certain boards I want, so then I can create webhooks for these boards.
I've tried using Trello.get("members/me/boards", { fields: "id, name"}) to get all the boards IDs and names like in the client.js API 'Trello.get(path[, params], success, error)' but my GET just returns unidentified when I try to print it to console. I have an array of objects in the settings.coffee file to compare the names with to select the boards I want but I can't get the full list in my file. At the moment I'm just looking at the data from the link: https://trello.com/1/members/my/boards?key=substitutewithyourapplicationkey&token=substitutethispartwiththeauthorizationtokenthatyougotfromtheuserand entering the IDs manually to create the webhooks, but I would like to automate this as much as possible.
I have also looked at 'GET /1/search' in Trello API but I'm unsure how to do that in my coffeescript file.
You need to pass a callback to Trello.get. It doesn't return anything meaningful, but instead passes the value to the callback:
Trello.get("members/me/boards", { fields: "id,name"}, function(err, boards) {
console.log(boards); // got them!
console.log(err); // if something went wrong, this will be non-null
})

meteorjs subscribe usage when collection is huge

I don't know the best way to handle huge mongo databases with meteorjs.
In my example I have a database collection with addresses in it with the geo location. (the whole code snippets are just examples)
Example:
{
address : 'Some Street',
geoData : [lat, long]
}
Now I have a form where the user can enter an address to get the geo-data. Very simple. But the problem is, that the collection with the geo data has millions of documents in it.
In Meteor you have to publish a collection on Server side and to subscribe on Client and Server side. So my code is like this:
// Client / Server
Geodata = new Meteor.collection('geodata');
// Server side
Meteor.publish('geodata', function(){
return Geodata.find();
});
// Client / Server
Meteor.subscribe('geodata');
Now a person has filled the form - after this I get the data. After this I search for the right document to return. My method is this:
// Server / Client
Meteor.methods({
getGeoData : function (address) {
return Geodata.find({address : address});
}
});
The result is the right one. And this is still working. But my question is now:
Which is the best way to handle this example with a huge database like in my example ? The problem is that Meteor saves the whole collection in the users cache when I subscribed it. Is there a way to subscribe to just the results I need and when the user reused the form then I can overwrite the subscribe? Or is there another good way to save the performance with huge databases and the way I use it in my example?
Any ideas?
Yes, you can do something like this:
// client
Deps.autorun(function () {
// will re subscribe every the 'center' session changes
Meteor.subscribe("locations", Session.get('center'));
});
// server
Meteor.publish('locations', function (centerPoint) {
// sanitize the input
check(centerPoint, { lat: Number, lng: Number });
// return a limited number of documents, relevant to our app
return Locations.find({ $near: centerPoint, $maxDistance: 500 }, { limit: 50 });
});
Your clients would ask only for some subset of the data at the time. i.e. you don't need the entire collection most of the time, usually you need some specific subset. And you can ask server to keep you up to date only to that particular subset. Bare in mind that more different "publish requests" your clients make, more work there is for your server to do, but that's how it is usually done (here is the simplified version).
Notice how we subscribe in a Deps.autorun block which will resubscribe depending on the center Session variable (which is reactive). So your client can just check out a different subset of data by changing this variable.
When it doesn't make sense to ship your entire collection to the client, you can use methods to retrieve data from the server.
In your case, you can call the getGeoData function when the form is filled out and then display the results after the method returns. Try taking the following steps:
Clearly divide your client and server code into their respective client and server directories if you haven't already.
Remove the geodata subscription on the server (only clients can activate subscriptions).
Remove the geodata publication on the server (assuming this isn't needed anymore).
Define the getGeoData method only on the server. It should return an object, not a cursor so use findOne instead of find.
In your form's submit event, do something like:
Meteor.call('getGeoData', address, function(err, geoData){Session.set('geoDataResult', geoData)});
You can then display the geoDataResult data in your template.

Categories

Resources