brewlog/src/presentation/web/views/cafes.rs
Jon Seager fa5386c671
feat(checkin): add roast/cafe summary bars and data attribute selects
- Add roast name and roaster name signals to check-in page
- Show selected cafe city as subtext in cafe summary bar
- Add roast summary bar showing roast name and roaster after selection
- Use data attributes on select options for structured cafe/roast data
- Add name/city fields to CafeOptionView and name/roaster_name to RoastOptionView
- Return roaster name signal from scan endpoint for roast summary display
2026-02-04 16:00:53 +00:00

115 lines
2.9 KiB
Rust

use crate::domain::cafes::Cafe;
use crate::infrastructure::foursquare::NearbyCafe;
pub struct CafeView {
pub id: String,
pub detail_path: String,
pub name: String,
pub city: String,
pub country: String,
pub latitude: f64,
pub longitude: f64,
pub map_url: String,
pub has_website: bool,
pub website_url: String,
pub website_label: String,
pub created_at: String,
pub created_at_sort_key: i64,
}
impl From<Cafe> for CafeView {
fn from(cafe: Cafe) -> Self {
let Cafe {
id,
slug,
name,
city,
country,
latitude,
longitude,
website,
created_at,
updated_at: _,
} = cafe;
let website = website.unwrap_or_default();
let has_website = !website.is_empty();
let detail_path = format!("/cafes/{slug}");
let map_url = format!("https://www.google.com/maps?q={latitude},{longitude}");
let created_at_sort_key = created_at.timestamp();
let created_at_label = created_at.format("%Y-%m-%d").to_string();
Self {
detail_path,
id: id.to_string(),
name,
city,
country,
latitude,
longitude,
map_url,
has_website,
website_url: website.clone(),
website_label: website,
created_at: created_at_label,
created_at_sort_key,
}
}
}
pub struct CafeOptionView {
pub id: String,
pub label: String,
pub name: String,
pub city: String,
}
impl From<Cafe> for CafeOptionView {
fn from(cafe: Cafe) -> Self {
Self {
id: cafe.id.to_string(),
label: format!("{} ({})", cafe.name, cafe.city),
name: cafe.name,
city: cafe.city,
}
}
}
pub struct NearbyCafeView {
pub name: String,
pub city: String,
pub country: String,
pub latitude: f64,
pub longitude: f64,
pub website: String,
pub distance: String,
pub location: String,
}
impl From<NearbyCafe> for NearbyCafeView {
fn from(cafe: NearbyCafe) -> Self {
let distance = if cafe.distance_meters < 1000 {
format!("{} m", cafe.distance_meters)
} else {
format!("{:.1} km", f64::from(cafe.distance_meters) / 1000.0)
};
let location = [&cafe.city, &cafe.country]
.iter()
.filter(|s| !s.is_empty())
.copied()
.cloned()
.collect::<Vec<_>>()
.join(", ");
Self {
name: cafe.name,
city: cafe.city,
country: cafe.country,
latitude: cafe.latitude,
longitude: cafe.longitude,
website: cafe.website.unwrap_or_default(),
distance,
location,
}
}
}