Advertisement
Guest User

Untitled

a guest
Aug 24th, 2019
666
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.15 KB | None | 0 0
  1. // .. imports
  2.  
  3. export class ScheduleComponent implements OnInit, CanNavigateAway {
  4. public days = [];
  5. public date: Date = new Date();
  6. public slotsCount: number = 0;
  7. public times = [];
  8. public slots = [];
  9. public boardHeight = 500;
  10. public status: string;
  11. public infoStep: number = 0;
  12. public readonly RATE_MODULES = RATE_MODULES;
  13. public rateButtonTitle = {
  14. yes: 'I like it!',
  15. ok: 'Not sure'
  16. };
  17.  
  18. private isActive: boolean = false;
  19. private startSlot?: number;
  20. private startTime?: number;
  21. private provider: Provider;
  22. private appointments: Appointment[];
  23. private schedule: Schedule;
  24. private headerHeight = 221;
  25. private headerFooterHeight = 298;
  26. private newDay;
  27. private newUrl: string;
  28. private confirmDialogConfig: MatDialogConfig;
  29. @ViewChild('sidebar') private leftSidebar: ElementRef;
  30.  
  31. constructor(
  32. private storageService: StorageService,
  33. private providerService: ProviderService,
  34. private appointmentService: AppointmentService,
  35. private scheduleService: ScheduleService,
  36. private intercomService: IntercomService,
  37. public dialog: MatDialog,
  38. public router: Router,
  39. public environment: AppConfig) {
  40. this.confirmDialogConfig = new MatDialogConfig();
  41. this.confirmDialogConfig.disableClose = true;
  42. }
  43.  
  44. public async ngOnInit() {
  45. let schedules;
  46. [this.provider, this.appointments, schedules] = await Promise.all([
  47. this.providerService.getProvider(),
  48. this.appointmentService.getProviderAppointments(this.date),
  49. this.scheduleService.getProviderSchedule()
  50. ]);
  51. this.initSchedule(schedules);
  52. this.initDays(schedules);
  53. this.initSlots();
  54. this.initTutorial();
  55. // to set the board directly inside the viewport
  56. this.boardHeight = window.innerHeight - this.headerHeight;
  57. }
  58.  
  59. public getDateString() {
  60. const dayName = stringUtils.getWeekDay(this.date);
  61. return `${dayName}, ${this.date.toLocaleDateString('en-us', {month: 'long'})}
  62. ${this.date.getDate()}, ${this.date.getFullYear()}`;
  63. }
  64.  
  65. public initSlots() {
  66. this.appointments = this.appointments.filter((a) => {
  67. return a.duration && a.status !== 'canceled' && a.status !== 'lateCanceled' &&
  68. !(a.status === 'failed' && a.failedAction === 'lateCanceled');
  69. });
  70. this.initTimes();
  71. const maxs = this.times.map((t) => {
  72. return t.appointments.length > t.freeSlots ? t.appointments.length : t.freeSlots;
  73. });
  74. this.slotsCount = Math.max.apply(null, maxs);
  75. if (!this.slotsCount) {
  76. this.slotsCount = 5;
  77. }
  78. this.slots = new Array(this.slotsCount);
  79. }
  80.  
  81. public changeSlotsCount() {
  82. this.slots = new Array(this.slotsCount);
  83. this.times.forEach((t) => {
  84. if (t.freeSlots > this.slotsCount) {
  85. t.freeSlots = this.slotsCount;
  86. this.changeStatus('save');
  87. }
  88. });
  89. }
  90.  
  91. public async selectDay(day) {
  92. if (!day.disabled) {
  93. if (this.status) {
  94. this.newDay = day;
  95. let dialogRef = this.dialog.open(ConfirmDialogComponent, this.confirmDialogConfig);
  96. dialogRef.componentInstance.caption =
  97. 'If you don’t save, your schedule changes will be lost.';
  98. dialogRef.afterClosed().subscribe((result) => {
  99. this.status = undefined;
  100. if (result) {
  101. this.saveScheduleSlots();
  102. }
  103. this.selectDay(this.newDay);
  104. this.changeStatus();
  105. });
  106. } else {
  107. this.date = day.date;
  108. let schedules;
  109. [this.appointments, schedules] = await Promise.all([
  110. this.appointmentService.getProviderAppointments(this.date),
  111. this.scheduleService.getProviderSchedule()
  112. ]);
  113. this.initSchedule(schedules);
  114. this.initSlots();
  115. }
  116. }
  117. }
  118.  
  119. public hoverIn(slotIndex, timeIndex) {
  120. if (!this.isActive) {
  121. this.startSlot = slotIndex;
  122. this.startTime = timeIndex;
  123. this.changePickedCells(false);
  124. this.changeCellState(slotIndex, timeIndex);
  125. }
  126. }
  127.  
  128. public selectStart(slotIndex, timeIndex) {
  129. this.isActive = true;
  130. this.startSlot = slotIndex;
  131. this.startTime = timeIndex;
  132. this.changeCellState(slotIndex, timeIndex);
  133. if (this.infoStep === 2) this.infoStep = 3;
  134. }
  135.  
  136. public selectEnd() {
  137. this.changePickedCells(true);
  138. this.isActive = false;
  139. this.startSlot = undefined;
  140. this.startTime = undefined;
  141. }
  142.  
  143. public cellOver(slotIndex, timeIndex) {
  144. if (this.isActive) {
  145. this.changePickedCells(false);
  146. this.changeCellState(slotIndex, timeIndex);
  147. }
  148. }
  149.  
  150. public changeCellState(slotIndex, timeIndex) {
  151. const index: number = this.startSlot > slotIndex ? this.startSlot : slotIndex;
  152. if (this.startTime === timeIndex) {
  153. this.times[timeIndex].picked = index + 1;
  154. } else {
  155. const [fromTime, toTime] = this.startTime > timeIndex ? [timeIndex, this.startTime] :
  156. [this.startTime, timeIndex];
  157. for (let t = fromTime; t <= toTime; t++) {
  158. this.times[t].picked = index + 1;
  159. }
  160. }
  161. }
  162.  
  163. public getCellContent(t) {
  164. const chunk = this.provider.publishStatus === 'virtual' ? 15 : 30;
  165. const endTime = t.time.clone().addMinutes(chunk);
  166. const result = `${t.freeSlots} at ${t.time.toString(false)}-${endTime.toString(false)}`;
  167. return result;
  168. }
  169.  
  170. public removeSlots(t) {
  171. t.freeSlots = 0;
  172. }
  173.  
  174. public changeStatus(status?: string) {
  175. this.status = status;
  176. switch (status) {
  177. case 'save':
  178. this.boardHeight = window.innerHeight - this.headerFooterHeight;
  179. this.intercomService.hide();
  180. break;
  181. case 'saving':
  182. this.saveScheduleSlots();
  183. this.intercomService.hide();
  184. break;
  185. case 'saved': setTimeout(() => {
  186. this.changeStatus();
  187. this.intercomService.show();
  188. }, 500); break;
  189. default: this.boardHeight = window.innerHeight - this.headerHeight;
  190. }
  191. }
  192.  
  193. public canNavigateAway(nextUrl: string): boolean {
  194. if (this.status) {
  195. let dialogRef = this.dialog.open(ConfirmDialogComponent, this.confirmDialogConfig);
  196. dialogRef.componentInstance.caption =
  197. 'If you don’t save, your schedule changes will be lost.';
  198. dialogRef.afterClosed().subscribe((result) => {
  199. this.changeStatus();
  200. if (result) {
  201. this.saveScheduleSlots();
  202. }
  203. this.router.navigate([nextUrl]);
  204. });
  205. return false;
  206. }
  207. return true;
  208. }
  209.  
  210. public onScroll(event) {
  211. this.leftSidebar.nativeElement.scrollTop = event.target.scrollTop;
  212. }
  213.  
  214. public nextStep() {
  215. this.infoStep++;
  216. if (this.infoStep > 3) {
  217. this.infoStep = 0;
  218. const passedArray = this.storageService.getConfigItem('scheduleTutorialPassed') || [];
  219. passedArray.push(this.provider.id);
  220. this.storageService.setConfigItem('scheduleTutorialPassed', passedArray);
  221. }
  222. }
  223.  
  224. // ----- window events -----
  225.  
  226. @HostListener('window:resize', ['$event'])
  227. public onResize(event) {
  228. this.boardHeight = window.innerHeight -
  229. (this.status ? this.headerFooterHeight : this.headerHeight);
  230. }
  231.  
  232. @HostListener('window:beforeunload', ['$event'])
  233. public beforeUnload(event) {
  234. return !this.status;
  235. }
  236.  
  237. // ----- private functions -----
  238.  
  239. private initTutorial() {
  240. const passedArray = this.storageService.getConfigItem('scheduleTutorialPassed') || [];
  241. if (passedArray.indexOf(this.provider.id) === -1) {
  242. if (!this.schedule || !this.schedule.slots || !this.schedule.slots.length) {
  243. this.infoStep = 1;
  244. } else {
  245. passedArray.push(this.provider.id);
  246. this.storageService.setConfigItem('scheduleTutorialPassed', passedArray);
  247. }
  248. }
  249. }
  250.  
  251. private initDays(schedules) {
  252. for (let i = 0; i < 7; i++) {
  253. this.days.push(this.initDayByOffest(i, schedules));
  254. }
  255. if (this.schedule.dayoff) {
  256. const availableDate = this.days.find((d) => !d.disabled);
  257. if (availableDate) {
  258. this.selectDay(availableDate);
  259. }
  260. }
  261. }
  262.  
  263. private initDayByOffest(offset: number, schedules: Schedule[]) {
  264. const data: any = {};
  265. const date: Date = new Date();
  266. date.setDate(date.getDate() + offset);
  267. data.day = stringUtils.getWeekDay(date);
  268. data.dateString = `${date.getMonth() + 1}/${date.getDate()}`;
  269. data.date = date;
  270. if (schedules) {
  271. const schedule = schedules.find((s) => s.weekDay === date.getDay());
  272. if (schedule) {
  273. data.disabled = schedule.dayoff;
  274. }
  275. }
  276. return data;
  277. }
  278.  
  279. private initTimes() {
  280. this.times = [];
  281. const chunk = this.provider.publishStatus === 'virtual' ? 15 : 30;
  282. const endDate = new Time(this.schedule.end.hours, this.schedule.end.minutes).getDate();
  283. for (let step = new Time(this.schedule.start.hours, this.schedule.start.minutes);
  284. step.getDate() < endDate; step.addMinutes(chunk)) {
  285. const time = {
  286. id: null,
  287. time: step.clone(),
  288. appointments: [],
  289. freeSlots: 0
  290. };
  291. const schedule = this.schedule.slots.find((s) => time.time.isEqual(s.time));
  292. if (schedule) {
  293. time.freeSlots = schedule.slotsCount;
  294. }
  295. const appointments = this.appointments
  296. .filter((a) => {
  297. const serviceDate = new Date(a.serviceDate);
  298. const serviceTime = new Time(serviceDate.getHours(), serviceDate.getMinutes());
  299. return time.time.isEqual(serviceTime);
  300. });
  301. if (appointments && appointments.length) {
  302. appointments.forEach((a) => {
  303. time.appointments.push({
  304. service: a.service,
  305. name: `${a.client.firstName} ${a.client.lastName}`,
  306. duration: a.duration / chunk
  307. });
  308. });
  309. }
  310. this.times.push(time);
  311. }
  312. for (let i = 1; i < this.times.length; i++) {
  313. const prevApps = this.times[i - 1].appointments;
  314. const currApps = this.times[i].appointments;
  315. if (prevApps && prevApps.length) {
  316. for (let a = 0; a < prevApps.length; a++) {
  317. if (prevApps[a] && prevApps[a].duration > 1) {
  318. const prolongedApp = { duration: prevApps[a].duration - 1 };
  319. if (currApps.length < a) {
  320. currApps[a] = prolongedApp;
  321. } else {
  322. currApps.splice(a, 0, prolongedApp);
  323. }
  324. }
  325. }
  326. }
  327. }
  328. }
  329.  
  330. private changePickedCells(isFinish: boolean) {
  331. this.times.forEach((t) => {
  332. if (isFinish && t.picked && t.picked > t.freeSlots) {
  333. t.freeSlots = t.picked;
  334. }
  335. t.picked = 0;
  336. });
  337. if (isFinish) {
  338. this.changeStatus('save');
  339. }
  340. }
  341.  
  342. private async initSchedule(schedules) {
  343. const dayNum = this.date.getDay();
  344. this.schedule = schedules.find((s) => s.weekDay === dayNum);
  345. if (!this.schedule) {
  346. this.schedule = new Schedule();
  347. this.schedule.start = new Time(9, 0);
  348. this.schedule.end = new Time(18, 30);
  349. this.schedule.providerId = this.provider.id;
  350. this.schedule.weekDay = this.date.getDay();
  351. this.schedule.slots = [];
  352.  
  353. this.schedule = await this.scheduleService.saveSchedule(this.schedule);
  354. }
  355. }
  356.  
  357. private async saveScheduleSlots() {
  358. let result = [];
  359. result = this.times.filter((t) => t.freeSlots).map((t) => {
  360. return {
  361. time: t.time,
  362. slotsCount: t.freeSlots
  363. };
  364. });
  365. this.schedule.slots = result;
  366. await this.scheduleService.updateSchedule(this.schedule);
  367. this.changeStatus('saved');
  368. }
  369.  
  370. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement