synpad 0.1.0

A full-featured Matrix chat client built with Dioxus
use dioxus::prelude::*;

use crate::components::modal::Modal;
use crate::state::app_state::AppState;

/// Rageshake / bug report dialog.
/// Collects debug information and optionally sends it to a server.
#[component]
pub fn RageshakeDialog(on_close: EventHandler<()>) -> Element {
    let state = use_context::<Signal<AppState>>();
    let mut description = use_signal(|| String::new());
    let mut include_logs = use_signal(|| true);
    let include_screenshot = use_signal(|| false);
    let mut sending = use_signal(|| false);
    let mut sent = use_signal(|| false);
    let mut error = use_signal(|| Option::<String>::None);

    // Collect debug info
    let user_id = state
        .read()
        .user_profile
        .as_ref()
        .and_then(|p| p.user_id.as_ref())
        .map(|u| u.to_string())
        .unwrap_or_default();
    let sync_status = format!("{:?}", state.read().sync_status);
    let room_count = state.read().rooms.len();

    let on_send = move |_| {
        if description.read().trim().is_empty() {
            error.set(Some("Please describe the issue".to_string()));
            return;
        }
        sending.set(true);
        error.set(None);

        let desc = description.read().clone();
        let logs = *include_logs.read();
        let screenshot = *include_screenshot.read();

        spawn(async move {
            // Collect debug data
            let debug_info = collect_debug_info().await;

            // In a full implementation, this would POST to a rageshake server
            // (e.g., https://rageshake.element.io/api/submit)
            tracing::info!(
                "Bug report submitted: desc='{}', include_logs={}, include_screenshot={}, debug_info_len={}",
                desc, logs, screenshot, debug_info.len()
            );

            // Save locally as a fallback
            if let Ok(dir) = std::env::current_dir() {
                let report_path = dir.join("bug_report.txt");
                let report = format!(
                    "Bug Report\n\
                     ===========\n\
                     Description: {}\n\
                     \n\
                     Debug Info:\n\
                     {}\n",
                    desc, debug_info
                );
                if let Err(e) = tokio::fs::write(&report_path, &report).await {
                    tracing::error!("Failed to save bug report: {e}");
                    error.set(Some(format!("Failed to save report: {e}")));
                    sending.set(false);
                    return;
                }
                tracing::info!("Bug report saved to {}", report_path.display());
            }

            sending.set(false);
            sent.set(true);
        });
    };

    rsx! {
        Modal {
            title: "Submit Bug Report".to_string(),
            on_close: move |_| on_close.call(()),

            div {
                class: "rageshake",

                if *sent.read() {
                    div {
                        class: "rageshake__success",
                        h4 { "Report Submitted" }
                        p { "Thank you for your report! Bug report has been saved locally." }
                        button {
                            class: "btn btn--primary",
                            onclick: move |_| on_close.call(()),
                            "Close"
                        }
                    }
                } else {
                    div {
                        class: "rageshake__form",

                        p { class: "rageshake__description",
                            "Describe the issue you're experiencing. Debug information will be collected automatically."
                        }

                        textarea {
                            class: "settings-textarea rageshake__input",
                            placeholder: "Describe what happened...",
                            rows: "6",
                            value: "{description}",
                            oninput: move |evt| description.set(evt.value()),
                        }

                        div {
                            class: "rageshake__options",
                            label {
                                class: "settings-toggle",
                                input {
                                    r#type: "checkbox",
                                    checked: *include_logs.read(),
                                    oninput: move |evt| include_logs.set(evt.checked()),
                                }
                                span { "Include logs" }
                            }
                        }

                        // Debug summary
                        div {
                            class: "rageshake__debug-info",
                            h4 { "Debug Information" }
                            div {
                                class: "rageshake__debug-item",
                                span { "User: " } span { "{user_id}" }
                            }
                            div {
                                class: "rageshake__debug-item",
                                span { "Sync: " } span { "{sync_status}" }
                            }
                            div {
                                class: "rageshake__debug-item",
                                span { "Rooms: " } span { "{room_count}" }
                            }
                            div {
                                class: "rageshake__debug-item",
                                span { "Platform: " } span { "{std::env::consts::OS}" }
                            }
                            div {
                                class: "rageshake__debug-item",
                                span { "Version: " }
                                span { {env!("CARGO_PKG_VERSION")} }
                            }
                        }

                        if let Some(ref err) = *error.read() {
                            div { class: "rageshake__error", "{err}" }
                        }

                        div {
                            class: "rageshake__actions",
                            button {
                                class: "btn btn--secondary",
                                onclick: move |_| on_close.call(()),
                                "Cancel"
                            }
                            button {
                                class: "btn btn--primary",
                                disabled: *sending.read(),
                                onclick: on_send,
                                if *sending.read() { "Submitting..." } else { "Submit Report" }
                            }
                        }
                    }
                }
            }
        }
    }
}

/// Collect debug information for a bug report.
async fn collect_debug_info() -> String {
    let mut info = String::new();
    info.push_str(&format!("Netrix v{}\n", env!("CARGO_PKG_VERSION")));
    info.push_str(&format!("OS: {} {}\n", std::env::consts::OS, std::env::consts::ARCH));
    info.push_str(&format!(
        "Time: {}\n",
        chrono::Local::now().format("%Y-%m-%d %H:%M:%S %z")
    ));

    // Memory info (approximate)
    #[cfg(target_os = "windows")]
    {
        info.push_str("Platform: Windows\n");
    }
    #[cfg(target_os = "macos")]
    {
        info.push_str("Platform: macOS\n");
    }
    #[cfg(target_os = "linux")]
    {
        info.push_str("Platform: Linux\n");
    }

    info
}