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 +129 -83 1.5.01 → 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()
@@ -13,17 +17,17 @@
13 17 $this->registerIntegrations();
14 18
15 19 // Contextual SmartCodes
16 20 (new CrmSmartCode())->register();
21 +
22 + add_filter('fluent_crm_asset_listed_slugs', function ($lists) {
23 + $lists[] = 'fluent-booking';
24 + return $lists;
25 + });
17 26 }
18 27
19 - /**
20 - * Register all the CRM integrations from here
21 - * @return void
22 - */
23 28 public function registerIntegrations()
24 29 {
25 - $this->addContactMenuSection();
26 30 $this->addAutomations();
27 31 }
28 32
29 33 public function registerHooks()
@@ -28,22 +32,11 @@
28 32
29 33 public function registerHooks()
30 34 {
31 35 add_filter('fluentcrm_profile_sections', [$this, 'addProfileSection'], 10, 1);
32 - add_filter('fluentcrm_get_form_submissions_fluent_booking', [$this, 'getScheduledMeetings'], 10, 2);
36 + add_filter('fluencrm_profile_section_fluent_booking', [$this, 'getProfileSection'], 10, 2);
33 37 }
34 38
35 - /**
36 - * load Assets for to Fluent CRM contact section
37 - * @return void
38 - */
39 - public function addContactMenuSection()
40 - {
41 - add_action('fluent_crm/global_appjs_loaded', function () {
42 - wp_enqueue_script('fluent_booking_in_crm', FLUENT_BOOKING_URL . 'assets/admin/fluent-crm-in-calendar.js', [], FLUENT_BOOKING_ASSETS_VERSION, true);
43 - });
44 - }
45 -
46 39 public function addAutomations()
47 40 {
48 41 new NewBookingTrigger();
49 42 new CancelBookingTrigger();
@@ -50,100 +43,153 @@
50 43 new BookingCompletedTrigger();
51 44 new BookingRescheduledTrigger();
52 45 }
53 46
54 - private function getSubscriberId($email)
55 - {
56 - $contact = FluentCrmApi('contacts')->getContact($email);
57 - return $contact ? $contact->id : null;
58 - }
59 -
60 47 public function addProfileSection($sections)
61 48 {
62 49 $sections['booking'] = [
63 - 'name' => 'booking',
50 + 'name' => 'fluentcrm_profile_extended',
64 51 'title' => __('Bookings', 'fluent-booking'),
65 - 'handler' => 'route'
52 + 'handler' => 'route',
53 + 'query' => [
54 + 'handler' => 'fluent_booking'
55 + ],
66 56 ];
67 57
68 58 return $sections;
69 59 }
70 60
71 - private function getActionUrl($meeting)
61 + public function getProfileSection($sections, Subscriber $contact)
72 62 {
73 - $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 + }
74 66
75 - $link = '<a target="_blank" href="' . esc_url($url) . '">' . 'view' . '</a>';
76 -
77 - 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;
78 131 }
79 132
80 - private function getFormattedTime($meeting)
133 + private function getBookAppointmentButton(Subscriber $contact)
81 134 {
82 - $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);
83 136
84 - 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>';
85 141 }
86 142
87 - private function getBookingTitle($meeting)
143 + private function mapMeetingRow($meeting, $host)
88 144 {
89 - $host = $meeting->calendar->getAuthorProfile();
90 - $title = $meeting->slot->title . ' with ' . $host['name'];
145 + $groupRef = $meeting->group_id ?: $meeting->id;
91 146
92 - 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 + ];
93 154 }
94 155
95 - public function getScheduledMeetings($data, $subsriber)
156 + private function getViewAllLink(Subscriber $contact, $total, $limit)
96 157 {
97 - $app = fluentCrm();
98 - $page = intval($app->request->get('page', 1));
99 - $perPage = intval($app->request->get('per_page', 10));
158 + if ($total <= $limit) {
159 + return '';
160 + }
100 161
101 - $meetings = Booking::with(['slot', 'calendar'])
102 - ->where('email', $subsriber->email)
103 - ->distinct('group_id')
104 - ->orderBy('start_time', 'DESC')
105 - ->paginate();
162 + $url = admin_url('admin.php?page=fluent-booking#/scheduled-events?email=' . rawurlencode($contact->email) . '&period=all&author=all');
106 163
107 - $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 + }
108 169
109 - foreach ($meetings->items() as $meeting) {
110 - if (!$meeting->calendar || !$meeting->slot) {
111 - continue;
112 - }
170 + private function getActionUrl($meeting)
171 + {
172 + $url = admin_url('admin.php?page=fluent-booking#/scheduled-events?booking_id=' . $meeting->id);
113 173
114 - $formattedMeetings[] = [
115 - 'id' => '#' . $meeting->group_id,
116 - 'title' => $this->getBookingTitle($meeting),
117 - 'status' => $meeting->status,
118 - 'meeting_at' => $this->getFormattedTime($meeting),
119 - 'action' => $this->getActionUrl($meeting)
120 - ];
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();
121 186 }
122 187
123 - return [
124 - 'total' => $meetings->total(),
125 - 'data' => $formattedMeetings,
126 - 'columns_config' => [
127 - 'id' => [
128 - 'label' => __('ID', 'fluent-booking'),
129 - 'width' => '100px'
130 - ],
131 - 'title' => [
132 - 'label' => __('Event', 'fluent-booking'),
133 - ],
134 - 'status' => [
135 - 'label' => __('Status', 'fluent-booking'),
136 - 'width' => '150px'
137 - ],
138 - 'meeting_at' => [
139 - 'label' => __('Meeting At', 'fluent-booking'),
140 - 'width' => '200px'
141 - ],
142 - 'action' => [
143 - 'label' => __('Action', 'fluent-booking'),
144 - 'width' => '100px'
145 - ]
146 - ]
147 - ];
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 + );
148 194 }
149 195 }