fix: align realtime feedback and map privacy
This commit is contained in:
parent
f0512fab84
commit
7ce052d0a1
|
|
@ -393,15 +393,22 @@ const createAidMap = element => {
|
|||
|
||||
exactPoints.forEach(point => {
|
||||
const popup = new maplibregl.Popup({offset: 18}).setDOMContent(state.popupContent(point))
|
||||
const marker = new maplibregl.Marker({color: point.exact ? "#d6573b" : "#278467"})
|
||||
const markerColor = point.type === "live" ? "#2563eb" : point.exact ? "#d6573b" : "#278467"
|
||||
const marker = new maplibregl.Marker({color: markerColor})
|
||||
.setLngLat([point.longitude, point.latitude])
|
||||
.setPopup(popup)
|
||||
.addTo(state.map)
|
||||
|
||||
const markerElement = marker.getElement()
|
||||
markerElement.dataset.markerType = point.type || "request"
|
||||
markerElement.setAttribute("aria-label", point.title || "Map marker")
|
||||
|
||||
if (point.id) {
|
||||
markerElement.dataset.requestId = point.id
|
||||
markerElement.addEventListener("click", () => state.selectRequest(point.id))
|
||||
state.markerElements.set(point.id, markerElement)
|
||||
}
|
||||
|
||||
state.markers.push(marker)
|
||||
})
|
||||
|
||||
|
|
@ -591,6 +598,7 @@ export const Hooks = {
|
|||
PushNotifications: {
|
||||
mounted() {
|
||||
this.button = this.el.querySelector("[data-enable-push]")
|
||||
this.buttonLabel = this.el.querySelector("[data-enable-push-label]")
|
||||
this.status = this.el.querySelector("[data-push-status]")
|
||||
this.native = typeof window.WhoNeedHelpAndroid?.postMessage === "function"
|
||||
|
||||
|
|
@ -600,6 +608,13 @@ export const Hooks = {
|
|||
if (this.status) this.status.textContent = message
|
||||
}
|
||||
|
||||
this.setButtonState = enabled => {
|
||||
if (!this.buttonLabel) return
|
||||
this.buttonLabel.textContent = enabled
|
||||
? this.buttonLabel.dataset.enabledLabel
|
||||
: this.buttonLabel.dataset.enableLabel
|
||||
}
|
||||
|
||||
this.decodeApplicationServerKey = value => {
|
||||
const padding = "=".repeat((4 - value.length % 4) % 4)
|
||||
const base64 = (value + padding).replace(/-/g, "+").replace(/_/g, "/")
|
||||
|
|
@ -701,6 +716,9 @@ export const Hooks = {
|
|||
await subscription?.unsubscribe()
|
||||
} catch (error) {
|
||||
console.warn("Browser push unsubscribe failed", error)
|
||||
} finally {
|
||||
this.setButtonState(false)
|
||||
this.setStatus("Push notifications are disabled on this device.")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -746,6 +764,7 @@ export const Hooks = {
|
|||
device_label: `${navigator.platform || "Browser"} · Web Push`.slice(0, 120),
|
||||
user_agent: navigator.userAgent.slice(0, 500)
|
||||
})
|
||||
this.setButtonState(true)
|
||||
this.setStatus("Push notifications are enabled on this device.")
|
||||
} catch (error) {
|
||||
console.warn("Push notification registration failed", error)
|
||||
|
|
@ -755,11 +774,48 @@ export const Hooks = {
|
|||
}
|
||||
}
|
||||
|
||||
this.restoreWebState = async () => {
|
||||
if (this.native) return
|
||||
|
||||
const publicKey = String(this.el.dataset.vapidPublicKey || "")
|
||||
if (!publicKey || !("serviceWorker" in navigator) || !("PushManager" in window)) {
|
||||
this.setStatus("Push notifications are unavailable in this browser.")
|
||||
return
|
||||
}
|
||||
|
||||
if (Notification.permission === "denied") {
|
||||
this.setStatus("Notification permission was not granted.")
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const registration = await navigator.serviceWorker.ready
|
||||
const subscription = await registration.pushManager.getSubscription()
|
||||
const deviceId = window.localStorage.getItem("wnh.push.server-device-id")
|
||||
const activeServerDevice = deviceId &&
|
||||
[...this.el.querySelectorAll("[data-disable-device]")]
|
||||
.some(element => element.dataset.disableDevice === deviceId)
|
||||
|
||||
if (subscription && activeServerDevice) {
|
||||
this.setButtonState(true)
|
||||
this.setStatus("Push notifications are enabled on this device.")
|
||||
} else if (subscription || activeServerDevice) {
|
||||
this.setStatus("This browser has a push subscription. Enable it to reconnect this device.")
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("Push notification state could not be restored", error)
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("wnh:native-push-token", this.nativeToken)
|
||||
window.addEventListener("wnh:native-push-error", this.nativeError)
|
||||
this.el.addEventListener("click", this.disableCurrentDevice)
|
||||
this.button?.addEventListener("click", this.enable)
|
||||
if (this.native) this.postNative({action: "push_token_request"})
|
||||
if (this.native) {
|
||||
this.postNative({action: "push_token_request"})
|
||||
} else {
|
||||
this.restoreWebState()
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener("wnh:native-push-token", this.nativeToken)
|
||||
|
|
@ -867,6 +923,7 @@ export const Hooks = {
|
|||
|
||||
LocalTime: {
|
||||
mounted() {
|
||||
this.format = () => {
|
||||
const value = this.el.dateTime || this.el.dataset.datetime
|
||||
const date = new Date(value)
|
||||
if (Number.isNaN(date.getTime())) return
|
||||
|
|
@ -877,6 +934,12 @@ export const Hooks = {
|
|||
}).format(date)
|
||||
this.el.title = date.toISOString()
|
||||
}
|
||||
|
||||
this.format()
|
||||
},
|
||||
updated() {
|
||||
this.format()
|
||||
}
|
||||
},
|
||||
|
||||
ChatMessages: {
|
||||
|
|
|
|||
|
|
@ -620,10 +620,17 @@ defmodule WhoNeedHelp.Help do
|
|||
request.assignment.status in [:accepted, :in_progress] and
|
||||
not Trust.blocked_between?(scope.user.id, request.requester_id)
|
||||
|
||||
if owner or
|
||||
(matched_participant and request.location_visibility == :exact_for_active_match) do
|
||||
cond do
|
||||
owner and request.location_visibility == :approximate_public ->
|
||||
HelpRequest.public_coordinates(request)
|
||||
|
||||
owner ->
|
||||
exact_request_coordinates(request)
|
||||
else
|
||||
|
||||
matched_participant and request.location_visibility == :exact_for_active_match ->
|
||||
exact_request_coordinates(request)
|
||||
|
||||
true ->
|
||||
HelpRequest.public_coordinates(request)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -302,7 +302,13 @@ defmodule WhoNeedHelpWeb.NotificationLive do
|
|||
class="btn btn-success w-full"
|
||||
>
|
||||
<.icon name="hero-bell-alert" class="size-5" />
|
||||
<span
|
||||
data-enable-push-label
|
||||
data-enable-label={gettext("Enable push on this device")}
|
||||
data-enabled-label={gettext("Push enabled on this device")}
|
||||
>
|
||||
{gettext("Enable push on this device")}
|
||||
</span>
|
||||
</button>
|
||||
<p data-push-status role="status" aria-live="polite" class="mt-2 text-xs">
|
||||
<%= if @web_push_public_key do %>
|
||||
|
|
|
|||
|
|
@ -74,7 +74,8 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
|> maybe_put_status_transition_flash(
|
||||
previous_status,
|
||||
request.status,
|
||||
previous_assignment
|
||||
previous_assignment,
|
||||
request.assignment
|
||||
)
|
||||
|
||||
{:noreply, sync_tracking_after_request_update(socket, request)}
|
||||
|
|
@ -142,10 +143,14 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
case Help.accept_request(socket.assigns.current_scope, socket.assigns.request.id) do
|
||||
{:ok, _} ->
|
||||
{:noreply,
|
||||
put_flash(socket, :info, gettext("You are matched. Use chat to coordinate safely."))}
|
||||
put_action_flash(
|
||||
socket,
|
||||
:info,
|
||||
gettext("You accepted this request. Use private chat to coordinate safely.")
|
||||
)}
|
||||
|
||||
{:error, reason} ->
|
||||
{:noreply, put_flash(socket, :error, message(reason))}
|
||||
{:noreply, put_action_flash(socket, :error, message(reason))}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -154,10 +159,10 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
|
||||
case Help.cancel_request(socket.assigns.current_scope, socket.assigns.request.id, attrs) do
|
||||
{:ok, _request} ->
|
||||
{:noreply, put_flash(socket, :info, gettext("Request cancelled."))}
|
||||
{:noreply, put_action_flash(socket, :info, gettext("Request cancelled."))}
|
||||
|
||||
{:error, reason} ->
|
||||
{:noreply, put_flash(socket, :error, message(reason))}
|
||||
{:noreply, put_action_flash(socket, :error, message(reason))}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -185,24 +190,24 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
) do
|
||||
{:ok, _assignment} ->
|
||||
{:noreply,
|
||||
put_flash(
|
||||
put_action_flash(
|
||||
socket,
|
||||
:info,
|
||||
gettext("You left this match. The request is open for another helper if time remains.")
|
||||
)}
|
||||
|
||||
{:error, reason} ->
|
||||
{:noreply, put_flash(socket, :error, message(reason))}
|
||||
{:noreply, put_action_flash(socket, :error, message(reason))}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_event("verify-code", %{"handover" => %{"code" => code}}, socket) do
|
||||
case Help.verify_handover(socket.assigns.current_scope, socket.assigns.assignment.id, code) do
|
||||
{:ok, _} ->
|
||||
{:noreply, put_flash(socket, :info, gettext("Handover code verified."))}
|
||||
{:noreply, put_action_flash(socket, :info, gettext("Handover code verified."))}
|
||||
|
||||
{:error, reason} ->
|
||||
{:noreply, put_flash(socket, :error, message(reason))}
|
||||
{:noreply, put_action_flash(socket, :error, message(reason))}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -215,7 +220,7 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
|> push_event("reset-message-form", %{id: "message-form"})}
|
||||
|
||||
{:error, reason} ->
|
||||
{:noreply, put_flash(socket, :error, message(reason))}
|
||||
{:noreply, put_action_flash(socket, :error, message(reason))}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -276,7 +281,7 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
|> maybe_start_native_tracking()}
|
||||
|
||||
{:error, reason} ->
|
||||
{:noreply, put_flash(socket, :error, message(reason))}
|
||||
{:noreply, put_action_flash(socket, :error, message(reason))}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -294,7 +299,8 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
{:error, _reason} -> socket
|
||||
end
|
||||
|
||||
{:noreply, put_flash(socket, :error, gettext("The browser could not share your location."))}
|
||||
{:noreply,
|
||||
put_action_flash(socket, :error, gettext("The browser could not share your location."))}
|
||||
end
|
||||
|
||||
def handle_event("stop-tracking", _, socket) do
|
||||
|
|
@ -303,7 +309,7 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
{:noreply, stopped_socket}
|
||||
|
||||
{:error, reason} ->
|
||||
{:noreply, put_flash(socket, :error, message(reason))}
|
||||
{:noreply, put_action_flash(socket, :error, message(reason))}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -311,14 +317,14 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
case Trust.submit_review(socket.assigns.current_scope, socket.assigns.assignment, params) do
|
||||
{:ok, _} ->
|
||||
{:noreply,
|
||||
put_flash(
|
||||
put_action_flash(
|
||||
socket,
|
||||
:info,
|
||||
gettext("Review saved. It appears after both participants review.")
|
||||
)}
|
||||
|
||||
{:error, reason} ->
|
||||
{:noreply, put_flash(socket, :error, message(reason))}
|
||||
{:noreply, put_action_flash(socket, :error, message(reason))}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -342,11 +348,11 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
socket
|
||||
|> assign(:report_form, report_form())
|
||||
|> assign(:report_message_id, nil)
|
||||
|> put_flash(:info, gettext("Report sent to moderators."))
|
||||
|> put_action_flash(:info, gettext("Report sent to moderators."))
|
||||
|> push_event("reset-message-form", %{id: "request-report-form"})}
|
||||
|
||||
{:error, reason} ->
|
||||
{:noreply, put_flash(socket, :error, message(reason))}
|
||||
{:noreply, put_action_flash(socket, :error, message(reason))}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -360,7 +366,11 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
{:noreply, assign(socket, :report_message_id, message.id)}
|
||||
else
|
||||
{:noreply,
|
||||
put_flash(socket, :error, gettext("That message cannot be reported from this view."))}
|
||||
put_action_flash(
|
||||
socket,
|
||||
:error,
|
||||
gettext("That message cannot be reported from this view.")
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -384,17 +394,14 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
|> assign(:positions, %{})
|
||||
|> assign(:tracking_active, false)
|
||||
|> assign(:tracking_session_id, nil)
|
||||
|> assign(
|
||||
:markers,
|
||||
Jason.encode!(request_markers(socket.assigns.current_scope, socket.assigns.request))
|
||||
)
|
||||
|> put_flash(
|
||||
|> refresh_request_coordinates()
|
||||
|> put_action_flash(
|
||||
:info,
|
||||
gettext("User blocked. Their requests and new messages are hidden.")
|
||||
)}
|
||||
|
||||
{:error, reason} ->
|
||||
{:noreply, put_flash(socket, :error, message(reason))}
|
||||
{:noreply, put_action_flash(socket, :error, message(reason))}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -412,13 +419,14 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
socket
|
||||
|> assign(:blocked_by_current, false)
|
||||
|> assign(:interaction_blocked, interaction_blocked)
|
||||
|> refresh_request_coordinates()
|
||||
|> restore_private_interaction(interaction_blocked)
|
||||
|> put_flash(:info, gettext("User unblocked."))
|
||||
|> put_action_flash(:info, gettext("User unblocked."))
|
||||
|
||||
{:noreply, socket}
|
||||
|
||||
{:error, reason} ->
|
||||
{:noreply, put_flash(socket, :error, message(reason))}
|
||||
{:noreply, put_action_flash(socket, :error, message(reason))}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -488,57 +496,121 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
|
||||
defp transition(socket, fun, success) do
|
||||
case fun.(socket.assigns.current_scope, socket.assigns.assignment.id) do
|
||||
{:ok, _} -> {:noreply, put_flash(socket, :info, success)}
|
||||
{:error, reason} -> {:noreply, put_flash(socket, :error, message(reason))}
|
||||
{:ok, _} -> {:noreply, put_action_flash(socket, :info, success)}
|
||||
{:error, reason} -> {:noreply, put_action_flash(socket, :error, message(reason))}
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_put_status_transition_flash(socket, status, status, _previous_assignment), do: socket
|
||||
defp put_action_flash(socket, kind, message) do
|
||||
socket
|
||||
|> clear_flash()
|
||||
|> put_flash(kind, message)
|
||||
end
|
||||
|
||||
defp maybe_put_status_transition_flash(
|
||||
socket,
|
||||
status,
|
||||
status,
|
||||
_previous_assignment,
|
||||
_assignment
|
||||
),
|
||||
do: socket
|
||||
|
||||
defp maybe_put_status_transition_flash(
|
||||
%{assigns: %{current_scope: %{user: %{id: user_id}}}} = socket,
|
||||
previous,
|
||||
:open,
|
||||
%{helper_id: user_id}
|
||||
%{helper_id: user_id},
|
||||
_assignment
|
||||
)
|
||||
when previous in [:matched, :in_progress] do
|
||||
put_flash(
|
||||
put_action_flash(
|
||||
socket,
|
||||
:info,
|
||||
gettext("You left this match. The request is open for another helper if time remains.")
|
||||
)
|
||||
end
|
||||
|
||||
defp maybe_put_status_transition_flash(socket, previous, :open, _previous_assignment)
|
||||
defp maybe_put_status_transition_flash(
|
||||
socket,
|
||||
previous,
|
||||
:open,
|
||||
_previous_assignment,
|
||||
_assignment
|
||||
)
|
||||
when previous in [:matched, :in_progress] do
|
||||
put_flash(
|
||||
put_action_flash(
|
||||
socket,
|
||||
:info,
|
||||
gettext("The previous helper left. This request is open for a new helper again.")
|
||||
)
|
||||
end
|
||||
|
||||
defp maybe_put_status_transition_flash(socket, _previous, :matched, _previous_assignment) do
|
||||
put_flash(
|
||||
defp maybe_put_status_transition_flash(
|
||||
%{assigns: %{current_scope: %{user: %{id: user_id}}}} = socket,
|
||||
_previous,
|
||||
:matched,
|
||||
_previous_assignment,
|
||||
%{helper_id: user_id}
|
||||
) do
|
||||
put_action_flash(
|
||||
socket,
|
||||
:info,
|
||||
gettext("You accepted this request. Use private chat to coordinate safely.")
|
||||
)
|
||||
end
|
||||
|
||||
defp maybe_put_status_transition_flash(
|
||||
socket,
|
||||
_previous,
|
||||
:matched,
|
||||
_previous_assignment,
|
||||
_assignment
|
||||
) do
|
||||
put_action_flash(
|
||||
socket,
|
||||
:info,
|
||||
gettext("A volunteer accepted this request. Use private chat to coordinate safely.")
|
||||
)
|
||||
end
|
||||
|
||||
defp maybe_put_status_transition_flash(socket, _previous, :in_progress, _previous_assignment) do
|
||||
put_flash(socket, :info, gettext("Help is now in progress."))
|
||||
defp maybe_put_status_transition_flash(
|
||||
socket,
|
||||
_previous,
|
||||
:in_progress,
|
||||
_previous_assignment,
|
||||
_assignment
|
||||
) do
|
||||
put_action_flash(socket, :info, gettext("Help is now in progress."))
|
||||
end
|
||||
|
||||
defp maybe_put_status_transition_flash(socket, _previous, :completed, _previous_assignment) do
|
||||
put_flash(socket, :info, gettext("Help is complete."))
|
||||
defp maybe_put_status_transition_flash(
|
||||
socket,
|
||||
_previous,
|
||||
:completed,
|
||||
_previous_assignment,
|
||||
_assignment
|
||||
) do
|
||||
put_action_flash(socket, :info, gettext("Help is complete."))
|
||||
end
|
||||
|
||||
defp maybe_put_status_transition_flash(socket, _previous, :cancelled, _previous_assignment) do
|
||||
put_flash(socket, :info, gettext("This request was cancelled."))
|
||||
defp maybe_put_status_transition_flash(
|
||||
socket,
|
||||
_previous,
|
||||
:cancelled,
|
||||
_previous_assignment,
|
||||
_assignment
|
||||
) do
|
||||
put_action_flash(socket, :info, gettext("This request was cancelled."))
|
||||
end
|
||||
|
||||
defp maybe_put_status_transition_flash(socket, _previous, _status, _previous_assignment),
|
||||
defp maybe_put_status_transition_flash(
|
||||
socket,
|
||||
_previous,
|
||||
_status,
|
||||
_previous_assignment,
|
||||
_assignment
|
||||
),
|
||||
do: socket
|
||||
|
||||
defp restore_private_interaction(socket, true), do: socket
|
||||
|
|
@ -593,6 +665,8 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
|> Enum.reject(&is_nil/1)
|
||||
|> Trust.reputations()
|
||||
|
||||
request_coordinates = Help.request_coordinates(socket.assigns.current_scope, request)
|
||||
|
||||
socket
|
||||
|> assign(:page_title, request.title)
|
||||
|> assign(:request, request)
|
||||
|
|
@ -625,6 +699,7 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
|> assign(:message_window_limit, max(length(messages_page.entries), @initial_message_window))
|
||||
|> assign(:report_message_id, nil)
|
||||
|> assign(:positions, positions)
|
||||
|> assign(:request_coordinates, request_coordinates)
|
||||
|> assign(:tracking_active, tracking_active)
|
||||
|> assign(:message_form, to_form(%{"body" => ""}, as: :message))
|
||||
|> assign(:handover_form, to_form(%{"code" => ""}, as: :handover))
|
||||
|
|
@ -647,7 +722,8 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
|> assign(
|
||||
:markers,
|
||||
Jason.encode!(
|
||||
request_markers(socket.assigns.current_scope, request) ++ position_markers(positions)
|
||||
request_markers(request, request_coordinates) ++
|
||||
position_markers(positions, request, assignment)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
|
@ -711,14 +787,23 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
|
||||
defp assign_positions(socket, positions) do
|
||||
markers =
|
||||
request_markers(socket.assigns.current_scope, socket.assigns.request) ++
|
||||
position_markers(positions)
|
||||
request_markers(socket.assigns.request, socket.assigns.request_coordinates) ++
|
||||
position_markers(positions, socket.assigns.request, socket.assigns.assignment)
|
||||
|
||||
socket
|
||||
|> assign(:positions, positions)
|
||||
|> assign(:markers, Jason.encode!(markers))
|
||||
end
|
||||
|
||||
defp refresh_request_coordinates(socket) do
|
||||
request_coordinates =
|
||||
Help.request_coordinates(socket.assigns.current_scope, socket.assigns.request)
|
||||
|
||||
socket
|
||||
|> assign(:request_coordinates, request_coordinates)
|
||||
|> assign_positions(socket.assigns.positions)
|
||||
end
|
||||
|
||||
defp assign_assignment_evidence(%{assigns: %{assignment: nil}} = socket, _evidence),
|
||||
do: socket
|
||||
|
||||
|
|
@ -775,8 +860,8 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
|
||||
defp localized(_labels, _locale), do: nil
|
||||
|
||||
defp request_markers(scope, request) do
|
||||
case Help.request_coordinates(scope, request) do
|
||||
defp request_markers(request, request_coordinates) do
|
||||
case request_coordinates do
|
||||
nil ->
|
||||
[]
|
||||
|
||||
|
|
@ -790,13 +875,14 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
end
|
||||
end
|
||||
|
||||
defp position_markers(positions) do
|
||||
Enum.map(positions, fn {_user_id, point} ->
|
||||
defp position_markers(positions, request, assignment) do
|
||||
Enum.map(positions, fn {user_id, point} ->
|
||||
%{
|
||||
latitude: point.latitude,
|
||||
longitude: point.longitude,
|
||||
exact: true,
|
||||
title: gettext("Shared location"),
|
||||
type: "live",
|
||||
title: live_location_title(user_id, request, assignment),
|
||||
location:
|
||||
gettext(
|
||||
"Last update: %{time}",
|
||||
|
|
@ -806,6 +892,14 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
end)
|
||||
end
|
||||
|
||||
defp live_location_title(user_id, request, assignment) do
|
||||
cond do
|
||||
user_id == request.requester_id -> gettext("Requester's live location")
|
||||
assignment && user_id == assignment.helper_id -> gettext("Helper's live location")
|
||||
true -> gettext("Shared live location")
|
||||
end
|
||||
end
|
||||
|
||||
defp message(:own_request), do: gettext("You cannot accept your own request.")
|
||||
defp message(:not_open), do: gettext("Another helper already accepted this request.")
|
||||
defp message(:invalid_code), do: gettext("That handover code is not correct.")
|
||||
|
|
@ -1154,6 +1248,7 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
</div>
|
||||
|
||||
<aside class="space-y-5">
|
||||
<div class="space-y-2">
|
||||
<div
|
||||
id="show-map"
|
||||
phx-hook="AidMap"
|
||||
|
|
@ -1165,6 +1260,38 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
|||
data-map-retry-label={gettext("Try map again")}
|
||||
class="aid-map"
|
||||
/>
|
||||
<div
|
||||
:if={
|
||||
@request_coordinates || map_size(@positions) > 0
|
||||
}
|
||||
class="flex flex-wrap gap-x-4 gap-y-1 px-1 text-xs text-base-content/65"
|
||||
aria-label={gettext("Map legend")}
|
||||
>
|
||||
<span
|
||||
:if={@request_coordinates}
|
||||
class="inline-flex items-center gap-1.5"
|
||||
>
|
||||
<span
|
||||
class={[
|
||||
"size-2.5 rounded-full",
|
||||
@request.location_visibility == :approximate_public && "bg-success",
|
||||
@request.location_visibility != :approximate_public && "bg-error"
|
||||
]}
|
||||
aria-hidden="true"
|
||||
>
|
||||
</span>
|
||||
<span>
|
||||
{if @request.location_visibility == :approximate_public,
|
||||
do: gettext("Request area"),
|
||||
else: gettext("Request point")}
|
||||
</span>
|
||||
</span>
|
||||
<span :if={map_size(@positions) > 0} class="inline-flex items-center gap-1.5">
|
||||
<span class="size-2.5 rounded-full bg-blue-600" aria-hidden="true"></span>
|
||||
<span>{gettext("Live shared location")}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-3xl bg-neutral p-6 text-neutral-content">
|
||||
<h2 class="text-lg font-bold">{gettext("Action center")}</h2>
|
||||
|
|
|
|||
|
|
@ -416,6 +416,13 @@ defmodule WhoNeedHelp.TrustSafetyTest do
|
|||
radius_meters: 500
|
||||
} = WhoNeedHelp.Help.HelpRequest.public_coordinates(request)
|
||||
|
||||
assert %{
|
||||
latitude: 50.4501,
|
||||
longitude: 30.5234,
|
||||
exact: false,
|
||||
radius_meters: 500
|
||||
} = Help.request_coordinates(context.requester_scope, request)
|
||||
|
||||
invalid_attrs = Map.put(context.attrs, "location_radius_meters", "5000")
|
||||
assert {:error, changeset} = Help.create_request(context.requester_scope, invalid_attrs)
|
||||
assert "is invalid" in errors_on(changeset).location_radius_meters
|
||||
|
|
|
|||
|
|
@ -31,10 +31,24 @@ defmodule WhoNeedHelpWeb.MutualAidLiveTest do
|
|||
idempotency_key: "live-notification:#{Ecto.UUID.generate()}"
|
||||
})
|
||||
|
||||
{:ok, push_device} =
|
||||
Notifications.register_device(scope, %{
|
||||
"platform" => "web",
|
||||
"provider" => "web_push",
|
||||
"token" => "https://push.example/subscriptions/#{Ecto.UUID.generate()}",
|
||||
"installation_id" => Ecto.UUID.generate(),
|
||||
"p256dh" => "test-public-key",
|
||||
"auth_secret" => "test-auth-secret",
|
||||
"device_label" => "Test browser"
|
||||
})
|
||||
|
||||
{:ok, view, html} = live(conn, ~p"/notifications")
|
||||
assert html =~ "Notifications"
|
||||
assert html =~ "Support request updated"
|
||||
assert html =~ "1 unread"
|
||||
assert html =~ ~s(data-enable-label="Enable push on this device")
|
||||
assert html =~ ~s(data-enabled-label="Push enabled on this device")
|
||||
assert has_element?(view, "[data-disable-device='#{push_device.id}']")
|
||||
|
||||
view |> element("button[phx-click='mark-all-read']") |> render_click()
|
||||
assert render(view) =~ "0 unread"
|
||||
|
|
@ -704,6 +718,12 @@ defmodule WhoNeedHelpWeb.MutualAidLiveTest do
|
|||
|> element("button[phx-click='accept']")
|
||||
|> render_click()
|
||||
|
||||
assert render(helper_view) =~
|
||||
"You accepted this request. Use private chat to coordinate safely."
|
||||
|
||||
assert render(requester_view) =~
|
||||
"A volunteer accepted this request. Use private chat to coordinate safely."
|
||||
|
||||
assert render(requester_view) =~ "Private match chat"
|
||||
assert render(helper_view) =~ "Private match chat"
|
||||
assert has_element?(helper_view, "#message-form")
|
||||
|
|
@ -765,10 +785,15 @@ defmodule WhoNeedHelpWeb.MutualAidLiveTest do
|
|||
}}
|
||||
)
|
||||
|
||||
assert render(requester_view) =~ "50.452"
|
||||
assert render(requester_view) =~ "30.526"
|
||||
assert render(requester_view) =~ "helper movement supported"
|
||||
refute render(requester_view) =~ "no movement evidence"
|
||||
requester_html = render(requester_view)
|
||||
assert requester_html =~ "50.452"
|
||||
assert requester_html =~ "30.526"
|
||||
assert requester_html =~ "helper movement supported"
|
||||
assert requester_html =~ "Live shared location"
|
||||
refute requester_html =~ "no movement evidence"
|
||||
|
||||
assert has_element?(requester_view, "#show-map[data-markers*='live']")
|
||||
assert has_element?(requester_view, "#show-map[data-markers*='Helper']")
|
||||
|
||||
send(requester_view.pid, {:tracking_stopped, helper.id})
|
||||
|
||||
|
|
@ -1069,11 +1094,18 @@ defmodule WhoNeedHelpWeb.MutualAidLiveTest do
|
|||
code = Help.handover_code(request.id)
|
||||
pasted_code = String.slice(code, 0, 3) <> " " <> String.slice(code, 3, 3)
|
||||
|
||||
view
|
||||
|> form("#handover-form", handover: %{code: "000 000"})
|
||||
|> render_submit()
|
||||
|
||||
assert render(view) =~ "That handover code is not correct."
|
||||
|
||||
view
|
||||
|> form("#handover-form", handover: %{code: pasted_code})
|
||||
|> render_submit()
|
||||
|
||||
assert render(view) =~ "Handover code verified."
|
||||
refute render(view) =~ "That handover code is not correct."
|
||||
refute has_element?(view, "#handover-form")
|
||||
assert Help.get_request!(request.id).assignment.handover_verified_at
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user