React - sort messages in monthly sections - javascript

I am trying to group a list of messages in monthly sections. Every time the month changes I want to add a header <h2>Previous Month</h2> and then display all the messages from that month.
Here is my attempt:
MessageList.js
import React from "react"
export default class MessageList extends React.Component {
constructor() {
super()
}
render() {
var currentDate = new Date()
var currentMonth = currentDate.getMonth()
var timeline=""
var mssgTypeList = {
"this_month" : [],
"last_month" : [],
"previous_month" : []
}
this.props.messages.forEach(function(message,index){
var date = message.date.substring(0, 10)
var time = message.date.slice(12)
var messageDate = new Date(date)
var messageMonth = messageDate.getMonth()
if(currentMonth == messageMonth) {
timeline == 'this_month'
} else if(currentMonth == messageMonth + 1){
timeline = 'last_month'
} else if(currentMonth == messageMonth + 2) {
timeline = 'previous_month'
}
mssgTypeList[timeline].push(message);
});
const ThisMonthMessageList = mssgTypeList["this_month"].map((message) => {
var date = message.date.substring(0, 10);
var time = message.date.slice(12);
return (
<li className="list-group-item" key={message.id}>
Date: {date} <br></br>
Time: {time} <br></br>
Body: {message.body}
</li>
)
});
const LastMonthMessageList = mssgTypeList["last_month"].map((message) => {
var date = message.date.substring(0, 10);
var time = message.date.slice(12);
return (
<li className="list-group-item" key={message.id}>
Date: {date} <br></br>
Time: {time} <br></br>
Body: {message.body}
</li>
)
})
const PreviousMonthMessageList = mssgTypeList["previous_month"].map((message) => {
var date = message.date.substring(0, 10);
var time = message.date.slice(12);
return (
<li className="list-group-item" key={message.id}>
Date: {date} <br></br>
Time: {time} <br></br>
Body: {message.body}
</li>
)
})
return (
<div id="messageList">
<h2>This Month</h2>
<ul className="list-group this-month-group">
{ThisMonthMessageList}
</ul>
<h2>Last Month</h2>
<ul className="list-group last-month-group">
{LastMonthMessageList}
</ul>
<h2>Previous Month</h2>
<ul className="list-group previous-month-group">
{PreviousMonthMessageList}
</ul>
</div>
)
}
The problem here is that this only generates a limited number of monthly sections; Basically sections that I hardcoded in mssgTypeList. It does not dynamically create a new section whenever the month changes.
How do I dynamically generate a new section every time the month changes?
Or is there an alternative way to sort messages in monthly sections? Maybe create additional components?

Its probably a better idea to put all the logic that depends in the props in the componentWillReceiveProps Method and the same should be present in the componentDidMount function since componentWillReceiveProps is not being called the initial time. Also having all this logic in the render is expensive since render is called any state change.
Dynamic rendering can be achieved in the following manner, however it would be better if you include the month with the year as a key.
export default class MessageList extends React.Component {
constructor() {
super();
this.state = {
msgTypeList : {
}
}
}
componentDidMount() {
var currentDate = new Date()
var currentMonth = currentDate.getMonth()
var messageTypeList = {}
this.props.messages.forEach((message, index) => {
var date = message.date.substring(0, 10)
var messageDate = new Date(date)
var messageMonth = messageDate.getMonth();
messageTypeList[messageMonth].push(message);
})
this.setState({messageTypeList});
}
componentWillReceiveProps(nextProps) {
var currentDate = new Date()
var currentMonth = currentDate.getMonth()
var timeline=""
var messageTypeList = {}
nextProps.messages.forEach((message, index) => {
var date = message.date.substring(0, 10)
var messageDate = new Date(date)
var messageMonth = messageDate.getMonth();
messageTypeList[messageMonth].push(message);
})
this.setState({messageTypeList});
}
render() {
return (
<div id="messageList">
{Object.keys(this.state.messageTypeList).map((key) => {
return (
<div>
<h2>{key}</h2>
<ul className="list-group">
{this.state.messageTypeList[key].map((message) => {
var date = message.date.substring(0, 10);
var time = message.date.slice(12);
return (
<li className="list-group-item" key={message.id}>
Date: {date} <br></br>
Time: {time} <br></br>
Body: {message.body}
</li>
)
})}
</ul>
</div>
)
})
}
</div>
)
}

You are on the right track. Notice that {ThisMonthMessageList} is not hard-code but you build it. Well you can do the same thing for your entire message list. Your render return statement would then look something like this:
return (
<div id="messageList">
{messageList}
</div>
);
Hopefully that's enough to get you thinking about this the right way.

Related

How to save budget list in local storage?

I know local storage is not a secure solution for this, but for now, I am doing it this way for practice.
I think I am on the right track here, I want my created list for the budget app to store, this method seems to store the first created list.
/*----Store Stored budget list----*/
function storedEntry(){
const saveData = makeNewBudget();
const myJSON = JSON.stringify(saveData);
window.localStorage.setItem(STORAGE_KEY, myJSON);
}
I think what needs to happen is get that same method to work for the array.
let budgetArray = [];
I tried this method, but gives a JSON error, sop for some reason it's not converted to JSON
let budgetArray = JSON.parse(window.localStorage.getItem(STORAGE_KEY) ?? "[]");
End result should be set local storage for array in its own function and get the stored information when checking the array.
I put the entire JS code so you can see what is going on
/*----Generate ID----*/
const createId = () =>`${Math.floor(Math.random() * 10000)}$(new Date().getTime())}`;
/*----Get current Date----*/
function createdDate() {
let currentDate = new Date();
let day = String(currentDate.getDate()).padStart(2, '0');
let month = String(currentDate.getMonth() + 1).padStart(2, '0');
let year = currentDate.getFullYear();
currentDate = month + '/' + day + '/' + year;
console.log(currentDate)
return currentDate;
}
/*----Variable Objects----*/
const el = {
list: document.querySelector(".list"),
cashflow: document.querySelector("#cashflow"),
catagory: document.querySelector(".catagory"),
label: document.querySelector(".label"),
number: document.querySelector(".number"),
};
/*----Array with local Storage----*/
let budgetArray = [];
/*----Budget list Object----*/
function makeNewBudget(){
const data = {
id: createId(),
cashflowNew: el.cashflow.value,
catagoryNew: el.catagory.value,
labelNew: el.label.value,
dateNew: createdDate(),
numberNew: el.number.value,
};
return data;
}
/*----Render Budget List----*/
function renderList(){
el.list.innerHTML = budgetArray.map(function (data,i) {
return `<div class="entry">
<div class="list">
<button onclick="deleteItem(event, ${i})" class="Archive" data-id="${data.id}">
<img src="../resources/Images/archive.png" alt="Archive">
</button>
<button onclick="editItem(event, ${i})" class = "edit" data-id="${data.id}" class = "edit" data-id="${data.id}">
<img src="../resources/Images/edit.png" alt="Edit">
</button>
<div class="input" data-id="${data.id}"></div>
<label class="dateNew">${data.dateNew}</label>
<label class="cashflowNew">${data.cashflowNew}</label>
<label class="catagoryNew">${data.catagoryNew}</label>
<label class="labelNew">${data.labelNew}</label>
<label class="numberNew">${data.numberNew}</label>
</div>
</div>
<label class="total"></label>`;
});
}
/*----form validation----*/
let budgetButton = document.querySelector(".budget-button");
let label = document.querySelector(".label");
let num = document.querySelector(".number");
let entry = document.querySelector(".entry")
budgetButton.addEventListener("click", () => {
if (!label.value || !num.value) {
alert("please make sure all inputs are filled");
}
budgetArray.push(makeNewBudget())
renderList();
storedEntry();
});
/*----Archive list----*/
function deleteItem(event, i){
}
/*----Store Stored budget list----*/
function storedEntry(){
const saveData = makeNewBudget();
const myJSON = JSON.stringify(saveData);
window.localStorage.setItem(STORAGE_KEY, myJSON);
}

componentDidMount() method in react js

Hi, i maked a calendar than have some day class than they added in componentDidMount() method and after that i can not add event to the day classes.
In fact when i get the day class length, or i want to select this class, return me none object.
I add the target elements in componentdidMount() method.
i add the eventListener in the componentdidMount() method.
The element adder and eventListener both are in componentDidMount()
The codes:
the day adder and event listener
for (let day = 1; day <= days.length; day++){
const weekend = isWeekend(year, month, day);
const today = isToday(year, month, day);
let name = '';
if(day <= 7){
const dayName = getDayName(year, month,day);
name = `<div className="name">${dayName}</div>`
}
calendar.insertAdjacentHTML(
"beforeend",
`<div className='day${weekend ? " weekend" : ""}${today ? " today" : ""}' data-year="${year}" data-month="${month}" data-day="${day}" onClick={this.dayClick}>
${name}
${day}
${weekend ? "<br/><p style='color:#FFA500'>weekend</p>" : ""}
${today ? "<h3 style='color:#9af467'>today</h3>" : ""}
</div>`
);
}
document.querySelectorAll('#app-calendar .day').forEach(day => {
day.addEventListener("click", event => {
event.currentTarget.classList.toggle("selected");
});
day.addEventListener("dblclick", event => {
let element = event.target;
let year = element.getAttribute('data-year');
let month = element.getAttribute('data-month');
let day = element.getAttribute('data-day');
let date = Date(year + '-' + month + '-' + day);
this.setState({
date: formatDate(date)
});
console.log(this.state.date);
});
});
The render code(Html)
render(){
return(
<div className="root">
<div className="clalendar-header">
<div id="previous" className="shift"><h3>previous</h3></div>
<div id="month-name" className="month-name"></div>
<div id="future" className="shift"><h3>future</h3></div>
</div>
<div className="content">
<div id="app-calendar"></div>
</div>
</div>
);
}

My weather app only loads the data on the first try, and I have to refresh the page before it works again

I have been trying to figure out this bug for several days and I need some help.
This code is for a weather app that I am building that takes in coordinates after you share your location, or a city name from a search bar. This code only works one time however, meaning you have to refresh the page before you can type in a new location to search up, and if you allow the page to take your location, you won't be able to even search up a new city using the search bar.
// This section is for the search bar and submit button
let submit = document.querySelector('.weatherSubmit');
let searchBar = document.querySelector('.inputValue');
searchBar.addEventListener("keyup", function(e) {
if (e.keyCode === 13) {
submit.click();
}
});
submit.addEventListener('click', function() {
fetch(`http://api.openweathermap.org/data/2.5/weather?q=${searchBar.value}&units=imperial&APPID=4edd74c5cec3113209554fa2045fdb73`)
.then(response => response.json())
.then(data => {
let {lat, lon} = data.coord;
onecall(lat, lon);
reverseGeocode(lat, lon);
})
.catch(err => alert('Wrong city name!'));
})
// This takes in the data and displays it
const showData = (data) => {
let current_weather_container = document.querySelector('.current_weather_container');
let {temp, sunrise, sunset, wind_speed, dt, humidity} = data.current;
let {description} = data.current.weather[0];
let {max, min} = data.daily[0].temp;
description = description.charAt(0).toUpperCase() + description.slice(1);
wind_speed = Math.round(wind_speed);
max = Math.round(max);
min = Math.round(min);
temp = Math.round(temp);
let dateInMillisec = dt * 1000;
let sunriseInMillisec = sunrise * 1000;
let sunsetInMilliSec = sunset * 1000;
let dateObj = new Date(dateInMillisec);
let sunriseTimeObj = new Date(sunriseInMillisec);
let sunsetTimeObj = new Date(sunsetInMilliSec);
let date = dateObj.toLocaleString("en-US", {weekday: 'short', month: 'short', day: 'numeric'});
let sunriseTime = sunriseTimeObj.toLocaleString("en-US", {hour: "numeric", minute: "numeric"});
let sunsetTime = sunsetTimeObj.toLocaleString("en-US", {hour: "numeric", minute: "numeric"});
//This is the current weather section
current_weather_container.innerHTML =
`
<div class='current_time_container'>
<div class='current_date'>${date}</div>
</div>
<div class='current_weather'>
<div id='submitDiv'>
<input class='weatherSubmit' type="submit" value="Search">
<input class='inputValue' type='text' placeholder="Enter city name" required>
</div>
<div class='weather_class' id='current_temp'>
<div class='current_weather_item'>${temp + '\u00B0F'}</div>
</div>
<div class='weather_class'>
<div id='description' class='current_weather_item extraPadding'>${description}</div>
</div>
<div class='current_data'>
<div class='current_weather_class'>
<div class='weather_item'>${'Sunset: ' + sunsetTime}</div>
</div>
<div class='current_weather_class'>
<div class='weather_item'>${'Sunrise: ' + sunriseTime}</div>
</div>
<div class='current_weather_class'>
<div class='weather_item'>${'Humidity: ' + humidity + '%'}</div>
</div>
</div>
<div class='current_data'>
<div class='current_weather_class'>
<div class='weather_item'>${'High: ' + max + '\u00B0F'}</div>
</div>
<div class='current_weather_class'>
<div class='weather_item'>${'Low: ' + min + '\u00B0F'}</div>
</div>
<div class='current_weather_class'>
<div class='weather_item'>${'Wind: ' + wind_speed + 'mph'}</div>
</div>
</div>
</div>`
;
//This is the hourly section
let hourlyForecast = '';
let counter = 0;
data.hourly.forEach((hour) => {
let hourTime = hour.dt;
hourTimeInMilli = hourTime * 1000;
hourTimeObj = new Date(hourTimeInMilli);
time = hourTimeObj.toLocaleString("en-US", {hour: "numeric"});
while(counter < 12 && hourTime > dt) {
hourlyForecast +=
`<div class='forecast_weather_class'>
<div class='increaseFont'>${time}</div>
<div class='weather_image'><img id='icon2' class='icon2' src="http://openweathermap.org/img/w/${hour.weather[0].icon}.png"></div>
<div class='weather_item alignLeft'>${hour.weather[0].description.charAt(0).toUpperCase() + hour.weather[0].description.slice(1)}</div>
<div class='weather_class_container'>
<div class='weather_class alignLeft'>
<div class='weather_item increaseFont alignLeft'>${Math.round(hour.temp) + '\u00B0F'}</div>
</div>
</div>
</div>`;
return counter++;
}
});
let top = document.querySelector('.top');
top.innerHTML = hourlyForecast;
//This is the daily section
let dailyForecast = '';
let counter2 = 0;
data.daily.forEach((day) => {
let dayTime = day.dt;
dayInMilli = dayTime * 1000;
dateObject = new Date(dayInMilli);
time = dateObject.toLocaleString("en-US", {weekday: "short", day: "2-digit"});
if (counter2 === 0) {
return counter2++;
} else {
dailyForecast +=
`<div class='forecast_weather_class alignLeft'>
<div class='increaseFont'>${time}</div>
<div class='weather_image'><img id='icon2' class='icon2' src="http://openweathermap.org/img/w/${day.weather[0].icon}.png"></div>
<div class='weather_item'>${day.weather[0].description.charAt(0).toUpperCase() + day.weather[0].description.slice(1)}</div>
<div class='weather_class_container'>
<div class='weather_class alignLeft'>
<div class='weather_item increaseTempFont '>${Math.round(day.temp.max) + '\u00B0F'}</div>
<div class='weather_item decreaseTempFont '>${Math.round(day.temp.min) + '\u00B0F'}</div>
</div>
</div>
</div>`
}
});
let bottom = document.querySelector('.bottom');
bottom.innerHTML = dailyForecast;
}
// This adds the name of the city to the page
const nameSpot = (data) => {
let cityName = document.querySelector('.cityName');
let {city} = data;
cityName.innerHTML = `
<h2 class='cityName'>${city}</h2>
`
}
/// This grabs the lat & longitude
function grabGeolocation() {
navigator.geolocation.getCurrentPosition((success) => {
let { latitude, longitude } = success.coords;
let lat = latitude;
let lon = longitude;
onecall(lat, lon);
reverseGeocode(lat, lon);
});
}
grabGeolocation();
// This grabs all the data but the city name
function onecall(lat, lon) {
let weatherApiUrl = fetch(`http://api.openweathermap.org/data/2.5/onecall?lat=${lat}&lon=${lon}&units=imperial&appid=4edd74c5cec3113209554fa2045fdb73`);
weatherApiUrl.then(response => response.json())
.then(data => {
showData(data);
})
.catch(err => alert('Unable to grab coordinates!'));
}
// This grabs the city name
function reverseGeocode(lat, lon) {
let cityGeoLocationUrl = fetch(`https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=${lat}&longitude=${lon}&localityLanguage=en`);
cityGeoLocationUrl.then(response => response.json())
.then(data => {
nameSpot(data);
})
.catch(err => alert('Unable to grab coordinates!'));
}```

Get items by date by clicking day on calendar Javascript Django

I'm developing calendar app with Javascript and Django . I don't now how to display item by date by clicking the day . Is there any solutions ? I have a guess that I need to get elements by ajax on clicking the date . Here is some code :
models.py
class Item(models.Model):
title=models.CharField(max_length=200)
date = models.DateTimeField(default=datetime.now,blank=True)
is_published=models.BooleanField(default=True)
views.py
def calendar(request):
item = Item.objects.order_by('-date').filter(is_published=True)
context={
'item':item,
}
return render(request,'main/calendar.html',context)
Javascript calendar draw methods
drawAll() {
this.drawWeekDays();
this.drawMonths();
this.drawDays();
this.drawYearAndCurrentDay();
this.drawEvents();
}
drawYearAndCurrentDay() {
let calendar = this.getCalendar();
this.elements.year.innerHTML = calendar.active.year;
this.elements.currentDay.innerHTML = calendar.active.day;
this.elements.currentWeekDay.innerHTML = AVAILABLE_WEEK_DAYS[calendar.active.week];
}
drawDays() {
let calendar = this.getCalendar();
let latestDaysInPrevMonth = this.range(calendar.active.startWeek).map((day, idx) => {
return {
dayNumber: this.countOfDaysInMonth(calendar.pMonth) - idx,
month: new Date(calendar.pMonth).getMonth(),
year: new Date(calendar.pMonth).getFullYear(),
currentMonth: false
}
}).reverse();
let daysInActiveMonth = this.range(calendar.active.days).map((day, idx) => {
let dayNumber = idx + 1;
let today = new Date();
return {
dayNumber,
today: today.getDate() === dayNumber && today.getFullYear() === calendar.active.year && today.getMonth() === calendar.active.month,
month: calendar.active.month,
year: calendar.active.year,
selected: calendar.active.day === dayNumber,
currentMonth: true
}
});
Here is constructor of class Calendar
constructor(options) {
this.options = options;
this.elements = {
days: this.getFirstElementInsideIdByClassName('calendar-days'),
week: this.getFirstElementInsideIdByClassName('calendar-week'),
month: this.getFirstElementInsideIdByClassName('calendar-month'),
year: this.getFirstElementInsideIdByClassName('calendar-current-year'),
currentDay: this.getFirstElementInsideIdByClassName('display_day'),
currentWeekDay: this.getFirstElementInsideIdByClassName('calendar-left-side-day-of-week'),
prevYear: this.getFirstElementInsideIdByClassName('calendar-change-year-slider-prev'),
nextYear: this.getFirstElementInsideIdByClassName('calendar-change-year-slider-next')
};
this.date = +new Date();
this.options.maxDays = 37;
this.init();
}
getFirstElementInsideIdByClassName(className) {
return document.getElementById(this.options.id).getElementsByClassName(className)[0];
}
Here is template
<div class="right-side">
<div class="text-right calendar-change-year">
<div class="calendar-change-year-slider">
<span class="fa fa-caret-left cursor-pointer calendar-change-year-slider-prev"></span>
<span class="calendar-current-year"></span>
<span class="fa fa-caret-right cursor-pointer calendar-change-year-slider-next"></span>
</div>
</div>
<div class="calendar-month-list">
<ul class="calendar-month"></ul>
</div>
<div class="calendar-week-list">
<ul class="calendar-week"></ul>
</div>
<div class="calendar-day-list">
<ul class="calendar-days"></ul>
</div>
</div>
<h1 class="calendar__heading calendar__heading-2 display_day"></h1>
<h1 class="calendar__heading calendar-left-side-day-of-week"></h1>
Here is what I want
Or is there a way to change calendar ? This calendar isn't so necessary
The javascript code should detect which day you clicked, then it should call an endpoint that will end up in your django view. The view should receive the day and filter the items by date, something like this:
Entry.objects.filter(date=selected_day)
This should return all the items for a given day.

Issue with UI-scroll and promisse

I just want to scroll downside and after that come back to the beginning of the list.
Now I can't use my grid.
I know that there are thousands of examples of how to do ui-scroll,
but there are no any example with Angular 1.5 components
Please help.
index.html
//add ui-scroll-viewport
<md-content flex layout-padding class="viewport" id="viewport-serviceDatasource" ui-scroll-viewport>
// added ui-scroll, this part is responsible for loading by week
<div layout="raw" layout-xs="column" class="week" layout-sm="column" layout-align="space-between start" flex="none"
ui-scroll="week in $ctrl.grid">
<!-- outlines days -->
<div flex="none" layout="column" layout-fill ng-repeat="day in week">
<!-- current day header-->
<div layout="row" layout-align="space-between center" flex-gt-sm="none" flex="none" style="height: 30px">
<div flex="none" class="md-body-1" style="min-width: 24px">{{::day.title}}</div>
</div>
</div>
</div>
</md-content>
app.js
class CalendarCtrl {
constructor($log, $q, $timeout, $scope) {
'ngInject';
this._$log = $log;
this._$q = $q;
this._$timeout = $timeout;
this._$scope = $scope;
this.grid = {};
// Tried to use $Scope
this._$scope.grid = {};
}
$onInit() {
// Get the first day of the week curry
let currDay = moment().weekday(0),
startDay = moment(currDay).add(-5,'w'),
endDay = moment(currDay).add(5,'w');
// Error here. I think so
this.getCalendarGrid(startDay, endDay).then(
(success) => {
// Get all our days, in the form of a grid
var result = success;
var grid = {};
grid.get = (index, count, success) =>{
index = index <= 0 ? index + 1 : index -1;
success(result.slice(index, index + count));
};
this.grid = grid;
this._$log.debug('Calendar: getCalendarGrid', this.grid);
},
(error) => this._$log.debug('Calendar: onInit, getCalendar error', error),
(week) => this._$log.debug('Calendar: onInit, getCalendar notify', week)
);
}
/**
*
* #returns {Promisse}
*/
getCalendarGrid(startDay, endDay){
let start = startDay, end = endDay;
let result = this._$q.defer(),
grid = {},
index = 0,
diff = end.diff(start,'d'),
day = {
title: null,
activity: []
},
week = {};
while (diff != 0){
// go through all the days.
day.title = start.format('DD');
angular.extend(week, {[start.format('YYYYMMDD')]: day});
day = {
title: null,
activity: []
};
// put by week
if ((diff % 7 == 1) || diff == 0){
week = { [start.format('YYYYWW')]: week };
angular.extend(grid,week);
result.notify(week);
week = {};
}
start.add(1,'d');
diff = end.diff(start,'d');
}
result.resolve(grid);
return result.promise;
}
}
Console screen
Console screen with errors

Categories

Resources