Improve Nostr profile/relay settings forms
* Mark input fields as "added" when values were auto-added * Add suggested values for existing fields (NIP-05/LUD-16)
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<%= tag.p class: "flex gap-x-1", data: {
|
||||
<%= tag.div class: "flex gap-x-1", data: {
|
||||
controller: @resettable ? "settings--resettable-field" : nil,
|
||||
} do %>
|
||||
<%= content %>
|
||||
|
||||
@@ -24,13 +24,125 @@
|
||||
<% end %>
|
||||
<% end %>
|
||||
<%= render FormElements::FieldsetComponent.new(tag: "div", title: "Nostr address (NIP-05)") do %>
|
||||
<%= f.text_field :nip05_address, value: @profile["nip05"], class: "w-full sm:w-3/5" %>
|
||||
<% if @nip05_state[:status] == :added %>
|
||||
<div class="w-full sm:w-3/5 flex flex-col" data-controller="field-suggestion"
|
||||
data-field-suggestion-added-value-value="<%= @user.address %>">
|
||||
<div class="relative">
|
||||
<%= f.text_field :nip05_address, value: @nip05_state[:value],
|
||||
data: {
|
||||
:'field-suggestion-target' => "input",
|
||||
action: "input->field-suggestion#checkAdded"
|
||||
},
|
||||
class: "w-full pr-16 border-emerald-500 ring-1 ring-emerald-500 focus:border-emerald-500 focus:ring-emerald-500 bg-emerald-50/20" %>
|
||||
<span class="absolute inset-y-0 right-2.5 flex items-center pointer-events-none"
|
||||
data-field-suggestion-target="badge">
|
||||
<span class="rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-semibold text-emerald-800">
|
||||
added
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-1.5 flex items-center justify-between text-xs text-amber-800 bg-amber-50 rounded px-2.5 py-1.5 border border-amber-200 hidden"
|
||||
data-field-suggestion-target="suggestion">
|
||||
<span>Account address: <strong><%= @user.address %></strong></span>
|
||||
<button type="button" class="font-semibold text-blue-600 hover:text-blue-800 underline ml-2"
|
||||
data-action="click->field-suggestion#apply"
|
||||
data-field-suggestion-value-param="<%= @user.address %>">
|
||||
Use this
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<% elsif @nip05_state[:status] == :different %>
|
||||
<div class="w-full sm:w-3/5 flex flex-col" data-controller="field-suggestion"
|
||||
data-field-suggestion-added-value-value="<%= @nip05_state[:suggested] %>">
|
||||
<div class="relative">
|
||||
<%= f.text_field :nip05_address, value: @nip05_state[:value],
|
||||
data: {
|
||||
:'field-suggestion-target' => "input",
|
||||
action: "input->field-suggestion#checkAdded"
|
||||
},
|
||||
class: "w-full pr-20 border-amber-400 ring-1 ring-amber-400 focus:border-amber-400 focus:ring-amber-400" %>
|
||||
<span class="absolute inset-y-0 right-2.5 flex items-center pointer-events-none"
|
||||
data-field-suggestion-target="badge">
|
||||
<span class="rounded-full bg-amber-100 px-2 py-0.5 text-xs font-semibold text-amber-800">
|
||||
different
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-1.5 flex items-center justify-between text-xs text-amber-800 bg-amber-50 rounded px-2.5 py-1.5 border border-amber-200"
|
||||
data-field-suggestion-target="suggestion">
|
||||
<span>Account address: <strong><%= @nip05_state[:suggested] %></strong></span>
|
||||
<button type="button" class="font-semibold text-blue-600 hover:text-blue-800 underline ml-2"
|
||||
data-action="click->field-suggestion#apply"
|
||||
data-field-suggestion-value-param="<%= @nip05_state[:suggested] %>">
|
||||
Use this
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<%= f.text_field :nip05_address, value: @nip05_state[:value], class: "w-full sm:w-3/5" %>
|
||||
<% end %>
|
||||
<% if @validation_errors.present? && @validation_errors[:nip05_address].present? %>
|
||||
<p class="error-msg mt-2"><%= @validation_errors[:nip05_address].first %></p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<%= render FormElements::FieldsetComponent.new(tag: "div", title: "Ligtning address for Zaps") do %>
|
||||
<%= f.text_field :lud16_address, value: @profile["lud16"], class: "w-full sm:w-3/5" %>
|
||||
<%= render FormElements::FieldsetComponent.new(tag: "div", title: "Lightning address for Zaps") do %>
|
||||
<% if @lud16_state[:status] == :added %>
|
||||
<div class="w-full sm:w-3/5 flex flex-col" data-controller="field-suggestion"
|
||||
data-field-suggestion-added-value-value="<%= @user.address %>">
|
||||
<div class="relative">
|
||||
<%= f.text_field :lud16_address, value: @lud16_state[:value],
|
||||
data: {
|
||||
:'field-suggestion-target' => "input",
|
||||
action: "input->field-suggestion#checkAdded"
|
||||
},
|
||||
class: "w-full pr-16 border-emerald-500 ring-1 ring-emerald-500 focus:border-emerald-500 focus:ring-emerald-500 bg-emerald-50/20" %>
|
||||
<span class="absolute inset-y-0 right-2.5 flex items-center pointer-events-none"
|
||||
data-field-suggestion-target="badge">
|
||||
<span class="rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-semibold text-emerald-800">
|
||||
added
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-1.5 flex items-center justify-between text-xs text-amber-800 bg-amber-50 rounded px-2.5 py-1.5 border border-amber-200 hidden"
|
||||
data-field-suggestion-target="suggestion">
|
||||
<span>Account address: <strong><%= @user.address %></strong></span>
|
||||
<button type="button" class="font-semibold text-blue-600 hover:text-blue-800 underline ml-2"
|
||||
data-action="click->field-suggestion#apply"
|
||||
data-field-suggestion-value-param="<%= @user.address %>">
|
||||
Use this
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<% elsif @lud16_state[:status] == :different %>
|
||||
<div class="w-full sm:w-3/5 flex flex-col" data-controller="field-suggestion"
|
||||
data-field-suggestion-added-value-value="<%= @lud16_state[:suggested] %>">
|
||||
<div class="relative">
|
||||
<%= f.text_field :lud16_address, value: @lud16_state[:value],
|
||||
data: {
|
||||
:'field-suggestion-target' => "input",
|
||||
action: "input->field-suggestion#checkAdded"
|
||||
},
|
||||
class: "w-full pr-20 border-amber-400 ring-1 ring-amber-400 focus:border-amber-400 focus:ring-amber-400" %>
|
||||
<span class="absolute inset-y-0 right-2.5 flex items-center pointer-events-none"
|
||||
data-field-suggestion-target="badge">
|
||||
<span class="rounded-full bg-amber-100 px-2 py-0.5 text-xs font-semibold text-amber-800">
|
||||
different
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-1.5 flex items-center justify-between text-xs text-amber-800 bg-amber-50 rounded px-2.5 py-1.5 border border-amber-200"
|
||||
data-field-suggestion-target="suggestion">
|
||||
<span>Account address: <strong><%= @lud16_state[:suggested] %></strong></span>
|
||||
<button type="button" class="font-semibold text-blue-600 hover:text-blue-800 underline ml-2"
|
||||
data-action="click->field-suggestion#apply"
|
||||
data-field-suggestion-value-param="<%= @lud16_state[:suggested] %>">
|
||||
Use this
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<%= f.text_field :lud16_address, value: @lud16_state[:value], class: "w-full sm:w-3/5" %>
|
||||
<% end %>
|
||||
<% if @validation_errors.present? && @validation_errors[:lud16_address].present? %>
|
||||
<p class="error-msg mt-2"><%= @validation_errors[:lud16_address].first %></p>
|
||||
<% end %>
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
|
||||
module Settings
|
||||
class NostrEditProfileComponent < ViewComponent::Base
|
||||
def initialize(user:, profile_event:)
|
||||
attr_reader :user, :profile, :profile_event, :display_name, :nip05_state, :lud16_state
|
||||
|
||||
def initialize(user:, profile_event: nil, validation_errors: nil)
|
||||
@user = user
|
||||
@profile_event = profile_event
|
||||
@validation_errors = validation_errors
|
||||
@profile = {}
|
||||
@display_name = nil
|
||||
|
||||
@@ -12,6 +15,25 @@ module Settings
|
||||
@profile = JSON.parse(profile_event["content"]) rescue {}
|
||||
@display_name = @profile["display_name"] || @profile["displayName"]
|
||||
end
|
||||
|
||||
@display_name ||= @user.display_name
|
||||
|
||||
@nip05_state = compute_field_state(@profile["nip05"])
|
||||
@lud16_state = compute_field_state(@profile["lud16"])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def compute_field_state(current_value)
|
||||
target_value = @user.address
|
||||
|
||||
if current_value.blank?
|
||||
{ status: :added, value: target_value, suggested: nil }
|
||||
elsif current_value == target_value
|
||||
{ status: :matched, value: current_value, suggested: nil }
|
||||
else
|
||||
{ status: :different, value: current_value, suggested: target_value }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,8 +5,23 @@
|
||||
<ul data-relay-list-editor-target="list" class="mb-4 space-y-2">
|
||||
<% @relays.each do |relay| %>
|
||||
<li class="flex gap-x-2 items-center">
|
||||
<input type="text" name="relay_urls[]" value="<%= relay[:url] %>" class="grow" />
|
||||
<select name="relay_markers[]" class="shrink-0 w-32">
|
||||
<div class="relative grow">
|
||||
<% if relay[:added] %>
|
||||
<input type="text" name="relay_urls[]" value="<%= relay[:url] %>"
|
||||
data-added-value="<%= relay[:url] %>"
|
||||
data-action="input->relay-list-editor#checkAdded"
|
||||
class="w-full pr-16 border-emerald-500 ring-1 ring-emerald-500 focus:border-emerald-500 focus:ring-emerald-500 bg-emerald-50/20" />
|
||||
<span class="absolute inset-y-0 right-2.5 flex items-center pointer-events-none"
|
||||
data-relay-list-editor-target="addedBadge">
|
||||
<span class="rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-semibold text-emerald-800">
|
||||
added
|
||||
</span>
|
||||
</span>
|
||||
<% else %>
|
||||
<input type="text" name="relay_urls[]" value="<%= relay[:url] %>" class="w-full" />
|
||||
<% end %>
|
||||
</div>
|
||||
<select name="relay_markers[]" class="shrink-0 w-36 sm:w-40">
|
||||
<option value=""<%= %( selected="selected") if relay[:marker].nil? %>>Read & write</option>
|
||||
<option value="read"<%= %( selected="selected") if relay[:marker] == "read" %>>Read only</option>
|
||||
<option value="write"<%= %( selected="selected") if relay[:marker] == "write" %>>Write only</option>
|
||||
@@ -21,8 +36,10 @@
|
||||
|
||||
<template data-relay-list-editor-target="template">
|
||||
<li class="flex gap-x-2 items-center">
|
||||
<input type="text" name="relay_urls[]" value="" class="grow" />
|
||||
<select name="relay_markers[]" class="shrink-0 w-32">
|
||||
<div class="relative grow">
|
||||
<input type="text" name="relay_urls[]" value="" class="w-full" />
|
||||
</div>
|
||||
<select name="relay_markers[]" class="shrink-0 w-36 sm:w-40">
|
||||
<option value="">Read & write</option>
|
||||
<option value="read">Read only</option>
|
||||
<option value="write">Write only</option>
|
||||
|
||||
@@ -5,27 +5,30 @@ module Settings
|
||||
def initialize(nip65_event: nil)
|
||||
@nip65_event = nip65_event
|
||||
@relays = build_relays
|
||||
ensure_site_relay
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def build_relays
|
||||
if @nip65_event.present?
|
||||
@nip65_event["tags"]
|
||||
.select { |t| t[0] == "r" }
|
||||
.map { |t| { url: t[1], marker: t[2] } }
|
||||
site_relay = Setting.nostr_relay_url
|
||||
|
||||
if @nip65_event.blank?
|
||||
relays = Setting.nostr_discovery_relays.map { |url| { url: url, marker: nil, added: true } }
|
||||
if site_relay.present?
|
||||
relays.reject! { |r| r[:url] == site_relay }
|
||||
relays.unshift({ url: site_relay, marker: nil, added: true })
|
||||
end
|
||||
relays
|
||||
else
|
||||
Setting.nostr_discovery_relays.map { |url| { url: url, marker: nil } }
|
||||
existing = @nip65_event["tags"]
|
||||
.select { |t| t[0] == "r" }
|
||||
.map { |t| { url: t[1], marker: t[2], added: false } }
|
||||
|
||||
if site_relay.present? && existing.none? { |r| r[:url] == site_relay }
|
||||
existing.unshift({ url: site_relay, marker: nil, added: true })
|
||||
end
|
||||
existing
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_site_relay
|
||||
site_relay_url = Setting.nostr_relay_url
|
||||
return if site_relay_url.blank?
|
||||
|
||||
@relays.reject! { |r| r[:url] == site_relay_url }
|
||||
@relays.unshift({ url: site_relay_url, marker: nil })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = [ "input", "badge", "suggestion" ]
|
||||
static values = { addedValue: String }
|
||||
|
||||
apply (event) {
|
||||
event.preventDefault()
|
||||
const value = event.params.value ?? this.addedValueValue
|
||||
|
||||
if (this.hasInputTarget && value !== undefined) {
|
||||
this.inputTarget.value = value
|
||||
this.checkAdded()
|
||||
}
|
||||
}
|
||||
|
||||
checkAdded () {
|
||||
if (!this.hasInputTarget) return
|
||||
|
||||
const addedValue = this.hasAddedValueValue ? this.addedValueValue : null
|
||||
if (!addedValue) return
|
||||
|
||||
const isMatch = (this.inputTarget.value.trim() === addedValue.trim())
|
||||
|
||||
const emeraldClasses = [
|
||||
"border-emerald-500", "ring-1", "ring-emerald-500",
|
||||
"focus:border-emerald-500", "focus:ring-emerald-500",
|
||||
"bg-emerald-50/20"
|
||||
]
|
||||
const amberClasses = [
|
||||
"border-amber-400", "ring-1", "ring-amber-400",
|
||||
"focus:border-amber-400", "focus:ring-amber-400"
|
||||
]
|
||||
|
||||
if (isMatch) {
|
||||
this.inputTarget.classList.remove(...amberClasses)
|
||||
this.inputTarget.classList.add(...emeraldClasses)
|
||||
|
||||
if (this.hasBadgeTarget) {
|
||||
this.badgeTarget.innerHTML = `
|
||||
<span class="rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-semibold text-emerald-800">
|
||||
added
|
||||
</span>
|
||||
`.trim()
|
||||
this.badgeTarget.classList.remove("hidden")
|
||||
}
|
||||
|
||||
if (this.hasSuggestionTarget) {
|
||||
this.suggestionTarget.classList.add("hidden")
|
||||
}
|
||||
} else {
|
||||
this.inputTarget.classList.remove(...emeraldClasses)
|
||||
|
||||
if (this.hasBadgeTarget) {
|
||||
this.badgeTarget.classList.add("hidden")
|
||||
}
|
||||
|
||||
if (this.hasSuggestionTarget) {
|
||||
this.suggestionTarget.classList.remove("hidden")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = [ "list", "template" ]
|
||||
static targets = [ "list", "template", "addedBadge" ]
|
||||
|
||||
add (event) {
|
||||
event.preventDefault()
|
||||
@@ -14,4 +14,27 @@ export default class extends Controller {
|
||||
const row = event.target.closest("li")
|
||||
row.remove()
|
||||
}
|
||||
|
||||
checkAdded (event) {
|
||||
const input = event.target
|
||||
const addedValue = input.dataset.addedValue
|
||||
if (!addedValue) return
|
||||
|
||||
const container = input.closest(".relative")
|
||||
const badge = container?.querySelector("[data-relay-list-editor-target='addedBadge']")
|
||||
|
||||
const addedClasses = [
|
||||
"border-emerald-500", "ring-1", "ring-emerald-500",
|
||||
"focus:border-emerald-500", "focus:ring-emerald-500",
|
||||
"bg-emerald-50/20"
|
||||
]
|
||||
|
||||
if (input.value.trim() === addedValue.trim()) {
|
||||
input.classList.add(...addedClasses)
|
||||
if (badge) badge.classList.remove("hidden")
|
||||
} else {
|
||||
input.classList.remove(...addedClasses)
|
||||
if (badge) badge.classList.add("hidden")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe FormElements::FieldsetComponent, type: :component do
|
||||
it "renders a div with flex gap-x-1 for vertical positioning" do
|
||||
rendered = render_inline(described_class.new(title: "Username")) do
|
||||
"<input type='text' name='username' />".html_safe
|
||||
end
|
||||
|
||||
expect(rendered.css("label.block > div.flex.gap-x-1")).to be_present
|
||||
expect(rendered.css("label.block > p.flex")).not_to be_present
|
||||
end
|
||||
|
||||
it "renders a div for horizontal positioning" do
|
||||
rendered = render_inline(described_class.new(positioning: :horizontal, title: "Enable notifications")) do
|
||||
"<input type='checkbox' />".html_safe
|
||||
end
|
||||
|
||||
expect(rendered.css("label.block > div.relative")).to be_present
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,86 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Settings::NostrEditProfileComponent, type: :component do
|
||||
let(:user) { build(:user, cn: "alice") }
|
||||
|
||||
before do
|
||||
allow(user).to receive(:address).and_return("alice@kosmos.org")
|
||||
allow(user).to receive(:display_name).and_return("Alice Wonderland")
|
||||
end
|
||||
|
||||
describe "when profile event is missing or fields are empty" do
|
||||
it "prefills NIP-05 and Lightning addresses with user address and marks them as added" do
|
||||
rendered = render_inline(described_class.new(user: user, profile_event: nil))
|
||||
|
||||
nip05_input = rendered.css("input[name='user[nip05_address]']").first
|
||||
expect(nip05_input["value"]).to eq("alice@kosmos.org")
|
||||
expect(nip05_input["class"]).to include("border-emerald-500")
|
||||
expect(nip05_input["data-action"]).to include("input->field-suggestion#checkAdded")
|
||||
|
||||
lud16_input = rendered.css("input[name='user[lud16_address]']").first
|
||||
expect(lud16_input["value"]).to eq("alice@kosmos.org")
|
||||
expect(lud16_input["class"]).to include("border-emerald-500")
|
||||
expect(lud16_input["data-action"]).to include("input->field-suggestion#checkAdded")
|
||||
|
||||
badges = rendered.css("span.rounded-full").select { |el| el.text.strip == "added" }
|
||||
expect(badges.size).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when profile has different NIP-05 and Lightning addresses" do
|
||||
let(:profile_event) do
|
||||
{
|
||||
"content" => {
|
||||
"nip05" => "alice@other.org",
|
||||
"lud16" => "alice@getalby.com",
|
||||
"display_name" => "Alice External"
|
||||
}.to_json
|
||||
}
|
||||
end
|
||||
|
||||
it "shows current values with different badges and suggestion strips" do
|
||||
rendered = render_inline(described_class.new(user: user, profile_event: profile_event))
|
||||
|
||||
nip05_input = rendered.css("input[name='user[nip05_address]']").first
|
||||
expect(nip05_input["value"]).to eq("alice@other.org")
|
||||
expect(nip05_input["class"]).to include("border-amber-400")
|
||||
|
||||
lud16_input = rendered.css("input[name='user[lud16_address]']").first
|
||||
expect(lud16_input["value"]).to eq("alice@getalby.com")
|
||||
expect(lud16_input["class"]).to include("border-amber-400")
|
||||
|
||||
different_badges = rendered.css("span.rounded-full").select { |el| el.text.strip == "different" }
|
||||
expect(different_badges.size).to eq(2)
|
||||
|
||||
suggestion_buttons = rendered.css("button[data-action='click->field-suggestion#apply']")
|
||||
expect(suggestion_buttons.size).to eq(2)
|
||||
expect(suggestion_buttons.first["data-field-suggestion-value-param"]).to eq("alice@kosmos.org")
|
||||
end
|
||||
end
|
||||
|
||||
describe "when profile addresses match user address" do
|
||||
let(:profile_event) do
|
||||
{
|
||||
"content" => {
|
||||
"nip05" => "alice@kosmos.org",
|
||||
"lud16" => "alice@kosmos.org",
|
||||
"display_name" => "Alice Wonderland"
|
||||
}.to_json
|
||||
}
|
||||
end
|
||||
|
||||
it "renders standard inputs without added or different badges" do
|
||||
rendered = render_inline(described_class.new(user: user, profile_event: profile_event))
|
||||
|
||||
nip05_input = rendered.css("input[name='user[nip05_address]']").first
|
||||
expect(nip05_input["value"]).to eq("alice@kosmos.org")
|
||||
expect(nip05_input["class"]).not_to include("border-emerald-500")
|
||||
expect(nip05_input["class"]).not_to include("border-amber-400")
|
||||
|
||||
badges = rendered.css("span.rounded-full").select { |el| %w[added different].include?(el.text.strip) }
|
||||
expect(badges).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,79 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Settings::NostrEditRelaysComponent, type: :component do
|
||||
before do
|
||||
allow(Setting).to receive(:nostr_relay_url).and_return("wss://nostr.kosmos.org")
|
||||
allow(Setting).to receive(:nostr_discovery_relays).and_return([
|
||||
"wss://nos.lol",
|
||||
"wss://relay.damus.io"
|
||||
])
|
||||
end
|
||||
|
||||
describe "when user has no relay list (nip65_event is nil)" do
|
||||
it "renders all relays with added status and badges" do
|
||||
rendered = render_inline(described_class.new(nip65_event: nil))
|
||||
|
||||
expect(rendered.css("input[value='wss://nostr.kosmos.org']")).to be_present
|
||||
expect(rendered.css("input[value='wss://nos.lol']")).to be_present
|
||||
expect(rendered.css("input[value='wss://relay.damus.io']")).to be_present
|
||||
|
||||
badges = rendered.css("span.rounded-full").select { |el| el.text.strip == "added" }
|
||||
expect(badges.size).to eq(3)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when user has an existing relay list without site relay" do
|
||||
let(:nip65_event) do
|
||||
{
|
||||
"kind" => 10002,
|
||||
"tags" => [
|
||||
["r", "wss://nos.lol"],
|
||||
["r", "wss://relay.damus.io", "read"]
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
it "prepends the site relay marked as added, while existing relays are not added" do
|
||||
rendered = render_inline(described_class.new(nip65_event: nip65_event))
|
||||
|
||||
relay_inputs = rendered.css("input[name='relay_urls[]']").map { |el| el["value"] }
|
||||
expect(relay_inputs.first).to eq("wss://nostr.kosmos.org")
|
||||
|
||||
badges = rendered.css("span.rounded-full").select { |el| el.text.strip == "added" }
|
||||
expect(badges.size).to eq(1)
|
||||
|
||||
site_input = rendered.css("input[value='wss://nostr.kosmos.org']").first
|
||||
expect(site_input["class"]).to include("border-emerald-500")
|
||||
expect(site_input["data-added-value"]).to eq("wss://nostr.kosmos.org")
|
||||
expect(site_input["data-action"]).to include("input->relay-list-editor#checkAdded")
|
||||
|
||||
other_input = rendered.css("input[value='wss://nos.lol']").first
|
||||
expect(other_input["class"]).not_to include("border-emerald-500")
|
||||
expect(other_input["data-added-value"]).to be_nil
|
||||
|
||||
select = rendered.css("select[name='relay_markers[]']").first
|
||||
expect(select["class"]).to include("w-36")
|
||||
end
|
||||
end
|
||||
|
||||
describe "when user already has site relay in their relay list" do
|
||||
let(:nip65_event) do
|
||||
{
|
||||
"kind" => 10002,
|
||||
"tags" => [
|
||||
["r", "wss://nostr.kosmos.org"],
|
||||
["r", "wss://nos.lol"]
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
it "renders relays without any added badges" do
|
||||
rendered = render_inline(described_class.new(nip65_event: nip65_event))
|
||||
|
||||
badges = rendered.css("span.rounded-full").select { |el| el.text.strip == "added" }
|
||||
expect(badges).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user