mirror of
https://github.com/Freika/dawarich.git
synced 2025-12-17 18:54:39 -06:00
Extract tag serializer to its own file
This commit is contained in:
@@ -1,171 +0,0 @@
|
||||
# Layer Control Upgrade - Leaflet.Control.Layers.Tree
|
||||
|
||||
## Summary
|
||||
|
||||
Successfully installed and integrated the `Leaflet.Control.Layers.Tree` plugin to replace the standard Leaflet layer control with a hierarchical tree-based control that better organizes map layers and styles.
|
||||
|
||||
## Changes Made
|
||||
|
||||
### 1. Installation
|
||||
|
||||
- **Plugin**: Installed `leaflet.control.layers.tree` via importmap
|
||||
- **CSS**: Added plugin CSS file at `app/assets/stylesheets/leaflet.control.layers.tree.css`
|
||||
|
||||
### 2. Maps Controller Updates
|
||||
|
||||
#### File: `app/javascript/controllers/maps_controller.js`
|
||||
|
||||
**Import Changes:**
|
||||
- Added import for `leaflet.control.layers.tree`
|
||||
- Removed import for `createPlacesControl` (now integrated into tree control)
|
||||
|
||||
**Initialization Changes:**
|
||||
- Removed standalone Places control initialization
|
||||
- Added `this.userTags` property to store user tags for places filtering
|
||||
- Updated layer control initialization to use `createTreeLayerControl()`
|
||||
|
||||
**New Methods:**
|
||||
|
||||
1. **`createTreeLayerControl(additionalLayers = {})`**
|
||||
- Creates a hierarchical tree structure for map layers
|
||||
- Organizes layers into two main groups:
|
||||
- **Map Styles**: All available base map layers
|
||||
- **Layers**: All overlay layers with nested groups
|
||||
- Supports dynamic additional layers (e.g., Family Members)
|
||||
|
||||
Structure:
|
||||
```
|
||||
+ Map Styles
|
||||
- OpenStreetMap
|
||||
- OpenStreetMap.HOT
|
||||
- ...
|
||||
+ Layers
|
||||
- Points
|
||||
- Routes
|
||||
- Tracks
|
||||
- Heatmap
|
||||
- Fog of War
|
||||
- Scratch map
|
||||
- Areas
|
||||
- Photos
|
||||
+ Visits
|
||||
- Suggested
|
||||
- Confirmed
|
||||
+ Places
|
||||
- All
|
||||
- Untagged
|
||||
- (each tag with icon)
|
||||
```
|
||||
|
||||
**Updated Methods:**
|
||||
- **`updateLayerControl()`**: Simplified to just recreate the tree control with additional layers
|
||||
- Updated all layer control recreations throughout the file to use `createTreeLayerControl()`
|
||||
|
||||
### 3. Places Manager Updates
|
||||
|
||||
#### File: `app/javascript/maps/places.js`
|
||||
|
||||
**New Methods:**
|
||||
|
||||
1. **`createFilteredLayer(tagIds)`**
|
||||
- Creates a layer group for filtered places
|
||||
- Returns a layer that loads places when added to the map
|
||||
- Supports tag-based and untagged filtering
|
||||
|
||||
2. **`loadPlacesIntoLayer(layer, tagIds)`**
|
||||
- Loads places into a specific layer with tag filtering
|
||||
- Handles API calls with tag_ids or untagged parameters
|
||||
- Creates markers using existing `createPlaceMarker()` method
|
||||
|
||||
## Features
|
||||
|
||||
### Hierarchical Organization
|
||||
- Map styles and layers are now clearly separated
|
||||
- Related layers are grouped together (Visits, Places)
|
||||
- Easy to expand/collapse sections
|
||||
|
||||
### Places Layer Integration
|
||||
- No longer needs a separate control
|
||||
- All places filters are now in the tree control
|
||||
- Each tag gets its own layer in the tree
|
||||
- Places group has "All", "Untagged", and individual tag layers regardless of tags
|
||||
- "Untagged" shows only places without tags
|
||||
|
||||
### Dynamic Layer Support
|
||||
- Family Members layer can be added dynamically
|
||||
- Additional layers can be easily integrated
|
||||
- Maintains compatibility with existing layer management
|
||||
|
||||
### Improved User Experience
|
||||
- Cleaner UI with collapsible sections
|
||||
- Better organization of many layers
|
||||
- Consistent interface for all layer types
|
||||
- Select All checkbox for grouped layers (Visits, Places)
|
||||
|
||||
## API Changes
|
||||
|
||||
### Places API
|
||||
The Places API now supports an `untagged` parameter:
|
||||
- `GET /api/v1/places?untagged=true` - Returns only untagged places
|
||||
- `GET /api/v1/places?tag_ids=1,2,3` - Returns places with specified tags
|
||||
|
||||
## Testing Recommendations
|
||||
|
||||
1. **Basic Functionality**
|
||||
- Verify all map styles load correctly
|
||||
- Test all overlay layers (Points, Routes, Tracks, etc.)
|
||||
- Confirm layer visibility persists correctly
|
||||
|
||||
2. **Places Integration**
|
||||
- Test "All" layer shows all places
|
||||
- Verify "Untagged" layer shows only untagged places
|
||||
- Test individual tag layers show correct places
|
||||
- Confirm places load when layer is enabled
|
||||
|
||||
3. **Visits Integration**
|
||||
- Test Suggested and Confirmed visits layers
|
||||
- Verify visits load correctly when enabled
|
||||
|
||||
4. **Family Members**
|
||||
- Test Family Members layer appears when family is available
|
||||
- Verify layer updates when family locations change
|
||||
|
||||
5. **Layer State Persistence**
|
||||
- Verify enabled layers are saved to user settings
|
||||
- Confirm layer state is restored on page load
|
||||
|
||||
## Migration Notes
|
||||
|
||||
### Removed Components
|
||||
- Standalone Places control button (📍)
|
||||
- `createPlacesControl` function no longer used in maps_controller
|
||||
|
||||
### Behavioral Changes
|
||||
- Places layer is no longer managed by a separate control
|
||||
- All places filtering is now done through the layer control
|
||||
- Places markers are created on-demand when layer is enabled
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
1. **Layer Icons**: Add custom icons for each layer type
|
||||
2. **Layer Counts**: Show number of items in each layer
|
||||
3. **Custom Styling**: Theme the tree control to match app theme
|
||||
4. **Layer Search**: Add search functionality for finding layers
|
||||
5. **Layer Presets**: Allow saving custom layer combinations
|
||||
|
||||
## Files Modified
|
||||
|
||||
1. `app/javascript/controllers/maps_controller.js` - Main map controller
|
||||
2. `app/javascript/maps/places.js` - Places manager with new filtering methods
|
||||
3. `config/importmap.rb` - Added tree control import (via bin/importmap)
|
||||
4. `app/assets/stylesheets/leaflet.control.layers.tree.css` - Plugin CSS
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
If needed, to rollback:
|
||||
1. Remove `import "leaflet.control.layers.tree"` from maps_controller.js
|
||||
2. Restore `import { createPlacesControl }` from places_control
|
||||
3. Revert `createTreeLayerControl()` to `L.control.layers()`
|
||||
4. Restore Places control initialization
|
||||
5. Remove `leaflet.control.layers.tree` from importmap
|
||||
6. Remove CSS file
|
||||
@@ -1,141 +0,0 @@
|
||||
# Places Integration Checklist
|
||||
|
||||
## Files Modified:
|
||||
- ✅ `app/javascript/controllers/stat_page_controller.js` - Added PlacesManager integration
|
||||
- ✅ `app/javascript/maps/places.js` - Fixed API authentication headers
|
||||
- ✅ `app/views/stats/_month.html.erb` - Added Places button and tag filters
|
||||
- ✅ `app/views/shared/_place_creation_modal.html.erb` - Already exists
|
||||
|
||||
## What Should Appear:
|
||||
|
||||
### On Monthly Stats Page (`/stats/YYYY/MM`):
|
||||
|
||||
1. **Map Controls** (top right of map):
|
||||
- [ ] "Heatmap" button
|
||||
- [ ] "Points" button
|
||||
- [ ] **"Places" button** ← NEW!
|
||||
|
||||
2. **Below the Map**:
|
||||
- [ ] **"Filter Places by Tags"** section ← NEW!
|
||||
- [ ] Checkboxes for each tag you've created
|
||||
- [ ] Each checkbox shows: icon + name + color dot
|
||||
|
||||
## Troubleshooting Steps:
|
||||
|
||||
### Step 1: Restart Server
|
||||
```bash
|
||||
# Stop server (Ctrl+C)
|
||||
bundle exec rails server
|
||||
|
||||
# Or with Docker:
|
||||
docker-compose restart web
|
||||
```
|
||||
|
||||
### Step 2: Hard Refresh Browser
|
||||
- Mac: `Cmd + Shift + R`
|
||||
- Windows/Linux: `Ctrl + Shift + R`
|
||||
|
||||
### Step 3: Check Browser Console
|
||||
1. Open Developer Tools (F12)
|
||||
2. Go to Console tab
|
||||
3. Look for errors (red text)
|
||||
4. You should see: "StatPage controller connected"
|
||||
|
||||
### Step 4: Verify URL
|
||||
Make sure you're on a monthly stats page:
|
||||
- ✅ `/stats/2024/11` ← Correct
|
||||
- ❌ `/stats` ← Wrong (main stats index)
|
||||
- ❌ `/stats/2024` ← Wrong (yearly stats)
|
||||
|
||||
### Step 5: Check JavaScript Loading
|
||||
In browser console, type:
|
||||
```javascript
|
||||
console.log(document.querySelector('[data-controller="stat-page"]'))
|
||||
```
|
||||
Should show the element, not null.
|
||||
|
||||
### Step 6: Verify Controller Registration
|
||||
In browser console:
|
||||
```javascript
|
||||
console.log(application.controllers)
|
||||
```
|
||||
Should include "stat-page" in the list.
|
||||
|
||||
## Expected Behavior:
|
||||
|
||||
### When You Click "Places" Button:
|
||||
1. Places layer toggles on/off
|
||||
2. Button highlights when active
|
||||
3. Map shows custom markers with tag icons
|
||||
|
||||
### When You Check Tag Filters:
|
||||
1. Map updates immediately
|
||||
2. Shows only places with selected tags
|
||||
3. Unchecking all shows all places
|
||||
|
||||
## If Nothing Shows:
|
||||
|
||||
### Check if you have any places created:
|
||||
```bash
|
||||
bundle exec rails console
|
||||
|
||||
# In console:
|
||||
user = User.find_by(email: 'your@email.com')
|
||||
user.places.count # Should be > 0
|
||||
user.tags.count # Should be > 0
|
||||
```
|
||||
|
||||
### Create test data:
|
||||
```bash
|
||||
bundle exec rails console
|
||||
|
||||
user = User.first
|
||||
tag = user.tags.create!(name: "Test", icon: "📍", color: "#FF5733")
|
||||
|
||||
# Create via API or console:
|
||||
place = user.places.create!(
|
||||
name: "Test Place",
|
||||
latitude: 40.7128,
|
||||
longitude: -74.0060,
|
||||
source: :manual
|
||||
)
|
||||
place.tags << tag
|
||||
```
|
||||
|
||||
## Verification Script:
|
||||
|
||||
Run this in Rails console to verify everything:
|
||||
|
||||
```ruby
|
||||
user = User.first
|
||||
puts "Tags: #{user.tags.count}"
|
||||
puts "Places: #{user.places.count}"
|
||||
puts "Places with tags: #{user.places.joins(:tags).distinct.count}"
|
||||
|
||||
if user.tags.any?
|
||||
puts "\nYour tags:"
|
||||
user.tags.each do |tag|
|
||||
puts " #{tag.icon} #{tag.name} (#{tag.places.count} places)"
|
||||
end
|
||||
end
|
||||
|
||||
if user.places.any?
|
||||
puts "\nYour places:"
|
||||
user.places.limit(5).each do |place|
|
||||
puts " #{place.name} at (#{place.latitude}, #{place.longitude})"
|
||||
puts " Tags: #{place.tags.map(&:name).join(', ')}"
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Still Having Issues?
|
||||
|
||||
Check these files exist and have the right content:
|
||||
- `app/javascript/maps/places.js` - Should export PlacesManager class
|
||||
- `app/javascript/controllers/stat_page_controller.js` - Should import PlacesManager
|
||||
- `app/views/stats/_month.html.erb` - Should have Places button at line ~73
|
||||
|
||||
Look for JavaScript errors in browser console that might indicate:
|
||||
- Import/export issues
|
||||
- Syntax errors
|
||||
- Missing dependencies
|
||||
@@ -1,194 +0,0 @@
|
||||
# Layer Control Upgrade - Testing Checklist
|
||||
|
||||
## Pre-Testing Setup
|
||||
|
||||
1. **Start the development server**
|
||||
```bash
|
||||
bin/dev
|
||||
```
|
||||
|
||||
2. **Clear browser cache** to ensure new JavaScript and CSS are loaded
|
||||
|
||||
3. **Log in** to the application with demo credentials or your account
|
||||
|
||||
4. **Navigate to the Map page** (`/map`)
|
||||
|
||||
## Visual Verification
|
||||
|
||||
- [ ] Layer control appears in the top-right corner
|
||||
- [ ] Layer control shows a hierarchical tree structure (not flat list)
|
||||
- [ ] Control has two main sections: "Map Styles" and "Layers"
|
||||
- [ ] Sections can be expanded/collapsed
|
||||
- [ ] No standalone Places control button (📍) is visible
|
||||
|
||||
## Map Styles Testing
|
||||
|
||||
- [ ] Expand "Map Styles" section
|
||||
- [ ] All map styles are listed (OpenStreetMap, OpenStreetMap.HOT, etc.)
|
||||
- [ ] Selecting a different style changes the base map
|
||||
- [ ] Only one map style can be selected at a time
|
||||
- [ ] Selected style is indicated with a radio button
|
||||
|
||||
## Layers Testing
|
||||
|
||||
### Basic Layers
|
||||
- [ ] Expand "Layers" section
|
||||
- [ ] All basic layers are present:
|
||||
- [ ] Points
|
||||
- [ ] Routes
|
||||
- [ ] Tracks
|
||||
- [ ] Heatmap
|
||||
- [ ] Fog of War
|
||||
- [ ] Scratch map
|
||||
- [ ] Areas
|
||||
- [ ] Photos
|
||||
|
||||
- [ ] Toggle each layer on/off
|
||||
- [ ] Verify each layer displays correctly when enabled
|
||||
- [ ] Multiple layers can be enabled simultaneously
|
||||
|
||||
### Visits Group
|
||||
- [ ] Expand "Visits" section
|
||||
- [ ] Two sub-layers are present:
|
||||
- [ ] Suggested
|
||||
- [ ] Confirmed
|
||||
- [ ] Enable "Suggested" - suggested visits appear on map
|
||||
- [ ] Enable "Confirmed" - confirmed visits appear on map
|
||||
- [ ] Disable both - no visits visible on map
|
||||
- [ ] Select All checkbox works for Visits group
|
||||
|
||||
### Places Group
|
||||
- [ ] Expand "Places" section
|
||||
- [ ] At least these options are present:
|
||||
- [ ] Places (top-level checkbox)
|
||||
- [ ] Untagged
|
||||
- [ ] (Individual tags if any exist)
|
||||
|
||||
**Testing "Places (top-level checkbox)":**
|
||||
- [ ] Enable "Places (top-level checkbox)"
|
||||
- [ ] All places appear on map regardless of tags
|
||||
- [ ] Place markers are clickable
|
||||
- [ ] Place popups show correct information
|
||||
|
||||
**Testing "Untagged":**
|
||||
- [ ] Enable "Untagged" (disable "Places (top-level checkbox)" first)
|
||||
- [ ] Only places without tags appear
|
||||
- [ ] Verify by checking places that have tags don't appear
|
||||
|
||||
**Testing Individual Tags:**
|
||||
(If you have tags created)
|
||||
- [ ] Each tag appears as a separate layer
|
||||
- [ ] Tag icon is displayed before tag name
|
||||
- [ ] Enable a tag layer
|
||||
- [ ] Only places with that tag appear
|
||||
- [ ] Multiple tag layers can be enabled simultaneously
|
||||
- [ ] Select All checkbox works for Places group
|
||||
|
||||
### Family Members (if applicable)
|
||||
- [ ] If in a family, "Family Members" layer appears
|
||||
- [ ] Enable Family Members layer
|
||||
- [ ] Family member locations appear on map
|
||||
- [ ] Family member markers are distinguishable from own markers
|
||||
|
||||
## Functional Testing
|
||||
|
||||
### Layer Persistence
|
||||
- [ ] Enable several layers (e.g., Points, Routes, Suggested Visits, Places (top-level checkbox))
|
||||
- [ ] Refresh the page
|
||||
- [ ] Verify enabled layers remain enabled after refresh
|
||||
- [ ] Verify disabled layers remain disabled after refresh
|
||||
|
||||
### Places API Integration
|
||||
- [ ] Open browser console (F12)
|
||||
- [ ] Enable "Network" tab
|
||||
- [ ] Enable "Untagged" places layer
|
||||
- [ ] Verify API call: `GET /api/v1/places?api_key=...&untagged=true`
|
||||
- [ ] Enable a tag layer
|
||||
- [ ] Verify API call: `GET /api/v1/places?api_key=...&tag_ids=<tag_id>`
|
||||
- [ ] Verify no JavaScript errors in console
|
||||
|
||||
### Layer Interaction
|
||||
- [ ] Enable Routes layer
|
||||
- [ ] Click on a route segment
|
||||
- [ ] Verify route details popup appears
|
||||
- [ ] Enable Places "Places (top-level checkbox)" layer
|
||||
- [ ] Click on a place marker
|
||||
- [ ] Verify place details popup appears
|
||||
- [ ] Verify layers don't interfere with each other
|
||||
|
||||
### Performance
|
||||
- [ ] Enable all layers simultaneously
|
||||
- [ ] Map remains responsive
|
||||
- [ ] No significant lag when toggling layers
|
||||
- [ ] No memory leaks (check browser dev tools)
|
||||
|
||||
## Edge Cases
|
||||
|
||||
### No Tags Scenario
|
||||
- [ ] If no tags exist, Places section should show:
|
||||
- [ ] Places (top-level checkbox)
|
||||
- [ ] Untagged
|
||||
- [ ] No error in console
|
||||
|
||||
### No Places Scenario
|
||||
- [ ] Disable all place layers
|
||||
- [ ] Enable "Untagged"
|
||||
- [ ] Verify appropriate message or empty state
|
||||
- [ ] No errors in console
|
||||
|
||||
### No Family Scenario
|
||||
- [ ] If not in a family, "Family Members" layer shouldn't appear
|
||||
- [ ] No errors in console
|
||||
|
||||
## Regression Testing
|
||||
|
||||
### Existing Functionality
|
||||
- [ ] Routes/Tracks selector still works (if visible with `tracks_debug=true`)
|
||||
- [ ] Settings panel still works
|
||||
- [ ] Calendar panel still works
|
||||
- [ ] Visit selection tool still works
|
||||
- [ ] Add visit button still works
|
||||
|
||||
### Other Controllers
|
||||
- [ ] Family members controller still works (if applicable)
|
||||
- [ ] Photo markers still load correctly
|
||||
- [ ] Area drawing still works
|
||||
- [ ] Fog of war updates correctly
|
||||
|
||||
## Mobile Testing (if applicable)
|
||||
|
||||
- [ ] Layer control is accessible on mobile
|
||||
- [ ] Tree structure expands/collapses on tap
|
||||
- [ ] Layers can be toggled on mobile
|
||||
- [ ] No layout issues on small screens
|
||||
|
||||
## Error Scenarios
|
||||
|
||||
- [ ] Disconnect internet, try to load a layer that requires API call
|
||||
- [ ] Verify appropriate error handling
|
||||
- [ ] Verify user gets feedback about the failure
|
||||
- [ ] Verify app doesn't crash
|
||||
|
||||
## Console Checks
|
||||
|
||||
Throughout all testing, monitor the browser console for:
|
||||
- [ ] No JavaScript errors
|
||||
- [ ] No unexpected warnings
|
||||
- [ ] No failed API requests (except during error scenario testing)
|
||||
- [ ] Appropriate log messages for debugging
|
||||
|
||||
## Sign-off
|
||||
|
||||
- [ ] All critical tests pass
|
||||
- [ ] Any failures are documented
|
||||
- [ ] Ready for production deployment
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
Record any issues, unexpected behavior, or suggestions for improvement:
|
||||
|
||||
```
|
||||
[Your notes here]
|
||||
```
|
||||
@@ -6,23 +6,7 @@ module Api
|
||||
def privacy_zones
|
||||
zones = current_api_user.tags.privacy_zones.includes(:places)
|
||||
|
||||
render json: zones.map { |tag|
|
||||
{
|
||||
tag_id: tag.id,
|
||||
tag_name: tag.name,
|
||||
tag_icon: tag.icon,
|
||||
tag_color: tag.color,
|
||||
radius_meters: tag.privacy_radius_meters,
|
||||
places: tag.places.map { |place|
|
||||
{
|
||||
id: place.id,
|
||||
name: place.name,
|
||||
latitude: place.latitude,
|
||||
longitude: place.longitude
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
render json: zones.map { |tag| TagSerializer.new(tag).call }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
33
app/serializers/tag_serializer.rb
Normal file
33
app/serializers/tag_serializer.rb
Normal file
@@ -0,0 +1,33 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class TagSerializer
|
||||
def initialize(tag)
|
||||
@tag = tag
|
||||
end
|
||||
|
||||
def call
|
||||
{
|
||||
tag_id: tag.id,
|
||||
tag_name: tag.name,
|
||||
tag_icon: tag.icon,
|
||||
tag_color: tag.color,
|
||||
radius_meters: tag.privacy_radius_meters,
|
||||
places: places
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :tag
|
||||
|
||||
def places
|
||||
tag.places.map do |place|
|
||||
{
|
||||
id: place.id,
|
||||
name: place.name,
|
||||
latitude: place.latitude.to_f,
|
||||
longitude: place.longitude.to_f
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,6 @@
|
||||
class AddUserIdToPlaces < ActiveRecord::Migration[8.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
# Add nullable for backward compatibility, will enforce later via data migration
|
||||
add_reference :places, :user, null: true, index: {algorithm: :concurrently} unless foreign_key_exists?(:places, :users)
|
||||
|
||||
@@ -14,6 +14,8 @@ RSpec.describe User, type: :model do
|
||||
it { is_expected.to have_many(:places).through(:visits) }
|
||||
it { is_expected.to have_many(:trips).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:tracks).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:tags).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:visited_places).through(:visits) }
|
||||
end
|
||||
|
||||
describe 'enums' do
|
||||
|
||||
52
spec/requests/api/v1/tags_spec.rb
Normal file
52
spec/requests/api/v1/tags_spec.rb
Normal file
@@ -0,0 +1,52 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Api::V1::Tags', type: :request do
|
||||
let(:user) { create(:user) }
|
||||
let(:tag) { create(:tag, user: user, name: 'Home', icon: '🏠', color: '#4CAF50', privacy_radius_meters: 500) }
|
||||
let!(:place) { create(:place, name: 'My Place', latitude: 10.0, longitude: 20.0) }
|
||||
|
||||
before do
|
||||
tag.places << place
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/tags/privacy_zones' do
|
||||
context 'when authenticated' do
|
||||
before do
|
||||
user.create_api_key unless user.api_key.present?
|
||||
get privacy_zones_api_v1_tags_path, params: { api_key: user.api_key }
|
||||
end
|
||||
|
||||
it 'returns success' do
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
it 'returns the correct JSON structure' do
|
||||
json_response = JSON.parse(response.body)
|
||||
expect(json_response).to be_an(Array)
|
||||
expect(json_response.first).to include(
|
||||
'tag_id' => tag.id,
|
||||
'tag_name' => 'Home',
|
||||
'tag_icon' => '🏠',
|
||||
'tag_color' => '#4CAF50',
|
||||
'radius_meters' => 500
|
||||
)
|
||||
expect(json_response.first['places']).to be_an(Array)
|
||||
expect(json_response.first['places'].first).to include(
|
||||
'id' => place.id,
|
||||
'name' => 'My Place',
|
||||
'latitude' => 10.0,
|
||||
'longitude' => 20.0
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when not authenticated' do
|
||||
it 'returns unauthorized' do
|
||||
get privacy_zones_api_v1_tags_path
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
32
spec/serializers/tag_serializer_spec.rb
Normal file
32
spec/serializers/tag_serializer_spec.rb
Normal file
@@ -0,0 +1,32 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe TagSerializer do
|
||||
let(:tag) { create(:tag, name: 'Home', icon: '🏠', color: '#4CAF50', privacy_radius_meters: 500) }
|
||||
let!(:place) { create(:place, name: 'My Place', latitude: 10.0, longitude: 20.0) }
|
||||
|
||||
before do
|
||||
tag.places << place
|
||||
end
|
||||
|
||||
subject { described_class.new(tag).call }
|
||||
|
||||
it 'returns the correct JSON structure' do
|
||||
expect(subject).to eq({
|
||||
tag_id: tag.id,
|
||||
tag_name: 'Home',
|
||||
tag_icon: '🏠',
|
||||
tag_color: '#4CAF50',
|
||||
radius_meters: 500,
|
||||
places: [
|
||||
{
|
||||
id: place.id,
|
||||
name: 'My Place',
|
||||
latitude: 10.0,
|
||||
longitude: 20.0
|
||||
}
|
||||
]
|
||||
})
|
||||
end
|
||||
end
|
||||
@@ -1,105 +0,0 @@
|
||||
# Run with: bundle exec rails runner verify_places_integration.rb
|
||||
|
||||
puts "🔍 Verifying Places Integration..."
|
||||
puts "=" * 50
|
||||
|
||||
# Check files exist
|
||||
files_to_check = [
|
||||
'app/javascript/maps/places.js',
|
||||
'app/javascript/controllers/stat_page_controller.js',
|
||||
'app/javascript/controllers/place_creation_controller.js',
|
||||
'app/views/stats/_month.html.erb',
|
||||
'app/views/shared/_place_creation_modal.html.erb'
|
||||
]
|
||||
|
||||
puts "\n📁 Checking Files:"
|
||||
files_to_check.each do |file|
|
||||
if File.exist?(file)
|
||||
puts " ✅ #{file}"
|
||||
else
|
||||
puts " ❌ MISSING: #{file}"
|
||||
end
|
||||
end
|
||||
|
||||
# Check view has our changes
|
||||
puts "\n🎨 Checking View Changes:"
|
||||
month_view = File.read('app/views/stats/_month.html.erb')
|
||||
|
||||
if month_view.include?('placesBtn')
|
||||
puts " ✅ Places button found in view"
|
||||
else
|
||||
puts " ❌ Places button NOT found in view"
|
||||
end
|
||||
|
||||
if month_view.include?('Filter Places by Tags')
|
||||
puts " ✅ Tag filter section found in view"
|
||||
else
|
||||
puts " ❌ Tag filter section NOT found in view"
|
||||
end
|
||||
|
||||
if month_view.include?('place_creation_modal')
|
||||
puts " ✅ Place creation modal included"
|
||||
else
|
||||
puts " ❌ Place creation modal NOT included"
|
||||
end
|
||||
|
||||
# Check JavaScript has our changes
|
||||
puts "\n💻 Checking JavaScript Changes:"
|
||||
controller_js = File.read('app/javascript/controllers/stat_page_controller.js')
|
||||
|
||||
if controller_js.include?('PlacesManager')
|
||||
puts " ✅ PlacesManager imported"
|
||||
else
|
||||
puts " ❌ PlacesManager NOT imported"
|
||||
end
|
||||
|
||||
if controller_js.include?('togglePlaces()')
|
||||
puts " ✅ togglePlaces() method found"
|
||||
else
|
||||
puts " ❌ togglePlaces() method NOT found"
|
||||
end
|
||||
|
||||
if controller_js.include?('filterPlacesByTags')
|
||||
puts " ✅ filterPlacesByTags() method found"
|
||||
else
|
||||
puts " ❌ filterPlacesByTags() method NOT found"
|
||||
end
|
||||
|
||||
# Check database
|
||||
puts "\n🗄️ Checking Database:"
|
||||
user = User.first
|
||||
if user
|
||||
puts " ✅ Found user: #{user.email}"
|
||||
puts " Tags: #{user.tags.count}"
|
||||
puts " Places: #{user.places.count}"
|
||||
|
||||
if user.tags.any?
|
||||
puts "\n 📌 Your Tags:"
|
||||
user.tags.limit(5).each do |tag|
|
||||
puts " #{tag.icon} #{tag.name} (#{tag.places.count} places)"
|
||||
end
|
||||
else
|
||||
puts " ⚠️ No tags created yet. Create some at /tags"
|
||||
end
|
||||
|
||||
if user.places.any?
|
||||
puts "\n 📍 Your Places:"
|
||||
user.places.limit(5).each do |place|
|
||||
puts " #{place.name} - #{place.tags.map(&:name).join(', ')}"
|
||||
end
|
||||
else
|
||||
puts " ⚠️ No places created yet. Use the API or create via console."
|
||||
end
|
||||
else
|
||||
puts " ❌ No users found"
|
||||
end
|
||||
|
||||
puts "\n" + "=" * 50
|
||||
puts "✅ Integration files are in place!"
|
||||
puts "\n📋 Next Steps:"
|
||||
puts " 1. Restart your Rails server"
|
||||
puts " 2. Hard refresh your browser (Cmd+Shift+R)"
|
||||
puts " 3. Navigate to /stats/#{Date.today.year}/#{Date.today.month}"
|
||||
puts " 4. Look for 'Places' button next to 'Heatmap' and 'Points'"
|
||||
puts " 5. Create tags at /tags if you haven't already"
|
||||
puts " 6. Create places via API with those tags"
|
||||
Reference in New Issue
Block a user