Yoshi’s Oakland

A custom front end solution for a high value client

WhenFebruary, 2019

RoleFront end developer

WhereDeveloped at Eventbrite

homepagebigger

Background

When we built our new Eventbrite plugin, an important feature was lost

A feature for grouping events
Jazz and comedy clubs loved our Consecutive Events feature, which allowed venues to group repeat performances into a single event. Without this option, recurring events—for example, a jazz club with a performer in residence—would clutter the venue’s event list, leading to confusion for customers trying to buy tickets.

Screen Shot 2020-05-16 at 7.41.15 PM

No Consecutive Events

Screen Shot 2020-05-16 at 7.41.34 PM

With Consecutive Events

Screen Shot 2020-08-26 at 12.57.41 PM

Full list of events

A new plugin
The Eventbrite Wordpress plugin allows venues to link their events, which are managed in Eventbrite, to their websites, which are built in Wordpress. When the plugin went through a critical update, the Consecutive Events feature was lost, and the clients who relied on it were shaken.

I was asked to build a temporary, front end solution to restore this popular feature.

Challenge

Replicating a feature that relied on data that was no longer available

Markup Before jQuery Work

<article class="list-view-item card event-status-live eb-event-id-109416507720 eb-org-id-23226392566 eb-venue-id-36082625">

	<div class="show-times">
        <time class="date-time">
	    	<span class="dates">Event Date</span>
	        <section class="times">
	        	<span class="start">Event Time</span>
	        </section>
        </time>
    </div>


    <a href="https://www.yoshis.com/e/event-title-109416507720/" class="image-url">
        <img src="https://img-dev.evbuc.com/https%3A%2F%2Fcdn.evbuc.com%2Fimages%2F103454848%2F312517813772%2F1%2Foriginal.20200612-212153?auto=compress&crop=top&fit=crop&h=100&w=100&s=948ddd95e664e1cf31aed4c587f0a6d8" width="100" height="100" alt="Event Title" title="EVENT TITLE">
    </a>
   	<section class="list-view-details">
        <article class="artist-info">
        	<section class="topline-info presented-by">Topline Info</section>
            <h1 class="event-name headliners">
            	<a href="https://www.yoshis.com/e/event-title-109416507720/">Event Title</a>
            </h1>
        </article>
    </section>
    

    <section class="ticket-price text-center">
        <noscript><a class="tickets" rel="noopener noreferrer" target="_blank"></noscript>
        <button id="eventbrite-widget-modal-trigger-100335849226" href="https://www.eventbrite.com/e/event-title-100335849226" type="button" class="ticket-link primary-link">Tickets</button>
        <noscript></a></noscript>
        <span class="price-range">Ticket Price</span>       
    </section>


</article>






Without grouped consecutive events, the list view was messy and repetitive.

Challenge 1: Grouping events
With the updated plugin, venues no longer had the option to mark an event as part of a series. Without this information, We had to manually group events together.

Challenge 2: Eliminating false positives in search results
Even after we managed to properly group the events, there was another issue: Eventbrites search function looked at events’ full descriptions, not just their titles. This led to false positives in the results, and confusion for customers.

search results

Searching for "con funk shun" would return results that contained "funk" in the description.

Solution

Writing custom JavaScript solutions

Solution 1: Combining events by title
How could we determine which events to group? Our team wrote code to find repeating event titles and automatically combine them into a single event. This code finds event list view items, pushes their titles into an array, and checks to see if any are the same string. If event titles are the same, the code notes the repeating events, gathers their information, and inserts it into the first instance of the event.

Consecutive Event JS Work


var listCount = 0;
var titleArr = [];
var duplicates = {};

// cycles through all the list-view items and puts the titles into an array 
// then adds a number class for future reference
$('.list-view .list-view-item').each(function(){
	$(this).addClass("consec"+listCount);
	var eventTitle = $(this).find('.event-name a').html();
	titleArr.push(eventTitle);
	listCount++;
});

// goes thorugh the array of titles 
// and makes an object with the array position of the titles that repeat
for (var i = 0; i < titleArr.length; i++) {
    if(duplicates.hasOwnProperty(titleArr[i])) {
        duplicates[titleArr[i]].push(i);
    } else if (titleArr.lastIndexOf(titleArr[i]) !== i) {
        duplicates[titleArr[i]] = [i];
    }
}


for(var j = 0; j < Object.values(duplicates).length; j++){
	// finds the first of the repeating events
	var nameCounter = Object.values(duplicates)[j];
	var nameCounterFirst = Object.values(duplicates)[j][0];
	var firstListing = $('.consec'+nameCounterFirst);
	var firstListClass = firstListing.attr('class');
	var classStingLoc = firstListClass.search("eb-event-id-")
	var stingClassCatch = firstListClass.substr(classStingLoc+12);
	var getEndofNumber = stingClassCatch.search(" ");
	var eventsID = stingClassCatch.substr(0, getEndofNumber);
	var theEventSting = eventsID;

	// appends the time and date to the first event
	var firstTimeinc = firstListing.find('.date-time');
	var firstTimes = firstTimeinc.addClass("dont-move");
	var deeets = firstListing.find('.list-view-details');
	$(firstTimes).insertAfter(deeets);
	var fakedate = $('<div class="show-times-wraped"></div>');
	$(fakedate).insertBefore( firstListing.find('.image-url') );
	$(firstTimes).wrap('<div class="event-group-times"></div>');

	//adding link to times
	var firstTime = firstListing.find('.times');
	var firstDate = firstListing.find('.dates');
	firstDate.add(firstTime).wrapAll('<div class="sub-dates0 first"></div>');
	var firstTimeText = firstTime.find('.start').text();
	var firstLink = firstListing.find('.image-url').attr('href');
	firstTime.replaceWith('<a class="times" href="'+firstLink+'" >'+firstTimeText+'</a>');

	//find & hide the ticket button
	var firstTicketButton = firstListing.find('.ticket-price');
	firstTicketButton.hide();
		
	// you get me the children / then I pull the childeren appart
	var lilcount = 0;
	for(var m = 1; m < nameCounter.length; m++){
		lilcount++
		var restofListings = $('.consec'+nameCounter[m]);
		var firstListClasss = restofListings.attr('class');
		var classStingLocc = firstListClasss.search("eb-event-id-")
		var stingClassCatchh = firstListClasss.substr(classStingLocc+12);
		var getEndofNumberr = stingClassCatchh.search(" ");
		var eventsIDD = stingClassCatchh.substr(0, getEndofNumberr);
		var eventIDString = theEventSting += ","+eventsIDD;
		var getDatesandTime = restofListings.find('.date-time');
		getDatesandTime.addClass("first sub-dates"+lilcount);
		var getLinks = restofListings.find('.image-url').attr('href');

		//adding link to times
		var restTime = restofListings.find('.times');
		var restTimeText = restTime.find('.start').text();
		var restLink = restofListings.find('.image-url').attr('href');
		restTime.replaceWith('<a class="times" href="'+restLink+'" >'+restTimeText+'</a>');
			
		getDatesandTime.appendTo(firstTimes);
		restofListings.remove();
	}

	// title & link replaced with seach for title page.
	var firstTitle = firstListing.find('.event-name');
	var titleLink = firstTitle.find('a');
	var titleText = firstTitle.text();
	var titleStrip = titleText.replace(/[^a-zA-Z ]/g, "");
	var searchLink = 'search/?' + eventIDString;
	titleLink.attr('href', searchLink);
}
Screen Shot 2020-08-26 at 3.44.54 PM

Event Id's highlighted in the URL

Solution 2: Using event IDs as a search query
How could we display the grouped events without the false positives? We came up with a workaround based on events’ IDs. We wrote code to pass an event’s ID into the URL as a query, and then pulled it into the list view code so it would display properly.

Markup After jQuery Work

<article class="list-view-item card event-status-live eb-event-id-89351491717 eb-org-id-23226392566 eb-venue-id-33259768 consec1">

    <div class="show-times-wraped"></div>
    <a href="https://www.yoshis.com/e/event-title-89351491717/" class="image-url">
    

        <img src="https://img-dev.evbuc.com/https%3A%2F%2Fcdn.evbuc.com%2Fimages%2F97432384%2F312517813772%2F1%2Foriginal.20200326-221251?auto=compress&crop=top&fit=crop&h=100&w=100&s=766264da99ec26c5a7fde40a03cf7a0d" width="100" height="100" alt="Event Title" title="Event Title">
    </a>
    <section class="list-view-details">
        <article class="artist-info">
            <section class="topline-info presented-by">Topline Info</section>
            <h1 class="event-name headliners">
                <a href="search/?89351491717,96301587641,96303310795,96304634755">Event Title</a>
            </h1>
        </article>
        <article class="date-age">
            <span class="more-info">
                <a href="https://www.yoshis.com/e/event-title-89351491717/">More Info</a>
            </span>
        </article>                	 
    </section>

        

    <div class="event-group-times">
        <time class="date-time dont-move">
            <div class="sub-dates0 first">
                <span class="dates">Event Date</span>
                <a class="times" href="https://www.yoshis.com/e/event-title-89351491717/">Time</a>
            </div>    
            <time class="date-time  sub-dates1">
               <span class="dates">Event Date</span>
	           <a class="times" href="https://www.yoshis.com/e/event-title-96301587641/">Time</a>
            </time>
            <time class="date-time  sub-dates2">
                <span class="dates">Event Date</span>
                <a class="times" href="https://www.yoshis.com/e/event-title-96303310795/">Time</a>
            </time>
            <time class="date-time  sub-dates3">
                <span class="dates">Event Date</span>
                <a class="times" href="https://www.yoshis.com/e/event-title-96304634755/">Time</a>
            </time>
        </time>
    </div>
    
           
</article>

Conclusion

Helped retain a tier one client