get('proIds')); $start = $request->get('start'); $end = $request->get('end'); $clientId = $request->get('clientId'); $timeZone = $request->get('timeZone'); // get appointments $appointments = Appointment ::where('status', '!=', 'COMPLETED') ->where('status', '!=', 'CANCELLED') ->where('start_time', '>=', $start) ->where('start_time', '<=', $end) ->where(function ($query) use ($proIds, $clientId) { $query ->whereIn('pro_id', $proIds) ->orWhere('client_id', '=', $clientId); }) ->get(); $events = []; foreach ($appointments as $appointment) { $events[] = [ "type" => "appointment", "title" => ($appointment->client->id != $clientId ? '* ' : '') . $appointment->pro->displayName(), "_title" => $appointment->title, "description" => $appointment->description, "clientName" => $appointment->client->displayName(), "appointmentUid" => $appointment->uid, "clientUid" => $appointment->client->uid, "proId" => $appointment->pro->id, "proUid" => $appointment->pro->uid, "start" => $this->convertToTimezone($appointment->start_time, $timeZone), "end" => $this->convertToTimezone($appointment->end_time, $timeZone), "clientOnly" => !in_array($appointment->pro->id, $proIds), "otherClient" => ($appointment->client->id != $clientId), "editable" => true ]; } // get availability $genAvail = ProGeneralAvailability ::where('is_cancelled', false) ->whereIn('pro_id', $proIds) ->get(); $specAvail = ProSpecificAvailability ::where('is_cancelled', false) ->whereIn('pro_id', $proIds) ->where(function ($query) use ($start, $end) { $query ->where(function ($query2) use ($start, $end) { $query2 ->where('start_time', '>=', $start) ->where('start_time', '<=', $end); }) ->orWhere(function ($query2) use ($start, $end) { $query2 ->where('end_time', '>=', $start) ->where('end_time', '<=', $end); }); }) ->get(); $specUnavail = ProSpecificUnavailability ::where('is_cancelled', false) ->whereIn('pro_id', $proIds) ->where(function ($query) use ($start, $end) { $query ->where(function ($query2) use ($start, $end) { $query2 ->where('start_time', '>=', $start) ->where('start_time', '<=', $end); }) ->orWhere(function ($query2) use ($start, $end) { $query2 ->where('end_time', '>=', $start) ->where('end_time', '<=', $end); }); }) ->get(); // logic // 1. enumerate days between start and end (inclusive) // 2. for each pro // 3. calculate pairs of start-end of availability // 1. enumerate days between start and end (inclusive) $phpTZ = $this->appTZtoPHPTZ($timeZone); $startDate = new \DateTime($start, new \DateTimeZone($phpTZ)); $endDate = new \DateTime($end, new \DateTimeZone($phpTZ)); $period = new \DatePeriod($startDate, \DateInterval::createFromDateString('1 day'), $endDate); $days = []; foreach ($period as $day) { $days[] = [ "day" => strtoupper($day->format("l")), // SUNDAY, etc. "date" => $day->format("Y-m-d"), // 2020-10-04, etc. ]; } foreach ($proIds as $proId) { $pro = Pro::where('id', $proId)->first(); $proGenAvail = $genAvail->filter(function ($record) use ($proId) { return $record->pro_id == $proId; }); foreach ($days as $day) { $proGenAvailForTheDay = $proGenAvail->filter(function ($record) use ($day) { return $record->day_of_week === $day["day"]; }); if(count($proGenAvailForTheDay)) { foreach ($proGenAvailForTheDay as $ga) { $gaStart = new \DateTime($day["date"], new \DateTimeZone($phpTZ)); $parts = explode(":", $ga->start_time); $gaStart->setTime(intval($parts[0]), intval($parts[1]), intval($parts[2])); $gaEnd = new \DateTime($day["date"], new \DateTimeZone($phpTZ)); $parts = explode(":", $ga->end_time); $gaEnd->setTime(intval($parts[0]), intval($parts[1]), intval($parts[2])); $events[] = [ "type" => "availability", "title" => $pro->displayName(), "proId" => $pro->id, "proUid" => $pro->uid, "start" => $gaStart->format('Y-m-d H:i:s'), "end" => $gaEnd->format('Y-m-d H:i:s'), "editable" => false ]; } } // TODO: add spec avail // TODO: subtract spec unavail } } return json_encode($events); } private function convertToTimezone($_dateTime, $_targetTimezone, $_sourceTimezone = 'UTC', $_returnRaw = false) { if(!$_dateTime) return $_dateTime; $date = new \DateTime($_dateTime, new \DateTimeZone($_sourceTimezone)); $date->setTimezone(new \DateTimeZone($this->appTZtoPHPTZ($_targetTimezone))); return $_returnRaw ? $date : $date->format('Y-m-d H:i:s'); } private function appTZtoPHPTZ($_timezone) { switch($_timezone) { case 'ALASKA': $timezone = "US/Alaska"; break; case 'CENTRAL': $timezone = "US/Central"; break; case 'HAWAII': $timezone = "US/Hawaii"; break; case 'MOUNTAIN': $timezone = "US/Mountain"; break; case 'PACIFIC': $timezone = "US/Pacific"; break; case 'PUERTO_RICO': $timezone = "America/Puerto_Rico"; break; default: $timezone = "US/Eastern"; break; } return $timezone; } }