Context
As part of an effort to enhance the user experience for managing digital campaigns, we were tasked with building a campaign management system. The goal was to allow users to create, update, preview, and publish campaigns, while also managing assets like logos and avatars.An essential requirement was the ability to embed campaign previews dynamically via an iframe, making it easily portable across various platforms.
The goal was to create a system that would not only work well on its own but also be adaptable for a variety of website platforms, ensuring campaigns could be embedded and viewed anywhere.
Challenge 1: Designing for Multiple Platforms
One of the core requirements was the need for an iframe-based campaign preview system that could work seamlessly across different content management systems (CMS) like WordPress, Ghost, and potentially more platforms in the future. Each of these platforms has different methods of handling embedded content, so we needed to ensure that the campaign preview could be easily integrated via an iframe, with minimal setup required from the user.
Approach:
We structured the system so that each campaign could be previewed using a unique URL, which was dynamically generated based on the campaign's data. This URL was then embedded into an iframe tag, allowing it to be seamlessly integrated into any platform that supports iframe embedding.
This URL could then be embedded into a WordPress post, Ghost article, or any other platform supporting iframes, ensuring the preview is always up to date based on the campaign data.
Complexity Overcome:
The major challenge was ensuring that the campaign preview, once embedded via an iframe, would function as intended across various platforms, each of which might have different handling for iframes. We overcame this by designing the iframe content to be responsive and ensuring it could adapt to different screen sizes, content, and platform-specific restrictions. Additionally, we optimized the iframe loading to ensure performance was not impacted when embedded in external platforms.
Challenge 2: Managing Global State with Recoil
One of the primary complexities of this project was managing global state in a React application. With multiple components needing access to the campaign data (including questions, status, title, etc.), React's traditional prop drilling would have resulted in highly complex and difficult-to-manage components. We chose Recoil for state management, as it allowed us to manage and update the campaign state in a centralized, efficient way.
Complexity Overcome: Managing dynamic forms, where the number of questions can vary and conditional logic must be applied, was a significant challenge. By using Recoil's flexibility, we were able to dynamically manage different types of questions and their associated data (e.g., MCQs, short text, sliders). This enabled us to easily scale and manage the complexity of the data as the user interacted with the form.
Challenge 3: Handling Image Uploads to Firebase with Dynamic Data
Another challenge was handling dynamic file uploads (logo and avatar images) for campaigns. The system required users to upload images, which had to be stored securely and referenced back in the campaign data.
Approach: We utilized Firebase Storage to manage image uploads. Firebase provided a reliable, scalable, and secure solution for storing assets. The images needed to be uploaded dynamically, with real-time updates to the state when the upload was successful. Here's how we approached the image upload flow:
Complexity Overcome: The primary challenge was ensuring that the file upload process was seamless for the user, providing real-time feedback. Firebase’s asynchronous nature meant that we had to handle multiple state updates, and we had to account for errors and loading states. Additionally, once the upload was complete, the image URL had to be integrated back into the campaign data.
We overcame this by utilizing the useState and useEffect hooks in React to manage the loading states and ensuring that the component was updated only after the upload completed successfully.
Challenge 4: Dynamic Campaign Preview with Iframe Integration
A key feature was the ability for users to preview their campaign in real-time before publishing. This required dynamically generating the URL for an iframe that displayed the campaign preview, based on the current state of the campaign.
Approach: We utilized React's useEffect hook to dynamically generate the iframe URL once the campaign data (specifically, the campaign ID) was available. The URL for the preview was then set in the component state (iframeSrc).
Complexity Overcome: One of the challenges was ensuring that the iframe was only rendered once the campaign data was fully available and properly validated. Additionally, we had to manage edge cases, such as when the campaign data wasn't ready yet or when the user hadn't uploaded an image or set a title. To mitigate these challenges, we used conditional rendering and loading indicators to ensure the user experience remained smooth.
Challenge 5: Handling Draft and Published Campaigns
The system needed to manage both draft and published states for campaigns. A draft allowed the user to save their progress, while publishing the campaign required a more permanent API call to update the campaign’s status.
Approach: To manage the draft and published states, we created separate functions for saving drafts and publishing campaigns. When the user clicked the "Save Draft" button, we checked whether the campaign was already in draft status. If it was, we simply updated the existing draft. If it was a new campaign, we created it with the draft status.
Complexity Overcome: Handling different statuses for campaigns, especially between drafts and published versions, was complex. The challenge was ensuring that the correct API endpoint was called, and the state was updated based on user actions. We overcame this by using a combination of PATCH and POST requests based on the campaign status and leveraging Recoil for seamless state updates.
Challenge 6: Ensuring Seamless User Experience
Throughout the development of this system, one of the biggest challenges was ensuring a smooth and intuitive user experience, especially as the application grew more complex. Features like form validation, dynamic previews, and real-time updates added layers of complexity.
Approach: We employed several strategies to ensure a smooth user experience:
- Asynchronous Data Fetching: We used useEffect to fetch data asynchronously and render loading states to improve UX.
- Optimized State Management: By utilizing Recoil, we ensured that state was updated only when necessary, preventing unnecessary re-renders and optimizing performance.
- User Feedback: For file uploads and form submissions, we provided real-time feedback (e.g., success/error messages and loading spinners) to keep the user informed at all stages.
Challenge 7:Campaign Results and Response Summaries
The next key feature was summarizing campaign responses. For multiple-choice questions or sliders, we needed to count the selections for each option and present a summary of all responses, enabling real-time insights into campaign performance.
Extracting meaningful insights from responses, especially for complex question types like sliders and multiple-choice.
Maintaining performance while aggregating large sets of responses in real-time.
Conclusion: Building a Scalable Evergreen Campaign System
Building this evergreen campaign management system was a complex but rewarding challenge. The system needed to be adaptable, scalable, and capable of functioning across multiple platforms. By leveraging technologies like React, Recoil, Firebase, and Axios, we were able to build a flexible system that met all the requirements, including real-time campaign previews, dynamic image uploads, and seamless platform integration via iframes.
The most significant technical challenges were managing global state efficiently, ensuring real-time updates, and making the system platform-agnostic. These were overcome through careful design choices, like using Recoil for state management, Firebase for file handling, and React's hooks for dynamic content rendering.
Ultimately, this project not only delivered a robust, scalable solution but also showcased our ability to design complex systems that integrate with multiple platforms, ensuring a smooth user experience regardless of where the campaign is embedded