diff --git a/app/controllers/admin/photo_spots_controller.rb b/app/controllers/admin/photo_spots_controller.rb index d7539a3..b252b96 100644 --- a/app/controllers/admin/photo_spots_controller.rb +++ b/app/controllers/admin/photo_spots_controller.rb @@ -71,8 +71,7 @@ def set_photo_spot end def photo_spot_params - - params.require(:photo_spot).permit(:name, :address, :detail, :parking_flag, :tags, images: []) - + params.require(:photo_spot).permit(:name, :address, :detail, :parking_flag, :tags, { images: [] }, + :latitude, :longitude, :timestart, :timeend) end end diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index 5e9e8b1..02dacd4 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -3,53 +3,101 @@ import L from "leaflet" // Connects to data-controller="map" export default class extends Controller { - static targets = ["container"] - static values = { onsens: Array } + // ターゲット名を変更しました + static targets = ["container", "latitudeInput", "longitudeInput"] + static values = { photo_spots: Array } connect() { - this.onsens = this._parseOnsensData(); - console.log(this.onsens); + this.currentMarker = null; + this.photo_spots = this._parsePhotoSpotsData(); + // 地図の初期化 this.map = L.map(this.containerTarget).setView([35.468, 133.0483], 11.5); - L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap' }).addTo(this.map); - const onsenIcon = L.icon({ - iconUrl: '/onsen.svg', + // 既存のスポットのマーカーを設置 + const photo_spotIcon = L.icon({ + iconUrl: '/photo_spot.svg', iconSize: [32, 32], iconAnchor: [16, 32], }); - - this.onsens.forEach(onsen => { - L.marker([onsen.geo_lat, onsen.geo_lng], { icon: onsenIcon }) + this.photo_spots.forEach(photo_spot => { + // プロパティ名を変更しました + L.marker([photo_spot.latitude, photo_spot.longitude], { icon: photo_spotIcon }) .addTo(this.map) - .bindPopup(onsen.name); + .bindPopup(photo_spot.name); }); + + // フォームに初期値があればピンを立てる + if (this.latitudeInputTarget.value && this.longitudeInputTarget.value) { + this.updateMarker(this.latitudeInputTarget.value, this.longitudeInputTarget.value); + } + + // マップクリック時のイベントリスナー + this.map.on("click", (e) => { + const { lat, lng } = e.latlng; + this.updateMarker(lat, lng); + // テキストボックスの値を更新 + this.latitudeInputTarget.value = lat.toFixed(5); + this.longitudeInputTarget.value = lng.toFixed(5); + }); + } + + // マーカーを更新し、マップの中心を移動する + updateMarker(lat, lng) { + if (this.currentMarker) { + this.map.removeLayer(this.currentMarker); + } + const latlng = [lat, lng]; + this.currentMarker = L.marker(latlng).addTo(this.map); + this.map.setView(latlng, this.map.getZoom()); + } + + // フォームの入力値からマーカーを更新する + updateMarkerFromInput() { + const lat = parseFloat(this.latitudeInputTarget.value); + const lng = parseFloat(this.longitudeInputTarget.value); + + if (!isNaN(lat) && !isNaN(lng)) { + this.updateMarker(lat, lng); + } } - disconnect() { - if (this.map) { - this.map.remove(); - this.map = null; + // 現在地を取得するメソッドを追加 + locate() { + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition( + (position) => { + const lat = position.coords.latitude; + const lng = position.coords.longitude; + this.updateMarker(lat, lng); + this.latitudeInputTarget.value = lat.toFixed(5); + this.longitudeInputTarget.value = lng.toFixed(5); + }, + (error) => { + console.error("現在地の取得に失敗しました: ", error); + alert("現在地の取得に失敗しました。ブラウザの設定をご確認ください。"); + } + ); + } else { + alert("お使いのブラウザは現在地の取得に対応していません。"); } } // === プライベートメソッド(内部処理用) === - /** - * HTML要素から温泉データを取得・パース - * @returns {Array} 温泉データの配列 - */ - _parseOnsensData() { + _parsePhotoSpotsData() { try { - const rawData = this.element.dataset.mapOnsens || "[]"; + const rawData = this.element.dataset.mapPhotoSpots || "[]"; + // パース後のデータが{id:..., name:..., geo_lat:..., geo_lng:...}のような構造であれば + // 必要に応じてキーをリマップする必要があります return JSON.parse(rawData); } catch (error) { - console.warn("温泉データのパースに失敗:", error); + console.warn("写真スポットデータのパースに失敗:", error); return []; } } -} +} \ No newline at end of file diff --git a/app/views/admin/photo_spots/_form.html.erb b/app/views/admin/photo_spots/_form.html.erb index 42275c6..519913e 100644 --- a/app/views/admin/photo_spots/_form.html.erb +++ b/app/views/admin/photo_spots/_form.html.erb @@ -1,4 +1,4 @@ -<%= form_with(model: [:admin, photo_spot || @photo_spot], html: { multipart: true, class: "space-y-6" }) do |form| %> +<%= form_with(model: [:admin, photo_spot || @photo_spot], html: { multipart: true, class: "space-y-6", data: { controller: "map" } }) do |form| %> <% if photo_spot.errors.any? %>

<%= pluralize(photo_spot.errors.count, "件のエラー") %>があります:

@@ -19,6 +19,30 @@ <%= form.text_field :address, class: "block shadow-sm rounded-md border px-3 py-2 w-full border-gray-300 focus:outline-blue-600" %>
+ <%# 緯度・経度の入力フィールド %> +
+
+ <%= form.label :latitude, '緯度', class: 'block font-semibold mb-1' %> + <%= form.text_field :latitude, + data: { map_target: 'latitudeInput', action: 'input->map#updateMarkerFromInput' }, + class: "block shadow-sm rounded-md border px-3 py-2 w-full border-gray-300 focus:outline-blue-600" %> +
+
+ <%= form.label :longitude, '経度', class: 'block font-semibold mb-1' %> + <%= form.text_field :longitude, + data: { map_target: 'longitudeInput', action: 'input->map#updateMarkerFromInput' }, + class: "block shadow-sm rounded-md border px-3 py-2 w-full border-gray-300 focus:outline-blue-600" %> +
+
+ <%# 地図エリア(デスクトップ時) %> +
+
+ +
<%= form.label :detail, '説明', class: 'block font-semibold mb-1' %> <%= form.text_area :detail, rows: 4, class: "block shadow-sm rounded-md border px-3 py-2 w-full border-gray-300 focus:outline-blue-600" %> @@ -50,4 +74,4 @@
<%= form.submit class: "rounded-md px-4 py-2 bg-blue-600 hover:bg-blue-500 text-white font-semibold w-full sm:w-auto" %>
-<% end %> +<% end %> \ No newline at end of file diff --git a/app/views/photo_spots/_map.html.erb b/app/views/photo_spots/_map.html.erb new file mode 100644 index 0000000..ecaefd3 --- /dev/null +++ b/app/views/photo_spots/_map.html.erb @@ -0,0 +1,9 @@ +<%# 地図エリア(左側・デスクトップ時) %> +
+
+ +
\ No newline at end of file diff --git a/app/views/photo_spots/index.html.erb b/app/views/photo_spots/index.html.erb index ff9c3f3..e8ed65a 100644 --- a/app/views/photo_spots/index.html.erb +++ b/app/views/photo_spots/index.html.erb @@ -7,7 +7,6 @@ <%= render 'search_form' %> <%# メインコンテンツ:地図 + フォトスポット一覧 %>
- <%# 地図エリア(左側・デスクトップ時) %>
diff --git a/db/schema.rb b/db/schema.rb index 6e3f14f..a01d909 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -77,6 +77,11 @@ t.index ["photo_spot_id"], name: "index_reviews_on_photo_spot_id" end + create_table "users", force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" add_foreign_key "reviews", "photo_spots"