Untitled
unknown
plain_text
2 years ago
14 kB
8
Indexable
"use node"; import { PMSPlatform, Integration } from "../../types"; import { fetchCalendarForListingIdInRange as fetchHostawayCalendarForListingIdInRange } from "../integrations/hostaway"; import { fetchCalendarForListingIdInRange as fetchGuestyCalendarForListingIdInRange } from "../integrations/guesty"; import { internalAction } from "../../_generated/server"; import { Doc, Id } from "../../_generated/dataModel"; import { internal } from "../../_generated/api"; import { logSlackError } from "./slackLogger"; export const changeDateWithMonthDelta = ( dateString: string, delta: number ): string => { const date = new Date(dateString); date.setMonth(date.getMonth() + delta); const formatted = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate(); return formatted; }; export const changeDateWithDayDelta = ( dateString: string, delta: number ): string => { const date = new Date(dateString); date.setDate(date.getDate() + delta); const formatted = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate(); return formatted; }; export const getDateWithMonthDelta = (delta: number): string => { const date = new Date(); date.setMonth(date.getMonth() + delta); const formatted = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate(); return formatted; }; export const getCurrentDateString = () => { const today = new Date(); const date = today.getFullYear() + "-" + (today.getMonth() + 1) + "-" + today.getDate(); return date; }; function formatDateString(dateString: string): string { let parts = dateString.split("-"); // Ensure the year, month, and day parts exist if (parts.length !== 3) { throw new Error("Invalid date format"); } let [year, month, day] = parts; // Pad month and day with leading zero if necessary month = month.length === 1 ? `0${month}` : month; day = day.length === 1 ? `0${day}` : day; return `${year}-${month}-${day}`; } export const getAvailabilityResponseWithStartEnd = internalAction( async ( { runQuery }, { userId, listing, reservation, startDate, endDate, }: { userId: Id<"users">; listing: Doc<"listings">; reservation: Doc<"reservations">; startDate: string; endDate: string; } ): Promise<{ response: string; possible: boolean }> => { const pmsPlatform = listing?.pmsPlatform; const pmsIntegration: Integration | null = await runQuery( internal.integrations.getForUser, { userId, pmsPlatform: pmsPlatform as PMSPlatform, } ); if (!pmsIntegration) { throw new Error( `No integration found for ${pmsPlatform}. Please connect to ${pmsPlatform} first.` ); } let passedStartDate = startDate; let passedEndDate = endDate; // if there isn't a start date, // if there is an end date, set start date to 10 days before end date // else set start date to 1 month before today if (!startDate) passedStartDate = endDate ? changeDateWithDayDelta(endDate, -10) : getDateWithMonthDelta(-1); // if there isn't an end date, set end date to 10 days after start date if (!endDate) passedEndDate = changeDateWithDayDelta(startDate, 10); let calendar: any[] = []; // if call is gonna be invalid, swap dates if (new Date(passedStartDate) > new Date(passedEndDate)) { const temp = passedStartDate; passedStartDate = passedEndDate; passedEndDate = temp; } passedStartDate = formatDateString(passedStartDate); passedEndDate = formatDateString(passedEndDate); try { switch (pmsPlatform) { case PMSPlatform.HOSTAWAY: calendar = await fetchHostawayCalendarForListingIdInRange( pmsIntegration.accessToken, listing.listingId as number, passedStartDate, passedEndDate ); break; case PMSPlatform.HOSTFULLY: break; case PMSPlatform.GUESTY: calendar = await fetchGuestyCalendarForListingIdInRange( pmsIntegration.accessToken, listing.listingId as number, passedStartDate, passedEndDate ); calendar = calendar.map((item) => { return { ...item, isAvailable: item.status === "available" ? 1 : 0, }; }); break; default: break; } // const maxDate = new Date(Math.max(...dates.map(date => date.getTime()))); if (startDate && endDate) { return checkAvailabilityWithStartEnd( reservation, startDate, endDate, calendar ); } if (startDate && !endDate) { const reservationStart = new Date(reservation.arrivalDate); if ( new Date(startDate).getTime() === reservationStart.getTime() ) { return { response: `The requested date of ${startDate} is available.`, possible: true, }; } return checkSingleDateAvailability(startDate, calendar); } if (!startDate && endDate) { const reservationEnd = new Date(reservation.departureDate); if (new Date(endDate).getTime() === reservationEnd.getTime()) { return { response: `The requested date of ${endDate} is available.`, possible: true, }; } return checkSingleDateAvailability(endDate, calendar); } return { response: "", possible: false, }; } catch (e: any) { console.log(e); await logSlackError( e.message, "getAvailabilityResponseWithStartEnd" ); return { response: "", possible: false, }; } } ); export const getAvailabilityResponseWithSingleDate = internalAction( async ( { runQuery }, { userId, listing, date, request, }: { userId: Id<"users">; listing: Doc<"listings">; date: string; request: string; } ): Promise<{ response: string; possible: boolean }> => { const pmsPlatform = listing?.pmsPlatform; const pmsIntegration: Integration | null = await runQuery( internal.integrations.getForUser, { userId, pmsPlatform: pmsPlatform as PMSPlatform, } ); if (!pmsIntegration) { throw new Error( `No integration found for ${pmsPlatform}. Please connect to ${pmsPlatform} first.` ); } let calendar: any[] = []; const formattedStartDate = formatDateString(date); const formattedEndDate = formatDateString( changeDateWithDayDelta(date, 1) ); try { switch (pmsPlatform) { case PMSPlatform.HOSTAWAY: calendar = await fetchHostawayCalendarForListingIdInRange( pmsIntegration.accessToken, listing.listingId as number, formattedStartDate, formattedEndDate ); break; case PMSPlatform.HOSTFULLY: break; case PMSPlatform.GUESTY: calendar = await fetchGuestyCalendarForListingIdInRange( pmsIntegration.accessToken, listing.listingId as number, formattedStartDate, formattedEndDate ); calendar = calendar.map((item) => { return { ...item, isAvailable: item.status === "available" ? 1 : 0, }; }); break; default: break; } // Check dates if (!date) { return { response: `No requested date.`, possible: false }; } return checkSingleDateAvailability(date, calendar, request); } catch (e: any) { console.log(e); await logSlackError( e.message, "getAvailabilityResponseWithStartEnd" ); return { response: "", possible: false, }; } } ); function checkAvailabilityWithStartEnd( reservation: { arrivalDate: string; departureDate: string }, startDate: string, endDate: string, calendar: { date: string; isAvailable: number }[] ): { response: string; possible: boolean } { const reservationStart = new Date(reservation.arrivalDate); const reservationEnd = new Date(reservation.departureDate); const requestedStart = new Date(startDate); const requestedEnd = new Date(endDate); let intervalsToCheck: [Date, Date][] = []; if ( reservationStart.getTime() === requestedStart.getTime() && reservationEnd.getTime() === requestedEnd.getTime() ) { return { response: `The requested dates of ${startDate} to ${endDate} are available.`, possible: true, }; } // Define intervals to check based on conditions if (reservationStart.getTime() === requestedStart.getTime()) { intervalsToCheck.push([reservationEnd, requestedEnd]); } else if (reservationEnd.getTime() === requestedEnd.getTime()) { intervalsToCheck.push([requestedStart, reservationStart]); } else if (requestedStart < reservationStart) { if (requestedEnd < reservationStart) { intervalsToCheck.push([requestedStart, requestedEnd]); } else { intervalsToCheck.push([requestedStart, reservationStart]); if (requestedEnd >= reservationEnd) { intervalsToCheck.push([reservationEnd, requestedEnd]); } } } else { if (requestedEnd < reservationEnd) { return { response: `The requested dates of ${startDate} to ${endDate} are available.`, possible: true, }; } else { intervalsToCheck.push([reservationEnd, requestedEnd]); } } // Check intervals const isUnavailable = intervalsToCheck.some(([start, end]) => calendar.some( (item) => new Date(item.date) >= start && new Date(item.date) < end && item.isAvailable === 0 ) ); if (isUnavailable) { console.log( `The requested dates of ${startDate} to ${endDate} are not available.` ); return { response: `The requested dates of ${startDate} to ${endDate} are not available.`, possible: false, }; } console.log( `The requested dates of ${startDate} to ${endDate} are available.` ); return { response: `The requested dates of ${startDate} to ${endDate} are available.`, possible: true, }; } function checkSingleDateAvailability( date: string | null, calendar: { date: string; isAvailable: number }[], request?: string ): { response: string; possible: boolean } { if (!date) return { response: "No date provided.", possible: true }; const targetTime = new Date(date).getTime(); const isUnavailable = calendar.some( (item) => new Date(item.date).getTime() === targetTime && item.isAvailable === 0 ); if (isUnavailable) { console.log(`The requested date of ${date} is not available.`); return { response: request ? `The requested date of ${date} is not available for ${request}.` : `The requested date of ${date} is not available.`, possible: false, }; } console.log(`The requested date of ${date} is available.`); return { response: request ? `The requested date of ${date} is available for ${request}.` : `The requested date of ${date} is available. No adjacent date was provided.`, possible: true, }; }
Editor is loading...
Leave a Comment