use crate::context::ClerkContext;
use crate::core::ClerkError;
use dioxus::prelude::*;
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum ClerkOperation {
OpenSignIn(serde_json::Value),
CloseSignIn,
OpenSignUp(serde_json::Value),
CloseSignUp,
OpenUserProfile(serde_json::Value),
CloseUserProfile,
SignOut(serde_json::Value),
RedirectToSignIn(serde_json::Value),
RedirectToSignUp(serde_json::Value),
}
pub(crate) fn schedule(ctx: ClerkContext, operation: ClerkOperation) {
let mut pending = ctx.pending;
pending.write().push(operation);
}
#[cfg(clerk_client)]
pub(crate) async fn try_run(
ctx: ClerkContext,
operation: ClerkOperation,
) -> Result<(), ClerkError> {
crate::lifecycle::run_async_bridge_action_after_loaded(ctx, move |bridge| async move {
bridge.run(operation).await
})
.await
}
#[cfg(not(clerk_client))]
pub(crate) async fn try_run(
_ctx: ClerkContext,
_operation: ClerkOperation,
) -> Result<(), ClerkError> {
Err(ClerkError::UnsupportedTarget)
}
#[cfg(clerk_client)]
pub(crate) fn use_action_scheduler(ctx: ClerkContext) {
let is_loaded = crate::lifecycle::use_loadedness(ctx);
let mut pending = ctx.pending;
let draining = use_signal(|| false);
use_effect(move || {
if pending.read().is_empty() {
return;
}
if ctx.load_error.read().is_some() {
pending.set(Vec::new());
return;
}
if !*is_loaded.read() {
return;
}
if *draining.peek() {
return;
}
let mut draining = draining;
draining.set(true);
let mut action_error = ctx.action_error;
spawn(async move {
loop {
let actions = std::mem::take(&mut *pending.write());
if actions.is_empty() {
break;
}
for action in actions {
let bridge = crate::bridge::ClerkBridge::current();
if let Err(err) = bridge.run(action).await {
action_error.set(Some(err));
}
}
}
draining.set(false);
});
});
}
#[cfg(all(test, not(clerk_client)))]
mod tests {
use super::*;
use crate::components::ClerkProvider;
use crate::context::use_clerk_context;
use std::cell::RefCell;
thread_local! {
static SEEN: RefCell<Vec<ClerkOperation>> = const { RefCell::new(Vec::new()) };
}
#[component]
fn Probe() -> Element {
let auth = crate::hooks::use_auth();
let clerk = crate::hooks::use_clerk();
use_hook(move || {
auth.sign_out();
clerk.open_sign_in();
clerk.close_sign_up();
});
let ctx = use_clerk_context();
SEEN.with(|seen| *seen.borrow_mut() = ctx.pending.peek().clone());
rsx! { div {} }
}
#[component]
fn App() -> Element {
rsx! {
ClerkProvider { publishable_key: "pk_test_queue", Probe {} }
}
}
#[test]
fn scheduled_operations_share_one_provider_queue_in_request_order() {
SEEN.with(|seen| seen.borrow_mut().clear());
let mut dom = VirtualDom::new(App);
dom.rebuild_in_place();
SEEN.with(|seen| {
assert_eq!(
*seen.borrow(),
vec![
ClerkOperation::SignOut(serde_json::Value::Null),
ClerkOperation::OpenSignIn(serde_json::Value::Null),
ClerkOperation::CloseSignUp,
],
);
});
}
}