How to modify value in data.json with react - reactjs

I am trying to modify a value in my data.json. I am working on a web entertainment app for my portfolio
So I want to modify the value "isBookmarked" in my data.json
here it is a part of my data.json
type here{
"title": "Beyond Earth",
"thumbnail": {
"trending": {
"small": "./assets/thumbnails/beyond-earth/trending/small.jpg",
"large": "./assets/thumbnails/beyond-earth/trending/large.jpg"
},
"regular": {
"small": "./assets/thumbnails/beyond-earth/regular/small.jpg",
"medium": "./assets/thumbnails/beyond-earth/regular/medium.jpg",
"large": "./assets/thumbnails/beyond-earth/regular/large.jpg"
}
},
"year": 2019,
"category": "Movie",
"rating": "PG",
"isBookmarked": false,
"isTrending": true
},
with the IsBookmarded value I know which of the movies I did bookmark and I need to modify the value directly in json so after I can display only the bookmarked one and then toggle the one I don't want anymore in the bookmark section. But the thing I am trying to do with useEffect it's fetching the data, and make a copy of it and put that in a copy of the data with state but there is a problem
type hereconst [data, setData] = useState([]);
useEffect(() => {
axios.get("./data.json")
.then(res => setData(res.data))
.catch(err => console.error(err));
}, []);
function handleUpdateData(index){
const newData = [...data];
console.log(data[0].isBookmarked) // Here it's not working ,
// newData[index].isBookmarked = newData[index].isBookmarked ? false : true;
// setData(newData);
};
The problem it's that console.log(data) work and console.log(data[0]) work too
but if I want to do console.log(data[0].isBookmarked) the console is telling me that the
isBookmarded is not defined so I don't know what to do I am bit lost

In the frontend of React you cannot update the .json file directly. You can import (or fetch) the .json, store it on state, and manipulate the state - however the original .json file will remain in-tact.
If you want to be able to update the .json file, I would ask "why not use a simple datastore?" Look into Firebase / Firestore - very easy and fun to use - the entire store is JSON based and can be manipulated from your React frontend.
Otherwise you are looking into more complicated solutions which involved:
Sending a request to a backend server or cloud function
Using fs to write a file to the server to overwrite your .json file
Refreshing your client so that it loads the newly updated .json file
These 3 steps are much much more difficult than just using an actual database / datastore. MySQL, Postgres, Firestore are all options.

You can try this package which you will be able to send HTTP requests to the endpoint and update data.json

Related

Getting Image from api

I have an api "https://www.pinkvilla.com/photo-gallery-feed-page/page/1" which returns response something like this.
"nodes": [
{
"node": {
"title": "PHOTOS: Shruti Haasan's Turkey vacay- A perfect mix of work and fun",
"nid_dont_use": "1",
"field_photo_image_section": "/files/styles/photogallery/public/shruti_haasan_in_turkey_main_0.jpeg?itok=ex_mE-AH",
"path": "/photos/shruti-haasan/photos-shruti-haasans-turkey-vacay-perfect-mix-work-and-fun-1184120",
"nid": "1184120",
"photo_image_nids": "1184114,1184115,1184116,1184117,1184118,1184119",
"ImageStyle_thumbnail": "/files/styles/imagestyle_1_1/public/shruti_haasan_in_turkey_main_0.jpeg?itok=44jwEbFY",
"last_update": "1661754431",
"views_count": "305",
"author_uid": "870656",
"author_name": "Pinkvilla Desk"
}
},
I am trying to get images from this api and I see two objects which have image path in it.
"ImageStyle_thumbnail": "/files/styles/imagestyle_1_1/public/shruti_haasan_in_turkey_main_0.jpeg?itok=44jwEbFY"
"field_photo_image_section": "/files/styles/photogallery/public/shruti_haasan_in_turkey_main_0.jpeg?itok=ex_mE-AH",
Is there any way I can get images from this api?
It seems like the pictures you're searching for can be composed by adding your API image url's to pinkvilla base url: https://www.pinkvilla.com/files/styles/photogallery/public/shruti_haasan_in_turkey_main_0.jpeg?itok=ex_mE-AH
You could try composing pinkvilla's base url with paths returned from your API, but it won't be a failsafe approach, as you can't possibly know if those images actually exists on pinkvilla's webserver.
You could do something like this to get the image URLs:
const [imageUrls, setImageUrls] = useState();
const fetchImages = async () => {
const baseUrl = "https://www.pinkvilla.com";
const result = await fetch(`${baseUrl}/photo-gallery-feed-page/page/1`).then((res) => res.json());
setImageUrls(result.nodes.map((node) => `${baseUrl}${node.node.field_photo_image_section}`));
};
fetchImages();
And then can use that array of URLs (imageUrl) to render the images using the <img src=""/> tag.

Upload react-pdf dynamically generated file to Sanity using NextJS

I'm working on an e-commerce app built on NextJS and Sanity, so far I've made some mock products with all the necessary requirements, a user login system and checkout. I've been trying to make an invoice system so that when the user confirms an order 3 things must happen:
send all the order data to a react-pdf component and generate the invoice(working)
post the invoice file to the sanity schema so that the user has access to it when he goes to his order history page(not working)
email both the company and the client about the order(not implemented yet but I can do it)
ReactPDF allows me to access the pdf through a hook that returns me the blob of the file and the URL. I've tried to POST both of them but the url returned 404 and the blob didn't upload at all.
Searched the docs of both ReactPDF and Sanity and I couldn't find anything, although I think it has to do something with this endpoint from Sanity:
myProjectId.api.sanity.io/v2021-06-07/assets/files/myDataset
This is how I POST the order to my sanity studio
const { data } = await axios.post(
'/api/orders',
{
user: userInfo,
invoice_id: orders.length + 1,
orderItems: cartItems.map((item) => ({
...item,
slug: undefined
})),
billingData,
paymentMethod,
itemsPrice,
taxPrice,
totalPrice
},
{
headers: {
authorization: `Bearer ${userInfo.token}`
}
}
);
I've tried making 2 POST requests, one for the invoice_file alone, trying to post the blob or the url but none did work. The schema for invoice file was updated for the type of post each time so I'm 99% sure that wasn't the issue, anyway here's how the schema for invoice_file looks as for file:
{
name: 'invoice_file',
title: 'Invoice',
type: 'file',
options: {
storeOriginalFilename: true
}
},
If there would be any other code snippets relevant please let me know.
I really don't know how to find the solution for this as it's the first time trying to do such thing, so help would be much appreciated.
Thanks in advance!
I apologies as I'm not really active here but it's hard to pass on your question especially as I'm working on something similar. There's probably other ways to do this but I suggest you work use the official Sanity client. There's a specific section in the README that tells us how to do the file uploads or here.
So here's kinda the very small snippet:
import {
Document,
pdf,
} from "#react-pdf/renderer";
const doc = <Document />;
const asPdf = pdf([]); // {} is important, throws without an argument
asPdf.updateContainer(doc);
const blob = await asPdf.toBlob();
// `blob` here is coming from your react-pdf blob
const fileName = "customfilename.pdf";
client.assets.upload("file", blob, { filename: fileName }).then((fileAsset) => {
console.log(fileAsset", fileAsset);
// you can then use the fileAsset to set and reference the file that we just uploaded to our document
client.patch("document-id-here").set({
invoice_file: {
_type: "file",
asset: {
_type: "reference",
_ref: fileAsset._id,
},
},
}).commit();
});

React API call, render data with QuickBase's new RESTful API

I'm trying to figure out what i'm doing wrong here... I've been out of coding for awhile and trying to jump back in for an external application utilizing QuickBase's RESTful API. I'm simply trying to get data from QuickBase to be used outside in an external app to create charts/graphs.
I'm not able to use GET as it gives me only the field names and no data, if I use POST, then I get the values of these fields as well. I'm able to get all the data rendered in the console, but am struggling to get each field rendered to be used in the app.
let headers = {
'QB-Realm-Hostname': 'XXXXXXXXXXXXX.quickbase.com',
'User-Agent': 'FileService_Integration_V2.1',
'Authorization': 'QB-USER-TOKEN XXXXXX_XXXXX_XXXXXXXXXXXXXXXX',
'Content-Type': 'application/json'
}
let body = {"from":"bpz99ram7","select":[3,6,80,81,82,83,86,84,88,89,90,91,92,93,94,95,96,97,98,99,101,103,104,105,106,107,109,111,113,115,120,123,224,225,226,227,228,229,230,231,477,479,480,481],"sortBy":[{"fieldId":6,"order":"ASC"}],"groupBy":[{"fieldId":40,"grouping":"equal-values"}],"options":{"skip":0,"top":0,"compareWithAppLocalTime":false}}
fetch('https://api.quickbase.com/v1/records/query',
{
method: 'POST',
headers: headers,
body: JSON.stringify(body)
})
.then(res => {
if (res.ok) {
return res.json().then(res => console.log(res));
}
return res.json().then(resBody => Promise.reject({status: res.status, ...resBody}));
})
.catch(err => console.log(err))
Hoping to get some help getting the data rendered to be used in React, as well as any tips from anyone who's used QuickBase's new API calls in their realm! And I apologize if it's an easy question/issue, haven't been in React for a couple years... and I'm feeling it!
Thanks!
A successful response from Quickbase for this call has a property data which is an array of the records returned. Each element of this array is an object where the FID for each field returned is a key for nested object - or objects for some field types - with the field's value. Here's a very contrived example:
{
"data": [
{
"1": {
"value": "2020-10-24T23:22:39Z"
},
"2": {
"value": "2020-10-24T23:22:39Z"
},
"3": {
"value": 2643415
}
}
],
"fields": [
{
"id": 1,
"label": "Date Created",
"type": "timestamp"
},
{
"id": 2,
"label": "Date Modified",
"type": "timestamp"
},
{
"id": 3,
"label": "Record ID#",
"type": "recordid"
}
]
}
If you put the data array of the response directly into state with const [quickbaseData, setQuickbaseData] = useState(res.data); for example, you need to keep the structure of the response in mind when accessing that data. If I want to get the value of FID 3 from the first record in the response I would need to use quickbaseData[0]["3"].value. For most field types value will be a string or integer but for some field types it will be an object. You can see the way values are returned for each field type in Field type details.
Depending on your needs you might consider processing the Quickbase response into a new, simpler array/object to use in your application. This is especially helpful if the value being returned needs additional processing such as converting into a Date() object. This would also allow you to make your application API agnostic since other than initially processing the response from Quickbase the rest of your application doesn't have to have any knowledge of how Quickbase returns queried data.
On the Quickbase side of things, there isn't the equivalent of 'SELECT *' so to get data for all fields of a table where you don't know the schema (or it changes frequently) you can run a GET on the Fields endpoint: https://developer.quickbase.com/operation/getFields an then use the field IDs in the response to make the POST call to /records/query

Updating state when database gets updated

I got a schema looking something like this:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
//Create Schema
const PhoneNumbersSchema = new Schema({
phone_numbers: {
phone_number: 072382838232
code: ""
used: false
},
});
module.exports = PhoneNumbers = mongoose.model(
"phonenumbers",
PhoneNumbersSchema
);
And then I got an end-point that gets called from a 3rd party application that looks like this:
let result = await PhoneNumbers.findOneAndUpdate(
{ country_name: phoneNumberCountry },
{ $set: {"phone_numbers.$[elem1].services.$[elem2].sms_code": 393} },
{ arrayFilters: [ { "elem1.phone_number": simNumberUsed }, { "elem2.service_name": "steam" } ] },
Basically the end-point updates the "code" from the phone numbers in the database.
In react this is how I retrieve my phone numbers from the state:
const phonenumbers_database = useSelector((state) => {
console.log(state);
return state.phonenumbers ? state.phonenumbers.phone_numbers_details : [];
});
Every time the code gets changed in my database from the API call I would like to update "phonenumbers_database" in my state automatically.
How would I be able to do that?
MongoDB can actually watch for changes to a collection or a DB by opening a Change Stream.
First, you would open up a WebSocket from your React app to the server using something like Socket.io, and then watch for changes on your model:
PhoneNumbers
.watch()
.on('change', data => socket.emit('phoneNumberUpdated', data));
Your third party app will make the changes to the database to your API, and then the changes will be automatically pushed back to the client.
You could do a polling and check the Database every N secs or by using change streams
After that, to notify your frontend app, you need to use WebSockets, check on Socket IO

How to set up admin-on-rest with couchDB?

Edit to the makers of AoR : Your framework suffers from horrid documentation. You should really focus on that, people would really adopt it then.
I cant for the life of me decipher how admin-on-rest does the 'rest' part. If there is a better framework with better documentation, Im open to that.
Im very new to react, so thats probably part of it.
What I can discern is that
1) The [Admin] tag takes a prop 'restClient', and this is a function that sets your base path to your JSON source, then returns a function with a specific signature (takes 3 arguments, returns a promise).
2) Then a [Resource] tag adds to the path with name="posts" and makes a list, which (heres where it turns to magic) basically does a wget to your database then iterates over the results.
What I want to do : hook up couchDB to admin-on-rest. I already have a few test docs made on localhost. The couchDB url looks like :
http://127.0.0.1:5984/myproject/_design/getclients/_view/getclient/
and this works in postman, giving me a json object like this :
{
"total_rows": 4,
"offset": 0,
"rows": [
{
"id": "afc3bb9218d1a5c1e81ab3cc9f004467",
"key": {
"status": "active",
"rating": 9.1,
"bio": {
"fname": "Sam",
"mname": "TestMName",
"lname": "TestLName",
"address": "712347 B Street",
"state": "CA",
"city": "Los Santos",
"zip": "90211",
"phone": "123-456-7890",
"email": "sam#samsemail.com",
"username": "TestSam",
"password": "abc123"
}
},
"value": null
},
At this point Im so confused I dont know where to look.
Heres my code now :
//App.js
import React from 'react';
import { jsonServerRestClient, Admin, Resource } from 'admin-on-rest';
import { PostList } from './Posts.js';
const App = () => (
<Admin restClient={jsonServerRestClient('http://127.0.0.1:5984/myproject/')}>
<Resource name="_design/getclients/_view/getclient" list={PostList} />
</Admin>
);
export default App;
And
//Posts.js
export const PostList = (props) => (
<List {...props}>
<Datagrid>
<TextField source="status" />
<TextField source="rating" />
</Datagrid>
</List>
);
The page loads but a little pink box pops up at the bottom saying :
The X-Total-Count header is missing in the HTTP Response. The jsonServer REST client expects responses
The RestClient is a bit of a murky beast. Not perfectly documented for sure.
But it is in the end quite straightforward if you know how the whole thing works together.
1) Admin-On-Rest has defined some REST types (below). These are usually shot off by Redux actions (in their meta tag). The system scans for these rest types and if it sees them, then it calls the RestClient
GET_LIST
GET_ONE
CREATE
UPDATE
DELETE
GET_MANY
GET_MANY_REFERENCE
The REST client is called with these types and some other params. It is the job of the rest client to interpret the type and then use the params to make a request to your API. For this AOR uses the new Fetch API that is built into browsers.
You can access it by calling. You should also go into AOR source code and check out how it works.
import { fetchUtils } from 'admin-on-rest';
2) The X total count is a header field that AOR needs for all responses to the GET_LIST type.
You can set this quite simply in your API. I use loopback and I set the X-Total-Count manually in a remote hook (don't worry about it if you don't know it)
It seems your api is still using the JSON server. JSON server is a dummy API. So your app is not connected to your couchDB right now.
https://github.com/typicode/json-server
If you are not using an api server like express or loopback, then you can also configure your restClient do all request and response handling. You have to construct the URL. Read the below link so you can follow my example code further down.
https://marmelab.com/admin-on-rest/RestClients.html#decorating-your-rest-client-example-of-file-upload
so something like this.
if (type === 'GET_LIST' && resource === 'posts') {
const url = http://127.0.0.1:5984/myproject/_design/getclients/_view/getclient/
options.method = 'GET';
return fetchUtils.fetchJson(url, options)
.then((response) => {
const {headers, json} = response;
//admin on rest needs the {data} key
return {data: json,
total: parseInt(headers.get('x-total-count').split('/').pop(), 10)}
})
You can also write a function like this to handle the request and response.
function handleRequestAndResponse(url, options={}) {
return fetchUtils.fetchJson(url, options)
.then((response) => {
const {headers, json} = response;
//admin on rest needs the {data} key
const data = {data: json}
if (headers.get('x-total-count')) {
data.total = parseInt(headers.get('x-total-count').split('/').pop(), 10)
} else {
data.total = json.length // this is why the X-Total-Count is needed by Aor
}
}
}
// handle get_list responses
return {data: json,
total: } else {
return data
}
})
}
The above code has been formatted in the window and so might not work straight out of the box. But I hope you get the idea.

Resources