Skip to content

Commit d20e90d

Browse files
committed
Add profile location
1 parent 8e54d0f commit d20e90d

File tree

9 files changed

+135
-10
lines changed

9 files changed

+135
-10
lines changed

app/assets/javascripts/user.js

+87-9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ $(document).ready(function () {
1010
var defaultHomeZoom = 12;
1111
var map, marker, deleted_lat, deleted_lon;
1212

13+
const locationInput = {
14+
dirty: true,
15+
request: null,
16+
countryName: "",
17+
deletedText: null
18+
};
19+
1320
if ($("#map").length) {
1421
map = L.map("map", {
1522
attributionControl: false,
@@ -73,6 +80,7 @@ $(document).ready(function () {
7380

7481
deleted_lat = null;
7582
deleted_lon = null;
83+
locationInput.deletedText = null;
7684
respondToHomeUpdate();
7785
}).on("moveend", function () {
7886
var lat = $("#home_lat").val().trim(),
@@ -93,9 +101,26 @@ $(document).ready(function () {
93101
$("#home_lat, #home_lon").on("input", function () {
94102
deleted_lat = null;
95103
deleted_lon = null;
104+
locationInput.deletedText = null;
96105
respondToHomeUpdate();
97106
});
98107

108+
$("#location_name").on("input", function () {
109+
locationInput.dirty = true;
110+
deleted_lat = null;
111+
deleted_lon = null;
112+
locationInput.deletedText = null;
113+
114+
updateLocationWarning();
115+
respondToHomeUpdate(false);
116+
});
117+
118+
$("#location_default_name").on("click", function () {
119+
$("#location_name").val(locationInput.countryName);
120+
$("#location_name_warning").addClass("d-none");
121+
locationInput.dirty = false;
122+
});
123+
99124
$("#home_show").click(function () {
100125
var lat = $("#home_lat").val(),
101126
lon = $("#home_lon").val();
@@ -104,24 +129,34 @@ $(document).ready(function () {
104129
});
105130

106131
$("#home_delete").click(function () {
107-
var lat = $("#home_lat").val(),
108-
lon = $("#home_lon").val();
132+
let lat = $("#home_lat").val(),
133+
lon = $("#home_lon").val(),
134+
locationName = $("#location_name").val();
109135

110-
$("#home_lat, #home_lon").val("");
136+
$("#location_name_warning").addClass("d-none");
137+
$("#home_lat, #home_lon, #location_name").val("");
111138
deleted_lat = lat;
112139
deleted_lon = lon;
113-
respondToHomeUpdate();
140+
locationInput.deletedText = locationName;
141+
142+
respondToHomeUpdate(false);
114143
$("#home_undelete").trigger("focus");
115144
});
116145

117146
$("#home_undelete").click(function () {
118147
$("#home_lat").val(deleted_lat);
119148
$("#home_lon").val(deleted_lon);
149+
$("#location_name").val(locationInput.deletedText);
120150
deleted_lat = null;
121151
deleted_lon = null;
122-
respondToHomeUpdate();
152+
locationInput.deletedText = null;
153+
154+
updateLocationWarning();
155+
respondToHomeUpdate(false);
123156
$("#home_delete").trigger("focus");
124157
});
158+
159+
updateHomeLocation();
125160
} else {
126161
$("[data-user]").each(function () {
127162
var user = $(this).data("user");
@@ -133,14 +168,18 @@ $(document).ready(function () {
133168
}
134169
}
135170

136-
function respondToHomeUpdate() {
137-
var lat = $("#home_lat").val().trim(),
171+
function respondToHomeUpdate(updateLocationName = true) {
172+
let lat = $("#home_lat").val().trim(),
138173
lon = $("#home_lon").val().trim(),
174+
locationName = $("#location_name").val().trim(),
139175
location;
140176

141177
try {
142178
if (lat && lon) {
143179
location = L.latLng(lat, lon);
180+
if (updateLocationName) {
181+
updateHomeLocation();
182+
}
144183
}
145184
$("#home_lat, #home_lon").removeClass("is-invalid");
146185
} catch (error) {
@@ -150,8 +189,11 @@ $(document).ready(function () {
150189

151190
$("#home_message").toggleClass("invisible", Boolean(location));
152191
$("#home_show").prop("hidden", !location);
153-
$("#home_delete").prop("hidden", !location);
154-
$("#home_undelete").prop("hidden", !(!location && deleted_lat && deleted_lon));
192+
$("#home_delete").prop("hidden", !location && !locationName);
193+
$("#home_undelete").prop("hidden", !(
194+
(!location || !locationName) &&
195+
((deleted_lat && deleted_lon) || locationInput.deletedText)
196+
));
155197
if (location) {
156198
marker.setLatLng([lat, lon]);
157199
marker.addTo(map);
@@ -178,6 +220,42 @@ $(document).ready(function () {
178220
}
179221
}
180222

223+
function updateHomeLocation() {
224+
const lat = $("#home_lat").val().trim();
225+
const lon = $("#home_lon").val().trim();
226+
if (!lat || !lon) {
227+
return;
228+
}
229+
230+
const geocodeUrl = `${OSM.NOMINATIM_URL}reverse?format=json&lat=${lat}&lon=${lon}`;
231+
232+
if (locationInput.request) locationInput.request.abort();
233+
locationInput.request = $.getJSON(geocodeUrl, function (data) {
234+
locationInput.request = null;
235+
236+
data.display_name = data.display_name || "";
237+
const displayName = data.display_name.split(",");
238+
const locationName = displayName[displayName.length - 1].trim();
239+
240+
locationInput.countryName = locationName;
241+
$("#location_default_name").text(locationName);
242+
if (locationInput.dirty) {
243+
updateLocationWarning();
244+
} else {
245+
$("#location_name").val(locationName);
246+
}
247+
});
248+
}
249+
250+
function updateLocationWarning() {
251+
const locationName = $("#location_name").val();
252+
if (!locationInput.dirty || locationName.includes(locationInput.countryName)) {
253+
$("#location_name_warning").addClass("d-none");
254+
} else {
255+
$("#location_name_warning").removeClass("d-none");
256+
}
257+
}
258+
181259
updateAuthUID();
182260

183261
$("select#user_auth_provider").on("change", updateAuthUID);

app/controllers/profiles_controller.rb

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def update
3131

3232
current_user.home_lat = params[:user][:home_lat]
3333
current_user.home_lon = params[:user][:home_lon]
34+
current_user.location_name = params[:user][:location_name]
3435

3536
if current_user.save
3637
flash[:notice] = t ".success"

app/models/user.rb

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# home_lat :float
1313
# home_lon :float
1414
# home_zoom :integer default(3)
15+
# location_name :string
1516
# pass_salt :string
1617
# email_valid :boolean default(FALSE), not null
1718
# new_email :string

app/views/profiles/edit.html.erb

+7
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@
5252
<button type="button" id="home_undelete" class="btn btn-outline-primary" hidden><%= t ".undelete" %></button>
5353
</div>
5454
</div>
55+
<div class="my-2">
56+
<%= f.text_field :location_name, :wrapper_class => "col-sm-4 d-flex flex-column pe-3", :class => "mt-auto", :id => "location_name" %>
57+
<div id="location_name_warning" class="row align-items-center d-none">
58+
<p class="m-0 w-auto fs-6 pe-1"><%= t ".location_name_warning" %></p>
59+
<button id="location_default_name" class="btn btn-link p-0 w-auto text-sm-start" type="button"></button>
60+
</div>
61+
</div>
5562
<div class="form-check">
5663
<input class="form-check-input" type="checkbox" name="updatehome" value="1" <% unless current_user.home_location? %> checked <% end %> id="updatehome" />
5764
<label class="form-check-label" for="updatehome"><%= t ".update home location on click" %></label>

app/views/users/show.html.erb

+8
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,14 @@
139139
<div class='text-body-secondary'>
140140
<small>
141141
<dl class="list-inline">
142+
<% if @user.location_name && @user.location_name.strip.present? %>
143+
<dt class="list-inline-item m-0">
144+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-geo-alt-fill" viewBox="0 0 16 16">
145+
<path d="M8 16s6-5.686 6-10A6 6 0 0 0 2 6c0 4.314 6 10 6 10m0-7a3 3 0 1 1 0-6 3 3 0 0 1 0 6" />
146+
</svg>
147+
</dt>
148+
<dd class="list-inline-item"><%= @user.location_name %></dd>
149+
<% end %>
142150
<dt class="list-inline-item m-0"><%= t ".mapper since" %></dt>
143151
<dd class="list-inline-item"><%= l @user.created_at.to_date, :format => :long %></dd>
144152
<dt class="list-inline-item m-0"><%= t ".last map edit" %></dt>

config/locales/en.yml

+1
Original file line numberDiff line numberDiff line change
@@ -1839,6 +1839,7 @@ en:
18391839
show: "Show"
18401840
delete: "Delete"
18411841
undelete: "Undo delete"
1842+
location_name_warning: "Location name doesn't match home location"
18421843
update:
18431844
success: Profile updated.
18441845
failure: Couldn't update profile.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class AddUserLocationName < ActiveRecord::Migration[7.2]
2+
def change
3+
add_column :users, :location_name, :string
4+
end
5+
end

db/structure.sql

+3-1
Original file line numberDiff line numberDiff line change
@@ -1499,7 +1499,8 @@ CREATE TABLE public.users (
14991499
tou_agreed timestamp without time zone,
15001500
diary_comments_count integer DEFAULT 0,
15011501
note_comments_count integer DEFAULT 0,
1502-
creation_address inet
1502+
creation_address inet,
1503+
location_name character varying
15031504
);
15041505

15051506

@@ -3356,6 +3357,7 @@ INSERT INTO "schema_migrations" (version) VALUES
33563357
('23'),
33573358
('22'),
33583359
('21'),
3360+
('20241030090336'),
33593361
('20240913171951'),
33603362
('20240912181413'),
33613363
('20240910175616'),
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
require "application_system_test_case"
2+
3+
class UserLocationChangeTest < ApplicationSystemTestCase
4+
def setup
5+
stub_request(:get, /.*gravatar.com.*d=404/).to_return(:status => 404)
6+
end
7+
8+
test "User can change their location" do
9+
user = create(:user)
10+
sign_in_as(user)
11+
12+
visit user_path(user.display_name)
13+
assert_no_selector ".bi.bi-geo-alt-fill"
14+
15+
visit edit_profile_path
16+
fill_in "Location name", :with => "Test Location"
17+
click_on "Update Profile"
18+
19+
visit user_path(user)
20+
assert_text "Test Location"
21+
end
22+
end

0 commit comments

Comments
 (0)