brewlog/src/presentation/web/views/cafes.rs
Jon Seager 3bc6fae656
refactor(ui): improve data table detail rows and mobile cards
- Split created_at into created_date + created_time across all view models
- Add inline card-detail pattern for mobile action buttons
- Add desktop detail-row with ellipsis toggle for table actions
- Add pill-warning and pill-success CSS variants with dark mode
- Center mobile card-detail buttons, fix card-date vertical spacing
- Rename action labels: "View on Map" → "View Map", "Visit website/homepage" → "Homepage"
2026-02-05 20:40:38 +00:00

118 lines
3 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_date: String,
pub created_time: 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_date = created_at.format("%Y-%m-%d").to_string();
let created_time = created_at.format("%H:%M").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_date,
created_time,
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,
}
}
}