Our church finds itself using the Duplicate Finder a lot. An issue I had was scanning people's info looking for things like spelling mistakes in emails, etc. Not only did this create human error on my part, but it also took up more time.

I ended up making a simple frontend script that checks and sees if the info matches in the Duplicate Finder table. If it does match, it turns green. It's pretty simple but makes things easier and more accurate.

Installation:

All you have to do is go to your

"Duplicate Finder" > select a potential duplicate > "Person Duplicate Details" > "Block Properties" > "Advanced Settings" > "Pre-HTML" and paste this in there.

  
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
$(document).ready(function() {
  // Select the header row
  const headerRow = document.querySelector(".grid-table.table.table-bordered.table-striped.table-hover > thead > tr:nth-child(2)");

  // Find all th elements within the header row
  const headerColumns = headerRow.querySelectorAll('th');

  let phoneColumnIndex = -1;
  let addressColumnIndex = -1; // Initialize address column index

  // Iterate over each th element to find the "Phone Numbers" and "Addresses" columns
  headerColumns.forEach((th, index) => {
    if (th.textContent.trim() === "Phone Numbers") {
      phoneColumnIndex = index;
    } else if (th.textContent.trim() === "Addresses") {
      addressColumnIndex = index; // Set address column index
    }
  });

  console.log("Phone Numbers column index:", phoneColumnIndex);
  console.log("Addresses column index:", addressColumnIndex); // Log address column index

  // Select the first row (the header row) to compare against
  const firstRow = $('.grid-table.table.table-bordered.table-striped.table-hover > tbody > tr:first-child');

  // Find the  elements in the first row
  const firstRowTds = firstRow.find('td');

  // Get the phone numbers from the top row
  const topRowPhoneNumbers = firstRowTds.eq(phoneColumnIndex).find('ul.list-unstyled li.phonenumber p').map(function() {
    return $(this).text().trim();
  }).get();

  const topRowAddresses = firstRowTds.eq(addressColumnIndex).find('ul.list-unstyled li.address p').map(function() {
    return $(this).text().trim();
  }).get();

  // Select all  elements except the first one (header row)
  const trElements = $('.grid-table.table.table-bordered.table-striped.table-hover > tbody > tr:not(:first-child)');

  // For each selected , find and compare the  elements
  trElements.each(function() {
    const currentRowTds = $(this).find('td');

    // Iterate through the  elements in the current row
    currentRowTds.each(function(index) {
      // Check if this is the phone number column
      if (index === phoneColumnIndex) {
        const phoneNumbers = $(this).find('ul.list-unstyled li.phonenumber p'); // Find all phone number paragraphs

        // Check if there are any phone numbers in the cell
        if (phoneNumbers.length > 0) {
          let matchFound = false;

          phoneNumbers.each(function() {
            const phoneNumber = $(this).text().trim(); // Get the text of the phone number

            // Check if the phone number appears anywhere in the top row's phone numbers
            if (topRowPhoneNumbers.includes(phoneNumber)) {
              matchFound = true;
              $(this).css('color', 'green'); // Set the color of the matching phone number to green
            } else {
              $(this).css('color', 'black'); // Set the color of the non-matching phone number to black
            }
          });

          if (matchFound) {
            $(this).css('background-color', '#90ee905c'); // Set the background color to #90ee905c if a match is found
          } else {
            $(this).css('background-color', 'transparent'); // Reset background color if no match is found
          }
        }
      } 
      // Check if this is the address column
      else if (index === addressColumnIndex) {
        const addresses = $(this).find('ul.list-unstyled li.address p'); // Find all address paragraphs

        // Check if there are any addresses in the cell
        if (addresses.length > 0) {
          let matchFound = false;

          addresses.each(function() {
            const address = $(this).text().trim(); // Get the text of the address

            // Check if the address appears anywhere in the top row's addresses
            if (topRowAddresses.includes(address)) {
              matchFound = true;
              $(this).css('color', 'green'); // Set the color of the matching address to green
            } else {
              $(this).css('color', 'black'); // Set the color of the non-matching address to black
            }
          });

          if (matchFound) {
            $(this).css('background-color', '#90ee905c'); // Set the background color to #90ee905c if a match is found
          } else {
            $(this).css('background-color', 'transparent'); // Reset background color if no match is found
          }
        }
      }
      // For other columns
      else {
        const currentCellText = $(this).text().toLowerCase(); // Convert to lowercase
        const firstRowCellText = firstRowTds.eq(index).text().toLowerCase(); // Convert to lowercase

        // Check if the first row's cell is not blank and if it doesn't match the current cell
        if (firstRowCellText.trim() !== '' && currentCellText !== firstRowCellText) {
          $(this).css({
            'color': 'red',
            'background-color': 'transparent' // Reset background color
          });
        } else if (firstRowCellText.trim() === '') {
          // If the first row's cell is blank, set the text color to black
          $(this).css({
            'color': 'black',
            'background-color': 'transparent' // Reset background color
          });
        } else {
          $(this).css({
            'color': 'green',
            'background-color': '#90ee905c' // Set background color to #90ee905c
          });
        }
      }
    });
  });
});
</script>
  

Additionally, you can add a custom column for when the profile was created.

If you add this to the custom grid options:

    
        {% person where:'Id == "{{ Row.PersonId }}"' %}
    {{ person.CreatedDateTime }}
{% endperson %}