Application Android et IOS pour l'amicale des élèves
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

EquipmentBooking.ts 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. * Copyright (c) 2019 - 2020 Arnaud Vergnet.
  3. *
  4. * This file is part of Campus INSAT.
  5. *
  6. * Campus INSAT is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Campus INSAT is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. import i18n from 'i18n-js';
  20. import type {DeviceType} from '../screens/Amicale/Equipment/EquipmentListScreen';
  21. import DateManager from '../managers/DateManager';
  22. import type {MarkedDatesObjectType} from '../screens/Amicale/Equipment/EquipmentRentScreen';
  23. import {PeriodMarking} from 'react-native-calendars';
  24. /**
  25. * Gets the current day at midnight
  26. *
  27. * @returns {Date}
  28. */
  29. export function getCurrentDay(): Date {
  30. const today = new Date(Date.now());
  31. today.setUTCHours(0, 0, 0, 0);
  32. return today;
  33. }
  34. /**
  35. * Returns the ISO date format (without the time)
  36. *
  37. * @param date The date to recover the ISO format from
  38. * @returns {*}
  39. */
  40. export function getISODate(date: Date): string {
  41. return date.toISOString().split('T')[0];
  42. }
  43. /**
  44. * Finds if the given equipment is available today
  45. *
  46. * @param item
  47. * @returns {boolean}
  48. */
  49. export function isEquipmentAvailable(item: DeviceType): boolean {
  50. let isAvailable = true;
  51. const today = getCurrentDay();
  52. const dates = item.booked_at;
  53. dates.forEach((date: {begin: string; end: string}) => {
  54. const start = new Date(date.begin);
  55. const end = new Date(date.end);
  56. if (!(today < start || today > end)) {
  57. isAvailable = false;
  58. }
  59. });
  60. return isAvailable;
  61. }
  62. /**
  63. * Finds the first date free for booking.
  64. *
  65. * @param item
  66. * @returns {Date}
  67. */
  68. export function getFirstEquipmentAvailability(item: DeviceType): Date {
  69. let firstAvailability = getCurrentDay();
  70. const dates = item.booked_at;
  71. dates.forEach((date: {begin: string; end: string}) => {
  72. const start = new Date(date.begin);
  73. const end = new Date(date.end);
  74. end.setDate(end.getDate() + 1);
  75. if (firstAvailability >= start) {
  76. firstAvailability = end;
  77. }
  78. });
  79. return firstAvailability;
  80. }
  81. /**
  82. * Gets a translated string representing the given date, relative to the current date
  83. *
  84. * @param date The date to translate
  85. */
  86. export function getRelativeDateString(date: Date): string {
  87. const today = getCurrentDay();
  88. const yearDelta = date.getUTCFullYear() - today.getUTCFullYear();
  89. const monthDelta = date.getUTCMonth() - today.getUTCMonth();
  90. const dayDelta = date.getUTCDate() - today.getUTCDate();
  91. let translatedString = i18n.t('screens.equipment.today');
  92. if (yearDelta > 0) {
  93. translatedString = i18n.t('screens.equipment.otherYear', {
  94. date: date.getDate(),
  95. month: DateManager.getInstance().getMonthsOfYear()[date.getMonth()],
  96. year: date.getFullYear(),
  97. });
  98. } else if (monthDelta > 0) {
  99. translatedString = i18n.t('screens.equipment.otherMonth', {
  100. date: date.getDate(),
  101. month: DateManager.getInstance().getMonthsOfYear()[date.getMonth()],
  102. });
  103. } else if (dayDelta > 1) {
  104. translatedString = i18n.t('screens.equipment.thisMonth', {
  105. date: date.getDate(),
  106. });
  107. } else if (dayDelta === 1) {
  108. translatedString = i18n.t('screens.equipment.tomorrow');
  109. }
  110. return translatedString;
  111. }
  112. /**
  113. * Gets a valid array of dates between the given start and end, for the corresponding item.
  114. * I stops at the first booked date encountered before the end.
  115. * It assumes the range start and end are valid.
  116. *
  117. * Start and End specify the range's direction.
  118. * If start < end, it will begin at Start and stop if it encounters any booked date before reaching End.
  119. * If start > end, it will begin at End and stop if it encounters any booked dates before reaching Start.
  120. *
  121. * @param start Range start
  122. * @param end Range end
  123. * @param item Item containing booked dates to look for
  124. * @returns {[string]}
  125. */
  126. export function getValidRange(
  127. start: Date,
  128. end: Date,
  129. item: DeviceType | null,
  130. ): Array<string> {
  131. const direction = start <= end ? 1 : -1;
  132. let limit = new Date(end);
  133. limit.setDate(limit.getDate() + direction); // Limit is excluded, but we want to include range end
  134. if (item != null) {
  135. if (direction === 1) {
  136. for (let i = 0; i < item.booked_at.length; i += 1) {
  137. const bookLimit = new Date(item.booked_at[i].begin);
  138. if (start < bookLimit && limit > bookLimit) {
  139. limit = bookLimit;
  140. break;
  141. }
  142. }
  143. } else {
  144. for (let i = item.booked_at.length - 1; i >= 0; i -= 1) {
  145. const bookLimit = new Date(item.booked_at[i].end);
  146. if (start > bookLimit && limit < bookLimit) {
  147. limit = bookLimit;
  148. break;
  149. }
  150. }
  151. }
  152. }
  153. const validRange = [];
  154. const date = new Date(start);
  155. while (
  156. (direction === 1 && date < limit) ||
  157. (direction === -1 && date > limit)
  158. ) {
  159. if (direction === 1) {
  160. validRange.push(getISODate(date));
  161. } else {
  162. validRange.unshift(getISODate(date));
  163. }
  164. date.setDate(date.getDate() + direction);
  165. }
  166. return validRange;
  167. }
  168. /**
  169. * Generates calendar compatible marked dates from the given array
  170. *
  171. *
  172. * @param isSelection True to use user selection color, false to use disabled color
  173. * @param theme The current App theme to get colors from
  174. * @param range The range to mark dates for
  175. * @returns {{}}
  176. */
  177. export function generateMarkedDates(
  178. isSelection: boolean,
  179. theme: ReactNativePaper.Theme,
  180. range: Array<string>,
  181. ): MarkedDatesObjectType {
  182. const markedDates: {
  183. [key: string]: PeriodMarking;
  184. } = {};
  185. for (let i = 0; i < range.length; i += 1) {
  186. const isStart = i === 0;
  187. const isEnd = i === range.length - 1;
  188. let color;
  189. if (isSelection && (isStart || isEnd)) {
  190. color = theme.colors.primary;
  191. } else if (isSelection) {
  192. color = theme.colors.danger;
  193. } else {
  194. color = theme.colors.textDisabled;
  195. }
  196. markedDates[range[i]] = {
  197. startingDay: isStart,
  198. endingDay: isEnd,
  199. color,
  200. };
  201. }
  202. return markedDates;
  203. }