angel.co SVG

 At Lou we build out tools to help customers onboard users onto their platform in order to provide a better user experience and increase user retention. One of these tools is the Lou Builder which is a Chrome browser extension that allows the customer to build an onboarding experience right on top of the website with little to no code at all. During my time at Lou I worked mainly on features for the Builder extension and also made improvements to our other services such as the Assistant Script, Dashboard, Landing Page, and API. Some of my most notable contributions included the Builder RedesignWidgets, and Workflow Screen Size.

 Over the 2+ years I spent at Lou, the team and I worked to plan and execute features that would address our current clients' needs but also help attract new customers. Our product adopted a tiered payment model ranging from free to enterprise to broaden the types of clients that we can service. With this, the free tier provides access to a majority of our features with limitations on their use which can be accessed through a paid tier. Along with the outreach done by our buisness development team, this model proved successful as our company"s Monthly Recurring Revenue (MRR) incease by a factor greater than 50x during this period. We attribute this to a collaboration of our team's actions from our client outreach to our service approach to new features. When a client uses Lou, they can expect a consistent flow of new features some of which have been GoalsA / B Testing, and many new Experience step types. Along with this our outreach team works in tandem with all of our clients to address any needs and improvements that can be made to the product to provide the best user experience.

Turnkey Segments

 For my first project I worked on creating "Turn Key" segments (which allows customers to identify and group users) so that using this feature is available out of the box. For this I worked on creating front-end components to display these items on both the dashboard and builder extension. My contributions to this feature focused mainly on updating the styles and served as a nice first project to get my development environment up and ready.

Dashboard page for segments displaying turn key segments.
Dashboard Segments page displaying Turnkey Segment list items.

Landing Page Redesign

 This project I worked on updating the landing page to provide pixel perfect and responsive implementations of the provided mock-ups. For this I utilized CSS grid properties to handle each of the sections and divide them into columns and rows. With appropriate media queries I updated each page to either scale each section or organize the sections into a single column to fit on mobile and tablet devices.

Home Page V2Home Page Menu V2Experience Page V2Build Page V2Personalize Page V2Analyze Page V2Pricing Page V2
Mock-ups used for each page.

 Later on the Pricing Page was updated to provide a more interactive experience to the client as a slider was introduced to display how pricing would change according to the amount of MAUs (Monthly Active Users). This along with small changes to the Home Page were implemented to achieve a more modern look.

Updated Pricing Page.
Pricing page updated to include MAUs slider.
Updated Pricing Table of the Pricing Page.Updated Home Page.Updated Products section of the home page.
Extended Pricing Table and small changes to Home Page.

Templates

 This feature is specific to the Builder where it made creating onboarding Experiences for new a client easier by selecting from a fitting template. From this, the created experience can be edited or added upon to better fit the customer's website. This is an improvement on the previous implementation of a blank Experience as it removes the friction encounter when creating the first Experience.

Lou Builder create from template example
Create an experience from one of Lou's pre-built templates.

 Templates were later on updated to have its own dedicated page within the sidebar as the variety of different Experience types and thus Templates had grown so large. Having this page specific to Experience Templates provided room to expand its functionality such that a Template option can preview its first step when hovered upon. This allows the client to see what would be created before selecting a specific option.

A Template for an Experience can be previewed before selection.

Builder Redesign

 The Builder extension provides a fairly intuitive user interface but its current implementation limits the potential features that can be added on top of it. In this state before its redesign, the extension provides a WYSIWYG (What You See Is What You Get) editor for editing content within an experience restricted inside an <iframe>, sufficient for its existing scope but limiting in potential features. Some of these difficulties include dealing with the height, width, positioning, and user interactions of the experience steps along with that of the <iframe> parent. With this in mind, we decided to move away from the contraints of an <iframe> and instead utilize the Shadow DOM to keep the experience step components isolated away from the host's website, however these also came with its own set of challenges.

 In addition to these structural refactoring, we also wanted to enhance the user experience by providing a set of customizable features such as colors, fonts, and themes. For this we needed to upgrade our implementation of our rich text editor so that these complex features can be added in. Along with this other small touches such as hover previews for created experiences were implemented to provide a more fluid user experience. As shown in the mock-ups below, the build flow of an experience was redesigned to make use of these new features and aid in creating a new experience.

Redesigned home page for Lou Builder Chrome extension.Redesigned build tab for Lou Builder Chrome extension.Redesigned deliver tab for Lou Builder Chrome extension.Redesigned segment tab for Lou Builder Chrome extension.Redesigned publish tab for Lou Builder Chrome extension.
Mockups for proposed Lou Builder Chrome extension redesign.

 This ended up being one of the larger projects that spanned over the course of a couple of months and completely changed the Lou Builder Chrome extension to provide a nicer and more comprehensive user experience.

Builder Redesign: [email protected]

 The first part of this project involved updating our implementation of the WYSIWYG (What You See Is What You Get) editor to utilize further customizable features such as color and fonts. For this we have been using a third party wrapper of the package draft-js called megadraft which has been sufficient for us at this point. However with the goals features of this project, we quickly ran into the  limitations of megadraft and opted to directly usedraft-js itself. This was feasable since the content is stored the same draft-js format in both of the packages and did not need to worry about migrating existing data to a new type of format.

 Since draft-js replaced megadraft as our core dependency for our rich text editor, the included out-of-the-box features such as the basic controls that we previously used were no longer available. This meant recreating the basic controls (i.e.Bold, Italics, Underline, etc.) along with new controls for font family and font color. For this we created our own package to house our components created using draft-js which we named @lou-assistant/draft-components.

Redesigned experience step toolbar component with updated controls.
Mockup for redesigned toolbar controls including those for color and font.

 In order to provide a font family that is as close or exactly that of the one used on the host site, we use an API provided by Google Fonts to provide access to hundreds of free fonts. To do this we follow the API documentation to use the npm package, webfontloader to load in the appropriate files to initialize the desired font family. As for finding the perfect font, a search dropdown component was created to allow the user to type in a desired fornt and peruse through a list of matching results. This search component was integrated into the toolbar alongside the custom font functionality for the WYSIWYG editor.

Utilizing Tangerine Google Font in Experience Step.

 For the font and highlight colors we used the npm package react-color as our color picker component to input or select a color from the host website. At this point we ran into incompatibility issues with the Shadow DOM and some of our core dependencies such including react-color and draft-js. Since moving away from using the Shadow DOM was not an option, the packages were forked and support for use within the Shadow DOM was added in. This was a major hurdle to overcome and once this was done a small amount of polishing and bug fixing was all that was necessary to implement this new editor into the builder. With these components published as a package, we were able to easily use this in our other products such as the Dashboard website and Assistant script.

Builder Redesign: Themes

 When building experiences, our users typically end up using the same styles that match their company's and it can be tedious to enter the same configurations each time. The Themes feature will solve this problem which allows for the commonly used company presets to be saved and used when creating other experiences with the Lou Builder. The configurations for these company style presets can be accessed mainly through the Dashboard page where when saved can be utilized through the Lou Builder.

Component for displaying available and created themes.
Dashboard component for viewing created themes and creating new ones.
Component for displaying available and created themes.
Dashboard page for editing and updating selected theme.

Workflow Revisions

 On the server we refer to experiences as workflows and record the changes made whenever saved as revisions. This is useful for archival purposes and for our own analytics when considering which new projects would have greatest impact. For this admin feature we want to provide a page on the KPI Dashboard to search and view workflows along with their respective revisions. On this feature I spent some time working on the API to build a paginated route to retrieve the appropriate revisions. This route is then called from the Dashboard and with some tweaks to the exisiting components, the experience can be viewed at the time of the revision. This feature gave me a taste of building out improvements to the back-end and integrating these changes on front-end applications such as the Builder and Dashboard.

Page component displaying first workflow revision.Page component displaying current workflow revision.
Dashboard KPI page component for displaying example revisions.

Goals

 Another feature that clients have asked for is the ability to create goals associated with experiences or when a specific event is created. To achieve this a Django app for handling events was created so that a specific goal can be marked as completed if the event with the corresponding name exists. With this the client is able to get insight into user segments and how they respond to the created experiences.

 The initial iteration of this goal form is built inside the existing sidebar page for building out experiences. For this Goals have their own dedicated tab in which the Title, Description, and Event Name can be attributed to it. Along with this the tab allows for a created Goal to be associated with the experience but the ability to create and attach an event is notably missing here. This is done intentionally as at this point the events can only be created through the Lou.track() function in our SDK provided when the user installs our script. This limited the accessibility of this feature to those familiar with our SDK but was enough to get the feature published.

Goals form on dedicated tab for workflow.
Initial implementation for creating a Goal on its own specific tab.

 For these goals to be useful, the client needs to access the accrued information and metrics from the users that complete these goals. For this the experience page was updated to display the associated metrics alongside the other general analytics.

Dashboard page to track analytics associated with Goals.
Dashboard page to track analytics associated with Goals.

 The Goals feature in its existing state allows for the collection of metrics associated with the attached experience. The issue it runs into is the accessiblity of this feature is quite limited due to its exclusive use through the Lou SDK's Lou.track() function. The next update to this feature would move the form to its own page and extend its uses to 4 different Goal types: Click Action, Hover Action, Page Load Action, and Custom Action.

 The Click and Hover Action Goal types allows for the client to select an eleement for the website and use that to send an event if it is clicked or hovered upon respectively. The Page Load Action Goal type will create an event to complete a goal when the URL for a specified page is loaded. Lastly the Custom Action Goal allows for the client to use the existing way of creating events through the Lou SDK's Lou.track() function. Each of these Goals will need an Event Name provided to it that will be used to determine if the Goal is completed. In addition a more readable title should be provided as this is displayed when selecting a Goal to associate with an Experience.

Goal page form for creating a Click Action Goal.Goal page form for creating a Hover Action Goal.Goal page form for creating a Page Load Action Goal.Goal page form for creating a Custom Action Goal.
Different types of goals that can be created through the Lou Builder.

 While creating the Goal, many of the fields are autogenerated for the client's benefit all of which can be edited. The Event Name uses a UUID as to create a unique identifier different from any created before. Once the Goal is created it is automatically selected to be used with the experience the user is currently working on.

The different types of goals that can be created through the Builder.

 With the enhancements to the Goal feature, it is made more accessible and convenient to use while creating an Experience making it appropriate to classify as "Code Free".

Workflow Profile Header

 In order to provide a more personalized Experience, the option to include more information about the client is available through Profile Headers. This Profile Header will allow for an image, first name, and company name to be displayed on each step of the Experience to the user. The aim for this feature is to give the end user of this Experience to feel like confident and comfortable by the guidance provided as there is now a face and name to attach to it.

Experience utilizing profile header.
Experience Modal utilizing default Profile Header.

 The first issue that needed to be addressed here is updating the Dashboard so that the client is able to input the appropriate details such as the client's name and image. For this a route was created to appropriately handle image uploading and attach this uploaded image to the profile data for the company member. Once the image was uploaded to our AWS Bucket, the corresponding URL is then attached to the profile data and utilized as the image for the Profile Header.

Dashboard page for updating profile details.Option to upload image to profile.
Dashboard profile page to update profile details and upload image.

 On the Lou Builder this feature is accessible through a simple toggle where if enabled, the Profile Header is place at the top of every Experience step.

Lou Builder toolbar for experience and toggling profile header.
Toolbar for toggling on Profile Header.

Workflow Banner Step

 So far the experiences have consisted of either Modal or Tooltip like steps of which help guide the user through the features available in the client's platform. These have been sufficient for most use cases but some situations would benefit from a Banner like Step in order to immediately get the user's attention. For this Banners builds on top of the existing structure for a workflow with the addition of special placement to the top and bottom of the page along with alignment of buttons to the left or right side of the Banner.

Option to create Banner Experience from Lou Builder Template.
Lou Builder page to create Banner Experience from Template.

 Creating a Banner Experience is virtually the same as any other Experience through the Lou Builder with a couple of different fields in the toolbar. The Banner Step can be used in combination with other Step types such as Modals or Tooltips as to provide an additional tool for creating experiences in the client's toolkit.

Toolbar inside the Lou Builder to customize Banner Step.Option to place Banner Step on the bottom of the page.Options for customizing buttons on Banner Step.
Special customization options for the Banner Step such as placement and buttons.

A / B Testing

 A / B Testing allows for clients to see if the experience that was created has an impact on their users. For this feature it utilizes the previous Goals feature as metrics regarding completetion rate can be use to measure the effectiveness of an Experience.

 To display the metrics of the A / B testing feature, another card specific to this is included below the other existing metrics for an Experience in the Dashboard. Here the card is divided into two sections of Group A and Group B where one is shown the Experience and the other is not respectively. The metrics then show the users' response with or without being shown the Experience with the percentage metric shown inside the Donut Pie Chart. The results of each group can be compared to each other differences between the two can be interpreted accordingly.

Initial dashboard metrics for Experience without A / B Testing.Dashboard metrics for Experience with A / B testing turned on.
Dashboard analytics page for Experience displaying A / B Test Metrics.

 As for enabling this feature, it can be done inside the Lou Builder and is as simple as toggling a switch.

Lou Builder page for enabling A / B testing.
A / B testing can be enabled through the last experience page of the Lou Builder.

Widgets

 Along with general workflow experiences such as Tours and Announcements, we want to provide our customers with a more persistant experience feature between page visits. After completing a Tour or Announcement, users would benefit from additional guidance on exploring platform features that might not be extremely obvious. For this we built out a new creatable experience type alongside workflows, called widgets. With widgets, experiences can be created to address a number of situations ranging from simple messages to checklists which indicates progress through connected experiences.

 This projects revamps the process for creating an experience through the Lou Builder by further broadening the customizability of an experience. The most prominent of these changes is the new Blocks structure of a widget, which allows customizability in the type (i.e. Checklist Item, Progress, Rich Text, etc.) and ordering of the content within. Other additions include the ability to connect workflows to checklist items, persisting experience state, new toolbar components for the Builder, and updated Sidebar pages for the Lou Builder. The ambitious scope of this project made it one of the largest I have worked on to this date as it was essentially a whole new product with prior knowledge from developing workflows. Due to this, the project was done on and off over the course of multiple quarters as to address some of the immediate concerns of our existing customers. In the end, we were able to complete this project and push out a new product that our customers enjoy using.

Lou Builder toolbar for widget container component.Lou Builder toolbar for widget trigger component.Lou Builder toolbar for widget content component.Lou Builder toolbar for widget progress component.Lou Builder toolbar for widget checklist item component.Lou Builder toolbar for widget spacer component.Lou Builder toolbar for widget divider component.
Mock-ups for proposed widget blocks and features for Lou Builder.

Widgets: Placement

 A widget is customizable such that it can be placed anywhere on the site but for ease of use we provide a 3 x 3  placement grid inside the Lou Builder toolbar for quick access to placements ranging from the top left corner to the bottom right corner. In conjunction with this, inputs for providing values for top, left, rightbottom positions can be used to further specify where the widget should be put. Because widgets can use precision greater than that of placements , the position values are stored and primarily used. It is only when the widget experiences are edited that these positions are also converted into placement values to be used within the Lou Builder's toolbar 3 x 3 grid.

Lou Builder toolbar for styling widget container component.
Mock-up of Lou Builder toolbar for styling widget container.

 As mentioned before, the area of the screen in which the widget is placed is primarily determined by the position values. The position values (i.e. string values for css properties such as top, left, rightbottom) needed to be converted into their appropriate placement values. These placement values would represent a 3 x 3 grid and as such would resemble something like the following.

+-------------+---------------+--------------+
|  Top Left   |  Top Center   |  Top Right   |
+-------------+---------------+--------------+
| Middle Left | Middle Center | Middle Right |
+-------------+---------------+--------------+
| Bottom Left | Bottom Center | Bottom Right |
+-------------+---------------+--------------+

Placement values in this grid are determined by a combination of position values that match either 0px or 50% (TopLeft, Bottom, Right, or Middle, Center respectively). Since this 3 x 3 grid uses a combination of these placement values, we need to be able to know if the position values are a valid combination. (i.e. A position where the css values for top is 0px and left is 50% would correspond to a placement of TopCenter). One possible approach to checking these combinations could be to extensively check every possible combination in order to provide the associated placement. Another approach would be to leverage the Bitwise shift operators in conjunction with TypeScript enums to check the individual values and determine if they add up into a valid combination.

/**
 * @description
 * Placments declared using bit shifting for complex conditionals.
 * +------------------+--------------------+-------------------+---+
 * |         8        |          16        |         32        | + |
 * +------------------+--------------------+-------------------+---+
 * |   Top Left (9)   |  Top Center (17)   |  Top Right (33)   | 1 |  
 * +------------------+--------------------+-------------------+---+
 * | Middle Left (10) | Middle Center (18) | Middle Right (34) | 2 | 
 * +------------------+--------------------+-------------------+---+
 * | Bottom Left (12) | Bottom Center (20) | Bottom Right (36) | 4 | 
 * +------------------+--------------------+-------------------+---+
 * 
 * @example Determining placement from dimensional values.
 * const dimensionsToPlacement = (dimensions): Placement => {
 *   // Placement will be returned unchanged if no conditionals are met.
 *   let placement = Placement.Custom; // 000000 = 0
 *   
 *   // Vertical
 *   if (dimensions.top === '0px') {
 *     placement += Placement.Top; // 000001 = 1
 *   } else if (dimensions.top === '50%') {
 *     placement += Placement.Middle; // 000010 = 2
 *   } else if (dimensions.bottom === '0px') {
 *     placement += Placement.Bottom; // 000100 = 4
 *   }
 * 
 *   // Horizontal
 *   if (dimensions.left === '0px') {
 *     placement += Placement.Left; // 001000 = 8
 *   } else if (dimensions.left === '50%') {
 *     placement += Placement.Center; // 010000 = 16
 *   } else if (dimensions.right === '0px') {
 *     placement += Placement.Right; // 100000 = 32
 *   }
 * 
 *   return placement; // Placement.TopLeft === 1 + 8
 * }
 */
export enum Placement {
  Custom = 0, // 000000 = 0

  Top = 1 << 0, // 000001 = 1
  Middle = 1 << 1, // 000010 = 2
  Bottom = 1 << 2, // 000100 = 4

  Left = 1 << 3, // 001000 = 8
  Center = 1 << 4, // 010000 = 16
  Right = 1 << 5, // 100000 = 32

  TopLeft = Top | Left, // 001001 = 9             (1 + 8 = 9)
  TopCenter = Top | Center, // 010001 = 17        (1 + 16 = 17)
  TopRight = Top | Right, // 100001 = 33          (1 + 32 = 33)

  MiddleLeft = Middle | Left, // 001010 = 10      (2 + 8 = 10)
  MiddleCenter = Middle | Center, // 010010 = 18  (2 + 16 = 18)
  MiddleRight = Middle | Right, // 100010 = 34    (2 + 32 = 34)

  BottomLeft = Bottom | Left, // 001100 = 12      (4 + 8 = 12)
  BottomCenter = Bottom | Center, // 010100 = 20  (4 + 16 = 20)
  BottomRight = Bottom | Right, // 100100 = 36    (4 + 32 = 36)
}

 In short, each of these enums can be added to another matching enum and the sum of these two would result in a separate but valid enum. This then can be used to populate the 3 x 3 grid within the toolbar to indicate that the following positions match the appropriate placement. The converse of this is applicable as selecting a placement will also provide the appropriate positions. The toolbar will also place itself appropriately alongside the widget container so that it visible regardless of placement.

Bottom right placement of widget container.Middle right placement of widget container.Middle center placement of widget container.
Displays placements of widget container and associated positions and toolbar.

 I credit dyc3 for introducing me to applications of bitwise operators while I watching one of his code review videos. This proved useful and applicable to this project as it solves a similar problem of dealing with complex states such as placements in the 3 x 3 grid.

Applications of bitwise operators in Yandere Simulator code review.

Widgets: [email protected]

 For workflow related experiences only one draft-js editor was utilized at a given time. With this assumption, much of the functions and components in [email protected] were constructed with far too much overhead to be practical if used multiple times within a parent element. The outline of this new widget features includes the blocks structure where multiple instances of the draft-js editor would need to be used alongside each other in blocks such as Checklist Item or Content. For this new feature, much of the content inside of draft-components would be refactored and redesigned to make it easier to use multiple instances of the draft-js editor alongside each other.

Checklist item block alongside toolbar for styles.
Multiple instances of the draft-js editor will be used in this widget in Checklist Item and Content blocks.

 In its current state, [email protected] heavily utilizes React's Context API for its state management. This is used primarily to dispatch actions and denote the current EditorState through the toolbar controls. This follows a design similar to the action, reducerstore seen in a state management package called Redux. This provided some needed structure when exploring some of the features and API in draft-js, however added significant overhead to each editor instance.

 The heaviest portion of this overhead is in the <Provider /> component required to wrap each draft-js editor component separately. Because of this requirement, it would be difficult to intialize / remove multiple <Provider /> components depending on the amount of applicable blocks are used. A better approach would be to move the state management for EditorState outside the package that way it only needs to be initialized when needed. This would also allow for multiple EditorState instances to be managed in a parent component making it extenisble to the blocks structure for a widget.

 One way of looking at this redesign to draft-components would be that it now provides the tools to assemble an editor instead of providing it out of the box. This has its drawbacks where more assembly is required in some cases such as the Lou Builder, but provides a simplier experience in most other cases. With this, draft-components provides a simple component export for <Editor />, the state of which can be controlled through props instead of a <Provider /> parent component. This new design replaces the previous but since the relegated design is still in use with workflow experiences those exports have been moved into a legacy folder to be addressed at a future date.

Widgets: Blocks

 The blocks structure that is utilized with widgets provides a new level of customizability and personalization to experiences. Customers have access to greater degree of freedom when building experiences in that they are able to select and arrange the appropriate blocks in any desired configuration. The blocks provide the basic content editor along with other specialized functions such as progress, checkboxes, and dividers; enabling additional interactive functionality. These new features allows for our customers to build out experiences as close to their ideal design while introducing new possible ways to interact with the user.

Lou Builder toolbar for widget content component.Lou Builder toolbar for widget progress component.Lou Builder toolbar for widget checklist item component.Lou Builder toolbar for widget spacer component.Lou Builder toolbar for widget divider component.
Mock-ups for proposed widget blocks (Content, Progress, Checklist Item, Spacer, and Divider respectively).

Blocks can be added directly from the toolbar through a dedicated page displaying the possible options and reached limits for types such as Progress block (Only one Progress block is allowed per widget since it does not make sense to allow multiple). In the example below a Divider block is added and rearranged to be moved below the Progress block and then removed. This outlines a small snippet of the user flow and freedom provided when building a widget such that quickly trying out new ideas is quite accessible.

Lou Builder toolbar page for adding widget block.Widget with newly added Divider block.Divider block moved down one block.Widget after block as been removed.
Example flow of adding a Divider block, moving it down, and deleting it.

Widgets: Blocks - Content

 The Content block is a newer iteration of the core rich text editor used with workflow experiences. This version of the editor utilizes the changes in [email protected] to provide a more responsive and faster building experience. Along with this, the popular Google Fonts search and text color features have been ported over so that no compromises are made between the two versions. For its use in widgets, this block acts as the basic building block for adding text and images viewable to the user.

Content block and Lou builder toolbar page.
Content block in widget with corresponding toolbar styles page.

Widget: Blocks - Progress

 The Progress block is a new addition as it provides a dynamic indicator to the user denoting the progress through checklist items as they are completed. In this block basic information such as the amount of completed checklist items and color of the progress bar can be customized to match that of the customer's designs.

Progress block and associated toolbar styles page.Toggling off the show step count switch.Checklist item previewed with toggled completetion.Updating color and step count switch.Checklist item previewed with toggled completetion with changes.
Example of changes to Progress block and previewed with Checklist Item completion.

 In order to display the completion of Checklist Items, the state of this needs to kept and updated somewhere. The Progress block component is kept simple by remaining a stateless component as it only visually indicates what is fed to it through props. The completion state is kept in the parent component and is managed to stay in sync with the data provided by the server, local storage, and user interactions. This block will update in realtime as Checklist Items are marked as completed or if Checklist Item blocks are added or removed. There is a limit of one Progress block per widget as having multiple Progress blocks would serve no additional purpose.

Widget: Blocks - Checklist Item

 The Checklist Item block is the flagship feature for widgets as it provides the same customizable editor used for the Content block alongside the dynamic state properites of the Progress block. A Checklist Item helps guide the user through the process of onboarding by providing an indicator of completed experiences or tasks alongside the remaining ones.

Styles toolbar tab for checklist item block.Checklist item previewed as completed.Actions toolbar tab for checklist item block.
Toolbar tabs and preview state of Checklist Item block.

 Similar to how the Content block is able to have its text styled through the draft-js editor, the Checklist Item block has all of that same functionality. This block in addition to content allows for the customer to change the color of the checkmark to a more appropriate one to better fit with the company's theme. This change can then be seen when previewed as complete so that the checkmark is displayed along with the expected strikethrough for text content. This "Preview as completed" directly updates the state of a checklist allowing otherblocks that display such as the Progress block to also update accordingly.

Selecting a workflow experience to link to checklist item.Redirecting to start url when this link is clicked.Changing this checklist item to be completed when goal is done.
The different ways to customize checklist item actions to start an experience when clicked and mark as complete.

 Checklist Items can have a workflow experience linked to it allowing for this experience to be started when clicked. This is useful for cases where an experience shows up only once or is more applicable to user interaction. The option to redirect the user to the appropriate URL is also possible with this action in order to provide the intended experience. For most cases with a connected experience the corresponding Checklist Item will automatically display its checked state when completed. However, for some other cases it is more desirable to connect the completion state of the Checklist Item to a separate Goal or just allow the user to manually mark it as complete. Both of these cases can be configured / combined for these Checklist Items providing a variety of different interaction avenues.

 As this block is our flagship and most complex feature in the aptly named Checklist Experience (a.k.a. widgets), at launch the actions for a Checklist Item are available only to paying customers. Styling for the Checklist Item block and all other features within the different block types are accessible to everyone. This feature proved to be our most capable addition as it provides a medium for our customers to leverage their library of experiences in a dynamic and interactive center for the user.

Widget: Blocks - Spacer

 The Spacer block is a simple component that is used inbetween blocks to provide customizable spacing through adjustment of the Spacer block height.

Spacer widget block component used alongside other blocks.
Spacer block alongside other blocks with toolbar styles page.

Widget: Blocks - Divider

 The Divider block is very much like the aforementioned spacer block in that it provides distinction between blocks through a solid divider line. This block has customizable attributes ranging from its line thickness, line color, space above, and space below.

Divider widget block component used alongside other blocks.
Divider block alongside inputs in toolbar styles page.

Widget: Outline

 The Lou Builder provides an interface to build out these widgets in an intuitive and interactive way. One of these attributes is the outline present around the block or container which is used to indicate hover or focus on the item that is to be edited. This tool also provides a couple of additional functions of which include displaying the block type, buttons to adjust ordering of block, and button to delete block. By clicking on specific parts of the widget, our client is able to navigate through the many of their created blocks and go about editing with the tools provided in the toolbar.

The Lou Builder provides a helpful dynamic outline when creating / editing a widget.

 This outline feature can be divided into two separate parts; one outline for the block or item that is focused upon and another outline for the client is currently hovering over. Both of these outlines share a couple of common features such as dynamically changing the height, width, and positioning based on their target (i.e. blocks and container). These outlines also leverages the capabilities of styled-components to create the transition styles that provide fluid movement between the items which are hovered or focused upon.

 The hover outline is the basic component for providing an slight outline around the block or container that will be focused upon when clicked. One way to provide this outline would be to utilize the border CSS Properties for each element but this would mean that the outlines for each block would be a separate element. This would make it overly difficult to emulate the fluid motion for the outline since each outline would be tied to a block or container.

 Another approach would be to have a single outline component which would make the fluid motion feasible with just the CSS Property transition-duration: 250ms;. This makes the styling for these transitions fairly straightfoward but shifts the brunt of the load to be done using React. This is primarily done by listening to mouse events which will provide height, width, and position, details about the target element. With this information, the state of the outline component will be updated to display at the correct position through the appropriate mouse events.

The hover outline indicates which block will be focused upon when clicked.

 The focus outline extends and builds off of the structure of the hover outline by using the same logic and adding in a couple features. Tweaks were made to the React logic to manage some of the edge cases when selecting text or using the associated buttons. The outline component uses a pseudo element to provide the text associate with the block type such as the Checklist Item, Content, and etc. Along with this the buttons on the side of provide options to move the block up, down, or remove it completely. Other small touches include hiding hover outline on focused outlines and removing the appropriate up and down buttons when necessary.

The focus outline provides the "Move Up" and "Move Down" buttons along with the button to delete the block.

 This addition proved to be a fairly complex feature for the Lou Builder as there were a couple of different ways to achieve the desired outcome, each with their tradeoffs. Opting to use React for the outline logic proved to work well with this feature as it provided a fast, responsive outline transitions while adhering to a design that is extensible to changes.

Workflow Screen Size

 Up to this point all Experiences have been the same regardless of the screen size of the browser when viewed. For instances where the screen size is smaller than 700px (i.e. Mobile and Tablet devices), the Experience has been hidden and not shown to the user. This is done since we cannot guarantee that the Experience will show up as the client intended for some of these screen sizes as the layout of the website may have changed to accomodate the smaller screen size. In this Screen Size feature for Experiences (more specifically Workflows) we want allow the client to create Experiences that are customized appropriately for each size range of the screen, allowing the Experience to be shown on a range of devices from Mobile to Desktop.

 In order to achieve this the Workflow Model is updated and extended to essentially allow multiple Experiences to be stored inside one Workflow. These "Experiences" would only show up under certain size range conditions and could have different Workflow Steps associated with it. As such, internally we refer to these as Variants as a variant of the experience is displayed when a certian screen size is met. In addition to this, the UI for the Lou Builder needed to redesigned in a way to indicate that the client is making changes to a specific variant of the Experience. For this portions of the build process such as the browser window and sidebar pages were overhauled to properly indicate which variant was being changed.

Mockup of uncustomized default screen sizes.Mockup of customized default screen sizes.Mockup of current Experience with multiple screen sizes.Mockup of adding in new screen size.
Mockups for updating Workflow to utilize screen size ranges on the Lou Builder.

Workflow Screen Size: Variant

Workflows were initially made to have only one set of steps that would be shown to the user during the Experience. As mentioned before, workflows would be updated to allow for more than one set of steps to be associated with an Experience leading this to be referred to as a workflow variant. For this some things needed to be taken into consideration, one of which was migrating the existing workflows to utilize additional screen size ranges.

 For this case previously existing workflows would behave exactly the same as before. The only change the client will see is the configuration that was implicitly set (i.e. Experience is not shown for screen sizes under 700px) is now configurable.

Modal for adjusting screen size ranges for existing workflow.
Existing workflows will have the following screen size configuration.

 The model for variants is similar to that of a workflow in that it references many of the same models for goal, steps, and type. To allow for specific display conditions, a couple of extra keys are included of which include screenSizeRangeMaxWidth, screenSizeRangeMinWidth, and screenSizeRangeType. These values are used to identify the screen size range in which this variant will appear and can be adjusted accordingly.

Workflow Screen Size: Slider

 Each variant associated with a screen size range has a minimum width that the Experience will show up under and a maximum width that it would stop appearing at. Another assumption made with this variant structure is that they are adjacent to one another. This would mean that the screenSizeRangeMaxWidth value would be 1px less than the screenSizeRangeMinWidth value to the variant to the right.

min            max     min            max
 |---variantA---|       |---variantB---|
null           400px   401px         1000px

 With this considerations in mind and the designs laid out in the mockups, a range slider would suit best as an interface to manage the screen size ranges of each variant. Unfortunately the native HTML element <input type="range"> does not support multiple range sliders and a specialized component for this had to be created or imported. For this rc-slider package proved to be a solid solution as it provided a simple component for managing multiple different range sliders seamlessly with plently of exposed props to customize to our needs.

rc-slider Multi Range with Custom track example.

 As for the values that these "Thumbs" represent, two adjacent screenSizeRangeMinWidth and screenSizeRangeMaxWidth values can be derived through the assumption that values are only 1px apart. With this, an array of screenSizeRangeMinWidth is provided to the <Slider /> component imported from rc-slider and the callback values can be utilized as the expected screen size range values.

 This then updates the appropriate values and the changes are reflected in the interface for each variant above the slider. The CSS for each list item providing information regarding each variant is updated to provide width values matching the "Thumb" placements within the slider below. The appropriate width and margin-left values are calculated by determining the percentage of space each variant's screen size range take relative to the total maximum width. The result is a slider that provides more visual feedback to the screen size range of each variant.

Information and size regarding the variant screen size range is also updated when the slider is moved.

 Another small feature behavior implemented within the slider is the ability to directly input the desired screen size ranges into the "Thumbs" of the slider. This is useful for many cases as clients usually have their screen size breakpoints already predefined within their website. This would allow for the client to simply enter these values into the "Thumbs" instead of arduously arraging the slider to their desired layout. This is achieved through the utilizing the exposed <Slider.Handle /> component from rc-slider and customizing it to allow an <input /> element to be positioned within. Within the component for the custom "thumb", the same callback for handing value changes is utilized for our <input /> element is used but debounced so that it waits 1 second from the last user input to update screen size range values.

Each of the slider "thumbs" allow for the client to directly input the desired values.

 Along with the <input /> element recently added variants also include an option to delete. This is useful for in cases where an added variant is no longer desired and should be easily removed. Notably the option to delete already existing (saved) variants is absent. This is a user constraint implemented to prevent the client from accidently deleting a variant that they spent considerable time building. Another constraint is that only the first or last slider "thumb" can be deleted at a time. This is a cursory check to make sure that each screen size range is adjacent to one another.

Only recently added screen size ranges on the ends of the slider can be deleted.

 Lastly the behavior to add in new screen size ranges is provided through as dropdown menu which provides the options of adding preset ranges for mobile, tablet, or desktop accordingly.

 There are many ways to create a simple dropdown component and the easiest way is to utilize the useState API from react to manage the display state of the dropdown through a button. This works as long as the button element is pressed but does not hide the dropdown if anything else is clicked. An approach to solve this issue would be to attach an event listeners higher up in the document to update the corresponding state for the dropdown but this comes at the cost of simplicity as managing this behavior can become a headache quite easily. Another approach would be to avoid state entirely and manage the display state of the dropdown with CSS. To achieve this the pseudo class for  :focus is utilized as a toggle for the visibility property such that the dropdown appears when the button is focused upon. The visibility CSS property is use instead of the similar looking display CSS property to allow for the callbacks within the dropdown to execute before disappearing. With this the state management within the dropdown is no longer an issue and the behavior of the dropdown are as expected.

 Back to the slider, adding new variants through the previously mentioned dropdown will append the new variant to the appropriate end. (i.e. mobile will be placed toward the left and desktop will be placed to the right.) When adding a new variant the properties of the previous variant such as steps are copied to the new. This is done since we expect that the client will make a minor of changes to the Experience to accomodate the respective screen size.

Variants can be added to either side of the slider depending on the selected type.

Workflow Screen Size: Default

 As with styles for Experiences, default screen size ranges can be applied to an Experience immediately after creation. This allows the client to save the commonly used screen size ranges such as their own breakpoints and reuse them in future workflows. For this convenience is key and as such the default screen sizes can be directly edited within the Lou Builder, saving the client from the need to switch between their site and Lou Dashboard browser tabs.

 Once the option to edit the default screen sizes is selected, the modal shrinks and a scroll up transition is applied to the slider. This animated change between the two is done to better convey that the client is now updating default screen sizes as the sliders look and function the same. In the provided slider, the default screen size ranges can be configured similar to a typical workflow with the only difference here being that there is a limit of 5 different ranges. Once the default values are saved, these default screen size range values can be applied to the workflow and saved.

Default screen size ranges can be applied on a newly created workflow and these default values can be updated as well.

 These default values can also be seen within the Lou Dashboard in the Design page alongside the Themes feature used to automatically style Experiences.

Dashboard page displaying the default screen size range.
The default values for screen size ranges can be configured within the Lou Builder and viewed on the Dashboard.

Workflow Screen Size: Footer

 Since there are multiple variants and corresponding steps with each a clear indicator is needed to denote which variant is being built. For this a footer component is implemented in on the Build Tab of the sidebar listing all the variants associated with the workflow. With this footer component the client is able to navigate through the existing variants with left and right chevron buttons. These buttons will appear only if the amount of created variants (3+) overflow past the width of the sidebar and make use of manipulating the scrollLeft value to display the appropriate variant.

 In addition to selecting which variant to focus on building, the option to delete is present on the top right of first and last variant list items. This option is present here as opposed to the previously mentioned Slider in order to provide a confirmation check to the client before deleting the selected variant.

Variants can be managed within the footer of the Build Tab.

Workflow Screen Size: Window

 In order to provide the client a environment that they would expect their Experience to appear on, the browser window automatically adjust to the associated screen size range. This allows the elements on the website to respond as expected when shown on devices with different widths. This behavior is only possible through the exposed chrome extension APIs which allow the Lou Builder to dictate the dimensions of the browser window.

The browser window will resize to the appropriate width for each variant.

 Once the client is finished editing the associated Experience, the Lou Builder will automatically resize the window back to its previous dimensions. This additional behavior reduces the amount of clicks the client need to make when building an Experience and provides a more natural user experience.

Workflow Survey Step

 Another common feature request is the support for a more in depth interactive survey workflow step where a user can provide feedback to the completed Experience. This would be its own workflow step type existing as a feedback step type where in its current state provides a "Thumbs Up" or "Thumbs Down" interaction option. This has been sufficient for most interactions but could be further expanded into other areas such as "Short Answer" and "0 - 10 Score" providing more areas to gather user feedback and compile into a Net Promoter Score (NPS).

Different types of survey types for a workflow step.Landing page image of Lou Builder toolbar for editing survey.Optional segment details and rules configurations on Dashboard.Analytics page on dashboard to display net promoter score.
Mockup images for Survey feature with images displayed on our Landing Page.

 These survey step types offer more customizability than the previous feedback step, more specifically in the text and color of the associated buttons. For this the model for data saved associated with a workflow was updated to save more specific properties for buttons and text. Some of the survey types such as the "0 - 10 Score" and "Short Answer" utilize multiple text and button properties and as such these have been prefixed with survey_primary and survey_secondary. Settings specific only to the feedback type of a workflow such as the "0/500" character limit in "Short Answer" survey are prefixed with survey.

# General primary button and text properties.
primary_button_background_color = models.CharField()
primary_button_border_radius = models.IntegerField()
primary_button_size = models.CharField()
primary_button_text = models.CharField()
primary_button_text_color = models.CharField()

# General secondary button and text properties.
secondary_button_background_color = models.CharField()
secondary_button_border_radius = models.IntegerField()
secondary_button_redirect_url = models.CharField()
secondary_button_size = models.CharField()
secondary_button_text = models.CharField()
secondary_button_text_color = models.CharField()

# Survey specific primary / secondary button and text properties.
survey_primary_button_background_color = models.CharField()
survey_primary_button_text_color = models.CharField()
survey_primary_text = models.CharField()
survey_primary_text_color = models.CharField()
survey_secondary_text = models.CharField()
survey_secondary_text_color = models.CharField()
survey_type = models.CharField()

 With these properties, each workflow survey step can be customized to best fit the client's needs. To further assist the creation process a template for creating "NPS" Experience is avaialable on the Templates page of the Lou Builder. Like a general Experience, the dashboard provides pages to configure user segments and view associated analytics. The analytics page has a special section specific to this feature to provide a visual graph of the "Net Promoter Score" and table highlighting the user responses and scores. This feature proved a success with our clients and a nice selling point as it provided a means to record more descriptive user feeedback and better visuals to interpret these results.