···102102 }
103103 };
104104105105- // Validate redirect URL when direct RSVP is disabled
105105+ // Validate redirect URL settings
106106 let disable_direct_rsvp = form.disable_direct_rsvp.unwrap_or(false);
107107 let rsvp_redirect_url = form.rsvp_redirect_url.as_deref().map(|s| s.trim());
108108109109+ // When disable_direct_rsvp is true, URL is required
109110 if disable_direct_rsvp {
110111 if let Some(url) = rsvp_redirect_url {
111112 if url.is_empty() || !url.starts_with("https://") {
···129130 );
130131 }
131132 }
133133+134134+ // When URL is provided, validate it's HTTPS (even if disable_direct_rsvp=false)
135135+ if let Some(url) = rsvp_redirect_url {
136136+ if !url.is_empty() && !url.starts_with("https://") {
137137+ return contextual_error!(
138138+ ctx.web_context,
139139+ ctx.language,
140140+ error_template,
141141+ default_context,
142142+ CommonError::FieldRequired,
143143+ StatusCode::BAD_REQUEST
144144+ );
145145+ }
146146+ }
147147+148148+ // Convert empty string to None for database storage
149149+ let rsvp_redirect_url = rsvp_redirect_url.filter(|url| !url.is_empty());
132150133151 // Update the event in the database only (settings are not stored in AT Protocol)
134152 let event_update_result = event_update_with_full_metadata(
+21-4
templates/en-us/create_rsvp.partial.html
···22{% if hx_request %}
33<article class="message is-success">
44 <div class="message-body">
55+ {% if redirect_url %}
66+ <p>Your RSVP has been recorded!</p>
77+ <p class="mt-3">
88+ <a href="{{ redirect_url }}" class="button is-primary" target="_blank" rel="noopener noreferrer">
99+ <span class="icon"><i class="fas fa-ticket-alt"></i></span>
1010+ <span>Continue to Tickets</span>
1111+ <span class="icon is-small"><i class="fas fa-external-link-alt"></i></span>
1212+ </a>
1313+ </p>
1414+ <p class="help mt-2">Click the button above to proceed to the external ticketing page.</p>
1515+ {% else %}
516 <p>The RSVP has been recorded!</p>
1717+ {% endif %}
618 </div>
719</article>
820{% else %}
921<article class="message is-success">
1022 <div class="message-header">
1111- <p>The RSVP has been recorded!</p>
2323+ <p>{% if redirect_url %}Your RSVP has been recorded!{% else %}The RSVP has been recorded!{% endif %}</p>
1224 </div>
1325 <div class="message-body">
1426 <p class="buttons">
2727+ {% if redirect_url %}
2828+ <a class="button is-primary" href="{{ redirect_url }}" target="_blank" rel="noopener noreferrer">
2929+ <span class="icon"><i class="fas fa-ticket-alt"></i></span>
3030+ <span>Continue to Tickets</span>
3131+ <span class="icon is-small"><i class="fas fa-external-link-alt"></i></span>
3232+ </a>
3333+ {% endif %}
1534 <a class="button" href="{{ event_url }}">
1616- <span class="icon">
1717- <i class="fas fa-file"></i>
1818- </span>
3535+ <span class="icon"><i class="fas fa-file"></i></span>
1936 <span>View Event</span>
2037 </a>
2138 </p>
+42-33
templates/en-us/manage_event_settings_tab.html
···41414242 <div class="content">
4343 <h3 class="subtitle is-6">External Ticketing</h3>
4444+4545+ {# Status display #}
4446 <p class="mb-3">
4547 {% if event.disable_direct_rsvp %}
4848+ <span class="tag is-warning is-light">
4949+ <span class="icon"><i class="fas fa-ban"></i></span>
5050+ <span>RSVPs Disabled</span>
5151+ </span>
5252+ <span class="ml-2">Users are redirected to external ticketing without recording an RSVP.</span>
5353+ {% elif event.rsvp_redirect_url %}
4654 <span class="tag is-info is-light">
4747- <span class="icon">
4848- <i class="fas fa-ticket-alt"></i>
4949- </span>
5050- <span>Enabled</span>
5555+ <span class="icon"><i class="fas fa-ticket-alt"></i></span>
5656+ <span>Post-RSVP Redirect</span>
5157 </span>
5252- <span class="ml-2">Users are redirected to external ticketing.</span>
5858+ <span class="ml-2">Users RSVP on Smoke Signal, then are directed to external ticketing.</span>
5959+ {% else %}
6060+ <span class="tag is-light">
6161+ <span class="icon"><i class="fas fa-check"></i></span>
6262+ <span>Standard RSVPs</span>
6363+ </span>
6464+ <span class="ml-2">Users can RSVP directly on Smoke Signal.</span>
6565+ {% endif %}
6666+ {% if event.rsvp_redirect_url %}
5367 <div class="mt-2">
5468 <strong>Redirect URL:</strong>
5569 <a href="{{ event.rsvp_redirect_url }}" target="_blank" rel="noopener noreferrer">
···5771 <span class="icon is-small"><i class="fas fa-external-link-alt"></i></span>
5872 </a>
5973 </div>
6060- {% else %}
6161- <span class="tag is-light">
6262- <span class="icon">
6363- <i class="fas fa-times"></i>
6464- </span>
6565- <span>Disabled</span>
6666- </span>
6767- <span class="ml-2">Users can RSVP directly on Smoke Signal.</span>
6874 {% endif %}
6975 </p>
70767177 {# Edit form for external ticketing settings #}
7278 <form hx-post="/{{ handle_slug }}/{{ event_rkey }}/edit-settings" hx-target="this" hx-swap="outerHTML">
7979+ {# URL field - always visible #}
8080+ <div class="field">
8181+ <label class="label">Ticket Purchase URL (Optional)</label>
8282+ <div class="control has-icons-left">
8383+ <input class="input" type="url" name="rsvp_redirect_url"
8484+ value="{{ event.rsvp_redirect_url | default(value='') }}"
8585+ placeholder="https://ti.to/your-event/tickets">
8686+ <span class="icon is-small is-left"><i class="fas fa-link"></i></span>
8787+ </div>
8888+ <p class="help">
8989+ When set, users who RSVP as "Going" will see a button to continue to this URL.
9090+ Must be HTTPS. Leave empty for standard RSVPs.
9191+ </p>
9292+ </div>
9393+9494+ {# Disable direct RSVP checkbox #}
7395 <div class="field">
7496 <div class="control">
7597 <label class="checkbox">
7698 <input type="checkbox" name="disable_direct_rsvp" value="true"
7777- {% if event.disable_direct_rsvp %}checked{% endif %}
7878- onchange="document.getElementById('rsvp-redirect-url-field').classList.toggle('is-hidden', !this.checked)">
7979- Redirect RSVPs to external ticketing system
9999+ {% if event.disable_direct_rsvp %}checked{% endif %}>
100100+ <strong>Disable direct RSVPs entirely</strong>
80101 </label>
81102 </div>
8282- <p class="help">When enabled, the "Going" button will redirect users to your external ticketing URL instead of creating an RSVP.</p>
8383- </div>
8484-8585- <div class="field {% if not event.disable_direct_rsvp %}is-hidden{% endif %}" id="rsvp-redirect-url-field">
8686- <label class="label">Ticket Purchase URL</label>
8787- <div class="control has-icons-left">
8888- <input class="input" type="url" name="rsvp_redirect_url"
8989- value="{{ event.rsvp_redirect_url | default(value='') }}"
9090- placeholder="https://ti.to/your-event/tickets">
9191- <span class="icon is-small is-left">
9292- <i class="fas fa-link"></i>
9393- </span>
9494- </div>
9595- <p class="help">Users clicking "Going" will be redirected to this URL. Must be HTTPS.</p>
103103+ <p class="help">
104104+ When enabled, users will ONLY see a "Get Tickets" button linking to the URL above.
105105+ No RSVP will be recorded on Smoke Signal. Requires the redirect URL to be set.
106106+ </p>
96107 </div>
9710898109 <div class="field">
99110 <div class="control">
100111 <button type="submit" class="button is-primary">
101101- <span class="icon">
102102- <i class="fas fa-save"></i>
103103- </span>
112112+ <span class="icon"><i class="fas fa-save"></i></span>
104113 <span>Save Ticketing Settings</span>
105114 </button>
106115 </div>