A modern, mobile-friendly web app for planning your Bonnaroo festival schedule.
Easily select your favorite events, view your custom schedule, and export it as a PDF, CSV, or calendar file.
-
Interactive Event Selection:
Choose your favorite events by day, stage, and time. -
Custom Schedule Table:
View your selections in a clean, printable table format. -
PDF, CSV & Calendar Export:
Download your schedule as a PDF (portrait or landscape), CSV, or export to.icsfor your calendar. -
Mobile Friendly:
Responsive design for use on phones, tablets, and desktops. -
Print Support:
Optimized print styles for a professional-looking hard copy. -
Automatic Festival Week Calculation:
The app automatically determines the festival week for any year inavailableYearsbased on the third Sunday in June (Father's Day). -
Efficient Schedule Fetching:
Schedules are only fetched once per year selection, and the app will default to the latest year with available schedule data. -
Status Message Color Coding:
The status message box color changes based on whether Bonnaroo has not started (yellow), is in progress (green), or has ended/no schedule (red). -
Date/Time Spoofing for Testing:
You can test status messages for any date/time by adding a?now=YYYY-MM-DDTHH:mm:ssquery parameter to the URL.
-
Clone the repository:
git clone https://github.com/CU-Jon/BonnarooPlanner-Static.git cd BonnarooPlanner-Static -
Install dependencies:
npm install # or yarn install -
Set up environment variables for local development:
Create a.env.localfile in your project root (not committed to git):REACT_APP_EMAIL_USER=youruser REACT_APP_EMAIL_DOMAIN=yourdomain.com REACT_APP_EMAIL_SUBJECT=Reporting an issue with Bonnaroo PlannerFor Azure Static Web Apps, you must set these as GitHub repository variables (not as Azure SWA Environment Variables or Secrets) and pass them to the build step in your workflow.
See the "Azure Static Web Apps Deployment" section below. -
Start the development server:
npm start # or yarn start -
Open in your browser:
Visit http://localhost:3000
public/
assets/
style.css # Main styles
schedules/ # JSON event data
centeroo_XXXX.json # Where "XXXX" is the year
outeroo_XXXX.json # Where "XXXX" is the year
favicon/ # Favicon and web app icons
favicon.ico # Standard favicon (ICO)
favicon.svg # SVG favicon (recommended for modern browsers)
favicon-96x96.png # PNG favicon (fallback for some browsers)
apple-touch-icon.png # iOS home screen icon
site.webmanifest # Web app manifest for PWA support
web-app-manifest-192x192.png # PWA icon
web-app-manifest-512x512.png # PWA icon
index.html
src/
components/ # React components
PlannerBuilder.js # Builder components (initial page)
PlannerView.js # Built planner "view" components
SelectionGrid.js # The selection grid where you pick the events/artists
TabContainer.js # Tab containers to separate Centeroo and Outeroo
YearSelector.js # Year selection, defaults to the latest year with schedule data
Footer.js # Footer component (handles obfuscated email link if chosen to use)
utils/ # Utility functions
csvExporter.js # Helper functions for exporting to .csv
icsExporter.js # Helper functions for exporting to .ics
timeUtils.js # Logic behind "late night" sets, festival date calculation, and overlaps
scheduleUtils.js # Efficient schedule fetching/checking
bonnarooStatus.js # Status message logic for festival state
config.js # App configuration and templates
App.js # Main app component
index.js # Entry point
package.json # Necessary modules for this project and the necessary versions
-
Select Year and Events:
Use the builder to choose your year and favorite events. -
View Your Planner:
Click "Build My Planner!" to switch to the planner view to see your custom schedule. -
Export or Print:
- Download as PDF (portrait or landscape)
- Export to CSV (with columns: Artist/Event, Location, Sublocation, Day, Start, End; sorted by day and time)
- Export to calendar (.ics)
- Print directly from your browser (Currently disabled in preference of exportable PDFs. Print button can be enabled in
config.js)
-
Event Data:
Update or add new schedules inpublic/assets/schedules/. -
Styling:
Editpublic/assets/style.cssfor custom themes or branding. -
Footer:
The footer is implemented as a dedicated React component (src/components/Footer.js).
The footer HTML is stored as a template string insrc/config.jsand uses a{{EMAIL_LINK}}token as a placeholder for the email link.
The email address is not hard-coded in the source code; instead, it is dynamically injected at runtime using environment variables and JavaScript for obfuscation.
If you remove{{EMAIL_LINK}}from the template, the email link will not be shown.
This helps prevent email scraping by bots and keeps your email private in forks and public clones. -
Titles, headers, and exported file names:
Titles, headers, and file names can be configured insrc/config.js. -
Late-night cutoff:
The late-night cutoff time can be configured insrc/config.jsto accommodate later "late-night" sets. Currently set to 7:00 AM as the last set for the "day" per Bonnaroo's official schedules. For example, Bonnaroo may show an artist or event from 3:00 AM - 5:00 AM on Thursday, when in reality, this is on Friday morning. This will place the artist or event at the end of Thursday's schedule to align with the official schedules (as opposed to in the morning on Thursday). Exported .ics files will show the artist or event on the actual day and time. -
Festival Start Date Calculation and Overrides
By default, the app automatically calculates the festival's Monday start date for any year inavailableYearsby finding the Monday before the third Sunday in June (the week of Father's Day).If Bonnaroo is ever scheduled for a different week, you can override the start date for that year by adding an entry to the
bonnarooMondayOverridesobject insrc/config.js:export const bonnarooMondayOverrides = { 2027: '2027-06-07' // Example: manually set Monday for 2027 };
The app will use the override for that year, and automatic calculation for all others. This approach keeps your code automatic for most years, but flexible for rare exceptions.
-
Status Message Color Coding:
The status message box color changes automatically:- Yellow: Before Bonnaroo starts
- Green: While Bonnaroo is in progress
- Red: After Bonnaroo ends or if no schedule is available
-
Date/Time Spoofing for Testing:
You can test status messages for any date/time by adding a?now=YYYY-MM-DDTHH:mm:ssquery parameter to the URL.
Example:http://localhost:3000/?now=2025-06-12T10:00:00
The src/config.js file centralizes all app-wide settings, templates, and customization options.
You can adjust these values to change the app’s behavior, appearance, and exported file formats.
| Name | Purpose & Usage |
|---|---|
jsonBase |
Path to the folder containing event schedule JSON files. |
availableYears |
Array of years available for selection. |
dayOffsets |
Maps day names to their offset from the festival’s Monday (e.g., Thursday = 3). |
LATE_NIGHT_CUTOFF |
The cutoff (in minutes after midnight) for “late night” sets to count as the previous day (default: 7:00 AM). |
bonnarooMondayOverrides |
Object for rare years to override the festival's starting Monday. Keys are years, values are 'YYYY-MM-DD'. |
BUILDER_TITLE_TEMPLATE |
Template for the builder page heading. Supports {yearPart} placeholder. |
HTML_TITLE_FALLBACK |
Fallback browser tab title before React loads. |
HTML_TITLE_TEMPLATE |
Template for the browser tab title. Supports {year} and {tabPart} placeholders. |
APP_TITLE_PLANNER |
Template for the planner view heading. Supports {year} and {tab} placeholders. |
PDF_FILENAME_TEMPLATE |
Template for exported PDF filenames. Supports {year}, {tab}, and {orientation} placeholders. |
CSV_FILENAME_TEMPLATE |
Template for exported CSV filenames. Supports {year} and {tab} placeholders. |
ICS_FILENAME_TEMPLATE |
Template for exported calendar filenames. Supports {year} and {tab} placeholders. |
ICS_CALENDARNAME_TEMPLATE |
Template for the calendar name in exported .ics files. Supports {year} and {tab} placeholders. |
SHOW_PRINT_BUTTON |
Boolean to show/hide the “Print” button in the planner view. |
BONNAROO_STATUS_ENDED_TEMPLATE |
Template for the status message when the festival has ended. |
BONNAROO_STATUS_NOT_STARTED_TEMPLATE |
Template for the status message before the festival starts. |
BONNAROO_STATUS_STARTED_TEMPLATE |
Template for the status message when the festival is in progress. |
SCHEDULE_NOT_AVAILABLE_TEMPLATE |
Template for the message shown if no schedule is available for the selected year. |
EMAIL_USER, EMAIL_DOMAIN, EMAIL_SUBJECT, EMAIL_LINK_TEXT |
Email footer config, loaded from environment variables (except EMAIL_LINK_TEXT) for privacy. (Optional) |
FOOTER_HTML |
HTML string for the app footer. Use {{EMAIL_LINK}} as a placeholder for the obfuscated email link if you choose to add a contact email address. |
-
Add or update years:
UpdateavailableYearsto support new festival years. The app will automatically calculate the festival week for each year. -
Change late-night cutoff:
AdjustLATE_NIGHT_CUTOFF(in minutes) to match how you want late-night sets to be grouped. Keep in mind this should be no less than the latest late-night cutoff for any of your schedules available. -
Edit titles and headings:
Change the templates to update how the app and exported files are named and displayed. -
Status and Unavailable Schedule Messages:
You can customize the status messages shown above the schedule (before, during, and after the festival) and the "schedule not available" message by editing the corresponding templates insrc/config.js:BONNAROO_STATUS_ENDED_TEMPLATEBONNAROO_STATUS_NOT_STARTED_TEMPLATEBONNAROO_STATUS_STARTED_TEMPLATESCHEDULE_NOT_AVAILABLE_TEMPLATE
-
Show/hide print button:
SetSHOW_PRINT_BUTTONtotrueorfalseto control whether users can print directly from the browser with a Print button. This does not enable/disable printing completely, just the button. -
Customize the footer:
EditFOOTER_HTMLto change the footer text or link. Use{{EMAIL_LINK}}as a placeholder for the obfuscated email link if you choose to add a contact email address. Change the text for the obfuscated email link in the footer by editingEMAIL_LINK_TEXTinsrc/config.js. (Please remember to give attribution to the original author :) )
To keep your email address private and out of the public repo, set the following in a .env.local file in your project root (not committed to git):
REACT_APP_EMAIL_USER=youruser
REACT_APP_EMAIL_DOMAIN=yourdomain.com
REACT_APP_EMAIL_SUBJECT=Reporting an issue with Bonnaroo Planner
Important:
For Azure Static Web Apps, you must set these as GitHub repository variables (not as Azure SWA Environment Variables or Secrets) and pass them to the build step in your workflow file.
Azure SWA Environment Variables are not injected into the frontend build for Create React App.
Steps:
-
Go to your GitHub repo → Settings → Secrets and variables → Actions → Variables tab → New repository variable.
-
Add:
REACT_APP_EMAIL_USERREACT_APP_EMAIL_DOMAINREACT_APP_EMAIL_SUBJECT
-
In your
.github/workflows/azure-static-web-apps-*.ymlworkflow file, add:env: REACT_APP_EMAIL_USER: ${{ vars.REACT_APP_EMAIL_USER }} REACT_APP_EMAIL_DOMAIN: ${{ vars.REACT_APP_EMAIL_DOMAIN }} REACT_APP_EMAIL_SUBJECT: ${{ vars.REACT_APP_EMAIL_SUBJECT }}under the build step.
-
Commit and push to trigger a new build.
The footer email link is not hard-coded in the HTML or JavaScript.
Instead, the footer template in config.js uses a {{EMAIL_LINK}} token, which is replaced at runtime by the Footer component with an obfuscated email link using environment variables.
If you remove {{EMAIL_LINK}} from the template, no email link will be shown.
This makes it much harder for bots to scrape your email address and keeps your email private in forks and public clones.
The app automatically calculates the festival's Monday start date for any year in availableYears by finding the Monday before the third Sunday in June (the weekend of Father's Day).
You do not need to manually update a start date for each year—just add the year to availableYears and the app will handle the rest.
On the rare occurrence that Bonnaroo does not land on the third Sunday in June, set bonnarooMondayOverrides in config.js for the Monday preceding Bonnaroo weekend.
- The app will only fetch schedule JSONs for a year when needed.
- On first load, it will default to the latest year in
availableYearsthat actually has schedule files available. - All years in
availableYearswill still appear in the dropdown, but only years with schedule files will load a schedule.
- The status message box color changes automatically:
- Yellow: Before Bonnaroo starts
- Green: While Bonnaroo is in progress
- Red: After Bonnaroo ends or if no schedule is available
- You can test status messages for any date/time by adding a
?now=YYYY-MM-DDTHH:mm:ssquery parameter to the URL. - Example:
http://localhost:3000/?now=2025-06-12T10:00:00
See the predecessor project BonnarooPlanner/jsonbuilder for the PHP code to build or edit schedules. Unfortunately, the builder/editor cannot be served as a static web app to perform live updates to the files for obvious reasons :(
This project is licensed under the MIT License.
Made with ❤️ by CU-Jon