loadMissing('user'); $user = $consultation->user; $locale = $user?->preferred_language ?? 'ar'; $startDateTime = Carbon::parse( $consultation->booking_date->format('Y-m-d').' '.$consultation->booking_time ); $duration = $consultation->duration ?? self::DEFAULT_DURATION_MINUTES; $endDateTime = $startDateTime->copy()->addMinutes($duration); $title = $locale === 'ar' ? 'استشارة مع مكتب ليبرا للمحاماة' : 'Consultation with Libra Law Firm'; $description = $this->buildDescription($consultation, $locale); $location = $this->getLocation($locale); $uid = sprintf('consultation-%d@libra.ps', $consultation->id); $ics = [ 'BEGIN:VCALENDAR', 'VERSION:2.0', 'PRODID:-//Libra Law Firm//Consultation Booking//EN', 'CALSCALE:GREGORIAN', 'METHOD:REQUEST', 'BEGIN:VTIMEZONE', 'TZID:Asia/Jerusalem', 'BEGIN:STANDARD', 'DTSTART:19701025T020000', 'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU', 'TZOFFSETFROM:+0300', 'TZOFFSETTO:+0200', 'END:STANDARD', 'BEGIN:DAYLIGHT', 'DTSTART:19700329T020000', 'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1FR', 'TZOFFSETFROM:+0200', 'TZOFFSETTO:+0300', 'END:DAYLIGHT', 'END:VTIMEZONE', 'BEGIN:VEVENT', 'UID:'.$uid, 'DTSTAMP:'.gmdate('Ymd\THis\Z'), 'DTSTART;TZID=Asia/Jerusalem:'.$startDateTime->format('Ymd\THis'), 'DTEND;TZID=Asia/Jerusalem:'.$endDateTime->format('Ymd\THis'), 'SUMMARY:'.$this->escapeIcs($title), 'DESCRIPTION:'.$this->escapeIcs($description), 'LOCATION:'.$this->escapeIcs($location), 'STATUS:CONFIRMED', 'SEQUENCE:0', 'BEGIN:VALARM', 'TRIGGER:-PT1H', 'ACTION:DISPLAY', 'DESCRIPTION:Reminder', 'END:VALARM', 'END:VEVENT', 'END:VCALENDAR', ]; return implode("\r\n", $ics); } /** * Build the event description based on locale. */ private function buildDescription(Consultation $consultation, string $locale): string { $lines = []; $type = $consultation->consultation_type?->value ?? 'free'; if ($locale === 'ar') { $lines[] = 'رقم الحجز: '.$consultation->id; $lines[] = 'نوع الاستشارة: '.($type === 'free' ? 'مجانية' : 'مدفوعة'); if ($type === 'paid' && $consultation->payment_amount) { $lines[] = 'المبلغ: '.number_format($consultation->payment_amount, 2).' شيكل'; } $lines[] = ''; $lines[] = 'للاستفسارات:'; $lines[] = 'مكتب ليبرا للمحاماة'; $lines[] = 'libra.ps'; } else { $lines[] = 'Booking Reference: '.$consultation->id; $lines[] = 'Consultation Type: '.ucfirst($type); if ($type === 'paid' && $consultation->payment_amount) { $lines[] = 'Amount: '.number_format($consultation->payment_amount, 2).' ILS'; } $lines[] = ''; $lines[] = 'For inquiries:'; $lines[] = 'Libra Law Firm'; $lines[] = 'libra.ps'; } return implode('\n', $lines); } /** * Get the office location based on locale. */ private function getLocation(string $locale): string { return config('libra.office_address.'.$locale, 'Libra Law Firm'); } /** * Escape special characters for ICS format. */ private function escapeIcs(string $text): string { // Order matters: backslash must be escaped first return str_replace( ['\\', ',', ';'], ['\\\\', '\,', '\;'], $text ); } /** * Generate a download response for the ICS file. */ public function generateDownloadResponse(Consultation $consultation): Response { $content = $this->generateIcs($consultation); $filename = sprintf( 'consultation-%s.ics', $consultation->booking_date->format('Y-m-d') ); return response($content) ->header('Content-Type', 'text/calendar; charset=utf-8') ->header('Content-Disposition', 'attachment; filename="'.$filename.'"'); } }