use plate_tool_lib::{plate::PlateType}; use uuid::Uuid; use wasm_bindgen::{prelude::*, JsCast}; use web_sys::{ HtmlDialogElement, HtmlElement, HtmlOptionElement, HtmlSelectElement, }; use yew::prelude::*; use yewdux::prelude::*; use std::rc::Rc; use std::str::FromStr; use crate::components::callbacks::main_window_callbacks::create_close_button; use crate::components::states::MainState; pub fn merge_button_callback(main_dispatch: Dispatch, id: Uuid) -> Callback { Callback::from(move |_| { let dialog_opt = create_merge_dialog(main_dispatch.clone(), id); if let Some(dialog) = dialog_opt { let window = web_sys::window().unwrap(); let document = window.document().unwrap(); let body = document.body().unwrap(); let _ = body.append_child(&dialog); dialog.set_open(true); } }) } fn create_merge_dialog(main_dispatch: Dispatch, id: Uuid) -> Option { let other_plates = get_all_plates_except(main_dispatch.clone(), id); if other_plates.is_empty() { return None; } let dialog = create_dialog(); let select = create_select_for_plates(&other_plates); dialog.append_child(&select).unwrap(); let select_rc = Rc::new(select); let ok_button = create_ok_button(main_dispatch.clone(), select_rc.clone(), id); dialog.append_child(&ok_button).unwrap(); Some(dialog) } fn create_dialog() -> HtmlDialogElement { let window = web_sys::window().unwrap(); let document = window.document().unwrap(); let dialog = document .create_element("dialog") .unwrap() .dyn_into::() .unwrap(); dialog.set_class_name("dialog shifted_dialog"); let onclose_callback = { let dialog = dialog.clone(); Closure::::new(move |_: Event| { dialog.remove(); }) }; dialog.set_onclose(Some(onclose_callback.as_ref().unchecked_ref())); let close_button = create_close_button(&onclose_callback); onclose_callback.forget(); dialog.append_child(&close_button).unwrap(); let header = document.create_element("h2").unwrap(); header.set_inner_html("Merge Plates"); dialog.append_child(&header).unwrap(); dialog } fn create_ok_button( main_dispatch: Dispatch, select: Rc, id: Uuid, ) -> HtmlElement { let window = web_sys::window().unwrap(); let document = window.document().unwrap(); let button = document .create_element("button") .unwrap() .dyn_into::() .unwrap(); button.set_inner_html("Ok"); let callback = ok_button_callback(main_dispatch, select, id); button.set_onclick(Some(callback.as_ref().unchecked_ref())); callback.forget(); button } fn ok_button_callback( main_dispatch: Dispatch, select: Rc, to_id: Uuid, ) -> Closure { Closure::::new(move |_: Event| { let selected = select .selected_options() .get_with_index(0) .map(|el| el.dyn_into::().unwrap()) .map(|opt_el| opt_el.value()) .and_then(|uuid_str| Uuid::from_str(&uuid_str).ok()); if let Some(from_id) = selected { let plate_type = find_plate_type(main_dispatch.clone(), from_id).unwrap(); let binding = main_dispatch.get(); let merge_to = match plate_type { PlateType::Source => binding.source_plates.iter().find(|x| x.get_uuid() == to_id).unwrap(), PlateType::Destination => binding .destination_plates .iter() .find(|x| x.get_uuid() == to_id).unwrap(), }; main_dispatch.reduce_mut(|x| { let merged_transfers = x.transfers.iter_mut().filter(|x| match plate_type { PlateType::Source => x.source_id, PlateType::Destination => x.dest_id } == from_id); for transfer in merged_transfers { match plate_type { PlateType::Source => { transfer.source_id = to_id; transfer.transfer_region.source_plate = merge_to.plate; }, PlateType::Destination => { transfer.dest_id = to_id; transfer.transfer_region.dest_plate = merge_to.plate; } } } match plate_type { PlateType::Source => x.source_plates.retain(|y| y.get_uuid() != from_id), PlateType::Destination => x.destination_plates.retain(|y| y.get_uuid() != from_id) }; }); } }) } fn create_select_for_plates(infos: &Vec<(Uuid, String)>) -> HtmlSelectElement { let window = web_sys::window().unwrap(); let document = window.document().unwrap(); let select = document .create_element("select") .unwrap() .dyn_into::() .unwrap(); for info in infos { let _ = select.append_child(&create_option_for_plate(info)); } select } fn create_option_for_plate(info: &(Uuid, String)) -> HtmlOptionElement { let window = web_sys::window().unwrap(); let document = window.document().unwrap(); let opt = document .create_element("option") .unwrap() .dyn_into::() .unwrap(); opt.set_value(&info.0.to_string()); opt.set_inner_text(&info.1); opt } fn get_all_plates_except(main_dispatch: Dispatch, id: Uuid) -> Vec<(Uuid, String)> { let plate_type = find_plate_type(main_dispatch.clone(), id); if plate_type.is_none() { return Vec::new(); } // Return early if not found somehow let plate_type = plate_type.unwrap(); let binding = main_dispatch.get(); let all_plates_iter = match plate_type { PlateType::Source => binding.source_plates.iter(), PlateType::Destination => binding.destination_plates.iter(), }; all_plates_iter .map(|x| (x.get_uuid(), x.name.to_string())) .filter(|y| y.0 != id) .collect() } fn find_plate_type(main_dispatch: Dispatch, id: Uuid) -> Option { if main_dispatch .get() .source_plates .iter() .any(|x| x.get_uuid() == id) { Some(PlateType::Source) } else if main_dispatch .get() .destination_plates .iter() .any(|x| x.get_uuid() == id) { return Some(PlateType::Destination); } else { return None; } }