use crate::components::game::cards::*; use crate::components::game::header::*; use crate::components::websocket::WebSocketContext; use leptos::*; use leptos_use::core::ConnectionReadyState; use lib::*; use serde_json::to_string; use std::collections::HashMap; pub mod cards; pub mod header; pub mod meta; pub mod scoreboard; #[component] pub fn Game() -> impl IntoView { // Websocket stuff let websocket = expect_context::<WebSocketContext>(); let tx = websocket.clone(); let (websocket_send, set_websocket_send) = create_signal("".to_string()); create_effect(move |_| { tx.send(&websocket_send()); }); // Incoming let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open; let game_meta = expect_context::<ReadSignal<Option<GameStateMeta>>>(); let judge_round = expect_context::<ReadSignal<Option<JudgeRound>>>(); // Signals // let (selected_cards, set_selected_cards) = create_signal::<Vec<WhiteCardMeta>>(vec![]); let (card_clicked, set_card_clicked) = create_signal::<String>(String::new()); let (player_hand, set_player_hand) = create_signal::<HashMap<String, WhiteCardMeta>>(HashMap::new()); let (judging, set_judging) = create_signal(false); // Outoging provide_context::<WriteSignal<String>>(set_card_clicked); // On Incoming Meta // // Put cards in a map for easier lookup // The server sends a vec to preserve ordering create_effect(move |_| { if game_meta().is_some() { for card in game_meta().unwrap().white { set_player_hand.update(|map| { map.insert(card.uuid.clone(), card.clone()); }); } } set_selected_cards.update(|list| { list.clear(); }); }); // On Incoming Judge // create_effect(move |_| { // Clear selected cards if judge_round().is_some() { set_selected_cards.update(|list| { list.clear(); }); set_judging(true); } }); // Player Submit Handler // let submit_move = move |_| { let msg = to_string(&PlayerMoveRequest { game_id: game_meta().unwrap().uuid.clone(), card_ids: selected_cards() .iter() .map(|card| card.uuid.clone()) .collect(), }) .unwrap(); set_websocket_send(msg); set_selected_cards.update(|list| { list.clear(); }); }; // Judging Submit Handler // let submit_judge = move |_| { let msg = to_string(&JudgeDecisionRequest { game_id: game_meta().unwrap().uuid.clone(), winning_cards: selected_cards() .iter() .map(|card| card.uuid.clone()) .collect(), }) .unwrap(); set_websocket_send(msg); set_judging(false); set_selected_cards.update(|list| { list.clear(); }); }; // Card selection // // Toggle selected status of cards create_effect(move |_| { if card_clicked() != "".to_string() { if judging.get_untracked() { let identical_cards = selected_cards .get_untracked() .into_iter() .filter(|card| card.uuid == card_clicked.get_untracked()) .collect::<Vec<WhiteCardMeta>>(); if identical_cards.len() > 0 { set_selected_cards.update(|list| { list.clear(); }); } else { // Clear selected cards set_selected_cards.update(|list| { list.clear(); }); // Select card group for group in judge_round.get_untracked().unwrap().cards_to_judge { for card in &group { if card.uuid == card_clicked() { set_selected_cards.update(|cards| cards.extend(group)); break; } } } } // Clear the signal otherwise it selects the last selected card again set_card_clicked.update_untracked(|value| value.clear()); } else { if !selected_cards.get_untracked().contains( player_hand .get_untracked() .get(&card_clicked.get_untracked()) .unwrap(), ) { set_selected_cards.update(|cards| { cards.push(player_hand().get(&card_clicked()).unwrap().clone()) }) } else if selected_cards .get_untracked() .contains(player_hand.get_untracked().get(&card_clicked()).unwrap()) { set_selected_cards.update(|cards| { cards.remove( cards .iter() .position(|card| { card == player_hand().get(&card_clicked()).unwrap() }) .unwrap(), ); }) } // Clear the signal otherwise it selects the last selected card again set_card_clicked.update_untracked(|value| value.clear()); } } }); view! { <div class="my-2"> <h2 class="text-2xl">Game</h2> <Show when=move || game_meta.get().is_some() && connected() fallback=|| view! { "You are not in a game" } > <Header game_meta=game_meta().unwrap() /> </Show> // Judging view // <Show when=move || { judging() && connected() }> <div class="w-full ms-16 inline-flex flex-wrap"> <BlackCard card_data=game_meta().unwrap().black /> // Selected cards <For each=move || selected_cards() key=move |card| card.uuid.clone() children=move |card| { view! { <WhiteCard card_data=card.clone() /> } } /> </div> // Submit button <div class="w-full inline-flex flex-wrap justify-center"> <button type="button" on:click=submit_judge> Submit </button> </div> <For each=move || judge_round().unwrap().cards_to_judge key=move |_| 69 children=move |group| { view! { <div class="m-2 inline-flex flex-wrap justify-center"> <For each=move || group.clone() key=move |card| card.uuid.clone() children=move |card| { view! { // Hide cards from hand view when they exist as selected <Show when={ let waste_of_memory = card.clone(); move || { !selected_cards().contains(&waste_of_memory) } }> <WhiteCard card_data=card.clone() /> </Show> } } /> </div> } } /> </Show> // Playing view // <Show when=move || game_meta.get().is_some() && connected() && !judging()> // Play cards <div class="w-full ms-16 inline-flex flex-wrap"> <BlackCard card_data=game_meta().unwrap().black /> // Selected cards <For each=move || selected_cards() key=move |card| card.uuid.clone() children=move |card| { view! { <WhiteCard card_data=card.clone() /> } } /> </div> // Submit button <div class="w-full inline-flex flex-wrap justify-center"> <button type="button" on:click=submit_move> Submit </button> </div> // Player hand <div class="inline-flex flex-wrap justify-center"> <For each=move || game_meta().unwrap().white key=move |card| card.uuid.clone() children=move |card| { view! { // Hide cards from hand view when they exist as selected <Show when={ let id = card.uuid.clone(); move || { if let Some(card) = player_hand().get(&id) { !selected_cards().contains(card) } else { true } } }> <WhiteCard card_data=card.clone() /> </Show> } } /> </div> </Show> </div> } }