settings = $settings; } /** * Hook registration. * * @return void */ public function init() { add_action( 'admin_menu', array( $this, 'menu' ) ); add_action( 'admin_init', array( $this, 'handle_actions' ) ); } /** * Register the admin menu. * * @return void */ public function menu() { add_menu_page( __( 'AiCB Chat', 'aicb-chat-widget' ), __( 'AiCB Chat', 'aicb-chat-widget' ), 'manage_options', 'aicbc-conversations', array( $this, 'render_conversations' ), 'dashicons-format-chat', 58 ); add_submenu_page( 'aicbc-conversations', __( 'Conversations', 'aicb-chat-widget' ), __( 'Conversations', 'aicb-chat-widget' ), 'manage_options', 'aicbc-conversations', array( $this, 'render_conversations' ) ); add_submenu_page( 'aicbc-conversations', __( 'Learnings', 'aicb-chat-widget' ), __( 'Learnings', 'aicb-chat-widget' ), 'manage_options', 'aicbc-learnings', array( $this, 'render_learnings' ) ); add_submenu_page( 'aicbc-conversations', __( 'Settings', 'aicb-chat-widget' ), __( 'Settings', 'aicb-chat-widget' ), 'manage_options', 'aicbc-settings', array( $this->settings, 'render_page' ) ); } /** * Process posted admin actions (review, learn, delete, learning toggles). * * @return void */ public function handle_actions() { if ( ! isset( $_POST['aicbc_action'] ) || ! current_user_can( 'manage_options' ) ) { return; } check_admin_referer( 'aicbc_admin' ); $action = sanitize_key( wp_unslash( $_POST['aicbc_action'] ) ); $conv_id = isset( $_POST['conversation_id'] ) ? absint( $_POST['conversation_id'] ) : 0; if ( 'mark_reviewed' === $action && $conv_id ) { AICBC_Store::update_conversation( $conv_id, array( 'reviewed' => 1 ) ); $this->redirect( admin_url( 'admin.php?page=aicbc-conversations&conversation=' . $conv_id . '&aicbc_done=reviewed' ) ); } if ( 'add_learning' === $action ) { $note = isset( $_POST['learning_note'] ) ? sanitize_textarea_field( wp_unslash( $_POST['learning_note'] ) ) : ''; $note = trim( mb_substr( $note, 0, 1000 ) ); if ( '' !== $note ) { AICBC_Store::add_learning( $note, $conv_id ); } $to = $conv_id ? 'admin.php?page=aicbc-conversations&conversation=' . $conv_id . '&aicbc_done=learned' : 'admin.php?page=aicbc-learnings&aicbc_done=learned'; $this->redirect( admin_url( $to ) ); } if ( 'delete_conversation' === $action && $conv_id ) { AICBC_Store::delete_conversation( $conv_id ); $this->redirect( admin_url( 'admin.php?page=aicbc-conversations&aicbc_done=deleted' ) ); } if ( in_array( $action, array( 'learning_enable', 'learning_disable', 'learning_delete' ), true ) ) { $lid = isset( $_POST['learning_id'] ) ? absint( $_POST['learning_id'] ) : 0; if ( $lid ) { AICBC_Store::learning_action( $lid, str_replace( 'learning_', '', $action ) ); } $this->redirect( admin_url( 'admin.php?page=aicbc-learnings' ) ); } } /** * Redirect helper. * * @param string $url Target URL. * @return void */ private function redirect( $url ) { wp_safe_redirect( $url ); exit; } /** * Success notice from the ?aicbc_done flag. * * @return void */ private function notice() { $done = isset( $_GET['aicbc_done'] ) ? sanitize_key( wp_unslash( $_GET['aicbc_done'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( '' === $done ) { return; } $map = array( 'reviewed' => __( 'Conversation marked as reviewed.', 'aicb-chat-widget' ), 'learned' => __( 'Learning saved — it will be applied to future chats.', 'aicb-chat-widget' ), 'deleted' => __( 'Conversation deleted.', 'aicb-chat-widget' ), ); if ( isset( $map[ $done ] ) ) { echo '

' . esc_html( $map[ $done ] ) . '

'; } } /** * Conversations list or single-conversation view. * * @return void */ public function render_conversations() { if ( ! current_user_can( 'manage_options' ) ) { return; } $conv_id = isset( $_GET['conversation'] ) ? absint( $_GET['conversation'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( $conv_id ) { $this->render_single( $conv_id ); return; } $paged = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $per = 20; $rows = AICBC_Store::list_conversations( $per, ( $paged - 1 ) * $per ); $total = AICBC_Store::count_conversations(); $pages = max( 1, (int) ceil( $total / $per ) ); ?>

notice(); ?>

started_at, 'j M Y H:i' ) ); ?> preview ? $c->preview : '—' ); ?> message_count ); ?> lead_name ? $c->lead_name . ' (' . $c->lead_contact . ')' : '—' ); ?> reviewed ? '✅' : '—'; ?>
1 ) : ?>

' . esc_html__( 'Conversation not found.', 'aicb-chat-widget' ) . '

'; return; } $msgs = AICBC_Store::get_messages( $conv_id ); $labels = array( 'visitor' => __( 'Visitor', 'aicb-chat-widget' ), 'assistant' => __( 'Assistant', 'aicb-chat-widget' ), 'human' => __( 'Team (live)', 'aicb-chat-widget' ), 'tool' => __( 'Tool', 'aicb-chat-widget' ), 'lead' => __( 'Lead', 'aicb-chat-widget' ), ); ?>

reviewed ) : ?> ✅

notice(); ?>

←  ·  started_at, 'j M Y H:i' ) ); ?> page_url ) : ?>  ·  page_url ); ?>

role; if ( $is_visitor ) { $style = 'align-self:flex-end;background:linear-gradient(135deg,#6E56F7,#19C8C0);color:#fff'; } elseif ( 'assistant' === $m->role ) { $style = 'align-self:flex-start;background:#f6f7fb;border:1px solid #e6e8f0'; } elseif ( 'human' === $m->role ) { $style = 'align-self:flex-start;background:#eef6ff;border:1px solid #9ec2e6'; } else { $style = 'align-self:stretch;background:#fffbe5;border:1px dashed #dba617;font-size:12px'; } ?>
role ] ) ? $labels[ $m->role ] : $m->role ); ?>
content ); ?>

notice(); ?>

note ); ?> conversation_id ) : ?>
created_at, 'j M Y' ) ); ?> enabled ? '' . esc_html__( 'Active', 'aicb-chat-widget' ) . '' : esc_html__( 'Off', 'aicb-chat-widget' ); ?>