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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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. /**
  24. * Gets the current day at midnight
  25. *
  26. * @returns {Date}
  27. */
  28. export function getCurrentDay(): Date {
  29. const today = new Date(Date.now());
  30. today.setUTCHours(0, 0, 0, 0);
  31. return today;
  32. }
  33. /**
  34. * Returns the ISO date format (without the time)
  35. *
  36. * @param date The date to recover the ISO format from
  37. * @returns {*}
  38. */
  39. export function getISODate(date: Date): string {
  40. return date.toISOString().split('T')[0];
  41. }
  42. /**
  43. * Finds if the given equipment is available today
  44. *
  45. * @param item
  46. * @returns {boolean}
  47. */
  48. export function isEquipmentAvailable(item: DeviceType): boolean {
  49. let isAvailable = true;
  50. const today = getCurrentDay();
  51. const dates = item.booked_at;
  52. dates.forEach((date: {begin: string; end: string}) => {
  53. const start = new Date(date.begin);
  54. const end = new Date(date.end);
  55. if (!(today < start || today > end)) {
  56. isAvailable = false;
  57. }
  58. });
  59. return isAvailable;
  60. }
  61. /**
  62. * Finds the first date free for booking.
  63. *
  64. * @param item
  65. * @returns {Date}
  66. */
  67. export function getFirstEquipmentAvailability(item: DeviceType): Date {
  68. let firstAvailability = getCurrentDay();
  69. const dates = item.booked_at;
  70. dates.forEach((date: {begin: string; end: string}) => {
  71. const start = new Date(date.begin);
  72. const end = new Date(date.end);
  73. end.setDate(end.getDate() + 1);
  74. if (firstAvailability >= start) {
  75. firstAvailability = end;
  76. }
  77. });
  78. return firstAvailability;
  79. }
  80. /**
  81. * Gets a translated string representing the given date, relative to the current date
  82. *
  83. * @param date The date to translate
  84. */
  85. export function getRelativeDateString(date: Date): string {
  86. const today = getCurrentDay();
  87. const yearDelta = date.getUTCFullYear() - today.getUTCFullYear();
  88. const monthDelta = date.getUTCMonth() - today.getUTCMonth();
  89. const dayDelta = date.getUTCDate() - today.getUTCDate();
  90. let translatedString = i18n.t('screens.equipment.today');
  91. if (yearDelta > 0) {
  92. translatedString = i18n.t('screens.equipment.otherYear', {
  93. date: date.getDate(),
  94. month: DateManager.getInstance().getMonthsOfYear()[date.getMonth()],
  95. year: date.getFullYear(),
  96. });
  97. } else if (monthDelta > 0) {
  98. translatedString = i18n.t('screens.equipment.otherMonth', {
  99. date: date.getDate(),
  100. month: DateManager.getInstance().getMonthsOfYear()[date.getMonth()],
  101. });
  102. } else if (dayDelta > 1) {
  103. translatedString = i18n.t('screens.equipment.thisMonth', {
  104. date: date.getDate(),
  105. });
  106. } else if (dayDelta === 1) {
  107. translatedString = i18n.t('screens.equipment.tomorrow');
  108. }
  109. return translatedString;
  110. }
  111. /**
  112. * Gets a valid array of dates between the given start and end, for the corresponding item.
  113. * I stops at the first booked date encountered before the end.
  114. * It assumes the range start and end are valid.
  115. *
  116. * Start and End specify the range's direction.
  117. * If start < end, it will begin at Start and stop if it encounters any booked date before reaching End.
  118. * If start > end, it will begin at End and stop if it encounters any booked dates before reaching Start.
  119. *
  120. * @param start Range start
  121. * @param end Range end
  122. * @param item Item containing booked dates to look for
  123. * @returns {[string]}
  124. */
  125. export function getValidRange(
  126. start: Date,
  127. end: Date,
  128. item: DeviceType | null,
  129. ): Array<string> {
  130. const direction = start <= end ? 1 : -1;
  131. let limit = new Date(end);
  132. limit.setDate(limit.getDate() + direction); // Limit is excluded, but we want to include range end
  133. if (item != null) {
  134. if (direction === 1) {
  135. for (let i = 0; i < item.booked_at.length; i += 1) {
  136. const bookLimit = new Date(item.booked_at[i].begin);
  137. if (start < bookLimit && limit > bookLimit) {
  138. limit = bookLimit;
  139. break;
  140. }
  141. }
  142. } else {
  143. for (let i = item.booked_at.length - 1; i >= 0; i -= 1) {
  144. const bookLimit = new Date(item.booked_at[i].end);
  145. if (start > bookLimit && limit < bookLimit) {
  146. limit = bookLimit;
  147. break;
  148. }
  149. }
  150. }
  151. }
  152. const validRange = [];
  153. const date = new Date(start);
  154. while (
  155. (direction === 1 && date < limit) ||
  156. (direction === -1 && date > limit)
  157. ) {
  158. if (direction === 1) {
  159. validRange.push(getISODate(date));
  160. } else {
  161. validRange.unshift(getISODate(date));
  162. }
  163. date.setDate(date.getDate() + direction);
  164. }
  165. return validRange;
  166. }
  167. /**
  168. * Generates calendar compatible marked dates from the given array
  169. *
  170. *
  171. * @param isSelection True to use user selection color, false to use disabled color
  172. * @param theme The current App theme to get colors from
  173. * @param range The range to mark dates for
  174. * @returns {{}}
  175. */
  176. export function generateMarkedDates(
  177. isSelection: boolean,
  178. theme: ReactNativePaper.Theme,
  179. range: Array<string>,
  180. ): MarkedDatesObjectType {
  181. const markedDates: {
  182. [key: string]: {
  183. startingDay: boolean;
  184. endingDay: boolean;
  185. color: string;
  186. };
  187. } = {};
  188. for (let i = 0; i < range.length; i += 1) {
  189. const isStart = i === 0;
  190. const isEnd = i === range.length - 1;
  191. let color;
  192. if (isSelection && (isStart || isEnd)) {
  193. color = theme.colors.primary;
  194. } else if (isSelection) {
  195. color = theme.colors.danger;
  196. } else {
  197. color = theme.colors.textDisabled;
  198. }
  199. markedDates[range[i]] = {
  200. startingDay: isStart,
  201. endingDay: isEnd,
  202. color,
  203. };
  204. }
  205. return markedDates;
  206. }