use crate::infrastructure::config::ResourceConfig;
use crate::interface::slack::constants::*;
use chrono::{Local, Timelike};
use slack_morphism::prelude::*;
pub fn create_reserve_modal(
config: &ResourceConfig,
resource_type: Option<&str>,
selected_server: Option<&str>,
usage_id: Option<&str>,
callback_id: Option<&str>,
title: Option<&str>,
submit_text: Option<&str>,
) -> SlackView {
let now = Local::now();
let start_date = now.format("%Y-%m-%d").to_string();
let start_time = format!("{:02}:{:02}", now.hour(), now.minute());
let end = now + chrono::Duration::hours(1);
let end_date = end.format("%Y-%m-%d").to_string();
let end_time = format!("{:02}:{:02}", end.hour(), end.minute());
let current_resource_type = resource_type.unwrap_or("gpu");
let resource_type_options = vec![
SlackBlockChoiceItem::new(pt!("GPU Server"), "gpu".into()),
SlackBlockChoiceItem::new(pt!("Room"), "room".into()),
];
let initial_resource_type = if current_resource_type == "room" {
SlackBlockChoiceItem::new(pt!("Room"), "room".into())
} else {
SlackBlockChoiceItem::new(pt!("GPU Server"), "gpu".into())
};
let mut blocks: Vec<SlackBlock> = vec![];
blocks.push(SlackBlock::Input(
SlackInputBlock::new(
pt!("リソースタイプ"),
SlackInputBlockElement::RadioButtons(
SlackBlockRadioButtonsElement::new(
SlackActionId::new(ACTION_RESERVE_RESOURCE_TYPE.to_string()),
resource_type_options,
)
.with_initial_option(initial_resource_type),
),
)
.with_dispatch_action(true),
));
if current_resource_type == "gpu" {
add_gpu_blocks(&mut blocks, config, selected_server);
} else if current_resource_type == "room" {
add_room_blocks(&mut blocks, config);
}
add_datetime_blocks(&mut blocks, &start_date, &start_time, &end_date, &end_time);
blocks.push(SlackBlock::Input(
SlackInputBlock::new(
pt!("備考"),
SlackInputBlockElement::PlainTextInput(
SlackBlockPlainTextInputElement::new(SlackActionId::new(
ACTION_RESERVE_NOTES.to_string(),
))
.with_multiline(true),
),
)
.with_optional(true),
));
let callback_id = callback_id.unwrap_or(CALLBACK_RESERVE_SUBMIT);
let title = title.unwrap_or("リソース予約");
let submit_text = submit_text.unwrap_or("予約する");
let mut modal_view = SlackModalView::new(pt!(title), blocks)
.with_callback_id(callback_id.into())
.with_submit(pt!(submit_text))
.with_close(pt!("キャンセル"));
if let Some(id) = usage_id {
modal_view = modal_view.with_private_metadata(id.into());
}
SlackView::Modal(modal_view)
}
fn create_device_options(
server: &crate::infrastructure::config::resource_config::ServerConfig,
) -> Vec<SlackBlockChoiceItem<SlackBlockText>> {
server
.devices
.iter()
.map(|device| {
SlackBlockChoiceItem::new(
SlackBlockText::Plain(SlackBlockPlainText::from(format!(
"Device {} ({})",
device.id, device.model
))),
device.id.to_string(),
)
})
.collect()
}
fn add_gpu_blocks(
blocks: &mut Vec<SlackBlock>,
config: &ResourceConfig,
selected_server: Option<&str>,
) {
if config.servers.is_empty() {
blocks.push(SlackBlock::Section(SlackSectionBlock::new().with_text(
md!("⚠️ サーバー設定が見つかりません。管理者に問い合わせてください。"),
)));
return;
}
let server_options: Vec<SlackBlockChoiceItem<SlackBlockPlainTextOnly>> = config
.servers
.iter()
.map(|server| SlackBlockChoiceItem::new(pt!(server.name.clone()), server.name.clone()))
.collect();
let mut server_select_element = SlackBlockStaticSelectElement::new(SlackActionId::new(
ACTION_RESERVE_SERVER_SELECT.to_string(),
))
.with_placeholder(pt!("サーバーを選択"))
.with_options(server_options.clone());
let default_server_name =
selected_server.or_else(|| config.servers.first().map(|s| s.name.as_str()));
if let Some(server_name) = default_server_name {
let initial_server =
SlackBlockChoiceItem::new(pt!(server_name.to_string()), server_name.to_string());
server_select_element = server_select_element.with_initial_option(initial_server);
}
blocks.push(SlackBlock::Input(
SlackInputBlock::new(
pt!("GPU Server"),
SlackInputBlockElement::StaticSelect(server_select_element),
)
.with_dispatch_action(true),
));
let device_options: Vec<SlackBlockChoiceItem<SlackBlockText>> =
if let Some(server_name) = selected_server {
config
.servers
.iter()
.find(|s| s.name == server_name)
.map(create_device_options)
.unwrap_or_default()
} else {
config
.servers
.first()
.map(create_device_options)
.unwrap_or_default()
};
if !device_options.is_empty() {
blocks.push(SlackBlock::Input(
SlackInputBlock::new(
pt!("GPU Devices"),
SlackInputBlockElement::Checkboxes(SlackBlockCheckboxesElement::new(
SlackActionId::new(ACTION_RESERVE_DEVICES.to_string()),
device_options,
)),
)
.with_optional(true),
));
}
}
fn add_room_blocks(blocks: &mut Vec<SlackBlock>, config: &ResourceConfig) {
if config.rooms.is_empty() {
blocks.push(SlackBlock::Section(SlackSectionBlock::new().with_text(
md!("⚠️ 部屋設定が見つかりません。管理者に問い合わせてください。"),
)));
return;
}
let room_options: Vec<SlackBlockChoiceItem<SlackBlockPlainTextOnly>> = config
.rooms
.iter()
.map(|room| SlackBlockChoiceItem::new(pt!(room.name.clone()), room.name.clone()))
.collect();
let mut room_select_element = SlackBlockStaticSelectElement::new(SlackActionId::new(
ACTION_RESERVE_ROOM_SELECT.to_string(),
))
.with_placeholder(pt!("部屋を選択"))
.with_options(room_options.clone());
if let Some(first_room) = config.rooms.first() {
let initial_room =
SlackBlockChoiceItem::new(pt!(first_room.name.clone()), first_room.name.clone());
room_select_element = room_select_element.with_initial_option(initial_room);
}
blocks.push(SlackBlock::Input(SlackInputBlock::new(
pt!("Room"),
SlackInputBlockElement::StaticSelect(room_select_element),
)));
}
fn add_datetime_blocks(
blocks: &mut Vec<SlackBlock>,
start_date: &str,
start_time: &str,
end_date: &str,
end_time: &str,
) {
blocks.push(SlackBlock::Input(SlackInputBlock::new(
pt!("開始日"),
SlackInputBlockElement::DatePicker(
SlackBlockDatePickerElement::new(SlackActionId::new(
ACTION_RESERVE_START_DATE.to_string(),
))
.with_initial_date(start_date.to_string()),
),
)));
blocks.push(SlackBlock::Input(SlackInputBlock::new(
pt!("開始時刻"),
SlackInputBlockElement::TimePicker(
SlackBlockTimePickerElement::new(SlackActionId::new(
ACTION_RESERVE_START_TIME.to_string(),
))
.with_initial_time(start_time.to_string()),
),
)));
blocks.push(SlackBlock::Input(SlackInputBlock::new(
pt!("終了日"),
SlackInputBlockElement::DatePicker(
SlackBlockDatePickerElement::new(SlackActionId::new(
ACTION_RESERVE_END_DATE.to_string(),
))
.with_initial_date(end_date.to_string()),
),
)));
blocks.push(SlackBlock::Input(SlackInputBlock::new(
pt!("終了時刻"),
SlackInputBlockElement::TimePicker(
SlackBlockTimePickerElement::new(SlackActionId::new(
ACTION_RESERVE_END_TIME.to_string(),
))
.with_initial_time(end_time.to_string()),
),
)));
}