React Redux Provider Store: No Overload Matches This Call

react redux IDE

This post documents a solution for the following error I encountered in a React TypeScript project that was using Redux:

No overload matches this call.
  Overload 1 of 2, '(props: ProviderProps<Action> | Readonly<ProviderProps<Action>>): Provider<Action>', gave the following error.
    Type '{ children: Element; store: Store<{ readonly [$CombinedState]?: undefined; } & { repos: ReposState; }, Action>; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Provider<Action>> & Readonly<ProviderProps<Action>>'.
      Property 'children' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Provider<Action>> & Readonly<ProviderProps<Action>>'.
  Overload 2 of 2, '(props: ProviderProps<Action>, context: any): Provider<Action>', gave the following error.

React is a JavaScript framework used to build web apps. Redux is an open-source library used to manage the state of an application, and is often used along with React JS.

In this context, the Redux <Provider> component is used to pass application state along to its children components. It is best practice to wrap the entirety of your app in the <Provider> component, and pass the store object into it as an argument (property):

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import { Provider } from 'react-redux';
import App from './App';
import { store } from './state';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

root.render(
  <React.StrictMode>
    <Provider  store={store}> 
      <App />
    </Provider>
  </React.StrictMode>
);

In my project, this was producing an error on the <Provider> component that said “No overload matches this call.” I knew this must have something to with the argument(s) being passed along.

No overload matches this call.

At first I thought it might have something to do with my store object, but that was not it. I was able to resolve this roadblock by explicitly passing a ProviderProps object into the Provider component.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import { Provider, ProviderProps } from 'react-redux';
import App from './App';
import { store } from './state';


const providerProps: ProviderProps = {
  store: store,
};

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

root.render(
  <React.StrictMode>
    <Provider  {...providerProps}> 
      <App />
    </Provider>
  </React.StrictMode>
);

This worked because the store object is explicitly typed in the ProviderProps object. This ensures that it matches the type expected by the Provider component. Ultimately, it was a TypeScript error. TypeScript was not able to infer the store type correctly.

This was a bug I encountered while building a web app for an Udemy course called “React and Typescript: Build a Portfolio Project“.

Memoization (Caching) and Recursion with JavaScript

performant code

A common coding challenge that you may encounter will ask you to write a function that returns the Fibonacci sequence, up to the nth number (which is provided as an argument). Below is a solution, along with some commentary about the topic. This challenge is a great exercise in problem solving.

Fibonnaci sequence

Fibonacci numbers

The sequence starts with 0 and 1, and the next number in the sequence is always the sum of the previous two numbers. The first few terms of the sequence are:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811

Since this series follows a known pattern, we can write code to generate it up to a specified position.

In mathematics, the Fibonacci sequence is a sequence in which each number is the sum of the two preceding ones. Numbers that are part of the Fibonacci sequence are known as Fibonacci numbers.

These numbers were first described in ancient Indian mathematics. They are named after the Italian mathematician Leonardo of Pisa, also known as Fibonacci, who introduced the sequence to Western European mathematics in his 1202 book Liber Abaci. Fibonacci numbers are also strongly related to the golden ratio. In computer science, these numbers can be applied to programming algorithms related to search, data structures, and graphs.

Recursion

In programming, recursion is an important concept. Recursion is when a function calls itself. Writing code that generates the Fibonacci sequence requires recursion. Here is an example in JavaScript:

function fibonacci(n) {
    if (n < 2){
        return 1;
    }else{
        return fibonacci(n-2) + fibonacci(n-1);
    }
}
console.log(fibonacci(7)); // Returns 21

If you ask this function for 0 or 1 terms, it will simply return 1. It is the condition that will ultimately stop the recursion. Anything above that, it will have to call itself recursively. What exactly is happening there? This Stack Overflow thread does a great job stepping though the logic and illustrating each iteration.

fibonacci visualized

When I decorate the code from above with console log statements and collect the results into an array, it becomes obvious:

function fibonacci(n) {
  console.log("Iterating on n = " + n)
  if (n <= 1) {
    console.log("n is: "+n)
    return [0, 1].slice(0, n + 1);
  } else {
    const fib = fibonacci(n - 1);
    console.log("fib is: "+fib)
    console.log("iterating on " + n)
    fib.push(fib[fib.length - 1] + fib[fib.length - 2]);
    return fib;
  }
}

You can see it iterates all the way down, starting at the desired argument of term numbers, and ending with 1. Once it gets to the bottom, it starts going back up. On each subsequent round, it adds a new number to the result array by summing the previous two numbers.

fibonacci console log

I asked ChatGPT to rewrite this code for me, and this is how it was cleaned up:

function fibonacci(n) {
  if (n <= 1) {
    return [0, 1].slice(0, n + 1);
  } else {
    var sequence = fibonacci(n - 1);
    sequence.push(sequence[sequence.length - 1] + sequence[sequence.length - 2]);
    return sequence;
  }
}

This function has an exponential time complexity. It can be very slow for larger values of n.

Memoization and Cacheing

This challenge is often followed with a request to make it “more performant”. I mentioned above that our solution has “exponential time complexity”. Its algorithmic efficiency can be described as O(2^n) in Big O notation.

big o notation

Every call (while n is greater than 1) results in two additional recursive calls, one with n-1 and another with n-2. Each of those calls then results in two more recursive calls, and so on, resulting in a binary tree of recursive calls.

The performance of this code can be improved by implementing memoization. Memoization is when we store the results of our function call. On subsequent calls, our application can look up answers it previously calculated without have to do the work again.

function fibonacci2(n, memo = {}) {
  if (n in memo) {
    console.log("we used the memo on: " + n)
    return memo[n];
  }
  if (n <= 1) {
    return [0, 1].slice(0, n + 1);
  } else {
    const fib = fibonacci2(n - 1, memo);
    fib.push(fib[fib.length - 1] + fib[fib.length - 2]);
    memo[n] = fib;
    return fib;
  }
}
memo = {}
console.log(fibonacci2(7, memo));
console.log(fibonacci2(15, memo));

On each iteration we save the results to an array called memo. When we use the function, we first check to see if the answer we want is already stored in our cache. Our course, the work still needs to be done the first time around, but never again – making computation much faster in the future. You can see that my 2nd call can start where the results of the previous call left off:

memoization results

By using memoization, this implementation of the Fibonacci function has a time complexity of O(n). Another way to improve the performance of our code, without using memoization, is to use a loop:

function fibonacci(n) {
  var sequence = [0, 1];
  for (var i = 2; i <= n; i++) {
    sequence.push(sequence[i-1] + sequence[i-2]);
  }
  return sequence;
}

The choice between memoization or a loop depends on the specific requirements and constraints of the use-case. While the time complexity of a loop-based solution is still O(n), it can be faster than the memoization approach for small or medium-sized values of n. If simplicity and readability are a higher priority, or if memory usage is a concern, a loop-based solution may be a better option.

Memoization is considered a “dynamic programming” technique. Dynamic programming involves solving sub-problems once and storing the results for future reference, which can significantly improve the efficiency of the overall solution.

Debugging Mobile CSS on Chrome for Android

debug mobile css on Android

On this website (this very one you are reading) I have a resume page. On it, I display a timeline styled with CSS. I use the border-radius property to create circles for the years on that timeline. The years connect between <div> elements that represent my work experience.

timeline displayed on a resume webpage
An image can be worth a forty-two words

It looks great (at least,  I think so). Except on mobile. Specifically, on Android running Chrome. The circle appears oblongly squished.

Broken CSS on Android
Broken CSS on Android

I could not recreate this bug on my laptop, even when I used Chrome Developer Tools to simulate mobile. Not being able to reproduce a bug consistently is a very frustrating experience.

Chrome developer tools
I couldn’t recreate the mobile bug on my laptop. *Sigh*

USB debugging

I would have to use remote debugging via Chrome DevTools. The first step was to enable “Developer Options” on my Android device. I was using a S21 Galaxy Ultra. On this device I navigated to “Settings” -> “About Phone” -> “Software information”. Then I triple tapped the “Build number” and received a toast message “Developer mode activated”. This feels familiar, as it has been a similar process on previous Android devices that I have owned. I’d post a picture of my software information screen, but am worried that some of the data could be used maliciously by strangers on the internet.

“Developer options” was revealed in my “Settings” app. From there, I could turn on “USB debugging”

usb debugging in the developer options menu

Now, I could connect my Android to my MacBook. From my MacBook, I opened Chrome and navigated to chrome://inspect/#devices

view usb connected devices running chrome

As long as my Android also had Chrome running, I could see my device listed with any open browser tabs. Clicking “inspect” opened a new window on my laptop that mirrored my cellphone’s screen. When I scrolled on one, it reflected on the other.

Inspect mobile device from desktop

CSS Solution

I could inspect elements from the developer tools panel. This was exactly what I needed to debug the problem. And, the fix ended up being pretty easy. Here’s the original, relevant CSS:

.timeline .year {
  font-size: 1em; 
  line-height: 4;
  border-radius: 50%;
  width: 6em; 
}

The issue was ultimately with the width and height properties. The circles look correct on my desktop browser because the width and height rendered to nearly identical – 64px by 66px. To get a circle with CSS you need an element with the same height and width (the greater the difference, the less even and more stretched the circle appears), and then set the border-radius to 50%. On Android, that same element was being rendered as 64px by 85px. This was most probably happening because the height was not being explicitly defined.

As a remedy, I hard-coded the width and height properties. I changed the unit of measurement to pixels for both.

.timeline .year {
  font-size: 1em; 
  line-height: 4;
  border-radius: 50%;
  width: 65px;
  height: 65px;
}

This fixed the circle from being stretched. But, now the text was not centered that way that it should be.

Fixed CSS displays a circle

That was happening because of the line-height property. Since it was set without a unit of measure, most browsers would interpret it to mean a multiplier of the current font-size. And, the font-size was also using a relative unit of measure, em. Right away, that was a code smell. It was a browser issue, where along the way values were not being calculated as expected.

On mobile, the font-size was being calculated to 20.8px. On desktop, the font-was was being calculated to 16px. I fixed this by changing the line-height value to an absolute unit of measure:

.timeline .year {
  font-size: 1em; 
  line-height: 65px;
  border-radius: 50%;
  width: 65px;
  height: 65px;
}

Palindromes in PHP

php code

A palindrome is a word (or a string of characters) that can be read identically either forwards or backwards. Examples include:

racecar
madam
mom
level
civic
kayak
rotavator

The logic for determining a palindrome is simple. Take the input, reverse it, and then compare it to the original. PHP even has a built-in operation, strrev(), to reverse strings. We can write a function to judge if an input string is a palindrome:

function determinePalindromeWithReverse($value){
	$reverse = strrev($value);
	if($reverse === $value){
		echo "true \n";
		return true;
	}
        return false;
}

During an interview, for a role as a Software Engineer, I was asked “Given a string, determine if you can make it a palindrome by removing at most 1 character.”

To solve that challenge, I can loop through the string while increasing the value of a counter variable. On each iteration, I’d remove a single character (whose index is determined by the count), reverse the result, and then compare it.

function determinePalindromeWithReverseRemoveCharacter($value){
	$reverse = strrev($value);
	if($reverse === $value){
		echo "true \n";
		return true;
	}

	for($i=0;$i<=strlen($value);$i++){
		$first_half = substr($value, 0, $i); // first half of string
		$second_half = substr($value, $i + 1);
		$string_with_one_char_removed = $first_half . $second_half;
		echo "$string_with_one_char_removed \n";
		$reverse = strrev($string_with_one_char_removed);
		if($reverse === $string_with_one_char_removed){
			echo "true \n";
			return true;
		}
	}

}
determinePalindromeWithReverseRemoveCharacter("racecfar"); // true

I use PHP’s substr() function to get the each half of “the new string with one character removed.” The first division starts from the beginning (zero index) and continues up until the counter determined position (zero on the first loop, one on the second, and so on). The second part starts one step past the iterative count, and finishes with the string’s end. This results is the original input with a single letter deleted.

To illustrate how this works, I printed out the concatenation each time. You can see that the program continues until the result is a palindrome.

php palindrome

Although this works, reversing the string each time is costly. It reduces the algorithmic efficiency, making the solution “not scalable.” How can we decide if a string is a palindrome without reversing it?

Validating a palindrome using recursion

Judging a string to be a palindrome can be done using recursion. In programming, recursion is when a function calls itself.

Before we worry about removing any characters like we did above, we need a new function to verify a palindrome without reversing it:

function determinePalindromeRecursively($value){
    if ((strlen($value) < 2)){
        // echo "true \n";
        return true;
    }else{
        if (substr($value,0,1) == substr($value,(strlen($value) - 1),1)){
            echo substr($value,1,strlen($value) - 2) . "\n";
            return determinePalindromeRecursively(substr($value,1,strlen($value) -2));
        }else{
            // echo " Not a Palindrome"; 
            return false;
        }
    }
}

This method compares the first and last characters of the input. If they match, our code will remove them and pass the updated $value back around to itself, recursively. This continues until we get down to a single letter, or less – when we know that the original string was a palindrome.

To get the first character, we tell the substr() method to take the $value, start at the beginning (zero index), and collect a single element: substr($value,0,1)

To get the last character, we tell the substr() method to take the $value, start at the end (the string’s length minus one), and collect a single element: substr($value,(strlen($value) – 1),1)

To remove both the first and last letters, we tell substr() to start just past the first element (represented by an index of 1), and to collect the string’s length worth of characters minus two.

Notice that on each recursive loop, the string loses the front and back symbols.

cli output

Now, remember the original challenge: “Given a string, determine if you can make it a palindrome by removing at most 1 character.”

All that is left is to use our recursive function in tandem with removing a single character per loop.

function determinePalindromeRecursively($value){
    if ((strlen($value) < 2)){
        // echo "true \n";
        return true;
    }else{
        if (substr($value,0,1) == substr($value,(strlen($value) - 1),1)){
            echo substr($value,1,strlen($value) -2) . "\n";
            return determinePalindromeRecursively(substr($value,1,strlen($value) -2));
        }else{
            // echo " Not a Palindrome"; 
            return false;
        }
    }
}

function determinePalindromeRecursivelyWhileRemovingOneCharacter($value){

    for($i=0;$i<=strlen($value);$i++){
        $first_half = substr($value, 0, $i); // first half of string
        $second_half = substr($value, $i + 1);
        $string_with_one_char_removed = $first_half . $second_half;
        // echo "$string_with_one_char_removed \n";
         
        if(determinePalindromeRecursively($string_with_one_char_removed)){
            echo "true \n";
            return true;
        }
    }
    echo "false \n";
    return false;

}

determinePalindromeRecursivelyWhileRemovingOneCharacter("racecadr");

Give it a try, refactor my code, and see if you can solve this problem in a different way. There are other computer science puzzles about palindromes that you can apply this logic towards. Have fun!

Meditation & Mindfulness for Programmers

Meditation & Mindfulness for Programmers

Programming and meditation have a lot in common. Both demand focus and concentration and can enhance your ability to think clearly and solve problems.

When you program, you are constantly thinking critically and solving problems. You must be able to debug your code when something goes wrong, pay close attention to the little things, and think rationally. This can be mentally difficult since it calls for intense focus and concentration.

Focus and concentration can be enhanced through the practice of meditation. It can entail sitting in quiet while concentrating on your breath or a mantra, which is a particular word or phrase. This can assist with distraction removal and strengthen your capacity for sustained attention.

I started meditating early in my career as a programmer. Having had an interest in Buddhism, the tangental practice of meditation was appealing as a self-care ritual. I didn’t anticipate the impact its benefits would have on my skill, motivation, and focus. These necessary attributes compounded as my practice grew.

Meditation can help reduce stress and anxiety. This is important for programmers, as the work can be challenging. The ability to stay calm and focused in the face of stress can be invaluable in the programming world.

I had always been a workhorse, spending hours upon hours coding and debugging. Meditating for just a few minutes a day helped me to clear my mind and focus on the task at hand. I discovered I could sleep better and was less irritable.

As I continued to meditate, I found that my productivity increased, and I was able to tackle problems that previously seemed insurmountable with ease. My coding was more precise and effective. I was able to think more imaginatively and provide fresh ideas for problems.

I was so impressed with the benefits of meditation that I began to teach it to my colleagues. They also discovered that it made people more productive and happier at work.

Writing as a Meditation Practice

In another post, Reading Habits for Programmers, I discuss the benefits of practicing focus to improve coding skills. I mention that “if reading benefits your coding ability, then meditation does too”. I would go as far as to say that reading is a form of meditation. Any time we intentionally shift our focus from scattered to laser-like, we are practicing mindfulness. Note-taking and blogging is a great way to do that too.

Writing about how the world seems through your own particular lens fosters mindfulness and appreciation. It keeps your mind grounded in this realm. Journaling is an important ritual that I practice daily, but it is hard to take note of and digest everything that happens in our lives. Doing it here is a way that I can highlight the stuff that has truly touched me.

To get philosophical about it, I think that what’s really out there and what we experience might be very different things.  Like how a the experience of a computer screen showing a beautifully drawn graphical user interface never hints at the reality of computer boards directing electrical circuits to represent the information we see. Our notion of reality is a digital simulation instigated by the sensory input interpreted through our senses.

Walking meditation (kinhin) is another form that has helped get my through challenging times. Solutions, both to engineering problems as well as life obstacles, reveal themselves mid-stride. Stress relief can be induced by physical activity. Fresh air and blood flow are good for the brain. Light exercise is the necessary distraction that gives our mind space to breathe.

Mindfulness

Our senses keep us plugged into reality. They instantly create a connection to the present. Paying attention is the only way to experience this moment in life. If you’re feeling distracted, panicked, or out-of-touch with reality, try taking time to intentionally notice the things that stimulate you.

Setting out a short period of time each day to sit quietly and concentrate on your breathing might serve as a simple way to include meditation & mindfulness into your regular schedule. There are numerous styles of meditation, so it’s worthwhile to try out different techniques to determine which ones suit you.

Though they may appear unrelated, programming and meditation have more in common than you may imagine. Making meditation & mindfulness a daily habit can help you focus better, manage stress and anxiety, and become a better programmer.

Even under the richest of experiential excitement, without mindfulness there is no participation with, nor illusion of, reality. If you mindlessly read a book, you might as well have not read it. If you day-dream during a movie, you may know as much about the plot as someone who has never saw it. The same is true for life in its entirety. Don’t miss out – pay attention.

You can train yourself to get better at paying attention. The better you get at it, the more you will experience the richness of vibrancy of this world. The two best techniques I have found for this is: meditation and reading.

Sort an HTML Table Using JavaScript

Sort an HTML Table Using JavaScript

For a recent side project I was tasked with enhancing an existing HTML table. That table displayed search results. The records were dynamic, populated by an AJAX call after the “search” button was pressed. One of the requests was to let users click on the column headers to sort the table. Each click would organize the data, toggling ascending and descending, based on the column values.

A table with data about dogs

My first idea was to use a front-end library. I love abstractions, and hate reinventing the wheel. I’ve used the DataTables jQuery plug-in before, and thought it might be a good fit. All I had to do was include two CDN file references – one for CSS styles and another for JavaScript functionality. After that, I could select the table by ID and call a single function:

<link href='//cdn.datatables.net/1.13.2/css/jquery.dataTables.min.css' rel='stylesheet' type='text/css'>
<script src="//cdn.datatables.net/1.13.2/js/jquery.dataTables.min.js"></script>

<script>
$(document).ready( function () {
	$('#dog-table').DataTable();
} );
</script>

This added quick and easily out-of-the-box functionality, with bells and whistles.

It seemed great, but the extras that it added, such as pagination and front-end search were unnecessary, and actually got in the way of the design specification. Those might be easy enough to clean up by passing options into the method call, or even with a bit of custom CSS, but still seemed like overkill.

Further, the DataTables library would occasionally throw errors about an “incorrect column count”, depending on what results my back-end provided. That was because the data model, and possible front-end actions for this app were more complex that you might think. The HTML wasn’t strictly semantic and the information wasn’t just tabular.

The more I thought about it, the more I felt that plain vanilla JavaScript should be enough to get the job done. And, since we’re living in the future, I decided to ask an AI chat-bot called ChatGPT.

I asked “How can I use jQuery to sort an HTML table by a specific column?”

Asking ChatGPT about coding

It told me that “You can use the sort method of JavaScript arrays combined with the map method to sort an HTML table by a specific column,” and gave me a specific code example!

I was very impressed. Here is the JavaScript code it provided:

<script>
$(document).ready(function() {
  var table = $('#myTable tbody tr').get();

  table.sort(function(a, b) {
    var A = $(a).children('td').eq(1).text();
    var B = $(b).children('td').eq(1).text();

    if(A < B) {
      return -1;
    }

    if(A > B) {
      return 1;
    }

    return 0;
  });

  $.each(table, function(index, row) {
    $('#myTable').children('tbody').append(row);
  });
});
</script>

I added this code to a click-handler in my app, after adjusting the element selectors. Although it worked (kind of), it did not operate quite as I expected. It only performed the sort on a single column, and did not alternate the order on each click.

I continued to ask the chat-bot more questions, making refinements to the functionality. I wanted the code to toggle between ascending and descending on each click. Also, I figured it could be nice to avoid jQuery completely and just use basic JS.

Chat bot solving code problems

Eventually, it told me “To toggle between ascending and descending order when sorting the table, you can keep track of the current sorting order for each column in a separate array”. Below, you can see the full code implementation:

<style>
  table {
  border-collapse: collapse;
  width: 100%;
}

th, td {
  text-align: left;
  padding: 8px;
  border-bottom: 1px solid #ddd;
}

tr:nth-child(even) {
  background-color: #f2f2f2;
}

th {
  background-color: #4CAF50;
  color: white;
  cursor: pointer;
}

td:first-child {
  font-weight: bold;
}

td:nth-child(3), td:nth-child(4) {
  text-transform: capitalize;
}
#search-input {
  padding: 8px;
  margin-bottom: 12px;
  width: 100%;
  box-sizing: border-box;
  border: 2px solid #ccc;
  border-radius: 4px;
  font-size: 16px;
}

#search-input:focus {
  outline: none;
  border-color: #4CAF50;
}
</style>
<input type="text" id="search-input" placeholder="Search breeds...">
<button>Search</button>
<table id="dog-table">
  <thead>
    <tr>
      <th>Breed</th>
      <th>Origin</th>
      <th>Size</th>
      <th>Temperament</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Labrador Retriever</td>
      <td>Canada</td>
      <td>Large</td>
      <td>Friendly, outgoing, and active</td>
    </tr>
    <tr>
      <td>German Shepherd</td>
      <td>Germany</td>
      <td>Large</td>
      <td>Loyal, confident, and courageous</td>
    </tr>
    <tr>
      <td>Poodle</td>
      <td>France</td>
      <td>Small to Large</td>
      <td>Intelligent, elegant, and proud</td>
    </tr>
    <tr>
      <td>Bulldog</td>
      <td>England</td>
      <td>Medium</td>
      <td>Determined, friendly, and calm</td>
    </tr>
    <tr>
      <td>Beagle</td>
      <td>England</td>
      <td>Small to Medium</td>
      <td>Cheerful, determined, and friendly</td>
    </tr>
  </tbody>
</table>


<script>
// Get the table element
const table = document.querySelector('table');

// Get the header row and its cells
const headerRow = table.querySelector('thead tr');
const headerCells = headerRow.querySelectorAll('th');

// Get the table body and its rows
const tableBody = table.querySelector('tbody');
const tableRows = tableBody.querySelectorAll('tr');

// Initialize sort order for each column
let sortOrders = Array.from(headerCells).map(() => null);

// Attach a click event listener to each header cell
headerCells.forEach((headerCell, index) => {
  headerCell.addEventListener('click', () => {
    // Extract the column index of the clicked header cell
    const clickedColumnIndex = index;
    
    // Toggle the sort order for the clicked column
    if (sortOrders[clickedColumnIndex] === 'asc') {
      sortOrders[clickedColumnIndex] = 'desc';
    } else {
      sortOrders[clickedColumnIndex] = 'asc';
    }
    
    // Sort the rows based on the values in the clicked column and the sort order
    const sortedRows = Array.from(tableRows).sort((rowA, rowB) => {
      const valueA = rowA.cells[clickedColumnIndex].textContent;
      const valueB = rowB.cells[clickedColumnIndex].textContent;
      const sortOrder = sortOrders[clickedColumnIndex];
      const compareResult = valueA.localeCompare(valueB, undefined, { numeric: true });
      return sortOrder === 'asc' ? compareResult : -compareResult;
    });
    
    // Rebuild the table in the sorted order
    tableBody.append(...sortedRows);
  });
});

</script>

Using predictive language models as a coding assistant is very helpful. I can’t wait to see what other uses we find for this technology, especially as it gets better.

Remove Duplicates From a MySQL Database Table

Remove duplicates from a MySQL database table

I discovered a bug in a web app that I built a few years ago. It was difficult to debug because it only happened intermittently. As any programmer knows, issues that can’t be reproduced consistently (and locally) present the most pain. Ultimately, it was causing database records to be created in double – but only when certain conditions evaluated true in the app state.

I’ll get into the code fix in another post. Here, I’ll show you how I cleaned up the database. This application has over ten-thousand data records in production. The first thing I did before messing around was to export a back-up of the prod DB. That was only me being extra careful –  I already have a nightly job that dumps the entire production database as a .sql file to an S3 bucket. Taking an export on the fly is easy through phpMyAdmin.

Export database from phpMyAdmin
Export database from phpMyAdmin

Step one is to identify duplicates and store them in a temporary table, using a GROUP BY clause. In MySQL (and most other SQL-based database systems),GROUP BY is used to group rows from a table based on one or more columns.

The duplicate rows that I am interested in have all identical values, except for their primary keys. I can group those rows (and put them into a new, temporary, table) by including all of the table columns names (except the primary key) in my SQL statement. You can list those names in phpMyAdmin with this command:

SHOW COLUMNS FROM `records`;

Show all columns

My tables have quite a few columns. Instead of copy/pasting each field name, I used SQL code to list them out together. This was possible by leveraging the INFORMATION_SCHEMA database, a special system database that provides metadata about the database server itself in MySQL.  I could retrieve the column names and then concatenate them into a single string using the GROUP_CONCAT function:

SELECT GROUP_CONCAT(column_name SEPARATOR ', ') AS column_list
FROM information_schema.columns
WHERE table_schema = 'bjjtracker'
  AND table_name = 'records';

The result displayed as abbreviated until I selected “Full texts” from the options menu (highlighted below)

mysql columns

I could now copy/paste that column_list into my SQL statement. Remove the primary key field (usually the first one), or else no duplicates will be found (unless your use-case involves records having repeated primary key values, which is a less likely scenario).

CREATE TABLE TempTable AS
SELECT userid, type, date, beltrank, medal, weight, notes, created_date, style -- List all columns except the primary key
FROM `records`
GROUP BY userid, type, date, beltrank, medal, weight, notes, created_date, style -- Group by all columns except the primary key
HAVING COUNT(*) > 1; -- Indicates their is more than one record with exactly matching values

Now we have a new table that contains records that are duplicative in our original table. Step 2 is to delete the duplicates from the original table.

DELETE FROM `records`
WHERE (userid, type, date, beltrank, medal, weight, notes, created_date, style) IN (
    SELECT userid, type, date, beltrank, medal, weight, notes, created_date, style
    FROM TempTable
);

Don’t forget to delete that temporary table before you leave:

DROP TEMPORARY TABLE IF EXISTS TempTable;

Dealing with NULL values

On the first table I used this on, everything worked as expected. On a subsequent run against another table, zero rows were deleted even though my temp table contained duplicate records. I deduced that it was because of NULL values causing the comparison to not work as expected. I figured that I had to handle NULL values explicitly using the IS NULL condition on each field.

DELETE FROM recordsdetails
WHERE 
    (userid IS NULL OR userid, 
     recordid IS NULL OR recordid, 
     detailtype IS NULL OR detailtype, 
     technique IS NULL OR technique, 
     reps IS NULL OR reps, 
     partnername IS NULL OR partnername, 
     partnerrank IS NULL OR partnerrank, 
     pointsscored IS NULL OR pointsscored, 
     pointsgiven IS NULL OR pointsgiven, 
     taps IS NULL OR taps, 
     tappedout IS NULL OR tappedout, 
     result IS NULL OR result, 
     finish IS NULL OR finish, 
     created_date IS NULL OR created_date) 
IN (
    SELECT userid, recordid, detailtype, technique, reps, partnername, partnerrank, pointsscored, pointsgiven, taps, tappedout, result, finish, created_date
    FROM TempTable
);

But yet, I still got zero rows being deleted. This time though, I was seeing a warning. It complained: “Warning: #1292 Truncated incorrect DOUBLE value”

Zero rows found

This suggests that there is a data type mismatch or issue in the comparison involving numeric and string values. My guess is that the IS NULL handling was causing type conversion issues. To remedy this, I wrote a more explicit query by combining the AND and OR conditions.

DELETE FROM recordsdetails
WHERE 
    (userid IS NULL OR userid IN (SELECT userid FROM TempTable)) AND
    (recordid IS NULL OR recordid IN (SELECT recordid FROM TempTable)) AND
    (detailtype IS NULL OR detailtype IN (SELECT detailtype FROM TempTable)) AND
    (technique IS NULL OR technique IN (SELECT technique FROM TempTable)) AND
    (reps IS NULL OR reps IN (SELECT reps FROM TempTable)) AND
    (partnername IS NULL OR partnername IN (SELECT partnername FROM TempTable)) AND
    (partnerrank IS NULL OR partnerrank IN (SELECT partnerrank FROM TempTable)) AND
    (pointsscored IS NULL OR pointsscored IN (SELECT pointsscored FROM TempTable)) AND
    (pointsgiven IS NULL OR pointsgiven IN (SELECT pointsgiven FROM TempTable)) AND
    (taps IS NULL OR taps IN (SELECT taps FROM TempTable)) AND
    (tappedout IS NULL OR tappedout IN (SELECT tappedout FROM TempTable)) AND
    (result IS NULL OR result IN (SELECT result FROM TempTable)) AND
    (finish IS NULL OR finish IN (SELECT finish FROM TempTable)) AND
    (created_date IS NULL OR created_date IN (SELECT created_date FROM TempTable));

That worked! With a cleaned database, it was time to figure out what was causing the bug in the first place, and to fix the problem.


 

 

Clones in quiet dance; Copies of our code converge; Echoes of our souls;

Online Ordering for a Restaurant Website

online ordering system

A Digital Transformation Case Study: Boosting Restaurant Sales with Custom Web Development and Online Ordering Integration

Client background & challenge

When I was younger I worked as a pizza delivery driver. Years later, the pizzeria where I once worked commissioned me to build their website. They were busier than ever thanks to online ordering (GrubHub, Seamless, UberEats), but were getting hit with high service fees.

They wanted their own website to be able to take orders for food online and send a notification to their iPad. That way they could avoid using apps like GrubHub that charged additional fees.

Project overview & execution

I used a service called GloriaFood that provides ready-made website templates, a secure payment process, and a messaging system. It integrates with Stripe for processing payments. There is an iPad app that receives push notifications when new orders are placed. The website builder required no code, and had a ton of options. I was able to register the pizzeria’s domain name directly though the admin portal, and generate a sales optimized website with hosting all setup.  It was “seamless” – pun intended!

GloriaFood admin panel

There are also options for integrating their ordering UI with an existing website, a Facebook page, or a dine-in QR code. The an option to publish a custom app required an additional cost per month.

pizza website

I even traveled to this restaurant’s physical location, selected and purchased a tablet computer for them, installed the GloriaFood app to receive orders, and connected it to their mobile printer.

gloriafood order received

It’s amazing how much I was able to accomplish without writing a single line of code. The most technical part of this project was setting up a Stripe account and putting the API keys into the GloriaFood admin panel. GloriaFood is a product by Oracle, a company that specializes in providing a wide range of software and hardware products and services.

Print Design

As an extra part of this project, I designed a business card with a QR code linking to the new website. The business owner planned to give this to customers who ordered through other food ordering apps such as GrubHub, Seamless, UberEats, and Slice.

Business card for pizza business website

Results

Sales Increase

Since the launch of the new website, the restaurant has witnessed a notable surge in online orders, marking a 25% increase. This substantial rise not only signifies a successful digital transformation but also illustrates the growing customer preference for a seamless, direct ordering experience. The intuitive interface and easy navigation on the restaurant’s website have played a strong role in attracting and retaining customers, driving a higher volume of online orders and significantly contributing to the restaurant’s revenue growth.

Cost Savings

Transitioning from third-party ordering platforms like GrubHub, Seamless, and UberEats to a self-hosted online ordering system through has led to big cost savings. Third-party platforms usually charge hefty commissions, which eat into the restaurant’s profits and inflate prices for customers. With the new website, the restaurant has eliminated these intermediary costs, ensuring better profitability while also offering customers more competitive pricing.

Customer Feedback

The feedback received from both the restaurant management and its customers has been overwhelmingly positive.  The restaurant staff has praised the streamlined process, which has simplified order management and allowed for a smoother operation during busy hours.

How I Helped a Business Optimize Their Google Ads

Google Ads being set up

After a client approached me about improving their Google Ads campaign, I could tell they were doing a lot of things right—but they weren’t getting the results they wanted. Their ads were active, their click-through rate was decent, and they were spending about $650 per month. On the surface, everything seemed fine.

But as I dug deeper, I saw an opportunity to transform their campaign from “good enough” into something that could truly drive new clients to their business.

Google Ad Account Audit

The first thing I noticed was that their ads setup was missing some key pieces. For starters, there was no way to measure what happened after someone clicked on an ad. Conversion tracking hadn’t been set up, so there was no way to tell if those clicks led to sign-ups, contact form submissions, or any other meaningful action. It’s like running a sales campaign and never finding out how many people bought something.

Another issue was the structure of the ads themselves. Everything was running through a single ad and ad group, all of which pointed to their homepage. While this kind of setup can work as a starting point, it’s not ideal for targeting specific audiences. Imagine searching for “self-defense classes” and landing on a generic homepage with no mention of self-defense—it’s a missed opportunity to connect with a potential client.

Finally, their campaign wasn’t linked to Google Analytics, which meant there was no insight into what visitors did once they arrived on the site. Did they spend time exploring? Did they leave immediately? Did they look at multiple pages? These questions were left unanswered.

Google Ad Campaign Improvements Plan

After reviewing their campaign, I proposed a complete overhaul. First, I explained the importance of defining what success looks like—what actions do we want people to take when they click on an ad? For this client, it made sense to track things like contact form submissions and clicks to their scheduling platform. By setting up conversion tracking, we could finally measure the real impact of their ad spend.

Next, I suggested restructuring their campaign into three distinct ad groups, each with its own audience and purpose. The first ad group would target people new to their services, highlighting beginner-friendly options. The second would focus on fitness enthusiasts looking for a fun and effective workout. The third would spotlight programs for women, emphasizing empowerment and inclusion.

Each ad group would feature two different ads to test different messages and see what resonated most with each audience. And instead of pointing all traffic to the homepage, I recommended creating dedicated landing pages tailored to the ad group. If someone clicked on an ad for fitness classes, they’d land on a page showcasing the physical and mental benefits of their programs. If they clicked on an ad for women’s classes, they’d be greeted with content specifically designed for that audience.

Finally, I emphasized the need to connect Google Analytics to their campaign. This would give us a clearer picture of how people interacted with the site after clicking on an ad, providing valuable insights for ongoing optimization.

Marketing & Development Implementation

The client loved the plan, and here’s what I did next. I spent a couple of hours implementing these changes, setting up the ad groups, writing the ads, building the landing pages, and integrating analytics and conversion tracking. Once that was done, we were ready to relaunch the campaign with a much stronger foundation. I used the Google Site Kit plugin for WordPress to manage analytics.

Google site kit integrations

I built the landing pages as part of their WordPress website. I drafted the copy for each page, added relevant photos, and applied proven design principles that would guide potential customers through the sales funnel. I used the same copy outline and content layout for each.

Landing Page Content Outline

  1. Hero Section
    1. Headline
    2. Subheadline
    3. CTA Button
  2. Benefits Section
    Headline: Why this offer is valuable

    1. Highlight key benefit 1
    2. Highlight key benefit 2
    3. Highlight key benefit 3
  3. What to Expect / Program Details
    1. Headline: Set expectations
    2. Short paragraph explaining details or structure
    3. CTA button
  4. Testimonials
    Headline (Social Proof): “What are customers are saying”

    1. Testimonial 1
    2. Testimonial 2
  5. FAQ Section
    Headline: Answer common questions

    1. Q1 & Answer
    2. Q2 & Answer
    3. Q3 & Answer
  6. Final CTA Section
    1. Headline (Closing statement)
    2. CTA button

Getting Results with Google Ads

Of course, ads don’t run themselves. The client will need to decide when they want to turn the campaign back on and how much they’re comfortable spending each month. But with these optimizations in place, they’ll be able to make data-driven decisions and see exactly how their investment is paying off.

Every business wants to get the most out of their marketing budget. For this client, that means attracting new customers who are truly interested in their services. By taking the time to set up conversion tracking, target specific audiences, and create tailored landing pages, we’re turning their Google Ads campaign into a powerful tool for growth.

If you’re running Google Ads and feel like you’re not getting the results you should, you’re not alone. With the right strategy and a little bit of work, you can transform your campaign into something that delivers real, measurable value.

Want to learn more about how I can help your business grow? Let’s talk.