Add 15-minute snapping and time display to drag-to-create functionality

Enhance the drag-to-create event feature with precision improvements:

- Add snap_to_15_minutes() function to align drag coordinates to 15-minute increments
- Update mousedown and mousemove handlers to use coordinate snapping
- Replace pixel coordinate display with actual time ranges in temporary event box
- Display times in 12-hour format with AM/PM (e.g., "2:15 PM - 3:30 PM")
- Remove unused wasm_bindgen::JsCast import for cleaner code

Users can now create events that automatically align to 15-minute boundaries with clear visual feedback showing the exact time range being selected.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Connor Johnstone
2025-08-29 11:04:13 -04:00
parent df714a43a2
commit 53815c4814

View File

@@ -2,7 +2,6 @@ use yew::prelude::*;
use chrono::{Datelike, NaiveDate, Duration, Weekday, Local, Timelike, NaiveDateTime, NaiveTime};
use std::collections::HashMap;
use web_sys::MouseEvent;
use wasm_bindgen::JsCast;
use crate::services::calendar_service::{CalendarEvent, UserInfo};
#[derive(Properties, PartialEq)]
@@ -126,11 +125,14 @@ pub fn week_view(props: &WeekViewProps) -> Html {
let relative_y = e.layer_y() as f64;
let relative_y = if relative_y > 0.0 { relative_y } else { e.offset_y() as f64 };
// Snap to 15-minute increments
let snapped_y = snap_to_15_minutes(relative_y);
drag_state.set(Some(DragState {
is_dragging: true,
start_date: date_for_drag,
start_y: relative_y,
current_y: relative_y,
start_y: snapped_y,
current_y: snapped_y,
}));
e.prevent_default();
})
@@ -145,7 +147,10 @@ pub fn week_view(props: &WeekViewProps) -> Html {
let relative_y = e.layer_y() as f64;
let relative_y = if relative_y > 0.0 { relative_y } else { e.offset_y() as f64 };
current_drag.current_y = relative_y;
// Snap to 15-minute increments
let snapped_y = snap_to_15_minutes(relative_y);
current_drag.current_y = snapped_y;
drag_state.set(Some(current_drag));
}
}
@@ -323,16 +328,19 @@ pub fn week_view(props: &WeekViewProps) -> Html {
if let Some(drag) = (*drag_state).clone() {
if drag.is_dragging && drag.start_date == *date {
let start_y = drag.start_y.min(drag.current_y);
let end_y = drag.start_y.max(drag.current_y);
let height = (drag.current_y - drag.start_y).abs().max(20.0);
// Debug logging
// Convert pixels to times for display
let start_time = pixels_to_time(start_y);
let end_time = pixels_to_time(end_y);
html! {
<div
class="temp-event-box"
style={format!("top: {}px; height: {}px;", start_y, height)}
>
{format!("{}px - {}px", start_y as u32, (start_y + height) as u32)}
{format!("{} - {}", start_time.format("%I:%M %p"), end_time.format("%I:%M %p"))}
</div>
}
} else {
@@ -381,6 +389,12 @@ fn get_weekday_name(weekday: Weekday) -> &'static str {
// Calculate the pixel position of an event based on its time
// Each hour is 60px, so we convert time to pixels
// Snap pixel position to 15-minute increments (15px = 15 minutes since 60px = 60 minutes)
fn snap_to_15_minutes(pixels: f64) -> f64 {
let increment = 15.0; // 15px = 15 minutes
(pixels / increment).round() * increment
}
// Convert pixel position to time (inverse of time to pixels)
fn pixels_to_time(pixels: f64) -> NaiveTime {
let total_minutes = (pixels / 60.0) * 60.0; // 60px per hour, 60 minutes per hour