Files
kgpz_web/viewmodels/place_view.go
2025-09-27 23:30:37 +02:00

104 lines
2.8 KiB
Go

package viewmodels
import (
"maps"
"slices"
"strings"
"github.com/Theodor-Springmann-Stiftung/kgpz_web/xmlmodels"
)
// PlacesListView represents the data for the places overview
type PlacesListView struct {
Search string
AvailableLetters []string
Places map[string]xmlmodels.Place
Sorted []string
SelectedPlace *PlaceDetailView
TotalPiecesWithPlaces int
}
// PlaceDetailView represents a specific place with its associated pieces
type PlaceDetailView struct {
Place xmlmodels.Place
Pieces []xmlmodels.Piece
}
// PlacesView returns places data for the overview page
func PlacesView(placeID string, lib *xmlmodels.Library) *PlacesListView {
res := PlacesListView{Search: placeID, Places: make(map[string]xmlmodels.Place)}
av := make(map[string]bool)
// Get all places that are referenced in pieces and count total pieces with places
referencedPlaces := make(map[string]bool)
totalPiecesWithPlaces := 0
for _, piece := range lib.Pieces.Array {
hasPlace := false
for _, placeRef := range piece.PlaceRefs {
referencedPlaces[placeRef.Ref] = true
hasPlace = true
}
if hasPlace {
totalPiecesWithPlaces++
}
}
// Build available letters and places list
for _, place := range lib.Places.Array {
// Only include places that are actually referenced in pieces
if referencedPlaces[place.ID] {
av[strings.ToUpper(place.ID[:1])] = true
res.Sorted = append(res.Sorted, place.ID)
res.Places[place.ID] = place
}
}
// If a specific place is requested, get its details
if placeID != "" && len(placeID) > 1 {
if place, exists := res.Places[placeID]; exists {
res.SelectedPlace = GetPlaceDetail(place, lib)
}
}
res.AvailableLetters = slices.Collect(maps.Keys(av))
slices.Sort(res.AvailableLetters)
slices.Sort(res.Sorted)
res.TotalPiecesWithPlaces = totalPiecesWithPlaces
return &res
}
// GetPlaceDetail returns detailed information for a specific place including associated pieces
func GetPlaceDetail(place xmlmodels.Place, lib *xmlmodels.Library) *PlaceDetailView {
detail := &PlaceDetailView{
Place: place,
Pieces: make([]xmlmodels.Piece, 0),
}
// Find all pieces that reference this place
for _, piece := range lib.Pieces.Array {
for _, placeRef := range piece.PlaceRefs {
if placeRef.Ref == place.ID {
detail.Pieces = append(detail.Pieces, piece)
break // Don't add the same piece multiple times
}
}
}
// Sort pieces by title for consistent display
slices.SortFunc(detail.Pieces, func(a, b xmlmodels.Piece) int {
// Get first title from each piece, or use empty string if no titles
titleA := ""
if len(a.Title) > 0 {
titleA = a.Title[0]
}
titleB := ""
if len(b.Title) > 0 {
titleB = b.Title[0]
}
return strings.Compare(strings.ToLower(titleA), strings.ToLower(titleB))
})
return detail
}