I get a csv with multiple columns from the backend, but I would like to change the data in a column before exporting this csv as a report.
Today I am using the react-csv library to export the report.
The column I want to modify is the Type. Currently she returns the values Product and Service. Instead of displaying Product I would like to display New Product and instead of Service I would like to display Used Product
report:
"Title","Type","Advertiser","Category"
"2 plots of 15x35 - R $ 15,000.00 each","product","LUIZ FABIANO DE OLIVEIRA0","Properties"
"3 Industrial machines","service","GISELE SANTANA","services"
code:
export default function exem() {
const [dataExport, setDataExport] = React.useState([]);
function getCSV() {
request
.get(urlGetCSV() + `&page=${page}`)
.text()
.then(response => {
setDataExport(response)
});
}
return (
<>
<CSVLink
data={dataExport}
filename={`report-${new Date().toLocaleString()}.csv`}
onClick={getCSV}
>
<Button>
Report
<Button.Icon>
<ReportIcon />
</Button.Icon>
</Button>
</CSVLink>
</>
)
}
If response is an array you could remap it before calling setDataExport:
const typeMappings = {
'product': 'New Product',
'service': 'Used Product'
}
.then(response => {
// find the "Type" column
const headers = response[0]; // assumes headers in the first row
const typeColumnIndex = headers.indexOf('Type'); // index of the column with 'Type' header
response.forEach(item => { // iterate over each row
// get the type from the row
const originalType = item[typeColumnIndex];
// replace it with the corresponding mapping.
// if no mapping exists, leave the original value.
item[typeColumnIndex] = typeMappings[originalType] || originalType;
})
setDataExport(response)
});
Related
I want to add some data on the bookChapters object, like a random id and inside of it the name of the chapters, I tried this but it doesn't work, after I add the previous data I also want to add a new object "takeAways", like the previous one, inside the random id object.
export const createNewChapter = (bookId, inputText) => {
return async dispatch => {
dispatch(createNewChapterStart());
try {
firebase
.firestore()
.doc(`Users/${bookId}/bookChapters/${inputText}`)
.onSnapshot(querySnapshot => {
//There I want to add the chapters to the firestore database
});
dispatch(createNewChapterSuccess(inputText));
} catch (error) {
dispatch(createNewChapterFail(error));
console.log(error);
}
};
};
I wanna know how to do add from scratch the bookChapters object
The database screenshot shows that the bookChapters object is a map. So to add (populate) this object you need to generate a simple JavaScript object with some properties as “key: value” pairs.
Something along these lines, making the assumption the chapter titles are in an Array:
function arrayToObject(arr) {
var obj = {};
for (var i = 0; i < arr.length; ++i) {
obj[i] = arr[i];
}
return obj;
}
const chapterList = ['Intro', 'Chapter 1', 'Chapter2', 'Conclusion'];
const bookChaptersObj = arrayToObject(chapterList);
firebase.firestore().doc(`Users/${bookId}`).update(bookChaptersObj);
Or, if the document does not already exist:
firebase.firestore().doc(`Users/${bookId}`).set(bookChaptersObj, {merge: true});
How to filter the columns? Here I need a date filter column, When we click the header of the date, it automatically sorts the column.
Actually, they asked like this "Need to sort by date and stick the 6 newest on this one as well"
Can you please help with this?
Here is the code I used.
You need to use a helper function in order to parse the string to Date object.
Then you can apply the sorting
Check the code snippet.
I store the Date object into another property in order not to break anything. You can of course replace it with the current property and format it accordingly inside your table cell.
function parseStr(str) {
let parts =str.substring(0, 10).split('.');
return new Date(parts[2], parts[1] - 1, parts[0]);
}
let array = [
{
"number":"5421787",
"amount":1391.74,
"duedate":"28.08.2020 00.00.00",
"voucherdate":"14.08.2020 00.00.00",
"invoicelink":"",
"status":"Betalt"
},
{
"number":"5499047",
"amount":499.0,
"duedate":"29.09.2020 00.00.00",
"voucherdate":"15.09.2020 00.00.00",
"invoicelink":"",
"status":"Betalt"
},
{
"number":"5574780",
"amount":499.0,
"duedate":"29.10.2020 00.00.00",
"voucherdate":"15.10.2020 00.00.00",
"invoicelink":"",
"status":"Betalt"
}
]
console.log(array.map(obj => ({ ...obj, voucherdate2: parseStr(obj.voucherdate)})).sort((a,b) => b.voucherdate2.getTime() - a.voucherdate2.getTime()))
So in your code
const invoiceData = useSelector((state) => state.userReducer.invoices)
let sortableInvoiceData = invoiceData.map(obj => ({ ...obj, voucherdate2: parseStr(obj.voucherdate)})).sort((a,b) => b.voucherdate2.getTime() - a.voucherdate2.getTime())
const renderInvoices = sortableInvoiceData.map((invoice, index) => {
I am uploading the data from excel file using react-excel-renderer, storing the excel render response containing column & rows response in state and passing to other component.
Expected Use-case result:- I am fetching the data from excel using render storing the values in states(rows). I am passing the state to other component where i need these values to pass in API .
The data stored is in nested form. Can you please let me know how to get data separately stored under array in props. Attached is the screenshot.
Excel Render code:-
changeHandler(event) {
let fileObj = event.target.files[0];
//just pass the fileObj as parameter
ExcelRenderer(fileObj, (err, resp) => {
if (err) {
console.log(err);
} else {
this.setState({
cols: resp.cols,
rows: resp.rows,
});
}
});
}
Code to fetch the prop data:-
for (let i = 0; i < this.props.data.length; i++) {
let stDate = this.props.data[i].startDate;let TripName = this.props.data[i].TripName;
let totalFare = this.props.data[i].totalFare;
let FirstName = this.props.data[i].FirstName;
let LastName = this.props.data[i].LastName;
let Currency = this.props.data[i].Currency;
}
You can use an Array method
Still not 100% sure what your final data should look like, but it feels like you're using 2 arrays. 1 as the key and 1 as the value.
So to combine these 2 we can use Reduce
const keys = data[0];
const values = data[1];
keys.reduce((acc, keys, index) => {
return {...acc, [key]: values[index]}
}, {})
That will return an object of key values.
I know that firestore doesn't support full text search and it giving us solution to use third party services. However I found a simple solution to simple "full text search" and I think this might help others who doesn't want to use third party services as me for such a simple task.
I'm trying to search for company name which is saved in firestore collection under my companyName which can be in any format for example "My Awesome Company". When adding new company with companyName or updating a value in companyName I'm also saving searchName with it which is the same value as company name but in lower case without spaces
searchName: removeSpace(companyName).toLowerCase()
removeSpace is my simple custom function which remove all spaces from a text
export const removeSpace = (string) => {
return string.replace(/\s/g, '');
}
That turns our company name to myawesomecompany which is saved in searchName
Now I've got a firestore function to search for company which indexing through searchName and returning companyName. Minumum search value is a searched value without last character and maximum search value is a searched value with added "zzzzzzzzzzzzzzzzzzzzzzzz" transformed to lower case. That means if you search for My Aw then min value will be mya and max value will be myawzzzzzzzzzzzzzzzzzzzzzzz
exports.handler = ((data) => {
const searchValue = data.value.replace(/\s/g, '').toLowerCase()
const minName = searchValue.substr(0, searchName.length-1)
const maxName = searchValue + "zzzzzzzzzzzzzzzzzzzzzzzz"
let list = []
const newRef = db.collection("user").where("profile.searchName", ">=", minName).where("profile.searchName", "<=", maxName)
return newRef.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
list.push({ name: doc.data().profile.companyName})
})
return list
})
})
I didn't have time to fully test it but so far it works without any problems. Please let me know if you spot anything wrong with it. Now the question is
Is "z" character the highest value character in firestore or is there any other more decent way to add into the search value maximum amount without adding "zzzzzzzzzzzzz"?
I like your decision to preprocess the text so that it can be queried, but you could provide for a more flexible search by storing lowercase keywords with the users and searching those. In other words, transform:
"My Awesome Company"
to...
{ my: true, awesome: true, company: true }
...and test against that.
When adding/updating the property:
// save keywords on the user
let keywords = {}
companyName.split(' ').forEach(word => keywords[word.toLowerCase()] = true)
When querying:
let searchKeywords = userInputString.split(' ').map(word => word.toLowerCase())
let collection = db.collection("user")
searchKeywords.forEach(keyword => {
collection = collection.where(`keywords.${keyword}` , '==' , true);
});
With a little modification of previous answer I have made another simple text search. I'm saving keyword to an array instead of saving it in object like this
nameIndex: textIndexToArray(companyName)
where textIndexToArray is my custom function
export const textIndexToArray = (str) => {
const string = str.trim().replace(/ +(?= )/g,'')
let arr = []
for (let i = 0; i < string.trim().length; i++) {
arr.push(string.substr(0,i+1).toLowerCase());
}
return arr
}
which transfer a text into array. For example
"My Company"
will return
[m, my, my , my c, my co, my com, my comp, my compa, my compan, my company]
with nameIndex saved in firestore we can simply query the data thorough nameIndex and return companyName
exports.handler = ((data) => {
const searchValue = data.value.toLowerCase()
let list = []
const newRef = db.collection("user").where("nameIndex", "array-contains", searchValue)
return newRef.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
list.push({ name: doc.data().companyName, })
})
return list
})
})
I'm storing an array of objects in AsyncStorage and would like to know the best way to remove a specific object. Right now I´m passing an id to my function and then I loop through the array to match the id and remove the object and then the array in AsyncStorage is updated. This seems to work ok, but I wonder if this is optimal or if there is a better way to do this?
My function right now:
export function removeData(id) {
AsyncStorage.getItem('#books')
.then((books) => {
const updatedBooks = (JSON.parse(books))
for (let i = 0; i < updatedBooks.length; i++) {
if(updatedBooks[i].id == id) {
updatedBooks.splice(i, 1);
}
}
AsyncStorage.setItem('#books', JSON.stringify(updatedBooks));
})
}
My function for adding data to AsyncStorage:
export function addData(book) {
AsyncStorage.getItem('#books')
.then((books) => {
const b = books ? JSON.parse(books) : [];
b.push(book);
AsyncStorage.setItem('#books', JSON.stringify(b));
});
}
Button to add data with sample data to show structure:
<Button
title = "Add book"
onPress={() => addData({
id: 1,
title: 'Harry Potter',
author:'J.K. Rowling',
thumbnail:'https://covers.openlibrary.org/w/id/7984916-M.jpg',
})
To remove single item
AsyncStorage.removeItem('key', (err) => {
// key 'key' will be removed, if they existed
// callback to do some action after removal of item
});
To remove multiple items
let keys = ['k1', 'k2'];
AsyncStorage.multiRemove(keys, (err) => {
// keys k1 & k2 removed, if they existed
// callback to do some action after removal of item
});
Reference:
RemoveItem method
MultiRemove method