use crate::components::AppContext; use crate::components::{BiddingBox, BiddingTable, Hand, TrickInPlay, HandDiagram}; use crate::{services, use_app_context}; use futures::FutureExt; use log::info; use protocol::actions::Bid; use protocol::bridge_engine::{ BiddingStatePlayerView, GameStatePlayerView, PlayResult, PlayStatePlayerView, TableStatePlayerView, }; use protocol::card::Card; use protocol::core::Player; use yew::prelude::*; #[derive(PartialEq, Properties, Clone)] pub struct OnlineTableProps { pub table: protocol::Table, } #[function_component(OnlineTable)] pub fn online_table(props: &OnlineTableProps) -> Html { let ctx = use_app_context(); html! { } } #[derive(PartialEq, Properties, Clone)] pub struct OnlineTableInnerProps { pub table: protocol::Table, pub app_ctx: AppContext, } struct OnlineTableInner { table_state: Option, } pub enum Msg { TableStateUpdated(Result), RequestNewDeal, Bid(Bid), Play(Card), } impl OnlineTableInner { fn play(&mut self, ctx: &yew::Context, card: Card) { let _play_state = match &self.table_state { Some(TableStatePlayerView::Game(GameStatePlayerView::Playing( play_state, ))) => play_state, _ => { info!( "Cannot play card with table state: {:#?}", self.table_state ); return; } }; info!("Playing card {card:?}"); let table = ctx.props().table.clone(); ctx.link().send_future( async move { services::play(table.clone(), card).await?; services::get_table_player_view(table).await } .map(Msg::TableStateUpdated), ); } fn view_result( &self, ctx: &yew::Context, result: &PlayResult, ) -> Html { let leave_table = { let ctx = ctx.props().app_ctx.clone(); Callback::from(move |_| ctx.leave_table()) }; let center = html! { <>
}; html! { <>
{center}
} } fn view_game( &self, ctx: &yew::Context, game: &GameStatePlayerView, ) -> Html { let center = match game { GameStatePlayerView::Bidding(bidding) => { bidding_view(bidding, ctx.link().callback(Msg::Bid)) } GameStatePlayerView::Playing(playing) => { playing_view(playing, ctx.link().callback(Msg::Play)) } }; let leave_table = { let ctx = ctx.props().app_ctx.clone(); Callback::from(move |_| ctx.leave_table()) }; html! { <>
{center}
} } } impl Component for OnlineTableInner { type Message = Msg; type Properties = OnlineTableInnerProps; fn create(ctx: &yew::Context) -> Self { ctx.link().send_future( services::get_table_player_view(ctx.props().table.clone()) .map(Msg::TableStateUpdated), ); Self { table_state: None } } fn update(&mut self, ctx: &yew::Context, msg: Msg) -> bool { match msg { Msg::Bid(bid) => { info!("Bid clicked: {bid:?}"); let table = ctx.props().table.clone(); ctx.link().send_future( async move { services::bid(table.clone(), bid).await?; services::get_table_player_view(table).await } .map(Msg::TableStateUpdated), ); false } Msg::Play(card) => { self.play(ctx, card); false } Msg::TableStateUpdated(Ok(table_state)) => { self.table_state = Some(table_state); true } Msg::TableStateUpdated(Err(error)) => { ctx.props().app_ctx.set_error(error); false } Msg::RequestNewDeal => { let table = ctx.props().table.clone(); ctx.link().send_future( async move { services::new_deal(table.clone()).await?; services::get_table_player_view(table).await } .map(Msg::TableStateUpdated), ); false } } } fn view(&self, ctx: &yew::Context) -> Html { match &self.table_state { None => loading(), Some(TableStatePlayerView::Unknown) => html! {

{"An error occurred."}

}, Some(TableStatePlayerView::Game(game)) => self.view_game(ctx, game), Some(TableStatePlayerView::Result(result)) => { self.view_result(ctx, result) } } } } fn loading() -> Html { html! {

{"Loading table information"}

} } pub fn bidding_view( bidding: &BiddingStatePlayerView, on_bid: Callback, ) -> Html { html! { <>
{ format!("It is {:?} to bid", bidding.bidding.current_bidder()) }
} } pub fn playing_view( playing: &PlayStatePlayerView, on_card_clicked: Callback, ) -> Html { // Only one layout is currently supported. assert_eq!(playing.player_position, Player::South); assert_eq!(playing.contract.declarer, Player::South); let dummy = match &playing.dummy { Some(hand) => html! { }, None => html! {

{"Dummy is not visible yet"}

}, }; html! { <>

{ format!("It is {:?} to play", playing.current_player()) }

{ dummy }
} }