Dandelion is an open-source project. View the code on Github

Improved Event Discovery and Browsing

We've significantly enhanced how you find events and people on the platform. You'll now see more recommendations, with up to 20 suggested events and 100 recommended people, now including gatherings and referred to as "connections." A new interactive map view is available on the public homepage for all users, offering a full-screen mode and smoother navigation on mobile devices. Location-based searches are also more accurate, using bounding boxes instead of simple circles to match visible map areas more precisely, and a default minimum search radius of 25km ensures you always get relevant results even for broad city searches.

Enhanced Event Management for Organisers

Organisers will find several new tools to manage events more effectively. Creating discount codes is now streamlined with a better form and the ability to apply a single code to multiple ticket types. Events will automatically lock if a Stripe payment fails, and organisers will be immediately notified with clear instructions on how to unlock them. Furthermore, you can now instantly hide or unhide events from the homepage, duplicate events with new profit-share fields copied over, and customise location filter suffixes for your organisation.

Better Notifications and User Experience

We've made several updates to improve communications and overall usability. When you list your very first event, you'll receive a warm, celebratory welcome mail. If a ticket you previously held is resold, you will now be automatically notified via mail. Organisers also gain the ability to schedule future promotional mails, which will now automatically match your organisation's theme colors for a consistent brand experience.

Commits on Aug 30, 2025
f708697

🐛 (organisation_validation): strip leading/trailing whitespace from critical fields Ensures consistent data by removing accidental spaces in name, facebook_pixel_id, gocardless_access_token, gocardless_endpoint_secret, coinbase_api_key, coinbase_webhook_secret, patreon_api_key, mailgun_api_key, evm_address and oc_slug.

732e233

♻️ refactor(_build.erb): replace manual threshold & discount inputs with reusable helpers

bbe4b39

💄 Improve discount code form UX and styling - Replace text inputs with percentage_block and currency_block - Add dynamic currency symbol update on currency change - Show validation messages inline with .invalid-feedback - Clarify field descriptions for percentage, fixed discount and filter

Commits on Aug 29, 2025
68f3fdf

🐛 Fix ERB syntax errors in recommendations views - Move break statements outside of ERB closing tags - Ensure proper closing of ERB blocks in events.erb and people.erb

09c0091

✨ (events.erb): increase displayed recommendations from 10 to 20
🐛 (events.erb): stop hard-coding 10-item limit, use counter instead
🎨 (events.erb): add counter variable to track displayed events

8335ee7

🐛 (people.erb): fix pagination logic to stop after 20 public recommendations
♻️ (people.erb): replace hard-coded 100 limit with dynamic counter and break
💄 (people.erb): keep consistent indentation for the new counter

6364d3b

💄 Increase recommended people list from 50 to 100 items

b237156

⚡️ (recommendations): bulk-load events & gatherings to cut N+1 queries
♻️ (recommendations): extract ID collections and use single queries
🎨 (recommendations): fix indentation and remove redundant rescue nil

dcecaa6

💄 change icon from people-fill to moon-fill in people recommendations

14533e1

✏️ Fix typo in recommendations/events.erb Change "connection" to "event" in the pluralize helper to accurately reflect that the count represents shared events, not connections.

1ef907d

🚚 rename recommendations/accounts route to recommendations/people
📝 update copy from "past events" to "connections" in recommendations
✨ include gatherings in people recommendations
🎨 refactor event block markup and styles for map display

Commits on Aug 28, 2025
01b5caa

🔥 Remove unused Substack newsletter invite code and fields
♻️ (event_stats.erb): merge nested form-row into one to simplify layout
🗃️ Drop sent_substack_invite and substack_opt_in from Account model

d9e66e0

💬 Update first-event email copy with celebratory emoji

3ee0026

🚚 Move send_first_event_email from EventNotifications to AccountNotifications

The congratulatory email should be triggered when an account creates its first event, not when any event is created. This prevents duplicate emails and aligns the responsibility with the Account model.

21e605c

✨ Send welcome email when user lists their first event

  • Add new email template first_event.erb with congratulatory copy
  • Introduce sent_first_event_email timestamp field on Account
  • Trigger email from EventCallbacks only when it's the first event
  • Add send_first_event_email method to EventNotifications using Mailgun batch messaging
708735f

🔧 Add test Stripe keys to CI environment

32509f5

🔐 Replace hard-coded secrets with dynamic SESSION_SECRET in CI

c3b3cde

👷 (ruby.yml): split CI tests into parallel matrix jobs by test file
⬆️ (ruby.yml): bump checkout action to v4 and MongoDB action to 1.12
🔧 (ruby.yml): include test file in cache key to avoid collisions

7cf885d

💄 (events/_locked.erb): add warning styling to edit link for better UX

7317d3f

💄 (events/_locked.erb): add link to unlock event when locked
🚸 (events/_locked.erb): guide user to edit page to uncheck locked checkbox

f97f495

✨ (event_duplication): copy new profit-share fields when duplicating events

92c77be

🐛 Fix pagelet loading spinner in table rows
🎨 Remove redundant inline style for pagelet-loading

a6cb473

🐛 Lock event when Stripe payment fails to prevent further purchase attempts
✨ Notify organiser that event is now locked and explain how to unlock

cba8643

💄 Remove bottom margin from events page header row

301f300

🐛 Fix map display when Google Maps fails to load
✨ Add client-side check to hide the map container if Google Maps is unavailable, preventing broken UI
🎨 Wrap map container in #homepage-map for easier targeting

12afbd4

♻️ (map.js): convert mapOptions from static object to lazy-loaded getter This prevents a runtime error when google.maps is not yet loaded

51d44f3

✨ Filter homepage events to only show those with images

94d7949

💄 Add visual feedback for hidden events on homepage
🚸 Improve admin UX for hiding/unhiding events with instant opacity change

8b0806a

✨ Add AJAX toggle for hiding events from homepage

  • Split hide/unhide endpoints into separate GET routes that return 200 instead of redirecting, enabling AJAX usage.
  • Introduce new partial _hide_from_homepage.erb to render the eye icon inside a pagelet, allowing in-place updates without full reload.
  • Update _block_main.erb and _blocks.erb to load the new pagelet and pass the admin flag so the control is only shown to admins.
  • Remove inline links in _block_main.erb; visibility toggle is now handled via the pagelet.
  • Remove redundant CSS class "event-star" from star placeholders.
Commits on Aug 27, 2025
0c33361

💄 Remove extra padding class from pagelet loading icon
💄 Add left margin to spinner icons in event build preview

91abbfc

💄 Add right margin to map close button for better spacing

c9f6798

💄 Replace all spinners from bi-arrow-repeat to bi-slash-lg Replace the old rotating-arrow spinner with a simpler slash spinner across the entire codebase for a cleaner, more modern loading indicator.

f67997a

💄 Adjust map close button height and margin for better alignment
🎨 Inline admin toggle links to reduce whitespace in event block

f492196

💄 (app.scss): simplify close button styling on map canvas

8756921

✨ add ability to hide events from homepage
🗃️ add hidden_from_homepage boolean field to events
🎨 add admin toggle links in event block to hide/unhide from homepage
♻️ filter homepage events to exclude hidden ones

b59c61f

💄 (app.scss): position map close button top-right with high z-index to prevent overlap issues
🐛 (gatherings.rb, organisations.rb): move pagination inside non-XHR branch so map endpoints return all points

448889e

💄 Update pagelet loading spinner icon and add padding

9c0fb68

🚚 Rename MapUtils to DandelionMap to avoid generic naming conflicts

120598a

➕ Add jquery-deparam.js to external JS list
🐛 Fix URL query parsing by replacing URLSearchParams with $.deparam This fixes issues with array parameters not being parsed correctly

adc7855

Revert "
🔥 Remove unused jquery-deparam.js dependency ♻️ Replace $.deparam with native URLSearchParams in map.js and discounts
🚚 Update getPageletParams → getContainerParams to support Turbo Frames
✨ Add Turbo Frame support alongside legacy pagelets in map loading"

This reverts commit 445021f4e6e5d1d430138e4b0a0819c2a9de2c81.

f7f782a

🚸 Improve map UX by disabling clickable POI icons

acaaab3

✨ Add map view to public home page for anonymous users

  • Pass @no_content_padding_bottom flag when no events are present
  • Embed map pagelet that loads /events?display=map
  • Extend conditional style to remove bottom padding for map view
041c229

💄 Change map-canvas background from white to transparent

7c8ffcd

💄 (maps): force white background on map tiles to prevent dark-mode flicker

cd50c03

🗺️ change default map center from (0, 0) to (0, 35)

a1a6dbb

💄 (events): conditionally align search toggle right when carousel buttons present
💄 (events): remove bottom margin from "View your events" link

b21d5f4

💄 (organisation.erb): add placeholder while feedback pagelet loads

eebef4d

♻️ Extract event-tag search dropdown into reusable partial - Move duplicated tag-selection markup from _search_form.erb into new _search_event_tags.erb partial - Replace inline code in events and organisations search forms with single render call to keep templates DRY


🚧 Temporarily disable local-groups, activities & carousels filters - Comment out partial includes in organisations search form while requirements are being clarified

7bb913f

✨ Add collapsible search form for map view
♻️ Extract toggle logic into reusable partial _toggle_search_well.erb
🚸 Hide search well by default on map display to maximise map space
🗑️ Remove duplicated toggleAdvancedSearch from carousel_buttons.erb

7c73f5e

⚡️ Reduce dynamicLoadingTimeout from 750 ms to 500 ms

a4577d8

🎨 (map.js): remove unused defaultCenter & defaultZoom constants
💄 (controllers & views): add fill_screen: true to all map partial calls to enable full-screen map display across gatherings, organisations and events

455f820

✨ Add full-screen map mode for events display

  • Introduce fillScreen flag to toggle dynamic map height
  • Add fillScreen() helper to calculate remaining viewport height
  • Wire resize listener to keep map responsive on window resize
  • Remove bottom padding on #content when map is shown
  • Default map-canvas height reduced to 50vh when not filling screen
4ade9e1

💄 (map.js): change gestureHandling from cooperative to greedy for smoother mobile UX

0ebb8d3

🎨 (CLAUDE.md): remove trailing whitespace for consistent formatting
🚸 (map.js): add cooperative gesture handling to improve mobile UX

445021f

🔥 Remove unused jquery-deparam.js dependency
♻️ Replace $.deparam with native URLSearchParams in map.js and discounts
🚚 Update getPageletParams → getContainerParams to support Turbo Frames
✨ Add Turbo Frame support alongside legacy pagelets in map loading

5bc913d

♻️ Replace deprecated changes with previous_changes in callbacks

781d546

✨ Add skeleton placeholder for async pagelets

Introduce a reusable _placeholder.erb partial that renders grey-box skeletons while pagelets load. Move section titles out of the partials and into the parent templates so the placeholder can sit under the correct heading. Wrap every pagelet container with data-with-placeholder and render the skeleton to improve perceived performance.

c26e327

🐛 Fix tooltip calculation in orders table Use to_date on both sides of distance_of_time_in_words to avoid mixing Date and Time objects, ensuring accurate “time to go” display.

2e15a27

💄 (events/_orders_table.erb): show plus icon when event is more than 28 days away

84ff08b

💄 (orders_table): move white-space: nowrap style from

to inner

360f1e7

💄 (orders_table): remove fixed column width and add nowrap style
💄 (orders_table): add line breaks every 7 squares in progress bar

ccbdc76

💄 (events/_orders_table.erb): fix visual overflow by setting fixed width on event column
🚸 (events/_orders_table.erb): replace raw day count with human-readable "distance_of_time_in_words"
🚸 (events/_orders_table.erb): cap progress squares at 28 to prevent line wrap

51a6ea2

🐛 (organisation_events): allow single carousel_id param to be treated as carousel_ids array Ensures backward compatibility when only one carousel_id is provided

Commits on Aug 26, 2025
8860b77

🐛 (map): rename explicitBounds → bounds to fix ignored map bounds
🎨 (map): improve console logs for easier debugging of view logic

97bcc0d

♻️ Refactor cluster styles and map bounds handling - Replace hard-coded clusterStyles array with a reusable generateClusterStyle helper - Remove unused getCenterZoomParams() and inline its logic into bounds_changed listener - Always use full bounds object instead of center/zoom fallback, simplifying the payload

66a8f71

🐛 Fix map.js bounds logic by removing string comparison
✨ Add map.js to asset loading in .cursorrules and CLAUDE.md

af3e4a6

🙈 Add _map_old.erb to .gitignore


🐛 Fix polygonables check from array length to boolean string - Previously compared array length, but polygonables is now passed as string 'true'/'false' from the template

8bb1716

✨ Add bounds validation helpers and improve map view robustness

Introduce validateBounds, setDefaultView, fitValidBounds and getCenterZoomParams helpers to centralise view-state logic.

Replace inline bounds handling with the new helpers to prevent crashes when coordinates are missing or malformed.

ac69952

🍱 add new map.js asset and refactor map partial to use it
♻️ extract inline map logic into reusable MapUtils module
🚚 move model configs and styles from _map.erb to map.js

Commits on Aug 25, 2025
db9850e

💄 (events/_block.erb): restyle carousel text to match new design - Replace alert-success with plain div - Reduce font size from 1rem to 0.9rem - Remove padding class p-lg-3 and use p-1

72e6c7e

💄 (organisation.scss): extend theme color to .bg-primary.text-white selector

8323162

💄 Add .bg-primary utility class using $theme-color

c7e8765

🐛 Fix stylesheet generation when no theme_color param provided
♻️ Move SCSS file read outside conditional to avoid nil content
✨ Add to_param to Event and Organisation for slug-based URLs
🐛 Fix page_views_count query by adding .all before .or

Commits on Aug 22, 2025
939e845

🐛 Fix unclosed quote in minimal view container markup

da00c11

🎨 Refactor spacing and layout classes for minimal view

Remove legacy body padding rule from organisation.scss to let layout be controlled by Bootstrap utilities. Replace fixed margin classes with responsive Bootstrap utilities (container-fluid my-3, mb-3, mt-3) so the minimal view renders with consistent vertical rhythm regardless of carousel/search presence.

3efc203

💄 (organisation.scss): add 40px top padding to body for fixed header clearance

254ee5d

🐛 Fix location dropdown to include custom user-entered locations
✨ Allow users to select previously typed custom locations in the filter

4375ae3

🐛 (carousel.rb): remove duplicate field :o declaration

118d673

⬆️ (.cursorrules, CLAUDE.md): remove version pin from mailgun-ruby to allow latest version

2f4fb5d

⬆️ Replace unmaintained coinbase_commerce gem with official coinbase_commerce_client

  • Remove quiknode-labs fork that was blocking mailgun-ruby upgrades
  • Update mailgun-ruby to latest version by removing version constraint
4388df2

⬆️ replace unmaintained coinbase_commerce gem with official coinbase_commerce_client

The old forked gem was blocking upgrades of mailgun-ruby and is no longer maintained. All references updated to the new namespace CoinbaseCommerceClient to keep crypto payments working.

9470a32

🐛 Fix skipping validations when updating ticket email

17c0431

💄 (maps/_event.erb): adjust event title layout on map - make h4 inline-block and remove bottom margin for tighter fit

c91947e

🎨 (events/_block_main.erb): wrap entire block in a single root div to simplify styling
🎨 (maps/_event.erb): refine map-event styles to target nested elements and reduce font sizes

00c9e2e

🐛 Fix typo in events and organisation_events controllers - Change @event.and to @events.and to correctly chain query conditions on the existing scope

fd713b5

🐛 (organisation_events): exclude locked events from map view

d648255

🐛 (events): exclude locked events from geo-box query results

423f50c

🐛 Fix empty filter bug in event queries across controllers

Replace ternary logic with explicit if/elsif/else to correctly handle cases where either q_ids or event_tag_ids is empty. Previously, when event_tag_ids was empty, the intersection would always return an empty set, causing no events to be returned even when q_ids had valid IDs.

This change ensures that: - When q_ids is empty, we use event_tag_ids - When event_tag_ids is empty, we use q_ids - Only when both are present do we perform the intersection

2fc67ea

🐛 Fix inverted filtering logic in organisation events controller

9e13e0b

♻️ Refactor event filtering logic across controllers

Replace the old union/intersection logic with a clearer ternary expression that only intersects when both query and tag filters are present. This removes duplicate code in activities, local_groups, organisation_events and organisations controllers.

Also streamline the stylesheet endpoint by reading the SCSS file only when a theme_color parameter is provided, avoiding unnecessary file reads and simplifying the flow.

1cc84b7

✨ Add event-type filter to organisation events search

  • Accept new event_type param in controller and translate it to the corresponding EventTag name
  • Build the event list by intersecting the search query IDs with the IDs of events tagged with the selected type
  • Render a select box in the search form when the organisation has configured available event types
  • Persist new event_types field on Organisation to store the comma- separated list of allowed event type names
4eea583

🐛 Remove hidden carousel filter to show all carousels in stats view

ff76afb

🐛 Fix invalid date handling in /daily route
✨ Add graceful fallback to today when date param is malformed

9673433

💄 (carousels): display hidden carousels with reduced opacity instead of hiding them
✨ (carousels): add button indicator column to carousel list view

bb48ff2

🔥 Remove unused image asset (stephen-reid.jpg)


✨ Add "hidden" flag to carousels - Introduce new boolean field :hidden on Carousel model - Add checkbox to carousel build form to toggle visibility - Filter out hidden carousels from all public-facing queries - Update human-readable labels for admin UI

Commits on Aug 21, 2025
6290131

🐛 Fix donation display in orders table Only show donation revenue when both the application fee has been paid to Dandelion and the donation revenue is greater than zero, preventing empty or misleading donation rows from appearing.

91f266b

✨ Add donation-to-Dandelion column to orders table - Display optional "Donation to Dandelion" column when donation_to_dandelion flag is passed - Show formatted donation amount only when application_fee_paid_to_dandelion? is true - Enable column in stats/orders view by passing new local flag

0408001

🔒️ Restrict /geolocate endpoint to admins only
🗑️ Remove unused Substack newsletter views and email template
🗑️ Remove unused token distribution page and views
♻️ Move static legal pages to the bottom of the route list for clarity
♻️ Add before-hook to enforce admin-only access on all /stats routes

4a3e9ff

🐛 Fix missing leading # in theme_color parameter for stylesheet

3139d4d

✨ Add email to previous ticketholder when ticket is resold
📝 Create new template for previous ticketholder resale notification
♻️ Split resale notification into two methods: one for previous ticketholder, one for organiser

6ef7e6b

💄 (events/_questions.erb): style conditional headers based on next question type

a51fa74

✨ Improve search relevance with phrase boosting
♻️ Replace simple text search with compound query
✨ Add phrase match with 1.5× boost for better ranking
💬 Update search hint text to "Fuzzy search"

9d0eacc

✨ (helpers): add relevance scoring to MongoDB text search
♻️ (helpers): refactor search to use score-based filtering
🐛 (account_contribution): fix duplicate nil check for event

5c869e4

🐛 Fix nil handling for organisation theme_color - Remove default '#00B963' fallback in controller - Add fallback to '#00B963' in view when @organisation.theme_color is nil - Prevent nil entries in tickets email list with compact

e46f211

💄 Make email CSS theme-aware and centralise colour handling

  • Move all colour rules from email.css into inline