Skip to content

Commit

Permalink
Refac
Browse files Browse the repository at this point in the history
  • Loading branch information
justinh-rahb committed Oct 2, 2024
1 parent 48aaf17 commit 0d2aba8
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 51 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ Displays a searchable directory of offices using the Bridge Data Output API.
- **Search Functionality:** Users can search offices by name, phone, or email.
- **Customizable Display:** Adjust the number of columns and rows in the block editor.
- **Cache Management:** Clear the cache manually if needed.
- **Enhanced Directory Display:** Offices are displayed as a grid of cards for better visual presentation.
- **Live Search with Debounce:** Users can search offices with instant feedback, and the search input is debounced to optimize performance.
- **Infinite Scroll:** As users scroll down, more offices are loaded automatically without needing to click pagination links.

## Data Storage

Expand Down
37 changes: 37 additions & 0 deletions bridge-directory/assets/css/bridge-directory.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.bridge-directory-grid {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}

.bridge-directory-search {
margin-bottom: 20px;
}

.bridge-directory-search input {
width: 100%;
padding: 10px;
font-size: 16px;
}

.bridge-directory-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
}

.bridge-directory-card {
border: 1px solid #ccc;
padding: 15px;
background-color: #fff;
}

.bridge-directory-card h3 {
margin-top: 0;
}

.bridge-directory-loader {
text-align: center;
padding: 20px;
font-size: 18px;
}
86 changes: 86 additions & 0 deletions bridge-directory/assets/js/bridge-directory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
(function ($) {
let currentPage = 1;
let isLoading = false;
let noMoreResults = false;
let lastQuery = '';
let debounceTimeout;

$(document).ready(function () {
const $searchInput = $('#bridge-directory-search-input');
const $cardsContainer = $('#bridge-directory-cards');
const $loader = $('#bridge-directory-loader');

function loadResults(reset = false) {
if (isLoading || noMoreResults) return;
isLoading = true;
$loader.show();

$.ajax({
url: bridgeDirectory.ajax_url,
type: 'POST',
data: {
action: 'bridge_directory_load_offices',
nonce: bridgeDirectory.nonce,
page: currentPage,
query: lastQuery,
},
success: function (response) {
if (reset) {
$cardsContainer.empty();
currentPage = 1;
noMoreResults = false;
}
if (response.success) {
const offices = response.data.offices;
if (offices.length === 0) {
noMoreResults = true;
} else {
appendResultsToGrid(offices);
currentPage++;
}
}
},
complete: function () {
isLoading = false;
$loader.hide();
},
});
}

function appendResultsToGrid(offices) {
offices.forEach(function (office) {
const card = `
<div class="bridge-directory-card">
<h3>${office.OfficeName}</h3>
<p><strong>Phone:</strong> ${office.OfficePhone || ''}</p>
<p><strong>Email:</strong> ${office.OfficeEmail || ''}</p>
<p><strong>Address:</strong> ${office.OfficeAddress1 || ''} ${office.OfficeAddress2 || ''}, ${office.OfficeCity || ''}, ${office.OfficeStateOrProvince || ''} ${office.OfficePostalCode || ''}</p>
${office.SocialMediaWebsiteUrlOrId ? `<p><strong>Website:</strong> <a href="${office.SocialMediaWebsiteUrlOrId}" target="_blank">${office.SocialMediaWebsiteUrlOrId}</a></p>` : ''}
</div>
`;
$cardsContainer.append(card);
});
}

function debounceSearch() {
clearTimeout(debounceTimeout);
debounceTimeout = setTimeout(function () {
lastQuery = $searchInput.val();
currentPage = 1;
noMoreResults = false;
loadResults(true);
}, 300);
}

$searchInput.on('input', debounceSearch);

$(window).on('scroll', function () {
if ($(window).scrollTop() + $(window).height() >= $(document).height() - 100) {
loadResults();
}
});

// Initial load
loadResults();
});
})(jQuery);
4 changes: 3 additions & 1 deletion bridge-directory/bridge-directory.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
$data_sync = new Data_Sync( $db_handler );
$data_sync->schedule_incremental_sync();

// Initialize AJAX Handler
$ajax_handler = new AJAX_Handler( $search_handler );

// Activation and Deactivation Hooks
register_activation_hook( __FILE__, [ 'BridgeDirectory\DB_Handler', 'activate' ] );
register_deactivation_hook( __FILE__, [ 'BridgeDirectory\DB_Handler', 'deactivate' ] );
Expand All @@ -56,4 +59,3 @@ function bridge_directory_custom_cron_schedule( $schedules ) {
];
return $schedules;
}

27 changes: 27 additions & 0 deletions bridge-directory/includes/class-ajax-handler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
namespace BridgeDirectory;

defined( 'ABSPATH' ) || exit;

class AJAX_Handler {
private $search_handler;

public function __construct( $search_handler ) {
$this->search_handler = $search_handler;

add_action( 'wp_ajax_bridge_directory_load_offices', [ $this, 'load_offices' ] );
add_action( 'wp_ajax_nopriv_bridge_directory_load_offices', [ $this, 'load_offices' ] );
}

public function load_offices() {
check_ajax_referer( 'bridge_directory_nonce', 'nonce' );

$page = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
$query = isset( $_POST['query'] ) ? sanitize_text_field( $_POST['query'] ) : '';
$limit = 20; // Number of results per page

$offices = $this->search_handler->search_offices( $query, $page, $limit );

wp_send_json_success( [ 'offices' => $offices ] );
}
}
73 changes: 36 additions & 37 deletions bridge-directory/includes/class-block-register.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public function __construct( $search_handler ) {

public function register() {
add_action( 'init', [ $this, 'register_blocks' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
}

public function register_blocks() {
Expand All @@ -30,52 +31,50 @@ public function register_blocks() {
'type' => 'number',
'default' => 3,
],
'rows' => [
'type' => 'number',
'default' => 5,
],
],
'render_callback' => [ $this, 'render_block' ],
] );
}

public function render_block( $attributes ) {
$query = isset( $_GET['bridge_search'] ) ? sanitize_text_field( $_GET['bridge_search'] ) : '';
$offices = $this->search_handler->search_offices( $query );
public function enqueue_scripts() {
if ( has_block( 'bridge-directory/office-list' ) ) {
wp_enqueue_script(
'bridge-directory-frontend',
plugins_url( 'assets/js/bridge-directory.js', __DIR__ ),
[ 'jquery' ],
'1.0.0',
true
);

ob_start();
?>
wp_enqueue_style(
'bridge-directory-style',
plugins_url( 'assets/css/bridge-directory.css', __DIR__ ),
[],
'1.0.0'
);

<form method="get">
<input type="text" name="bridge_search" placeholder="Search offices..." value="<?php echo esc_attr( $query ); ?>" />
<button type="submit">Search</button>
</form>
wp_localize_script( 'bridge-directory-frontend', 'bridgeDirectory', [
'ajax_url' => admin_url( 'admin-ajax.php' ),
'columns' => get_option( 'bridge_directory_columns', 3 ),
'nonce' => wp_create_nonce( 'bridge_directory_nonce' ),
] );
}
}

<div class="bridge-directory" style="display: grid; grid-template-columns: repeat(<?php echo esc_attr( $attributes['columns'] ); ?>, 1fr); gap: 20px;">
<?php
$count = 0;
foreach ( $offices as $office ) {
if ( $count >= $attributes['rows'] * $attributes['columns'] ) {
break;
}
?>
<div class="office-item">
<h3><?php echo esc_html( $office['OfficeName'] ); ?></h3>
<p>Phone: <?php echo esc_html( $office['OfficePhone'] ); ?></p>
<p>Email: <?php echo esc_html( $office['OfficeEmail'] ); ?></p>
<p>Address: <?php
echo esc_html( $office['OfficeAddress1'] . ' ' . $office['OfficeAddress2'] . ', ' . $office['OfficeCity'] . ', ' . $office['OfficeStateOrProvince'] . ' ' . $office['OfficePostalCode'] );
?></p>
<?php if ( ! empty( $office['SocialMediaWebsiteUrlOrId'] ) ) : ?>
<p>Website: <a href="<?php echo esc_url( $office['SocialMediaWebsiteUrlOrId'] ); ?>"><?php echo esc_html( $office['SocialMediaWebsiteUrlOrId'] ); ?></a></p>
<?php endif; ?>
</div>
<?php
$count++;
}
?>
public function render_block( $attributes ) {
ob_start();
?>
<div class="bridge-directory-grid">
<div class="bridge-directory-search">
<input type="text" id="bridge-directory-search-input" placeholder="Search...">
</div>
<div id="bridge-directory-cards" class="bridge-directory-cards">
<!-- Cards will be dynamically added here -->
</div>
<div id="bridge-directory-loader" class="bridge-directory-loader" style="display: none;">
Loading...
</div>
</div>

<?php
return ob_get_clean();
}
Expand Down
14 changes: 11 additions & 3 deletions bridge-directory/includes/class-search-handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,31 @@ public function __construct( $db_handler ) {
$this->db_handler = $db_handler;
}

public function search_offices( $query ) {
public function search_offices( $query = '', $page = 1, $limit = 20 ) {
global $wpdb;

$offset = ( $page - 1 ) * $limit;
$table_name = $this->db_handler->table_name;

$sql = "SELECT * FROM {$table_name}";
$where_clauses = [];

if ( ! empty( $query ) ) {
$like_query = '%' . $wpdb->esc_like( $query ) . '%';
$sql .= $wpdb->prepare(
" WHERE OfficeName LIKE %s OR OfficePhone LIKE %s OR OfficeEmail LIKE %s",
$where_clauses[] = $wpdb->prepare(
"(OfficeName LIKE %s OR OfficePhone LIKE %s OR OfficeEmail LIKE %s)",
$like_query,
$like_query,
$like_query
);
}

if ( ! empty( $where_clauses ) ) {
$sql .= ' WHERE ' . implode( ' AND ', $where_clauses );
}

$sql .= $wpdb->prepare( ' LIMIT %d OFFSET %d', $limit, $offset );

$results = $wpdb->get_results( $sql, ARRAY_A );
return $results;
}
Expand Down
20 changes: 10 additions & 10 deletions bridge-directory/vendor/composer/installed.php
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
<?php return array(
'root' => array(
'name' => '__root__',
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => null,
'type' => 'library',
'name' => 'justinh-rahb/bridge-directory',
'pretty_version' => 'dev-main',
'version' => 'dev-main',
'reference' => '48aaf176c17a698321aeff4ea84371fcbab1577b',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev' => true,
),
'versions' => array(
'__root__' => array(
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => null,
'type' => 'library',
'justinh-rahb/bridge-directory' => array(
'pretty_version' => 'dev-main',
'version' => 'dev-main',
'reference' => '48aaf176c17a698321aeff4ea84371fcbab1577b',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev_requirement' => false,
Expand Down

0 comments on commit 0d2aba8

Please sign in to comment.