PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 2.5.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v2.5.0
2.5.0 2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 All 34 releases
← All changes | app/Services/Integrations/FluentCRM/FluentCrmInit.php +124 -83 1.7.1 → 2.5.0 View file →
@@ -2,9 +2,13 @@
2 2
3 3 namespace FluentBooking\App\Services\Integrations\FluentCRM;
4 4
5 5 use FluentBooking\App\Models\Booking;
6 +use FluentBooking\Framework\Support\Arr;
6 7 use FluentBooking\App\Services\DateTimeHelper;
8 +use FluentCrm\App\Models\Subscriber;
9 +use FluentCrm\App\Services\Html\TableBuilder;
10 +use FluentCrm\App\Services\PermissionManager as CrmPermissionManager;
7 11
8 12 class FluentCrmInit
9 13 {
10 14 public function __construct()
@@ -20,15 +24,10 @@
20 24 return $lists;
21 25 });
22 26 }
23 27
24 - /**
25 - * Register all the CRM integrations from here
26 - * @return void
27 - */
28 28 public function registerIntegrations()
29 29 {
30 - $this->addContactMenuSection();
31 30 $this->addAutomations();
32 31 }
33 32
34 33 public function registerHooks()
@@ -33,22 +32,11 @@
33 32
34 33 public function registerHooks()
35 34 {
36 35 add_filter('fluentcrm_profile_sections', [$this, 'addProfileSection'], 10, 1);
37 - add_filter('fluentcrm_get_form_submissions_fluent_booking', [$this, 'getScheduledMeetings'], 10, 2);
36 + add_filter('fluencrm_profile_section_fluent_booking', [$this, 'getProfileSection'], 10, 2);
38 37 }
39 38
40 - /**
41 - * load Assets for to Fluent CRM contact section
42 - * @return void
43 - */
44 - public function addContactMenuSection()
45 - {
46 - add_action('fluent_crm/global_appjs_loaded', function () {
47 - wp_enqueue_script('fluent_booking_in_crm', FLUENT_BOOKING_URL . 'assets/admin/fluent-crm-in-calendar.js', [], FLUENT_BOOKING_ASSETS_VERSION, true);
48 - });
49 - }
50 -
51 39 public function addAutomations()
52 40 {
53 41 new NewBookingTrigger();
54 42 new CancelBookingTrigger();
@@ -55,100 +43,153 @@
55 43 new BookingCompletedTrigger();
56 44 new BookingRescheduledTrigger();
57 45 }
58 46
59 - private function getSubscriberId($email)
60 - {
61 - $contact = FluentCrmApi('contacts')->getContact($email);
62 - return $contact ? $contact->id : null;
63 - }
64 -
65 47 public function addProfileSection($sections)
66 48 {
67 49 $sections['booking'] = [
68 - 'name' => 'booking',
50 + 'name' => 'fluentcrm_profile_extended',
69 51 'title' => __('Bookings', 'fluent-booking'),
70 - 'handler' => 'route'
52 + 'handler' => 'route',
53 + 'query' => [
54 + 'handler' => 'fluent_booking'
55 + ],
71 56 ];
72 57
73 58 return $sections;
74 59 }
75 60
76 - private function getActionUrl($meeting)
61 + public function getProfileSection($sections, Subscriber $contact)
77 62 {
78 - $url = admin_url('admin.php?page=fluent-booking#/scheduled-events?booking_id=' . $meeting->id);
63 + if (!CrmPermissionManager::currentUserCan('fcrm_read_contacts')) {
64 + return $sections;
65 + }
79 66
80 - $link = '<a target="_blank" href="' . esc_url($url) . '">' . 'view' . '</a>';
81 -
82 - return $link;
67 + $sections['heading'] = __('Bookings (Fluent Booking)', 'fluent-booking');
68 +
69 + $limit = (int) apply_filters('fluent_booking/crm_meetings_limit', 20);
70 + $limit = max(1, $limit);
71 +
72 + $email = strtolower(trim((string) $contact->email));
73 +
74 + $base = Booking::where('email', $email);
75 +
76 + $total = (clone $base)->count();
77 +
78 + $meetings = (clone $base)
79 + ->with(['slot', 'calendar', 'calendar.metas'])
80 + ->orderBy('start_time', 'DESC')
81 + ->limit($limit)
82 + ->get();
83 +
84 + $rows = [];
85 + $hostCache = [];
86 + foreach ($meetings as $meeting) {
87 + if (!$meeting->calendar || !$meeting->slot) {
88 + continue;
89 + }
90 + $cid = $meeting->calendar->id;
91 + if (!isset($hostCache[$cid])) {
92 + $hostCache[$cid] = $meeting->calendar->getAuthorProfile();
93 + }
94 +
95 + $rows[] = apply_filters('fluent_booking/crm_meeting_data', $this->mapMeetingRow($meeting, $hostCache[$cid]), $meeting);
96 + }
97 +
98 + $response = apply_filters('fluent_booking/crm_meetings_response', [
99 + 'total' => $total,
100 + 'data' => $rows,
101 + 'columns_config' => [
102 + 'id' => ['label' => __('ID', 'fluent-booking'), 'width' => '100px'],
103 + 'title' => ['label' => __('Event', 'fluent-booking')],
104 + 'status' => ['label' => __('Status', 'fluent-booking'), 'width' => '150px'],
105 + 'meeting_at' => ['label' => __('Meeting At', 'fluent-booking'), 'width' => '200px'],
106 + 'action' => ['label' => __('Action', 'fluent-booking'), 'width' => '100px'],
107 + ],
108 + ], $meetings, $contact);
109 +
110 + $bookButton = $this->getBookAppointmentButton($contact);
111 +
112 + if (empty($response['data'])) {
113 + $sections['content_html'] = $bookButton . '<p style="padding:0 20px;">' . esc_html__('No scheduled meetings found for this contact.', 'fluent-booking') . '</p>';
114 + return $sections;
115 + }
116 +
117 + $header = [];
118 + foreach ($response['columns_config'] as $key => $col) {
119 + $header[$key] = Arr::get($col, 'label', ucfirst($key));
120 + }
121 +
122 + $table = new TableBuilder();
123 + $table->setHeader($header);
124 + foreach ($response['data'] as $row) {
125 + $table->addRow($row);
126 + }
127 +
128 + $sections['content_html'] = $bookButton . $table->getHtml() . $this->getViewAllLink($contact, $total, $limit);
129 +
130 + return $sections;
83 131 }
84 132
85 - private function getFormattedTime($meeting)
133 + private function getBookAppointmentButton(Subscriber $contact)
86 134 {
87 - $formattedTime = DateTimeHelper::convertToTimeZone($meeting->start_time, 'utc', $meeting->calendar->author_timezone, 'j M Y, g:i A');
135 + $url = admin_url('admin.php?page=fluent-booking#/scheduled-events?new_booking=1&crm_contact_id=' . (int) $contact->id);
88 136
89 - return $formattedTime;
137 + return '<p class="fcal_crm_book_appointment" style="padding:0px 20px;margin-top:-36px;text-align:end;">'
138 + . '<a class="el-button el-button--small" target="_blank" rel="noopener noreferrer" href="' . esc_url($url) . '">'
139 + . esc_html__('Book Appointment', 'fluent-booking')
140 + . '</a></p>';
90 141 }
91 142
92 - private function getBookingTitle($meeting)
143 + private function mapMeetingRow($meeting, $host)
93 144 {
94 - $host = $meeting->calendar->getAuthorProfile();
95 - $title = $meeting->slot->title . ' with ' . $host['name'];
145 + $groupRef = $meeting->group_id ?: $meeting->id;
96 146
97 - return $title;
147 + return [
148 + 'id' => '#' . $groupRef,
149 + 'title' => esc_html($this->getBookingTitle($meeting, $host)),
150 + 'status' => esc_html($meeting->status),
151 + 'meeting_at' => esc_html($this->getFormattedTime($meeting)),
152 + 'action' => $this->getActionUrl($meeting),
153 + ];
98 154 }
99 155
100 - public function getScheduledMeetings($data, $subsriber)
156 + private function getViewAllLink(Subscriber $contact, $total, $limit)
101 157 {
102 - $app = fluentCrm();
103 - $page = intval($app->request->get('page', 1));
104 - $perPage = intval($app->request->get('per_page', 10));
158 + if ($total <= $limit) {
159 + return '';
160 + }
105 161
106 - $meetings = Booking::with(['slot', 'calendar'])
107 - ->where('email', $subsriber->email)
108 - ->distinct('group_id')
109 - ->orderBy('start_time', 'DESC')
110 - ->paginate();
162 + $url = admin_url('admin.php?page=fluent-booking#/scheduled-events?email=' . rawurlencode($contact->email) . '&period=all&author=all');
111 163
112 - $formattedMeetings = [];
164 + return '<p class="fcal_crm_view_all"><a style="color:#2271b1;padding:0 12px;text-decoration:underline" href="' . esc_url($url) . '">'
165 + /* translators: %d: total number of meetings */
166 + . sprintf(esc_html__('View all meetings (%d)', 'fluent-booking'), (int) $total)
167 + . '</a></p>';
168 + }
113 169
114 - foreach ($meetings->items() as $meeting) {
115 - if (!$meeting->calendar || !$meeting->slot) {
116 - continue;
117 - }
170 + private function getActionUrl($meeting)
171 + {
172 + $url = admin_url('admin.php?page=fluent-booking#/scheduled-events?booking_id=' . $meeting->id);
118 173
119 - $formattedMeetings[] = [
120 - 'id' => '#' . $meeting->group_id,
121 - 'title' => $this->getBookingTitle($meeting),
122 - 'status' => $meeting->status,
123 - 'meeting_at' => $this->getFormattedTime($meeting),
124 - 'action' => $this->getActionUrl($meeting)
125 - ];
174 + return '<a target="_blank" href="' . esc_url($url) . '">' . esc_html__('View', 'fluent-booking') . '</a>';
175 + }
176 +
177 + private function getFormattedTime($meeting)
178 + {
179 + return DateTimeHelper::convertToTimeZone($meeting->start_time, 'UTC', $meeting->calendar->author_timezone, 'j M Y, g:i A');
180 + }
181 +
182 + private function getBookingTitle($meeting, $host = null)
183 + {
184 + if ($host === null) {
185 + $host = $meeting->calendar->getAuthorProfile();
126 186 }
127 187
128 - return [
129 - 'total' => $meetings->total(),
130 - 'data' => $formattedMeetings,
131 - 'columns_config' => [
132 - 'id' => [
133 - 'label' => __('ID', 'fluent-booking'),
134 - 'width' => '100px'
135 - ],
136 - 'title' => [
137 - 'label' => __('Event', 'fluent-booking'),
138 - ],
139 - 'status' => [
140 - 'label' => __('Status', 'fluent-booking'),
141 - 'width' => '150px'
142 - ],
143 - 'meeting_at' => [
144 - 'label' => __('Meeting At', 'fluent-booking'),
145 - 'width' => '200px'
146 - ],
147 - 'action' => [
148 - 'label' => __('Action', 'fluent-booking'),
149 - 'width' => '100px'
150 - ]
151 - ]
152 - ];
188 + return sprintf(
189 + /* translators: 1: meeting title, 2: host name */
190 + __('%1$s with %2$s', 'fluent-booking'),
191 + (string) $meeting->slot->title,
192 + (string) $host['name']
193 + );
153 194 }
154 195 }