Skip to content

Commit 13fa45d

Browse files
committed
Feedback changes + improvements
1 parent 8a8cf31 commit 13fa45d

7 files changed

Lines changed: 192 additions & 13 deletions

File tree

plugins/bcc-login/includes/class-bcc-login-visibility.php

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,34 @@ function on_init() {
112112
'type' => 'boolean',
113113
'default' => false,
114114
) );
115+
116+
register_post_meta( $post_type, 'sent_notifications', array(
117+
'show_in_rest' => [
118+
'schema' => [
119+
'type' => 'array',
120+
'items' => [
121+
'type' => 'object',
122+
'properties' => [
123+
'date' => [
124+
'type' => 'string',
125+
'format' => 'date-time', // ISO-8601 like 2025-12-12T09:15:00Z
126+
],
127+
'notification_groups' => [
128+
'type' => 'array',
129+
'items' => [
130+
'type' => 'string',
131+
],
132+
],
133+
],
134+
'required' => [ 'date', 'notification_groups' ],
135+
],
136+
],
137+
],
138+
'single' => true,
139+
'type' => 'array',
140+
'default' => [],
141+
'sanitize_callback' => array( $this, 'sanitize_sent_notifications_meta' ),
142+
) );
115143
}
116144
}
117145

@@ -555,7 +583,7 @@ function filter_pre_get_posts( $query ) {
555583
),
556584
array(
557585
'key' => 'bcc_visibility_groups',
558-
'compare' => 'NOT EXISTS',
586+
'compare' => 'NOT EXISTS'
559587
)
560588
);
561589
} else {
@@ -1279,4 +1307,33 @@ function save_visibility_to_attachments( $attach_id ) {
12791307
static function on_uninstall() {
12801308
delete_metadata( 'post', 0, 'bcc_login_visibility', '', true );
12811309
}
1310+
1311+
public static function sanitize_sent_notifications_meta( $value, $meta_key, $object_type ) {
1312+
// Normalize to array
1313+
if ( ! is_array( $value ) ) {
1314+
return [];
1315+
}
1316+
1317+
$out = [];
1318+
foreach ( $value as $item ) {
1319+
if ( ! is_array( $item ) ) {
1320+
continue;
1321+
}
1322+
1323+
$date = isset( $item['date'] ) && is_string( $item['date'] ) ? $item['date'] : null;
1324+
$groups = isset( $item['notification_groups'] ) && is_array( $item['notification_groups'] )
1325+
? array_values( array_filter( $item['notification_groups'], fn( $uid ) => is_string( $uid ) && $uid !== '' ) )
1326+
: [];
1327+
1328+
if ( $date ) {
1329+
$out[] = array(
1330+
'date' => $date,
1331+
'notification_groups' => $groups,
1332+
);
1333+
}
1334+
}
1335+
1336+
// Reindex
1337+
return array_values( $out );
1338+
}
12821339
}

plugins/bcc-login/includes/class-bcc-notifications.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public function register_send_notifications_endpoint() {
2626
}
2727

2828
$this->send_notification($post_id);
29+
2930
return new WP_REST_Response(null, 200);
3031
} else {
3132
return new WP_REST_Response(array('error' => 'postId parameter is required'), 400);
@@ -235,6 +236,8 @@ public function send_notification($post_id) {
235236
$this->core_api->send_notification($notification_groups, 'email', 'simpleemail', $email_payload);
236237
$this->core_api->send_notification($notification_groups, 'inapp', 'simpleinapp', $inapp_payload);
237238

239+
$this->add_notification_sent_date($post_id, $notification_groups);
240+
238241
error_log('DEBUG: ' . __METHOD__ . ' - Sent notifications for ' . count($email_payload) . ' languages. Post ID: ' . $post_id);
239242

240243
} else {
@@ -246,6 +249,30 @@ public function send_notification($post_id) {
246249
}
247250
}
248251

252+
// Save the timestamp when the notification has been sent
253+
public function add_notification_sent_date($post_id, $notification_groups = array()) {
254+
// Ensure array of strings (UIDs)
255+
$group_uids = array_values(array_filter((array) $notification_groups, function($uid) {
256+
return is_string($uid) && $uid !== '';
257+
}));
258+
259+
// Load current meta; normalize to array
260+
$sent_notifications = get_post_meta($post_id, 'sent_notifications', true);
261+
if (!is_array($sent_notifications)) {
262+
$sent_notifications = [];
263+
}
264+
265+
// Append new record that matches the REST schema
266+
$sent_notifications[] = array(
267+
'date' => gmdate('c'), // ISO-8601 UTC
268+
'notification_groups' => $group_uids,
269+
);
270+
271+
// Reindex and save
272+
$sent_notifications = array_values($sent_notifications);
273+
update_post_meta($post_id, 'sent_notifications', $sent_notifications);
274+
}
275+
249276
public function bcc_get_wpml_post_translations($post_id) {
250277
if ( ! $post_id || ! get_post( $post_id ) ) {
251278
return new WP_Error(

plugins/bcc-login/src/components/group-selector.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ const GroupSelector = ({ tags, options, label, groupsName, groupsValue, isSettin
113113

114114
// Rebuild treeNodes when tags change via external Tag Input component
115115
useEffect(() => {
116-
const rebuild = (currentTags) => {
117-
const groupsByTag = getGroupsByTag(currentTags);
116+
const rebuild = (newTags) => {
117+
const groupsByTag = getGroupsByTag(newTags);
118118
setTreeNodes(groupsByTag);
119119

120120
// Keep selected groups belonging to current tags
@@ -142,14 +142,14 @@ const GroupSelector = ({ tags, options, label, groupsName, groupsValue, isSettin
142142
const { value } = ev.detail || {};
143143

144144
// Accept both array and comma-separated string
145-
const nextTags = Array.isArray(value)
145+
const newTags = Array.isArray(value)
146146
? value
147147
: (typeof value === 'string'
148148
? value.split(',').map(t => t.trim()).filter(Boolean)
149149
: tags
150150
);
151151

152-
rebuild(nextTags);
152+
rebuild(newTags);
153153
};
154154

155155
window.addEventListener('bcc:tagsChanged', handler);
@@ -294,6 +294,8 @@ const GroupSelector = ({ tags, options, label, groupsName, groupsValue, isSettin
294294
onHide={() => setVisible(false)}
295295
loading={true}
296296
className="bcc-group-selector__dialog"
297+
closeIcon={<i className="dashicons dashicons-yes" />}
298+
ariaCloseIconLabel={__('Done', 'bcc-login')}
297299
>
298300
<div id="target-groups-selector" class="group-selector-section">
299301
{ isSettingPostGroups && ( <h3>{__('Requires action', 'bcc-login')}</h3> ) }

plugins/bcc-login/src/components/send-notifications.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Tag } from 'primereact/tag';
66
import { Badge } from 'primereact/badge';
77
import { __ } from '@wordpress/i18n';
88

9-
const SendNotifications = ({ label, postId, status, targetGroupsCount, visibilityGroupsCount, isNotificationDryRun, isDirty, isAutoSaving }) => {
9+
const SendNotifications = ({ label, postId, postType, status, targetGroupsCount, visibilityGroupsCount, isNotificationDryRun, isDirty, isAutoSaving }) => {
1010
const [visible, setVisible] = useState(false);
1111
const toast = useRef(null);
1212
const [nonce, setNonce] = useState(null);
@@ -19,10 +19,14 @@ const SendNotifications = ({ label, postId, status, targetGroupsCount, visibilit
1919

2020
const showToast = (status) => {
2121
const messages = {
22-
success: { severity: 'success', summary: __('Success', 'bcc-login'), detail: __('Notifications sent!', 'bcc-login') },
22+
success: { severity: 'success', summary: __('Success', 'bcc-login'), detail: __('Notifications sent!', 'bcc-login'), life: 5000 },
2323
error: { severity: 'error', summary: __('Error', 'bcc-login'), detail: __('Error sending notifications.', 'bcc-login'), sticky: true },
24-
info: { severity: 'info', summary: __('Info', 'bcc-login'), detail: __('Sending notifications ...', 'bcc-login') },
24+
info: { severity: 'info', summary: __('Info', 'bcc-login'), detail: __('Sending notifications ...', 'bcc-login'), sticky: true },
2525
};
26+
27+
// First remove the info toast if it's showing
28+
toast.current.remove(messages.info);
29+
2630
toast.current.show(messages[status]);
2731
};
2832

@@ -52,6 +56,13 @@ const SendNotifications = ({ label, postId, status, targetGroupsCount, visibilit
5256
throw new Error(`Request failed (${response.status}): ${text}`);
5357
}
5458

59+
window.dispatchEvent(new CustomEvent('bcc:notificationSent', {
60+
detail: {
61+
date: new Date().toLocaleString(),
62+
no_of_groups: targetGroupsCount + visibilityGroupsCount
63+
}
64+
}));
65+
5566
showToast('success');
5667
} catch (error) {
5768
console.error('Error sending notifications:', error);
@@ -121,7 +132,7 @@ const SendNotifications = ({ label, postId, status, targetGroupsCount, visibilit
121132
<div class="bcc-send-notifications__translations">
122133
<p>{__('Translations', 'bcc-login')}: {translations === null
123134
? <Tag icon="dashicons dashicons-info" severity="info" className="italic" value={__('Loading translations ...', 'bcc-login')} />
124-
: (translations.length == 0 ? <Tag icon="dashicons dashicons-warning" severity="warning" value={__('No translations available', 'bcc-login')} /> : '')
135+
: (translations.length == 0 ? <Tag icon="dashicons dashicons-info" severity="info" value={__('No translations available', 'bcc-login')} /> : '')
125136
}</p>
126137

127138
{translations !== null && translations.length > 0 ? (
@@ -164,6 +175,8 @@ const SendNotifications = ({ label, postId, status, targetGroupsCount, visibilit
164175
) : (
165176
<Tag icon="dashicons dashicons-no" severity="danger" value={__('No groups', 'bcc-login')}></Tag>
166177
)}
178+
179+
<p className='bcc-send-notifications__info'>* {__('The email will be sent immediately when you click "Send"', 'bcc-login')}</p>
167180
</div>
168181

169182
{isNotificationDryRun && (
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { useState, useEffect } from 'react';
2+
import { DataTable } from 'primereact/datatable';
3+
import { Column } from 'primereact/column';
4+
import { __ } from '@wordpress/i18n';
5+
6+
const SentNotificationsList = ({ sentNotifications }) => {
7+
const [notifications, setNotifications] = useState(sentNotifications || []);
8+
9+
// Rebuild notifications when sentNotifications change via external Send Notifications component
10+
useEffect(() => {
11+
const rebuild = (newNotifications) => {
12+
setNotifications(newNotifications);
13+
};
14+
15+
const handler = (ev) => {
16+
const { date, no_of_groups } = ev.detail || {};
17+
const newNotifications = [...notifications, { date, no_of_groups }];
18+
19+
rebuild(newNotifications);
20+
};
21+
22+
window.addEventListener('bcc:notificationSent', handler);
23+
return () => window.removeEventListener('bcc:notificationSent', handler);
24+
}, [sentNotifications]);
25+
26+
return (
27+
<div className="bcc-sent-notifications-list">
28+
<DataTable value={notifications} emptyMessage={__("No notifications sent yet.", "bcc-login")} sortField="date" sortOrder={-1}>
29+
<Column field="date" header={__("Sent on", "bcc-login")}></Column>
30+
<Column field="no_of_groups" header={__("No. of groups", "bcc-login")} headerStyle={{ textAlign: 'center' }} bodyStyle={{ textAlign: 'center' }}></Column>
31+
</DataTable>
32+
</div>
33+
);
34+
};
35+
36+
export default SentNotificationsList;

plugins/bcc-login/src/visibility.css

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,30 @@
2020
/* Post Groups */
2121

2222
.bcc-group-selector__dialog {
23-
width: 100vw;
23+
min-width: 100vw;
2424
}
2525

2626
@media screen and (min-width: 768px) {
2727
.bcc-group-selector__dialog {
28-
width: 75vw;
28+
min-width: 60vw;
2929
}
3030
}
3131

32+
.bcc-group-selector__dialog button.p-dialog-header-close {
33+
width: auto;
34+
padding: 1rem !important;
35+
}
36+
37+
.bcc-group-selector__dialog button.p-dialog-header-close:hover {
38+
background: rgba(34, 197, 94, 0.1);
39+
color: #16a34a;
40+
}
41+
42+
.bcc-group-selector__dialog button.p-dialog-header-close:after {
43+
content: attr(aria-label);
44+
display: inline-block;
45+
}
46+
3247
.group-selector-section {
3348
padding: 1.25rem 1rem 0.5rem;
3449
}
@@ -168,11 +183,23 @@ ul.p-treenode-children .p-treenode-content {
168183
display: none !important;
169184
}
170185

186+
.all-done {
187+
border-radius: 6px;
188+
background: transparent;
189+
color: #0078d4;
190+
padding-block: 0.5rem;
191+
}
192+
171193
/* Send Notifications */
172194

195+
.bcc-login-notifications-plugin-post-status-info {
196+
flex-direction: column;
197+
margin: 1.25rem 0 0.5rem;
198+
gap: 0.25rem;
199+
}
200+
173201
.bcc-notifications {
174202
width: 100%;
175-
margin-top: 1rem;
176203
}
177204

178205
.bcc-notifications .p-button {
@@ -235,6 +262,12 @@ ul.p-treenode-children .p-treenode-content {
235262
align-items: center;
236263
}
237264

265+
.bcc-send-notifications__dialog .bcc-send-notifications__info {
266+
font-size: 0.875rem;
267+
font-style: italic;
268+
color: rgba(0,0,0,.6);
269+
}
270+
238271
.bcc-send-notifications__dialog .p-button {
239272
position: absolute;
240273
right: 1.5rem;
@@ -247,6 +280,7 @@ ul.p-treenode-children .p-treenode-content {
247280
.p-toast {
248281
opacity: 1;
249282
font-size: 1rem;
283+
z-index: 9999;
250284
}
251285

252286
.p-toast .p-toast-message {

plugins/bcc-login/src/visibility.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
} from "@wordpress/components";
1010
import GroupSelector from './components/group-selector';
1111
import SendNotifications from './components/send-notifications';
12+
import SentNotificationsList from './components/sent-notifications-list';
1213
import { registerPlugin } from "@wordpress/plugins";
1314
import { InspectorControls } from "@wordpress/block-editor";
1415
import { PluginPostStatusInfo } from "@wordpress/editor";
@@ -160,6 +161,13 @@ registerPlugin("bcc-notifications", {
160161
const postType = getCurrentPostType();
161162
const allowedTypes = Array.isArray(window.bccLoginNotificationPostTypes) ? window.bccLoginNotificationPostTypes : [];
162163

164+
const sentNotifications = meta?.sent_notifications.map(notification => {
165+
return {
166+
date: (new Date(notification.date)).toLocaleString(),
167+
no_of_groups: notification.notification_groups.length
168+
};
169+
}) ?? [];
170+
163171
return {
164172
postId: getCurrentPostId(),
165173
postType,
@@ -170,13 +178,15 @@ registerPlugin("bcc-notifications", {
170178
isDirty: isEditedPostDirty(),
171179
isAutoSaving: isAutosavingPost(),
172180
isAllowedPostType: allowedTypes.includes(postType),
181+
sentNotifications: sentNotifications
173182
};
174183
}),
175184
withInstanceId,
176185
])((props) => (
177186
props.isAllowedPostType ? (
178-
<PluginPostStatusInfo>
187+
<PluginPostStatusInfo className="bcc-login-notifications-plugin-post-status-info">
179188
<SendNotifications label={__("Send notifications", "bcc-login")} {...props} />
189+
<SentNotificationsList {...props} />
180190
</PluginPostStatusInfo>
181191
) : null
182192
)),

0 commit comments

Comments
 (0)