test(kanban): prove multiplayer milestone journey
req: ms/001 req: ms/002 req: ms/003
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
use axum::extract::{Query, Request, State};
|
||||
use axum::extract::{Form, Query, Request, State};
|
||||
use axum::http::{HeaderMap, StatusCode};
|
||||
use axum::middleware::{self, Next};
|
||||
use axum::response::sse::{Event, KeepAlive, Sse};
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use axum::response::{IntoResponse, Redirect, Response};
|
||||
use axum::routing::{get, post};
|
||||
use axum::{Json, Router};
|
||||
use futures_util::{stream, StreamExt};
|
||||
@@ -500,6 +500,7 @@ async fn main() {
|
||||
|
||||
let ordinary_routes = Router::new()
|
||||
.route("/", get(home).post(interact))
|
||||
.route("/move", post(move_card_without_script))
|
||||
.route("/events", get(events))
|
||||
.route("/sync/broadcast", get(sync_broadcast))
|
||||
.route("/sync/ack", get(sync_ack))
|
||||
@@ -554,6 +555,36 @@ async fn home(State(state): State<Arc<AppState>>, request: PageRequest) -> impl
|
||||
.fingerprint(ui::BUILD_FINGERPRINT)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
enum MoveDirection {
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct MoveCardForm {
|
||||
card_id: u64,
|
||||
direction: MoveDirection,
|
||||
}
|
||||
|
||||
// req: accessibility/001 req: ms/001
|
||||
async fn move_card_without_script(
|
||||
State(state): State<Arc<AppState>>,
|
||||
Form(command): Form<MoveCardForm>,
|
||||
) -> Result<Redirect, StatusCode> {
|
||||
let mut board = state.board.lock().unwrap();
|
||||
let moved = update_card(&mut board, Some(command.card_id), |card| {
|
||||
card.column = match command.direction {
|
||||
MoveDirection::Left => card.column.saturating_sub(1),
|
||||
MoveDirection::Right => (card.column + 1).min(COLUMNS.len() - 1),
|
||||
};
|
||||
});
|
||||
moved
|
||||
.then(|| Redirect::to("/"))
|
||||
.ok_or(StatusCode::BAD_REQUEST)
|
||||
}
|
||||
|
||||
async fn runtime() -> impl IntoResponse {
|
||||
runtime_js()
|
||||
}
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
<article class="card" +data-key="self.id">
|
||||
<strong>{+ self.title +}</strong>
|
||||
<menu>
|
||||
<button h-if="self.left_disabled" type="button" data-hemx-handle="move_left" +data-card-id="self.id" disabled="disabled">←</button>
|
||||
<button h-else type="button" data-hemx-handle="move_left" +data-card-id="self.id">←</button>
|
||||
<button h-if="self.right_disabled" type="button" data-hemx-handle="move_right" +data-card-id="self.id" disabled="disabled">→</button>
|
||||
<button h-else type="button" data-hemx-handle="move_right" +data-card-id="self.id">→</button>
|
||||
<button h-if="self.left_disabled" type="button" aria-label="Move card left" data-hemx-handle="move_left" +data-card-id="self.id" disabled="disabled">←</button>
|
||||
<form h-else method="post" action="/move">
|
||||
<input type="hidden" name="card_id" +value="self.id">
|
||||
<button type="submit" name="direction" value="left" aria-label="Move card left" data-hemx-handle="move_left" +data-card-id="self.id">←</button>
|
||||
</form>
|
||||
<button h-if="self.right_disabled" type="button" aria-label="Move card right" data-hemx-handle="move_right" +data-card-id="self.id" disabled="disabled">→</button>
|
||||
<form h-else method="post" action="/move">
|
||||
<input type="hidden" name="card_id" +value="self.id">
|
||||
<button type="submit" name="direction" value="right" aria-label="Move card right" data-hemx-handle="move_right" +data-card-id="self.id">→</button>
|
||||
</form>
|
||||
<button type="button" data-hemx-handle="delete_card" +data-card-id="self.id">Delete</button>
|
||||
</menu>
|
||||
</article>
|
||||
|
||||
Reference in New Issue
Block a user