React Native Create Components with multiple condition - reactjs

I have a data structure like this:
const _ = require('lodash');
const bills = [
{year:2021, month:5, bill:'bill in 2021 may'},
{year:2018, month:1, bill:'bill in 2018 jan'},
{year:2019, month:1, bill:'bill in 2019 jan'},
{year:2018, month:2, bill:'bill in 2018 feb'},
{year:2019, month:10,bill:'bill in 2019 oct'},
{year:2019, month:2, bill:'bill in 2019 feb'},
{year:2019, month:6, bill:'bill in 2019 jun'},
{year:2020, month:11,bill:'bill in 2020 nov'}
];
and I want to display like below using Text or Card component of native-base
2018
1
bill in 2018 jan
2
bill in 2018 feb
2019
1
bill in 2019 jan
2
bill in 2019 feb
6
bill in 2019 jun
10
bill in 2019 oct
2020
11
bill in 2020 nov
2021
5
bill in 2021 may
My codes are below using lodash library to generate above and display in the terminal
// sort the data first
let arrSortedTasks = _.orderBy(tasks, ['year', 'month'],['asc']);
// get all the different year from the data
let arrUniqYear = _.uniqBy(arrSortedTasks, 'year');
// get all the different month from the data
let arrUniqMonth = _.uniqBy(arrSortedTasks, 'month');
// take out only the value of the year
arrUniqYear =_.map(arrUniqYear, 'year');
// take out only the value of the month
arrUniqMonth =_.map(arrUniqMonth, 'month');
let taskList = '';
for (let year of arrUniqYear) {
console.log(year);
for (let month of arrUniqMonth) {
let displayMonth = false;
for (let obj of arrSortedTasks) {
if (obj.year === year && obj.month === month) {
taskList = taskList + obj.task;
displayMonth = true;
}
}
if (displayMonth) {
console.log(" " + month);
}
if (taskList.length > 0) {
console.log(" " + taskList);
}
taskList = '';
}
}
How can we display the components in react-native with native-base? SO here don't let me post if too many code sigh. I tried a few ways buy got errors and can't figure out.

I end up using array as a return object in rendering
renderBillsSection() {
const { bills } = this.props;
if(bills || bills.length > 0 ) {
let arrSortedTasks = _.orderBy(tasks, ['year', 'month'],['asc']);
let arrUniqYear = _.uniqBy(arrSortedTasks, 'year');
let arrUniqMonth = _.uniqBy(arrSortedTasks, 'month');
let billList = '', arr = [], yearIndex = 0, monthIndex = 0, billIndex = 0;
arrUniqYear = _.map(arrUniqYear, 'year');
arrUniqMonth = _.map(arrUniqMonth, 'month');
for (let year of arrUniqYear) {
arr.push(<Text key="{yearIndex}">{year}</Text>)
yearIndex++
for (let month of arrUniqMonth) {
let displayMonth = false;
for (let obj of arrSortedTasks) {
if (obj.year === year && obj.month === month) {
billList = billList + obj.task
displayMonth = true
}
}
if (displayMonth) {
arr.push(<Text key="{monthIndex}" style={{marginLeft:10}}>{month}</Text>)
monthIndex++
}
if (billList.length > 0) {
arr.push(<Text key="{taskIndex}" style={{marginLeft:20}}>{billList}</Text>)
billIndex++
}
billList = '';
}
}
return arr;
}
}

not sure about how you are planning to render it in UI, but if you want to have the data structure like this, you need to group it (and sort by monhts if its not already sorted)
_(bills).groupBy('year').map((v,k)=> ({year: k, docs: _.sortBy(v,'month')})).value()
it will give you another array where you have year, abd docs as nested array holding all the documents of that year, so that you can agaib have another repeat on that.
const bills = [
{year:2021, month:5, bill:'bill in 2021 may'},
{year:2018, month:1, bill:'bill in 2018 jan'},
{year:2019, month:1, bill:'bill in 2019 jan'},
{year:2018, month:2, bill:'bill in 2018 feb'},
{year:2019, month:10,bill:'bill in 2019 oct'},
{year:2019, month:2, bill:'bill in 2019 feb'},
{year:2019, month:6, bill:'bill in 2019 jun'},
{year:2020, month:11,bill:'bill in 2020 nov'}
]
let groupedDoc = _(bills).groupBy('year').map((v,year)=> ({year, docs: _.sortBy(v,'month')})).value();
console.log(groupedDoc);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>
Here is a working snippet:

I think you should do :
const gropuByYear = _.groupBy(bills,'year');
console.log(_.map(groupByYear, groups =>
groups.forEach(group=>(<View> {obj.bill}</View>)))
even you can orderBy year desc first then do the loop good luck

You need to take a look at SectionList of React Native.
Checkout this example and cuiyueshuai for more practical example.
SectionList Demo:
<SectionList
renderItem={({ item, index, section }) => <Text key={index}>{item}</Text>}
renderSectionHeader={({ section: { title } }) => <Text style={{ fontWeight: 'bold' }}>{title}</Text>}
sections={[
{ title: 'Title1', data: ['item1', 'item2'] },
{ title: 'Title2', data: ['item3', 'item4'] },
{ title: 'Title3', data: ['item5', 'item6'] },
]}
keyExtractor={(item, index) => item + index} />

Related

How to filter array from one date to another in Reactjs

I have an array of objects "mainData" like so:
0: {date: "2020-07-25T16:44:43.000Z"
description: "Qwerty"
id: 89329972},
1: {date: "2020-07-25T16:46:28.000Z"
description: "Place bins please"
id: 65586316},
2: {date: "2020-07-25T16:49:12.000Z"
description: "Solve sewerege problem"
id: 84687816},
3: {date: "2020-07-27T16:34:47.000Z"
description: "Test compl"
id: 56437370},
4: {date: "2020-07-28T08:40:34.000Z"
description: "Sewerage problem in my area"
id: 92402221},
5: {date: "2020-09-09T11:42:18.000Z"
description: "problem"
id: 25613902},
Now I am allowing the user to select from and to dates by using the mui datepicker. This is how I am receiving the values:
fromDate: Sat Jul 25 2020 11:43:00
toDate: Sat Aug 08 2020 11:43:00
Now I want to filter the array from this date to that date, including the from and to dates. I tried to do it this way but it just returns an empty array. I've put the code inside useEffect which is run every time toDate changes, Also I've used Moment to make the formats of both dates same:
useEffect( () => {
if (fromDate !== null && toDate !== null) {
setReportData(
mainData.filter(
(obj) =>{
return Moment(obj.date).format("DD MMM yyyy") >= Moment(fromDate).format("DD MMM yyyy") && Moment(obj.date).format("DD MMM yyyy") <= Moment(toDate).format("DD MMM yyyy")
}
)
)
}
},[toDate])
Edit
When I select a single date :
useEffect( () => {
if (oneDate !== null) {
setReportData(
mainData.filter(
(obj) =>{
return new Date(obj.date.substring(0, 19)).getTime() === oneDate.getTime()
}
)
)
}
},[oneDate])
Your object's date property can be parsed directly to Date object. So then you can use getTime.
Also, filter returns Date object.
So, you can change your code to this
useEffect( () => {
if (fromDate !== null && toDate !== null) {
setReportData(
mainData.filter(
(obj) =>{
return new Date(obj.date).getTime() >= fromDate.getTime() && new Date(obj.date).getTime() <= toDate.getTime()
}
)
)
}
},[toDate])
If you want to consider all dates to be of local timezone, then you need to remove the last part of each date's string in order for the parse method to consider each string as local timezone date.
So previous method becomes
useEffect( () => {
if (fromDate !== null && toDate !== null) {
setReportData(
mainData.filter(
(obj) =>{
return new Date(obj.date.substring(0, 19)).getTime() >= fromDate.getTime() && new Date(obj.date.substring(0, 19)).getTime() <= toDate.getTime()
}
)
)
}
},[toDate])
We can use moment.js too. By converting the moment to expected format.
In above case we have
Sat Jul 25 2020 11:43:00
Moment provides locale support format using llll, which is similar
to this one, usage as follow.
Initialize the format constant somewhere at top, after if statement;
const format = 'llll';
And just replace the filter return statement with :
return Moment(obj.date, format).unix() >= Moment(fromDate, format).unix() && Moment(obj.date, format).unix() <= Moment(toDate, format).unix()

React Redux - sorting array by 2 parameters

I am using React and redux to build an 'appointment schedule' feature for my app. At this point, I am receiving my array of objects where each object represents an appointment with properties 'date' and 'startTime'. My question is how can I sort my array by both date and time so that sooner appointments come first?
Here is my reducer (upcomingAppointments is the variable where I am storing the array):
case 'SCHEDULE_APT_SUCCESS':
//console.log('actions payload: ', action.payload )
return {
...state,
isSchedulingApt: false,
newlyAddedApt: action.payload,
aptScheduleDone: true,
upcomingAppointments: [...state.upcomingAppointments, action.payload]
};
Thanks in advance.
Let suppose your array looks something like this:
const upcomingAppointments = [
{ date: 'Wed Jun 03 2020', time: '11:39:04' },
{ date: 'Tue Jun 02 2020', time: '16:03:04' },
{ date: 'Wed Jun 03 2020', time: '17:59:12' },
// ...
];
Using Array.prototype.sort(), you can provide a custom sort function as argument:
const sortedAppointments = upcomingAppointments.sort((a, b) => {
const dateA = Date.parse(a.date + ' ' + a.time);
const dateB = Date.parse(b.date + ' ' + b.time);
// Sort in descending order
return dateA < dateB ? 1 : -1;
});

Add / Remove 1 day with Moment.js in React

I have a div with 2 dates inside, for example (< march 25th - march 26th >), and there are 2 arrows "<" and ">"
If a user presses the "<" arrow, I need to remove 1 day to the 2 dates :
(< march 25th - march 26th >) becomes (< march 24th - march 25th >),
and if a user presses the ">" arrow, I need to add 1 day to the 2 dates :
(< march 25th - march 26th >) becomes (< march 26th - march 27th >),
I stored the 2 dates in hooks, and by default, the firstValue is the day of today and the secondValue is 1 week later
const [firstValue, setFirstValue] = useState(
moment(new Date()).format("dddd Do MMMM YYYY")
);
const [secondValue, setSecondValue] = useState(
moment(new Date())
.add(1, "weeks")
.format("dddd Do MMMM YYYY")
);
I tried this when the user presses the "<" arrow :
function previousDay() {
console.log(firstValue, secondValue);
setFirstValue(moment(firstValue).remove(1, "days"));
setSecondValue(moment(secondValue).remove(1, "days"));
}
but I have the error
TypeError: moment__WEBPACK_IMPORTED_MODULE_2___default(...)(...).remove is not a function
Can somebody know how can I do that
Based on my comments, I'd suggest the following changes:
const [firstValue, setFirstValue] = useState(
moment(new Date()) // remove .format() here
);
const [secondValue, setSecondValue] = useState(
moment(new Date())
.add(1, "weeks")
);
On your render:
render() {
<>
...
...
{firstValue.format("dddd Do MMMM YYYY")}
</>
}
And your function should be something like:
function previousDay() {
setFirstValue(firstValue.subtract(1, "days")); // don't need to moment() anymore
setSecondValue(secondValue.subtract(1, "days"));
}
Change to :
function previousDay() {
console.log(firstValue, secondValue);
setFirstValue(moment(firstValue).subtract(1, "days"));
setSecondValue(moment(secondValue).subtract(1, "days"));
}
Because "remove" is not a valid property of [Moment object].

How to display Firestore datetime [duplicate]

I'm pulling a timestamp from a Firestore database, and I only want to display the date to the user. The original timestamp is
Timestamp(seconds=1555477200, nanoseconds=0)
I've tried a few variations to get the Date, but they all have the same output-
Due: Wed Apr 17 2019 06:10:21 GMT-0500 (Central Daylight Time)
<p>Due: ${Date(dueDate)}<br>
<p>Due: <time>${Date(dueDate)}</time><br>
<p>Due: <time type="date">${Date(dueDate)}</time><br>
How do I cut off the time part of the timestamp?
(Ideally, I'd want "April 17, 2019", but if the day is in there that's fine too)
If you have a particular format for date, you can do
function getDate (timestamp=Date.now()) {
const date = new Date(timestamp);
let dd = date.getDate();
let mm = date.getMonth()+1; //January is 0!
const yyyy = date.getFullYear();
if(dd<10) {
dd = '0'+dd
}
if(mm<10) {
mm = '0'+mm
}
// Use any date format you like, I have used YYYY-MM-DD
return `${yyyy}-${mm}-${dd}`;
}
getDate(1555477200000);
// -> 2019-04-17
Alternatively, you can also do:
const time = new Date(1555477200000);
// -> Wed Apr 17 2019 10:30:00 GMT+0530 (India Standard Time)
const date = time.toDateString();
// -> Wed Apr 17 2019
P.S: I have used ES6 here. If you are working on ES5, use babel's online transpiler to convert.
Link: https://babeljs.io/repl
You can do
var time= timeStampFromFirestore.toDate();
console.log(time);
console.log(time.toDateString());
See the full documentation :
toDateString()
toDate()
You can use Date.toLocaleString() like this:
new Date(date).toLocaleString('en-EN', { year: 'numeric', month: 'long', day: 'numeric' });
const timestamp = 1555477200000;
console.log(
new Date(timestamp).toLocaleString('en-EN', { year: 'numeric', month: 'long', day: 'numeric' })
);
Simply use moment.js and use your required format
date = moment();
console.log(date.format("MMMM D, YYYY"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.js"></script>

How to get the Days b/w current week in moment.js

I'm new to angular js and moment.js i have the following code which gives the start day and end day of a week like January 17th-January 23rd. but i want all the 7 days in this format january 17, monday.
My code
var currentDate,
weekStart,
weekEnd,
shortWeekFormat = 'MMMM Do';
function setCurrentDate(aMoment){
currentDate = aMoment,
weekStart = currentDate.clone().startOf('week'),
weekEnd = currentDate.clone().endOf('week')
}
setCurrentDate(moment());
$scope.currentWeek = function(){ return currentDate.format(shortWeekFormat); };
$scope.currentWeekStart = function(){ return weekStart.format(shortWeekFormat); };
$scope.currentWeekEnd = function(){ return weekEnd.format(shortWeekFormat); };
HTML
<h2><i class="fa fa-arrow-left"></i>Week Of {{currentWeek()}}{{currentWeekStart()}}-{{currentWeekEnd()}}<i class="fa fa-arrow-right"></i></h2>
<button ng-click="prevWeek()">previous week</button>
<button ng-click="nextWeek()">next week</button>
The format you want can be achieved with below moment code.
moment('01/19/2016').format("MMMM Do,dddd");
Now, to get all dates between a week you need to use array which holds all the seven dates for you. With simple for loop adding days to start date you can achieve what you want. Take a look at below sample code.
var currentDate = moment();
var weekStart = currentDate.clone().startOf('week');
var weekEnd = currentDate.clone().endOf('week');
var days = [];
for (i = 0; i <= 6; i++) {
days.push(moment(weekStart).add(i, 'days').format("MMMM Do,dddd"));
};
console.log(days);
console.log(moment('01/19/2016').format("MMMM Do,dddd"));
Now to use it with angular you can assign days array to some scope variable and use ng-repeat to display dates.
JSFiddle
Improving J-D's answer. This will return an array of moment objects:
const getCurrentWeekDays = () => {
const weekStart = moment().startOf('week');
const days = [];
for (let i = 0; i <= 6; i++) {
days.push(moment(weekStart).add(i, 'days'));
}
return days;
}

Resources