import { Api, api as defaultApi } from '../api' import { Flat } from '../flats' import { ProfileUrl } from '../profiles' import { parseDate } from '../utils/date' import { fetch } from '../utils/fetch' import { filter } from '../utils/filter' import { collection, JsonHalCollection, JsonHalObject, object, } from '../utils/jsonHal' // ===== Interfaces this file handles export interface Appointment { ID: string cancelationReason: string canceled: boolean date: Date // should be Date-only description: string expired: boolean flat: Flat maxInviteeCount: number readonly currentInviteeCount: number readonly defaultMaxInviteeCount: number showContactInformation: boolean userProfiles: ProfileUrl[] } // ====== Reolver - Function Parameters export interface FindAppointmentsByFlat { flatId: string } export interface FindAppointmentsByProfile { profileId: string } export interface FindAppointment { appointmentId: string } // ====== Resolver - Responses export interface AppointmentResponse { headers: Headers data: Appointment } export interface AppointmentsResponse { headers: Headers data: Appointment[] } /* tslint:disable:max-line-length */ const urls = { findAppointment: ':apiUrl/flatInvitations/:appointmentId', findAppointmentsByFlat: ':apiUrl/flatInvitations/search/findByFlatId?flatId=:flatId&projection=appointmentFlatProjection&size=100', findAppointmentsByProfile: ':apiUrl/flatInvitations/search/findByUserProfileId?userProfileId=:profileId', } /* tslint:enable:max-line-length */ /** converts an incoming appointment resource into a standard appointment */ export const convertAppointment = (data: any): Appointment => { const appointment = { ...data, date: parseDate(data.date), } return appointment } /** converts an appointment response to a jsonHal */ export const singleAppointmentResponse = async (response: Response): Promise => { const data = await response.json() return { ...object(data), data: convertAppointment(data), headers: response.headers, } } /** converts an appointment response to a jsonHal list */ export const multiAppointmentResponse = async ( response: Response, ): Promise => { const data = await response.json() const embedded = (data._embedded && data._embedded[Object.keys(data._embedded)[0]]) || [] return { ...collection(data, embedded.length), data: embedded.map(convertAppointment), headers: response.headers, } } /** Fetches the appointments for a given flat */ export const findAppointmentsByFlat = async (locals: FindAppointmentsByFlat, api: Api = defaultApi) => { const url = urls.findAppointmentsByFlat .replace(':apiUrl', api.apiUrl) .replace(':flatId', locals.flatId) return multiAppointmentResponse(await fetch(url, api)) } /** Fetches the appointments for a given profile */ export const findAppointmentsByProfile = async (locals: FindAppointmentsByProfile, api: Api = defaultApi) => { const url = urls.findAppointmentsByProfile .replace(':apiUrl', api.apiUrl) .replace(':profileId', locals.profileId) return multiAppointmentResponse(await fetch(url, api)) } /** Fetches on specific appointment */ export const findAppointment = async (locals: FindAppointment, api: Api = defaultApi) => { const url = urls.findAppointment .replace(':apiUrl', api.apiUrl) .replace(':appointmentId', locals.appointmentId) return singleAppointmentResponse(await fetch(url, api)) } /** checks if an appointment is after a given point in time */ const isAppointmentAfterDate = (appointment: Appointment, date: Date = new Date()) => parseDate(appointment.date) > date /** checks if an appointment has a slot open */ const hasAppointmentFreeSlots = (appointment: Appointment) => appointment.maxInviteeCount === -1 || appointment.currentInviteeCount < appointment.maxInviteeCount /** factory to generate functions that check if an appointment connects to a specific flat */ const appointmentForFlatFilter = (flat: Flat) => (appointment: Appointment) => appointment.flat.id === flat.id /** * Expect a list of appointments to check for validity agains the users given appointments and the flat * @param appointments List of appointments to check * @param validAppointments List of accepted appointments of an user * @param flat FlatUrl of the list of appointments */ export const filterValidAppointments = ( appointments: Appointment[], validAppointments: Appointment[], flat: Flat, ): Appointment[] => { const flatFilter = appointmentForFlatFilter(flat) const flatAppointments = filter(validAppointments, flatFilter, isAppointmentAfterDate) // all appointments found in the valid appointments should be in the appointments list if (flatAppointments.length > 0) return flatAppointments // filter the appointments by validation rules for tenants return filter(appointments, flatFilter, isAppointmentAfterDate, hasAppointmentFreeSlots) }