2023-07-03 23:20:19 +02:00
|
|
|
use std::{
|
|
|
|
|
cell::{Cell, Ref, RefCell},
|
|
|
|
|
collections::HashSet,
|
|
|
|
|
rc::Rc,
|
|
|
|
|
sync::Arc,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use dioxus::prelude::*;
|
2023-08-05 12:54:49 +02:00
|
|
|
use dioxus_router::prelude::*;
|
2023-07-03 23:20:19 +02:00
|
|
|
use gloo_storage::{errors::StorageError, LocalStorage, Storage};
|
|
|
|
|
use uuid::Uuid;
|
|
|
|
|
|
2023-08-05 12:54:49 +02:00
|
|
|
use crate::{HouseholdInfo, LoginInfo, Route};
|
|
|
|
|
|
|
|
|
|
#[derive(Props)]
|
|
|
|
|
pub struct RedirectorProps<'a> {
|
|
|
|
|
children: Element<'a>,
|
|
|
|
|
}
|
2023-07-03 23:20:19 +02:00
|
|
|
|
|
|
|
|
pub struct RefreshHandle {
|
|
|
|
|
run: Box<dyn FnOnce()>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl RefreshHandle {
|
|
|
|
|
pub fn refresh(self) {
|
|
|
|
|
(self.run)()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
|
pub struct FullContextState<'a> {
|
|
|
|
|
root: &'a ProvidedFullContext,
|
|
|
|
|
value: &'a Rc<RefCell<FullContext>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> FullContextState<'a> {
|
|
|
|
|
pub fn read(&self) -> Ref<'_, FullContext> {
|
|
|
|
|
self.value.borrow()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn refresh(&self) {
|
|
|
|
|
let r = self.root.borrow();
|
|
|
|
|
|
|
|
|
|
r.needs_regen.set(true);
|
|
|
|
|
(r.update_root)();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn refresh_handle(&self) -> RefreshHandle {
|
|
|
|
|
let r = self.root.clone();
|
|
|
|
|
RefreshHandle {
|
|
|
|
|
run: Box::new(move || {
|
|
|
|
|
let root = r.borrow();
|
|
|
|
|
root.needs_regen.set(true);
|
|
|
|
|
(root.update_root)();
|
|
|
|
|
}),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct FullContextStateInner {
|
|
|
|
|
root: ProvidedFullContext,
|
|
|
|
|
value: Rc<RefCell<FullContext>>,
|
|
|
|
|
scope_id: ScopeId,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Drop for FullContextStateInner {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
let mut root = self.root.borrow_mut();
|
|
|
|
|
root.consumers.remove(&self.scope_id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn use_full_context(cx: &ScopeState) -> FullContextState {
|
|
|
|
|
let state = cx.use_hook(|| {
|
|
|
|
|
let scope_id = cx.scope_id();
|
|
|
|
|
let root = cx
|
|
|
|
|
.consume_context::<ProvidedFullContext>()
|
|
|
|
|
.expect("Called use_full_context not in a full context scope");
|
|
|
|
|
|
|
|
|
|
let mut r = root.borrow_mut();
|
|
|
|
|
|
|
|
|
|
r.consumers.insert(scope_id);
|
|
|
|
|
let value = r.value.clone();
|
|
|
|
|
|
|
|
|
|
drop(r);
|
|
|
|
|
FullContextStateInner {
|
|
|
|
|
root,
|
|
|
|
|
value,
|
|
|
|
|
scope_id,
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
FullContextState {
|
|
|
|
|
root: &state.root,
|
|
|
|
|
value: &state.value,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn use_trimmed_context(cx: &ScopeState) -> (String, Uuid) {
|
|
|
|
|
let binding = use_full_context(cx);
|
|
|
|
|
let ctx = binding.read();
|
|
|
|
|
|
|
|
|
|
(ctx.login.token.clone(), ctx.household.id)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct FullContext {
|
|
|
|
|
pub login: LoginInfo,
|
|
|
|
|
pub household: HouseholdInfo,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type ProvidedFullContext = Rc<RefCell<ProvidedFullContextInner>>;
|
|
|
|
|
|
|
|
|
|
struct ProvidedFullContextInner {
|
|
|
|
|
value: Rc<RefCell<FullContext>>,
|
|
|
|
|
notify_any: Arc<dyn Fn(ScopeId)>,
|
|
|
|
|
consumers: HashSet<ScopeId>,
|
|
|
|
|
needs_regen: Cell<bool>,
|
|
|
|
|
update_root: Arc<dyn Fn()>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ProvidedFullContextInner {
|
|
|
|
|
fn notify_consumers(&mut self) {
|
|
|
|
|
for &consumer in &self.consumers {
|
|
|
|
|
(self.notify_any)(consumer)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn use_full_context_setter(cx: &ScopeState) {
|
|
|
|
|
let gen = || {
|
|
|
|
|
let login = LocalStorage::get::<LoginInfo>("token").expect("Not called in a full context");
|
|
|
|
|
let household =
|
|
|
|
|
LocalStorage::get::<HouseholdInfo>("household").expect("Not called in a full context");
|
|
|
|
|
|
|
|
|
|
FullContext { login, household }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let hook = cx.use_hook(move || {
|
|
|
|
|
let state = Rc::new(RefCell::new(ProvidedFullContextInner {
|
|
|
|
|
value: Rc::new(RefCell::new(gen())),
|
|
|
|
|
consumers: HashSet::new(),
|
|
|
|
|
notify_any: cx.schedule_update_any(),
|
|
|
|
|
update_root: cx.schedule_update(),
|
|
|
|
|
needs_regen: Cell::new(false),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
cx.provide_context(state.clone());
|
|
|
|
|
|
|
|
|
|
state
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if hook.borrow().needs_regen.get() {
|
|
|
|
|
let mut hook = (**hook).borrow_mut();
|
|
|
|
|
*(*hook.value).borrow_mut() = gen();
|
|
|
|
|
hook.notify_consumers();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn FullContextRedirectInner<'a>(cx: Scope<'a, RedirectorProps<'a>>) -> Element {
|
|
|
|
|
use_full_context_setter(cx);
|
|
|
|
|
|
|
|
|
|
cx.render(rsx! {&cx.props.children})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn FullContextRedirect<'a>(cx: Scope<'a, RedirectorProps<'a>>) -> Element {
|
2023-08-05 12:54:49 +02:00
|
|
|
let navigator = use_navigator(cx);
|
2023-07-03 23:20:19 +02:00
|
|
|
|
|
|
|
|
let check_token = match LocalStorage::get::<LoginInfo>("token") {
|
|
|
|
|
Ok(_) => true,
|
|
|
|
|
Err(StorageError::KeyNotFound(_)) => {
|
2023-08-05 12:54:49 +02:00
|
|
|
navigator.push(Route::Login);
|
2023-07-03 23:20:19 +02:00
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
Err(e) => unreachable!("Could not get token: {e:?}"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let check_household = match LocalStorage::get::<HouseholdInfo>("household") {
|
|
|
|
|
Ok(_) => true,
|
|
|
|
|
Err(StorageError::KeyNotFound(_)) => {
|
2023-08-05 12:54:49 +02:00
|
|
|
navigator.push(Route::HouseholdSelection);
|
2023-07-03 23:20:19 +02:00
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
Err(e) => unreachable!("Could not get household: {e:?}"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if check_token && check_household {
|
|
|
|
|
cx.render(rsx! {
|
|
|
|
|
FullContextRedirectInner { &cx.props.children }
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|