Limit react-day-picker range to x days - reactjs

I want to limit the range length in react-day-picker to e.g. 10 days. How should this be done, is something availlable in the package already?
This is an example range selector: https://react-day-picker.js.org/examples/selected-range/

Could be easily implemented, I've just added some lines to the handleDayClick function:
Instead of this:
handleDayClick(day) {
const range = DateUtils.addDayToRange(day, this.state);
this.setState(range);
}
Implement this:
handleDayClick(day) {
const oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds
const diffDays = Math.round(Math.abs((day - this.state.from) / oneDay));
const range = DateUtils.addDayToRange(day, undefined);
if(diffDays <= 10){
const range = DateUtils.addDayToRange(day, this.state);
this.setState(range);
}
else {
this.setState(range);
}
}

Related

how to shuffle an array except for the item in the middle?

Iยดm creating a Bingo board and I need that the one in the middle always stays the same even when shuffleing this array:
const bbb = [
"๐Ÿ˜‹",
"๐Ÿ˜",
"๐Ÿคฃ",
"๐Ÿ˜ƒ",
"๐Ÿ˜„",
"๐Ÿ˜…",
"๐Ÿ˜†",
"๐Ÿ˜‰",
"๐Ÿ˜Š",
"๐Ÿ˜Š",
"๐Ÿ˜Ž ",
"๐Ÿคฉ",
"๐ŸŽฏ",
"๐Ÿ˜ถ",
"๐Ÿ˜ซ",
"๐Ÿ˜ด",
"๐Ÿค ",
"๐Ÿ™„ ",
"๐Ÿ˜‘",
"๐Ÿ˜ฏ",
"๐Ÿ˜š",
"๐Ÿ˜ฅ",
"๐Ÿ˜ฎ ",
"๐Ÿ˜›",
"๐Ÿ˜"
];
const data = arrayShuffle(bbb).reduce(
(data, value, index) => ({ ...data, [index]: value }),
{}
);
and then Im maping the array to display the Tiles and create the board like this:
{Object.keys(data).map(id => (
<Tile
key={id}
id={id}
isSet={state.checked[id]}
onToggle={() => toggle(id)}
>
{data[id]}
</Tile>
))}
Remove the middle item from the array initially. Then do the in-place randomizing of items and finally attach the middle item to the array.
This runs in O(n) time complexity where n is the size of your array and you always get a uniform random permutation.
const bbb = [ "๐Ÿ˜‹", "๐Ÿ˜", "๐Ÿคฃ", "๐Ÿ˜ƒ", "๐Ÿ˜„", "๐Ÿ˜…", "๐Ÿ˜†", "๐Ÿ˜‰", "๐Ÿ˜Š", "๐Ÿ˜Š", "๐Ÿ˜Ž", "๐Ÿคฉ", "๐ŸŽฏ", "๐Ÿ˜ถ", "๐Ÿ˜ซ", "๐Ÿ˜ด", "๐Ÿค", "๐Ÿ™„", "๐Ÿ˜‘", "๐Ÿ˜ฏ", "๐Ÿ˜š", "๐Ÿ˜ฅ", "๐Ÿ˜ฎ", "๐Ÿ˜›", "๐Ÿ˜", ];
const getRandomInt = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
};
const arrayShuffleInplaceExceptMiddle = (A) => {
const middle = A.splice(A.length/2, 1);
const n = A.length;
const middleIndex = Math.floor(n / 2);
for (let i = 0; i < n; i++) {
let swapIndex = getRandomInt(i, n);
let a = A[i];
A[i] = A[swapIndex];
A[swapIndex] = a;
}
A.splice(n/2, 0, ...middle)
};
// test runs
Array.from({length: 10}, () => {
arrayShuffleInplaceExceptMiddle(bbb);
console.log(bbb.join(""));
})
Just shuffle the array normally, but remove the the value before the shuffle and insert it back afterward:
/**
* Durstenfeld shuffle
*
* - https://stackoverflow.com/a/12646864/438273
* - https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
*
* #param {unknown[]} array
*/
function shuffleArray (array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
/**
* Like a normal shuffle, but for a bingo board
*
* #param {unknown[]} array
*/
function bingoShuffle (array) {
const index = Math.floor((array.length - 1) / 2);
const [value] = array.splice(index, 1);
shuffleArray(array);
array.splice(index, 0, value);
}
// Let's keep the board small for this demo:
const board = [
"๐Ÿ˜Š",
"๐Ÿ˜Š",
"๐Ÿ˜Ž",
"๐Ÿคฉ",
"๐ŸŽฏ",
"๐Ÿ˜ถ",
"๐Ÿ˜ซ",
"๐Ÿ˜ด",
"๐Ÿค",
];
console.log(board.join(' '));
// Shuffle it a few times and look at the results:
for (let i = 0; i < 10; i += 1) {
bingoShuffle(board);
console.log(board.join(' '));
}
And because you tagged this with reactjs, I'm guessing this is (immutable) state, so you'll need to get a new array when shuffling, like this:
const updatedBoard = bingoShuffle([...board]);
// ^^^^^^^^^^
// Shallow copy into new array so you don't mutate React state

Sort an array of date ranges in typeScript

Array(6) [
"10-2022 - 12-2022",
"08-2022 - 09-2022",
"07-2023 - 10-2023",
"04-2022 - 07-2022",
"01-2023 - 06-2023",
"01-2022 - 03-2022" ]
I want to sort this array of date ranges to show the latest date range at the beginning of the array. Having some trouble because the dates are in string format.
Try with this utility function:
const arr = [
"10-2022 - 12-2022",
"08-2022 - 09-2022",
"07-2023 - 10-2023",
"07-2023 - 11-2023",
"04-2022 - 07-2022",
"01-2023 - 06-2023",
"01-2022 - 03-2022"
];
const getYearMonth = (date) => {
const dateSplit = date.split('-');
if (dateSplit.length < 2) return '';
return dateSplit[1] + '-' + dateSplit[0];
}
const sortedArr = arr.sort((a, b) => {
const aSplit = a.split(' - ');
const bSplit = b.split(' - ');
const aYearMonthStart = getYearMonth(aSplit[0]);
const bYearMonthStart = getYearMonth(bSplit[0]);
// Sort decreasing by start
if (aYearMonthStart > bYearMonthStart) return -1;
if (aYearMonthStart < bYearMonthStart) return 1;
// Sort decreasing by end date if start date equal
const aYearMonthEnd = getYearMonth(aSplit[1]);
const bYearMonthEnd = getYearMonth(bSplit[1]);
if (aYearMonthEnd > bYearMonthEnd) return -1;
if (aYearMonthEnd < bYearMonthEnd) return 1;
// Equal dates
return 0;
})
console.log(sortedArr);
Array.sort((a, b) => b.localeCompare(a))

React Intl with relativeTime formatting

I'm working on a kind of dynamic timestamp for messages using Intl.
I want the timestamps to be dynamic in the way that it automatically transitions from ".. seconds ago" to "... minutes ago" to "... hours ago" to "today", after which it'll just return the date it's been posted. I know there's the <RelativeFormat> component, but I want to use the API instead.
The API has a method called intl.relativeFormat, but can't seem to figure out how to use it...
I'm a junior programmer so it's all still a bit new to me ๐Ÿ˜…๐Ÿ˜…
I appreciate your time :)
If you need more info, please let me know. I'll try to provide you with more.
Thanks!
Documentation for the RelativeFormat function can be found here - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat.
The idea is that you create an instance of relative time format function, with some pre-defined settings that you want the output to follow. For example, you can set your relative time format function to return English strings in a shortened format.
const rtf = new Intl.RelativeTimeFormat('en', { style: 'narrow' });
console.log(rtf.format(3, 'quarters'));
//expected output: "in 3 qtrs."
You also need to pass negative values in order to get labels intended for the past.
const rtf = new Intl.RelativeTimeFormat('en', { style: 'narrow' });
console.log(rtf.format(-3, 'quarters'));
//expected output: "3 qtrs. ago"
The next part leverages an answer given by #fearofawhackplanet here on StackOverflow
//The 'timestamp' function parameter is your timestamp passed in milliseconds.
function timeDifference(timestamp, locale) {
const msPerMinute = 60 * 1000;
const msPerHour = msPerMinute * 60;
const msPerDay = msPerHour * 24;
const msPerMonth = msPerDay * 30;
const msPerYear = msPerDay * 365;
const current = Date.now();
const elapsed = current - timestamp;
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
if (elapsed < msPerMinute) {
return rtf.format(-Math.floor(elapsed/1000), 'seconds');
}
else if (elapsed < msPerHour) {
return rtf.format(-Math.floor(elapsed/msPerMinute), 'minutes');
}
else if (elapsed < msPerDay) {
return rtf.format(-Math.floor(elapsed/msPerHour), 'hours');
}
else {
return new Date(timestamp).toLocaleDateString(locale);
}
}
//
// code to test the above function
//
const fifteenSecondsAgo = new Date();
const tenMinutesAgo = new Date();
const twoHoursAgo = new Date();
fifteenSecondsAgo.setSeconds(fifteenSecondsAgo.getSeconds() - 15);
tenMinutesAgo.setMinutes(tenMinutesAgo.getMinutes() - 10);
twoHoursAgo.setHours(twoHoursAgo.getHours() - 2);
console.log(timeDifference(fifteenSecondsAgo.getTime(), 'en'));
console.log(timeDifference(fifteenSecondsAgo.getTime(), 'es'));
console.log(timeDifference(tenMinutesAgo.getTime(), 'en'));
console.log(timeDifference(tenMinutesAgo.getTime(), 'es'));
console.log(timeDifference(twoHoursAgo.getTime(), 'en'));
console.log(timeDifference(twoHoursAgo.getTime(), 'es'));
Here is a JSFiddle link to see the code running - https://jsfiddle.net/mhzya237/1/
Here is a similar idea, it also deals with future/present/past times.
function getRelativeTime(time) {
const now = new Date();
const diff = Math.abs(time - now);
const mark = (time - now) >> -1 || 1;
if (diff === 0) return new Intl.RelativeTimeFormat('en').format(0,"second");
const times = [
{ type: 'second', seconds: 1000 },
{ type: 'minute', seconds: 60 * 1000 },
{ type: 'hour', seconds: 60 * 60 * 1000 },
{ type: 'day', seconds: 24 * 60 * 60 * 1000 },
{ type: 'week', seconds: 7 * 24 * 60 * 60 * 1000 },
{ type: 'month', seconds: 30 * 24 * 60 * 60 * 1000 },
{ type: 'year', seconds: 12 * 30 * 24 * 60 * 60 * 1000 },
];
let params = [];
for (let t of times) {
const segment = Math.round(diff / t.seconds);
if (segment >= 0 && segment < 10) {
params = [(segment * mark) | 0, t.type];
break;
}
}
return new Intl.RelativeTimeFormat('en').format(...params);
}
const time = getRelativeTime(new Date(new Date().getTime() - 2 * 1000));
console.info('relative time is', time);
The function takes a time param, finds the seconds difference relative to now, uses the array map to calculate which type yields the closest match and uses it as a param for Intl.RelativeTimeFormat
You can improve getRelativeTime(time) function by either returning the params array and call Intl.RelativeTimeFormat from outside the function or also pass the locale (and options) to the function.
I'm sure there are smarter ways to get rid of the times array, perhaps by creating a wrapping closure but it will force you to "initialize" this utility function first

Round date to the nearest 5 minutes moment as array

I need to Using a Date() utc , to round a time to the nearest five minutes then push it as array
example:
[
"2019_10_9_00_05",
"2019_10_9_00_10",
"2019_10_9_00_15",
"2019_10_9_00_20",
]
Code
const now = moment();
const time= [];
for (let i = 0; i < 4; i++) {
now.add(5, 'minutes');
time.push(now.utcOffset(-1).format('YYYY_M_DD_HH_mm'));
}
console.log(time);
output
[
"2019_10_9_00_03",
"2019_10_9_00_7",
"2019_10_9_00_11",
"2019_10_9_00_16",
]
any solution's please
You need to check if minutes value is multiple of 5 first.
const now = moment();
const factor = 5;
const time = [];
const minutes = now.minutes();
if (minutes !== 0 && minutes % factor) { // Check if there is a remainder
const remainder = minutes % factor; // Get remainder
now.add(factor - remainder, 'minutes'); // Update minutes value to nearest 5
}
for (let i = 0; i < 4; i++) {
time.push(now.utcOffset(-1).format('YYYY_M_DD_HH_mm'));
now.add(5, 'minutes');
}
console.log(time);
Result:
now: 2019_10_11_09_19
["2019_10_10_21_20", "2019_10_10_21_25", "2019_10_10_21_30", "2019_10_10_21_35"]

Angular not detecting change to first element in array

I'm trying to display a list of dates for the current week in an Angular app. I want to allow users to view previous weeks at the click of a button, so I'm using an Observable to update the array of dates, and attempting to display the updated array.
All items are updated in the view, except for the first item in the array. Plunker example here
I've tried using *ngFor and the async pipe, as well as explicitly creating elements for each item in the array (like below). Both have the same issue. I'm struggling to find a solution.
//our root app component
import {Component, NgModule, VERSION} from '#angular/core'
import {BrowserModule} from '#angular/platform-browser'
import 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
#Component({
selector: 'my-app',
template: `
<button (click)="previousWeek()">Prev Week</button>
<div>{{dates[0]}}</div>
<div>{{dates[1]}}</div>
<div>{{dates[2]}}</div>
`,
})
export class App {
name:string;
dates: Date[];
public $datesSource: Observable<Date[]>;
private datesSource: Subject<Date[]>;
constructor() {
this.datesSource = new Subject<Date[]>();
this.datesSource$ = this.getDatesWithObservable();
this.datesSource$.subscribe((dates) => {
console.log(dates);
this.dates = dates;
})
this.setDates(new Date());
}
setMonday(date: Date): Date {
const day = date.getDay() || 7;
if (day !== 1) {
date.setHours(-24 * (day - 1));
}
return date;
}
setDates(date: Date): void {
const dates = [
new Date(),
new Date(),
new Date(),
new Date(),
new Date(),
new Date(),
new Date()
];
const monday = this.setMonday(date);
dates[0] = monday;
const mondayDate = monday.getTime();
dates.forEach((date, idx) => {
console.log(idx);
date.setTime(monday.getTime() + (idx * 24 * 60 * 60 * 1000));
});
this.addDates(dates);
}
addDates(dates: Date[]): void {
this.datesSource.next(dates);
}
getDatesWithObservable(): Observable<Date[]> {
return this.datesSource.asObservable();
}
previousWeek(): void {
const day = this.dates[0].getDay() || 7;
const lastWeek = this.dates[0];
const days = 7;
lastWeek.setTime(lastWeek.getTime() - (days * 24 * 60 * 60 * 1000));
this.setDates(lastWeek);
}
}
try this , i commented the line in the middle and it's working, can you check:
const monday = this.setMonday(date);
//dates[0] = monday;
const mondayDate = monday.getTime();

Resources