/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see .
*/
import i18n from 'i18n-js';
import type {DeviceType} from '../screens/Amicale/Equipment/EquipmentListScreen';
import DateManager from '../managers/DateManager';
import type {MarkedDatesObjectType} from '../screens/Amicale/Equipment/EquipmentRentScreen';
import {PeriodMarking} from 'react-native-calendars';
/**
* Gets the current day at midnight
*
* @returns {Date}
*/
export function getCurrentDay(): Date {
const today = new Date(Date.now());
today.setUTCHours(0, 0, 0, 0);
return today;
}
/**
* Returns the ISO date format (without the time)
*
* @param date The date to recover the ISO format from
* @returns {*}
*/
export function getISODate(date: Date): string {
return date.toISOString().split('T')[0];
}
/**
* Finds if the given equipment is available today
*
* @param item
* @returns {boolean}
*/
export function isEquipmentAvailable(item: DeviceType): boolean {
let isAvailable = true;
const today = getCurrentDay();
const dates = item.booked_at;
dates.forEach((date: {begin: string; end: string}) => {
const start = new Date(date.begin);
const end = new Date(date.end);
if (!(today < start || today > end)) {
isAvailable = false;
}
});
return isAvailable;
}
/**
* Finds the first date free for booking.
*
* @param item
* @returns {Date}
*/
export function getFirstEquipmentAvailability(item: DeviceType): Date {
let firstAvailability = getCurrentDay();
const dates = item.booked_at;
dates.forEach((date: {begin: string; end: string}) => {
const start = new Date(date.begin);
const end = new Date(date.end);
end.setDate(end.getDate() + 1);
if (firstAvailability >= start) {
firstAvailability = end;
}
});
return firstAvailability;
}
/**
* Gets a translated string representing the given date, relative to the current date
*
* @param date The date to translate
*/
export function getRelativeDateString(date: Date): string {
const today = getCurrentDay();
const yearDelta = date.getUTCFullYear() - today.getUTCFullYear();
const monthDelta = date.getUTCMonth() - today.getUTCMonth();
const dayDelta = date.getUTCDate() - today.getUTCDate();
let translatedString = i18n.t('screens.equipment.today');
if (yearDelta > 0) {
translatedString = i18n.t('screens.equipment.otherYear', {
date: date.getDate(),
month: DateManager.getInstance().getMonthsOfYear()[date.getMonth()],
year: date.getFullYear(),
});
} else if (monthDelta > 0) {
translatedString = i18n.t('screens.equipment.otherMonth', {
date: date.getDate(),
month: DateManager.getInstance().getMonthsOfYear()[date.getMonth()],
});
} else if (dayDelta > 1) {
translatedString = i18n.t('screens.equipment.thisMonth', {
date: date.getDate(),
});
} else if (dayDelta === 1) {
translatedString = i18n.t('screens.equipment.tomorrow');
}
return translatedString;
}
/**
* Gets a valid array of dates between the given start and end, for the corresponding item.
* I stops at the first booked date encountered before the end.
* It assumes the range start and end are valid.
*
* Start and End specify the range's direction.
* If start < end, it will begin at Start and stop if it encounters any booked date before reaching End.
* If start > end, it will begin at End and stop if it encounters any booked dates before reaching Start.
*
* @param start Range start
* @param end Range end
* @param item Item containing booked dates to look for
* @returns {[string]}
*/
export function getValidRange(
start: Date,
end: Date,
item: DeviceType | null,
): Array {
const direction = start <= end ? 1 : -1;
let limit = new Date(end);
limit.setDate(limit.getDate() + direction); // Limit is excluded, but we want to include range end
if (item != null) {
if (direction === 1) {
for (let i = 0; i < item.booked_at.length; i += 1) {
const bookLimit = new Date(item.booked_at[i].begin);
if (start < bookLimit && limit > bookLimit) {
limit = bookLimit;
break;
}
}
} else {
for (let i = item.booked_at.length - 1; i >= 0; i -= 1) {
const bookLimit = new Date(item.booked_at[i].end);
if (start > bookLimit && limit < bookLimit) {
limit = bookLimit;
break;
}
}
}
}
const validRange = [];
const date = new Date(start);
while (
(direction === 1 && date < limit) ||
(direction === -1 && date > limit)
) {
if (direction === 1) {
validRange.push(getISODate(date));
} else {
validRange.unshift(getISODate(date));
}
date.setDate(date.getDate() + direction);
}
return validRange;
}
/**
* Generates calendar compatible marked dates from the given array
*
*
* @param isSelection True to use user selection color, false to use disabled color
* @param theme The current App theme to get colors from
* @param range The range to mark dates for
* @returns {{}}
*/
export function generateMarkedDates(
isSelection: boolean,
theme: ReactNativePaper.Theme,
range: Array,
): MarkedDatesObjectType {
const markedDates: {
[key: string]: PeriodMarking;
} = {};
for (let i = 0; i < range.length; i += 1) {
const isStart = i === 0;
const isEnd = i === range.length - 1;
let color;
if (isSelection && (isStart || isEnd)) {
color = theme.colors.primary;
} else if (isSelection) {
color = theme.colors.danger;
} else {
color = theme.colors.textDisabled;
}
markedDates[range[i]] = {
startingDay: isStart,
endingDay: isEnd,
color,
};
}
return markedDates;
}