Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ def create
render json: { id: record.id, created_at: record.created_at }, status: :created
end

# GET /web_push/devices
# Renders the device list inside its turbo-frame so the Settings page
# can refresh just that section after enabling/disabling on this browser.
def devices
@web_push_subscriptions = current_user.web_push_subscriptions.order(created_at: :desc)
render partial: "coplan/settings/settings/devices",
locals: { web_push_subscriptions: @web_push_subscriptions }
end

# DELETE /web_push/subscription
# Body: { subscription: { endpoint } }
def destroy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as WebPush from "coplan/web_push"
// browser's subscription state (which the server can't know — it's per-device).
export default class extends Controller {
static targets = ["enableButton", "disableButton", "status"]
static values = { devicesUrl: { type: String, default: "" } }

async connect() {
await this._refresh()
Expand All @@ -15,6 +16,7 @@ export default class extends Controller {
try {
await WebPush.subscribe()
this._setStatus("Notifications enabled on this device.")
this._reloadDevices()
} catch (err) {
this._setStatus(this._friendlyError(err))
}
Expand All @@ -26,12 +28,23 @@ export default class extends Controller {
try {
await WebPush.unsubscribe()
this._setStatus("Notifications disabled on this device.")
this._reloadDevices()
} catch (err) {
this._setStatus(this._friendlyError(err))
}
await this._refresh()
}

// Tell the device-list turbo-frame to refetch itself so the row for this
// browser appears (or disappears) without a full page reload.
_reloadDevices() {
if (!this.devicesUrlValue) return
const frame = document.getElementById("web-push-devices")
if (!frame) return
// Setting src triggers a fetch even when the URL hasn't changed.
frame.src = this.devicesUrlValue
}

// ---- internals ----

async _refresh() {
Expand Down
28 changes: 28 additions & 0 deletions engine/app/views/coplan/settings/settings/_devices.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<%# Per-device list rendered both in-page (initial load) and as a turbo-frame %>
<%# response after the Stimulus controller refreshes it post-enable/disable. %>
<%= turbo_frame_tag "web-push-devices" do %>
<% if web_push_subscriptions.any? %>
<div class="settings-subsection">
<div class="settings-subsection__heading">Devices receiving notifications</div>
<ul class="device-list">
<% web_push_subscriptions.each do |sub| %>
<li class="device-list__item">
<div class="device-list__name"><%= sub.device_label %></div>
<div class="device-list__meta">
Added <%= time_ago_in_words(sub.created_at) %> ago
<% if sub.last_delivered_at %>
· last notified <%= time_ago_in_words(sub.last_delivered_at) %> ago
· <%= pluralize(sub.notifications_delivered_count, "notification") %>
<% else %>
· no notifications yet
<% end %>
</div>
</li>
<% end %>
</ul>
<p class="settings-subsection__hint">
To remove a device, sign in to CoPlan from that browser and click "Disable on this device".
</p>
</div>
<% end %>
<% end %>
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<% return unless CoPlan.configuration.web_push_configured? %>

<div class="card mb-md" data-controller="coplan--web-push-settings">
<div class="card mb-md"
data-controller="coplan--web-push-settings"
data-coplan--web-push-settings-devices-url-value="<%= coplan.web_push_devices_path %>">
<div class="settings-row">
<div class="settings-row__main">
<div class="settings-row__label">Browser notifications</div>
Expand Down Expand Up @@ -28,28 +30,6 @@
</div>
</div>

<% if @web_push_subscriptions.any? %>
<div class="settings-subsection">
<div class="settings-subsection__heading">Devices receiving notifications</div>
<ul class="device-list">
<% @web_push_subscriptions.each do |sub| %>
<li class="device-list__item">
<div class="device-list__name"><%= sub.device_label %></div>
<div class="device-list__meta">
Added <%= time_ago_in_words(sub.created_at) %> ago
<% if sub.last_delivered_at %>
· last notified <%= time_ago_in_words(sub.last_delivered_at) %> ago
· <%= pluralize(sub.notifications_delivered_count, "notification") %>
<% else %>
· no notifications yet
<% end %>
</div>
</li>
<% end %>
</ul>
<p class="settings-subsection__hint">
To remove a device, sign in to CoPlan from that browser and click "Disable on this device".
</p>
</div>
<% end %>
<%= render partial: "coplan/settings/settings/devices",
locals: { web_push_subscriptions: @web_push_subscriptions } %>
</div>
4 changes: 4 additions & 0 deletions engine/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@
# PushManager and uniquely identify a (browser, device, app) tuple per user.
scope :web_push, module: "web_push", as: :web_push do
resource :subscription, only: [:create, :destroy], controller: "subscriptions"
# Turbo-frame target for the per-device list on the Settings page.
# Reloaded by the settings Stimulus controller after enable/disable so
# the list reflects the new browser without a full page refresh.
get "devices", to: "subscriptions#devices", as: :devices
end

root "plans#index"
Expand Down
Loading