Added live updating timings
This commit is contained in:
parent
36c23f3740
commit
1f96cbcba6
@ -1,4 +1,4 @@
|
||||
use crate::util::surrealdb::schemas;
|
||||
use crate::util::surrealdb::{client::sort_participants, client::Time, schemas};
|
||||
use leptos::*;
|
||||
|
||||
/// Renders the home page of your application.
|
||||
@ -6,40 +6,53 @@ use leptos::*;
|
||||
pub fn Participants() -> impl IntoView {
|
||||
let participants_context = use_context::<schemas::ParticipantsContext>().unwrap();
|
||||
|
||||
let name = create_rw_signal("".to_string());
|
||||
|
||||
let participants_sorted =
|
||||
create_memo(move |_| sort_participants(participants_context.get(), name.get()));
|
||||
|
||||
view! {
|
||||
<div class="participants-container">
|
||||
<table>
|
||||
<input type="search"
|
||||
class="participants-search"
|
||||
placeholder="Search"
|
||||
autocomplete="off"
|
||||
autofocus=true
|
||||
on:input=move |ev| {
|
||||
name.set(event_target_value(&ev));
|
||||
}
|
||||
prop:value=name
|
||||
/>
|
||||
<table class="participants-table">
|
||||
<tr>
|
||||
<th>"Naam"</th>
|
||||
<th>"Groep"</th>
|
||||
<th>"Lifesaver"</th>
|
||||
<th>"Hindernis"</th>
|
||||
<th>"Popduiken"</th>
|
||||
</tr>
|
||||
<For
|
||||
each=move || participants_sorted.get()
|
||||
key=|state| state.id.clone()
|
||||
let:child
|
||||
>
|
||||
<tr>
|
||||
<th>"Naam"</th>
|
||||
<th>"Groep"</th>
|
||||
<th>"Lifesaver"</th>
|
||||
<th>"Hindernis"</th>
|
||||
<th>"Popduiken"</th>
|
||||
</tr>
|
||||
<For
|
||||
each=move || participants_context.get()
|
||||
key=|state| state.id.clone()
|
||||
let:child
|
||||
>
|
||||
<tr>
|
||||
<td>{ move || child.value.get().name }</td>
|
||||
<td>{ move || child.value.get().group }</td>
|
||||
{ move || match child.value.get().events {
|
||||
Some(events) => view! {
|
||||
<td>{ events.lifesaver.unwrap_or(0) }</td>
|
||||
<td>{ events.hindernis.unwrap_or(0) }</td>
|
||||
<td>{ events.popduiken.unwrap_or(0) }</td>
|
||||
},
|
||||
None => view! {
|
||||
<td>"0"</td>
|
||||
<td>"0"</td>
|
||||
<td>"0"</td>
|
||||
}
|
||||
<td>{ move || child.value.get().name }</td>
|
||||
<td>{ move || child.value.get().group }</td>
|
||||
{ move || match child.value.get().events {
|
||||
Some(events) => view! {
|
||||
<td>{ Time::from_milliseconds_to_string(events.lifesaver.unwrap_or(0)) }</td>
|
||||
<td>{ Time::from_milliseconds_to_string(events.hindernis.unwrap_or(0)) }</td>
|
||||
<td>{ Time::from_milliseconds_to_string(events.popduiken.unwrap_or(0)) }</td>
|
||||
},
|
||||
None => view! {
|
||||
<td>"0"</td>
|
||||
<td>"0"</td>
|
||||
<td>"0"</td>
|
||||
}
|
||||
}
|
||||
</tr>
|
||||
</For>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
</tr>
|
||||
</For>
|
||||
</table>
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ async fn add_participant(name: String, group: String) -> Result<(), ServerFnErro
|
||||
participant: schemas::Participant {
|
||||
name: participant.name.clone(),
|
||||
group: participant.group.clone(),
|
||||
id: participant.id.to_string(),
|
||||
id: participant.id.id.to_string(),
|
||||
events: participant.events.clone(),
|
||||
},
|
||||
};
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::util::surrealdb::schemas;
|
||||
use crate::util::surrealdb::{client::sort_participants, client::Time, schemas};
|
||||
use leptos::{ev::keydown, *};
|
||||
use leptos_use::*;
|
||||
use strsim::normalized_damerau_levenshtein;
|
||||
use web_sys::ScrollIntoViewOptions;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
@ -13,19 +12,6 @@ cfg_if::cfg_if! {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Time {
|
||||
minutes: u32,
|
||||
seconds: u32,
|
||||
milliseconds: u32,
|
||||
}
|
||||
|
||||
impl Time {
|
||||
fn as_milliseconds(&self) -> u32 {
|
||||
self.minutes * 60 * 1000 + self.seconds * 1000 + self.milliseconds * 10
|
||||
}
|
||||
}
|
||||
|
||||
#[server(AddTime)]
|
||||
async fn add_time(
|
||||
mut participant: schemas::Participant,
|
||||
@ -96,7 +82,7 @@ pub fn AddTime() -> impl IntoView {
|
||||
|
||||
let participant = &participants_sorted.get()[selected_index.get()];
|
||||
add_time_action.dispatch((
|
||||
participant.clone(),
|
||||
participant.value.get(),
|
||||
event.get(),
|
||||
time.get().as_milliseconds(),
|
||||
));
|
||||
@ -165,7 +151,7 @@ pub fn AddTime() -> impl IntoView {
|
||||
/>
|
||||
<ul node_ref=container_ref tabindex=-1>
|
||||
{move || participants_sorted.get().into_iter().enumerate().map(|(i, participant)| view! {
|
||||
<li on:click=move |_| selected_index.set(i) class:selected=move || selected_index.get() == i>{participant.name + " " + "(" + &participant.group + ")" }</li>
|
||||
<li on:click=move |_| selected_index.set(i) class:selected=move || selected_index.get() == i>{participant.value.get().name + " " + "(" + &participant.value.get().group + ")" }</li>
|
||||
}).collect_view()}
|
||||
</ul>
|
||||
</div>
|
||||
@ -227,33 +213,3 @@ pub fn SelectOption(is: &'static str, value: ReadSignal<String>) -> impl IntoVie
|
||||
</option>
|
||||
}
|
||||
}
|
||||
fn sort_participants(
|
||||
participants: Vec<schemas::ParticipantSignal>,
|
||||
search: String,
|
||||
) -> Vec<schemas::Participant> {
|
||||
let mut filtered_sorted_list: Vec<(schemas::Participant, f64)> = participants
|
||||
.into_iter()
|
||||
.map(|participant| {
|
||||
(
|
||||
participant.value.get(),
|
||||
normalized_damerau_levenshtein(
|
||||
&participant.value.get().name.to_lowercase(),
|
||||
&search.to_lowercase(),
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
filtered_sorted_list.sort_by(|a, b| {
|
||||
let (_, sim_score_a) = a;
|
||||
let (_, sim_score_b) = b;
|
||||
sim_score_b
|
||||
.partial_cmp(sim_score_a)
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
});
|
||||
|
||||
filtered_sorted_list
|
||||
.into_iter()
|
||||
.map(|(item, _)| item)
|
||||
.collect()
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use leptos::*;
|
||||
|
||||
pub mod client;
|
||||
pub mod schemas;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
|
57
application/src/util/surrealdb/client.rs
Normal file
57
application/src/util/surrealdb/client.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use crate::util::surrealdb::schemas;
|
||||
use leptos::*;
|
||||
use strsim::normalized_damerau_levenshtein;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Time {
|
||||
pub minutes: u32,
|
||||
pub seconds: u32,
|
||||
pub milliseconds: u32,
|
||||
}
|
||||
|
||||
impl Time {
|
||||
pub fn as_milliseconds(&self) -> u32 {
|
||||
self.minutes * 60 * 1000 + self.seconds * 1000 + self.milliseconds * 10
|
||||
}
|
||||
|
||||
pub fn from_milliseconds_to_string(mut time: u32) -> String {
|
||||
let milliseconds = (time % 1000) / 10;
|
||||
time /= 1000;
|
||||
let seconds = time % 60;
|
||||
time /= 60;
|
||||
let minutes = time;
|
||||
|
||||
format!("{minutes}:{seconds}:{milliseconds}")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sort_participants(
|
||||
participants: Vec<schemas::ParticipantSignal>,
|
||||
search: String,
|
||||
) -> Vec<schemas::ParticipantSignal> {
|
||||
let mut filtered_sorted_list: Vec<(schemas::ParticipantSignal, f64)> = participants
|
||||
.into_iter()
|
||||
.map(|participant| {
|
||||
(
|
||||
participant.clone(),
|
||||
normalized_damerau_levenshtein(
|
||||
&participant.value.get().name.to_lowercase(),
|
||||
&search.to_lowercase(),
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
filtered_sorted_list.sort_by(|a, b| {
|
||||
let (_, sim_score_a) = a;
|
||||
let (_, sim_score_b) = b;
|
||||
sim_score_b
|
||||
.partial_cmp(sim_score_a)
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
});
|
||||
|
||||
filtered_sorted_list
|
||||
.into_iter()
|
||||
.map(|(item, _)| item)
|
||||
.collect()
|
||||
}
|
@ -31,7 +31,7 @@ pub struct Participant {
|
||||
pub events: Option<Events>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct ParticipantSignal {
|
||||
pub id: String,
|
||||
pub value: RwSignal<Participant>,
|
||||
|
@ -12,22 +12,17 @@ pub fn init_websocket() {
|
||||
} = use_websocket("ws://localhost:3000/ws");
|
||||
|
||||
provide_context(ready_state);
|
||||
let participants_context = use_context::<schemas::ParticipantsContext>().unwrap();
|
||||
let owner = Owner::current().unwrap();
|
||||
|
||||
create_effect(move |prev_value| {
|
||||
let msg = message.get();
|
||||
|
||||
if prev_value != Some(msg.clone()) {
|
||||
match msg {
|
||||
Some(ref text) => handle_message(text),
|
||||
None => (),
|
||||
}
|
||||
create_effect(move |_| {
|
||||
if let Some(m) = message.get() {
|
||||
with_owner(owner, || handle_message(&participants_context, &m));
|
||||
}
|
||||
|
||||
msg
|
||||
});
|
||||
}
|
||||
|
||||
fn handle_message(message: &str) {
|
||||
fn handle_message(&participants_context: &schemas::ParticipantsContext, message: &str) {
|
||||
let action: ParticipantsAction = match serde_json::from_str(message) {
|
||||
Ok(res) => res,
|
||||
Err(_err) => {
|
||||
@ -37,8 +32,6 @@ fn handle_message(message: &str) {
|
||||
|
||||
logging::log!("Recieved action: {:?}", action);
|
||||
|
||||
let participants_context = use_context::<schemas::ParticipantsContext>().unwrap();
|
||||
|
||||
match action {
|
||||
ParticipantsAction::Add { participant } => participants_context.update(|participants| {
|
||||
participants.push(schemas::ParticipantSignal {
|
||||
@ -49,15 +42,13 @@ fn handle_message(message: &str) {
|
||||
ParticipantsAction::Remove { id } => participants_context
|
||||
.update(|participants| participants.retain(|participant| participant.id != id)),
|
||||
ParticipantsAction::Replace { participant } => {
|
||||
participants_context.with(|participants| {
|
||||
for participant_signal in participants {
|
||||
if participant_signal.id == participant.id {
|
||||
participant_signal.value.update(|value| {
|
||||
*value = participant.clone();
|
||||
})
|
||||
}
|
||||
let participants = participants_context.get();
|
||||
for participant_signal in participants {
|
||||
if participant_signal.id == participant.id {
|
||||
participant_signal.value.set(participant);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,3 +24,34 @@ a {
|
||||
background-color: $secondary-bg-color-light;
|
||||
}
|
||||
|
||||
.participants-search {
|
||||
margin-top: 40px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.participants-table {
|
||||
margin-top: 0px;
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.participants-table th {
|
||||
position: sticky;
|
||||
background-color: $secondary-bg-color-lighter;
|
||||
z-index: 100;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.participants-table th,td {
|
||||
text-align: left;
|
||||
padding: 8px 8px;
|
||||
}
|
||||
|
||||
.participants-table tr:hover {
|
||||
background-color: $secondary-color !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.participants-table tr:nth-child(odd) {
|
||||
background-color: $secondary-bg-color-light;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user