Skip to content

Commit

Permalink
Support archiving events
Browse files Browse the repository at this point in the history
  • Loading branch information
flosse committed Sep 21, 2023
1 parent 7e94bb9 commit 518be54
Show file tree
Hide file tree
Showing 10 changed files with 257 additions and 181 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ofdb-app-clearance/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ofdb-frontend-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ rust-version.workspace = true
[dependencies]
percent-encoding = "2.3.0"
serde = "1.0.188"
serde_json = "1.0.107"
thiserror = "1.0.48"

[dependencies.gloo-net]
Expand Down
14 changes: 13 additions & 1 deletion ofdb-frontend-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,25 @@ impl From<gloo_net::Error> for Error {
}
}

impl From<serde_json::Error> for Error {
fn from(err: serde_json::Error) -> Self {
Self::Fetch(format!("{err}"))
}
}

pub async fn into_json<T>(response: Response) -> Result<T>
where
T: DeserializeOwned,
{
// ensure we've got 2xx status
if response.ok() {
Ok(response.json().await?)
let data = if response.status() == 204 {
// No content
serde_json::from_value(serde_json::Value::Null)?
} else {
response.json().await?
};
Ok(data)
} else {
Err(response.json::<ofdb_boundary::Error>().await?.into())
}
Expand Down
16 changes: 11 additions & 5 deletions ofdb-frontend-api/src/user.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use gloo_net::http::{Request, RequestBuilder};
use ofdb_boundary::*;
use serde::de::DeserializeOwned;
use web_sys::RequestCredentials;

use ofdb_boundary::*;

use crate::{into_json, Result};

/// Authorized OpenFairDB API
Expand Down Expand Up @@ -32,8 +33,8 @@ impl UserApi {
}
pub async fn user_info(&self) -> Result<User> {
let url = format!("{}/users/current", self.url);
self.send(Request::get(&url).credentials(RequestCredentials::Include))
.await
let request = Request::get(&url).credentials(RequestCredentials::Include);
self.send(request).await
}
pub async fn bbox_subscriptions(&self) -> Result<Vec<BboxSubscription>> {
let url = format!("{}/bbox-subscriptions", self.url);
Expand All @@ -45,10 +46,15 @@ impl UserApi {
}
pub async fn logout(&self) -> Result<()> {
let url = format!("{}/logout", self.url);
self.send(Request::post(&url).credentials(RequestCredentials::Include))
.await
let request = Request::post(&url).credentials(RequestCredentials::Include);
self.send(request).await
}
pub fn token(&self) -> &JwtToken {
&self.token
}
pub async fn archive_events(&self, ids: &[&str]) -> Result<()> {
let url = format!("{}/events/{}/archive", self.url, ids.join(","));
let request = Request::post(&url).credentials(RequestCredentials::Include);
self.send(request).await
}
}
17 changes: 9 additions & 8 deletions ofdb-frontend/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

173 changes: 173 additions & 0 deletions ofdb-frontend/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
use gloo_storage::{LocalStorage, Storage};
use leptos::*;
use leptos_router::*;

use ofdb_boundary::{MapBbox, MapPoint, User};
use ofdb_frontend_api as api;

mod pages;
use pages::*;

mod components;
use components::*;

const DEFAULT_API_URL: &str = "/api";
const API_TOKEN_STORAGE_KEY: &str = "api-token";
const DEFAULT_BBOX: MapBbox = MapBbox {
sw: MapPoint {
lat: 43.0,
lng: -16.0,
},
ne: MapPoint {
lat: 60.0,
lng: 25.0,
},
};

#[component]
pub fn App() -> impl IntoView {
// -- signals -- //

let user_api = create_rw_signal(None::<api::UserApi>);
let user_info = create_rw_signal(None::<User>);
let logged_in = Signal::derive(move || user_api.get().is_some());
let (bbox, _) = create_signal(DEFAULT_BBOX);

// -- signal modifiers -- //

let clear_user_data = move || {
user_api.update(|a| *a = None);
user_info.update(|i| *i = None);
};

// -- actions -- //

let fetch_user_info = create_action(move |_| async move {
match user_api.get() {
Some(api) => match api.user_info().await {
Ok(info) => {
user_info.update(|i| *i = Some(info));
}
Err(err) => {
log::error!("Unable to fetch user info: {err}");
clear_user_data();
}
},
None => {
log::error!("Unable to fetch user info: not logged in")
}
}
});

let logout = create_action(move |_| async move {
match user_api.get() {
Some(api) => match api.logout().await {
Ok(_) => {
clear_user_data();
}
Err(err) => {
log::error!("Unable to logout: {err}")
}
},
None => {
log::error!("Unable to logout user: not logged in")
}
}
});

// -- callbacks -- //

let on_logout = move || {
logout.dispatch(());
};

// -- init API -- //

let public_api = api::PublicApi::new(DEFAULT_API_URL);

if let Ok(token) = LocalStorage::get(API_TOKEN_STORAGE_KEY) {
let api = api::UserApi::new(DEFAULT_API_URL, token);
user_api.update(|a| *a = Some(api));
fetch_user_info.dispatch(());
}

log::debug!("User is logged in: {}", logged_in.get());

// -- effects -- //

create_effect(move |_| {
log::debug!("API authorization state changed");
match user_api.get() {
Some(api) => {
log::debug!("API is now authorized: save token in LocalStorage");
LocalStorage::set(API_TOKEN_STORAGE_KEY, api.token()).expect("LocalStorage::set");
}
None => {
log::debug!("API is no longer authorized: delete token from LocalStorage");
LocalStorage::delete(API_TOKEN_STORAGE_KEY);
}
}
});

view! {
<Router>
<NavBar user = user_info.into() on_logout />
<main>
<Routes>
<Route
path=Page::Home.path()
view=move || view! { <Home public_api bbox /> }
/>
<Route
path=Page::Login.path()
view=move || view! {
<Login
public_api
on_success = move |api| {
log::info!("Successfully logged in");
user_api.update(|v| *v = Some(api));
let navigate = use_navigate();
navigate(Page::Dashboard.path(), Default::default());
fetch_user_info.dispatch(());
} />
}
/>
<Route
path=Page::Register.path()
view=move || view! { <Register public_api /> }
/>
<Route
path=Page::ResetPassword.path()
view=move|| view! { <ResetPassword public_api /> }
/>
<Route
path=Page::Dashboard.path()
view=move|| view! {
<Dashboard
public_api
user_api = user_api.into()
/>
}
/>
<Route
path=format!("{}/:id", Page::Entries.path())
view=move|| view! { <Entry public_api /> }
/>
<Route
path=Page::Events.path()
view=move|| view! { <Events public_api /> }
/>
<Route
path=format!("{}/:id", Page::Events.path())
view=move|| view! {
<Event
public_api
user_api = user_api.into()
/>
}
/>
</Routes>
</main>
</Router>
}
}
Loading

0 comments on commit 518be54

Please sign in to comment.