Basic functions, Home and Community Tab
This commit is contained in:
144
src/pages/community.rs
Normal file
144
src/pages/community.rs
Normal file
@@ -0,0 +1,144 @@
|
||||
use leptos::prelude::*;
|
||||
use leptos::html::Div;
|
||||
use crate::backend::logic::*;
|
||||
|
||||
#[component]
|
||||
pub fn CommunityPage() -> impl IntoView {
|
||||
// --- STATE & SIGNALS ---
|
||||
// Wer ist eingeloggt? (ID und Benutzername)
|
||||
let (user_id, set_user_id) = signal(None::<i64>);
|
||||
let (username, set_username) = signal(String::new());
|
||||
|
||||
// Referenz auf das Chat-Fenster für automatisches Scrollen
|
||||
let scroll_ref = NodeRef::<Div>::new();
|
||||
|
||||
// --- DATEN-ABFRAGE (RESOURCE) ---
|
||||
// Holt die Nachrichten vom Server
|
||||
let messages = Resource::new(|| (), |_| async move {
|
||||
get_all_messages().await.unwrap_or_default()
|
||||
});
|
||||
|
||||
// --- ECHTZEIT-POLLING ---
|
||||
// Fragt alle 2 Sekunden den Server nach neuen Nachrichten (nur im Browser)
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
use std::time::Duration;
|
||||
Effect::new(move |_| {
|
||||
let _ = set_interval_with_handle(move || {
|
||||
messages.refetch();
|
||||
}, Duration::from_secs(2));
|
||||
});
|
||||
}
|
||||
|
||||
// --- AUTO-SCROLL EFFEKT ---
|
||||
// Immer wenn neue Nachrichten geladen werden, scrollen wir nach ganz unten
|
||||
Effect::new(move |_| {
|
||||
messages.get(); // Reagiere auf Änderungen der Nachrichten
|
||||
if let Some(div) = scroll_ref.get() {
|
||||
request_animation_frame(move || {
|
||||
div.set_scroll_top(div.scroll_height());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// --- SERVER ACTIONS ---
|
||||
let login_action = ServerAction::<LoginOrRegister>::new();
|
||||
let send_action = ServerAction::<SendMessage>::new();
|
||||
|
||||
// --- LOGIK-EFFEKTE ---
|
||||
// 1. Login-Erfolg verarbeiten
|
||||
Effect::new(move |_| {
|
||||
if let Some(Ok(id)) = login_action.value().get() {
|
||||
set_user_id.set(Some(id));
|
||||
}
|
||||
});
|
||||
|
||||
// 2. Nach dem Senden sofort Nachrichten aktualisieren
|
||||
Effect::new(move |_| {
|
||||
if send_action.value().get().is_some() {
|
||||
messages.refetch();
|
||||
}
|
||||
});
|
||||
|
||||
// --- VIEW / UI ---
|
||||
view! {
|
||||
<div class="community-container">
|
||||
{move || match user_id.get() {
|
||||
// FALL A: Nutzer ist nicht eingeloggt (Anmelde-Karte)
|
||||
None => view! {
|
||||
<div class="auth-card">
|
||||
<h2>"Community Login"</h2>
|
||||
<p>"Tritt der Diskussion bei und schreibe mit Malxte."</p>
|
||||
<ActionForm action=login_action>
|
||||
<input
|
||||
type="text"
|
||||
name="user"
|
||||
placeholder="Dein Name"
|
||||
on:input:target=move |ev| set_username.set(ev.target().value())
|
||||
required
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
name="pass"
|
||||
placeholder="Passwort"
|
||||
required
|
||||
/>
|
||||
<button type="submit">"Beitreten"</button>
|
||||
</ActionForm>
|
||||
|
||||
// Fehlermeldung anzeigen, falls Login fehlschlägt
|
||||
{move || login_action.value().get().map(|v| match v {
|
||||
Err(e) => view! { <p style="color: red; margin-top: 10px;">{e.to_string()}</p> }.into_any(),
|
||||
_ => view! {}.into_any()
|
||||
})}
|
||||
</div>
|
||||
}.into_any(),
|
||||
|
||||
// FALL B: Nutzer ist eingeloggt (Chat-Fenster)
|
||||
Some(id) => view! {
|
||||
<div class="chat-main">
|
||||
<header class="chat-top-bar">
|
||||
<h3>"Globaler Chat"</h3>
|
||||
<span class="badge">{move || username.get()}</span>
|
||||
</header>
|
||||
|
||||
<div class="message-area" node_ref=scroll_ref>
|
||||
<Suspense fallback=|| view! { <div class="loading">"Lade Nachrichten..."</div> }>
|
||||
{move || messages.get().map(|list| {
|
||||
list.into_iter().map(|msg| {
|
||||
let is_me = msg.username == username.get();
|
||||
view! {
|
||||
<div class=if is_me { "msg-row me" } else { "msg-row other" }>
|
||||
<div class="msg-bubble">
|
||||
<strong>{msg.username}</strong>
|
||||
<p>{msg.content}</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}).collect_view()
|
||||
})}
|
||||
</Suspense>
|
||||
</div>
|
||||
|
||||
<div class="chat-input-wrapper">
|
||||
<ActionForm action=send_action>
|
||||
// Die ID wird versteckt mitgesendet
|
||||
<input type="hidden" name="user_id" value=id.to_string() />
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text"
|
||||
name="content"
|
||||
placeholder="Deine Nachricht..."
|
||||
required
|
||||
autocomplete="off"
|
||||
/>
|
||||
<button type="submit">"Senden"</button>
|
||||
</div>
|
||||
</ActionForm>
|
||||
</div>
|
||||
</div>
|
||||
}.into_any()
|
||||
}}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
9
src/pages/dashboard.rs
Normal file
9
src/pages/dashboard.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
use leptos::prelude::*;
|
||||
|
||||
#[component]
|
||||
pub fn DashboardPage() -> impl IntoView {
|
||||
view! {
|
||||
<h1>"Dashboard"</h1>
|
||||
<p>"Hier werden später Community-Statistiken stehen."</p>
|
||||
}
|
||||
}
|
||||
11
src/pages/home.rs
Normal file
11
src/pages/home.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
use leptos::prelude::*;
|
||||
|
||||
#[component]
|
||||
pub fn HomePage() -> impl IntoView {
|
||||
view! {
|
||||
<div class="home-hero">
|
||||
<h1>"Malxte."</h1>
|
||||
<p>"Willkommen in der Rust-Community."</p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
2
src/pages/mod.rs
Normal file
2
src/pages/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod home;
|
||||
pub mod community; // Das hat gefehlt!
|
||||
Reference in New Issue
Block a user