telegram_webapp_sdk/api/
user.rs

1// SPDX-FileCopyrightText: 2025 RAprogramm <andrey.rozanov.vl@gmail.com>
2// SPDX-License-Identifier: MIT
3
4use js_sys::{Function, Reflect};
5use wasm_bindgen::{JsCast, prelude::*};
6use web_sys::window;
7
8/// Calls `Telegram.WebApp.requestContact()`.
9///
10/// Requires the user's explicit permission to share their contact information.
11///
12/// # Errors
13/// Returns `Err(JsValue)` if `Telegram.WebApp` or the method is unavailable, or
14/// if the call fails.
15///
16/// # Examples
17/// ```no_run
18/// use telegram_webapp_sdk::api::user::request_contact;
19///
20/// let _ = request_contact();
21/// ```
22pub fn request_contact() -> Result<(), JsValue> {
23    let webapp = webapp_object()?;
24    let func =
25        Reflect::get(&webapp, &JsValue::from_str("requestContact"))?.dyn_into::<Function>()?;
26    func.call0(&webapp)?;
27    Ok(())
28}
29
30/// Calls `Telegram.WebApp.requestPhoneNumber()`.
31///
32/// Requires the user's explicit permission to share their phone number.
33///
34/// # Errors
35/// Returns `Err(JsValue)` if `Telegram.WebApp` or the method is unavailable, or
36/// if the call fails.
37///
38/// # Examples
39/// ```no_run
40/// use telegram_webapp_sdk::api::user::request_phone_number;
41///
42/// let _ = request_phone_number();
43/// ```
44pub fn request_phone_number() -> Result<(), JsValue> {
45    let webapp = webapp_object()?;
46    let func =
47        Reflect::get(&webapp, &JsValue::from_str("requestPhoneNumber"))?.dyn_into::<Function>()?;
48    func.call0(&webapp)?;
49    Ok(())
50}
51
52/// Calls `Telegram.WebApp.openContact()`.
53///
54/// Requires the user's permission to open the contact interface in Telegram.
55///
56/// # Errors
57/// Returns `Err(JsValue)` if `Telegram.WebApp` or the method is unavailable, or
58/// if the call fails.
59///
60/// # Examples
61/// ```no_run
62/// use telegram_webapp_sdk::api::user::open_contact;
63///
64/// let _ = open_contact();
65/// ```
66pub fn open_contact() -> Result<(), JsValue> {
67    let webapp = webapp_object()?;
68    let func = Reflect::get(&webapp, &JsValue::from_str("openContact"))?.dyn_into::<Function>()?;
69    func.call0(&webapp)?;
70    Ok(())
71}
72
73fn webapp_object() -> Result<JsValue, JsValue> {
74    let win = window().ok_or_else(|| JsValue::from_str("no window"))?;
75    let tg = Reflect::get(&win, &JsValue::from_str("Telegram"))?;
76    Reflect::get(&tg, &JsValue::from_str("WebApp"))
77}
78
79#[cfg(test)]
80mod tests {
81    use js_sys::{Function, Object, Reflect};
82    use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure};
83    use web_sys::window;
84
85    use super::*;
86
87    wasm_bindgen_test_configure!(run_in_browser);
88
89    #[allow(dead_code)]
90    fn setup_webapp() -> Object {
91        let win = window().unwrap();
92        let telegram = Object::new();
93        let webapp = Object::new();
94        let _ = Reflect::set(&win, &"Telegram".into(), &telegram);
95        let _ = Reflect::set(&telegram, &"WebApp".into(), &webapp);
96        webapp
97    }
98
99    #[wasm_bindgen_test]
100    #[allow(dead_code, clippy::unused_unit)]
101    fn request_contact_ok() {
102        let webapp = setup_webapp();
103        let func = Function::new_no_args("this.called = true;");
104        let _ = Reflect::set(&webapp, &"requestContact".into(), &func);
105        assert!(request_contact().is_ok());
106        assert!(
107            Reflect::get(&webapp, &"called".into())
108                .unwrap()
109                .as_bool()
110                .unwrap()
111        );
112    }
113
114    #[wasm_bindgen_test]
115    #[allow(dead_code, clippy::unused_unit)]
116    fn request_contact_err() {
117        let _ = setup_webapp();
118        assert!(request_contact().is_err());
119    }
120
121    #[wasm_bindgen_test]
122    #[allow(dead_code, clippy::unused_unit)]
123    fn request_phone_number_ok() {
124        let webapp = setup_webapp();
125        let func = Function::new_no_args("this.called = true;");
126        let _ = Reflect::set(&webapp, &"requestPhoneNumber".into(), &func);
127        assert!(request_phone_number().is_ok());
128        assert!(
129            Reflect::get(&webapp, &"called".into())
130                .unwrap()
131                .as_bool()
132                .unwrap()
133        );
134    }
135
136    #[wasm_bindgen_test]
137    #[allow(dead_code, clippy::unused_unit)]
138    fn request_phone_number_err() {
139        let _ = setup_webapp();
140        assert!(request_phone_number().is_err());
141    }
142
143    #[wasm_bindgen_test]
144    #[allow(dead_code, clippy::unused_unit)]
145    fn open_contact_ok() {
146        let webapp = setup_webapp();
147        let func = Function::new_no_args("this.called = true;");
148        let _ = Reflect::set(&webapp, &"openContact".into(), &func);
149        assert!(open_contact().is_ok());
150        assert!(
151            Reflect::get(&webapp, &"called".into())
152                .unwrap()
153                .as_bool()
154                .unwrap()
155        );
156    }
157
158    #[wasm_bindgen_test]
159    #[allow(dead_code, clippy::unused_unit)]
160    fn open_contact_err() {
161        let _ = setup_webapp();
162        assert!(open_contact().is_err());
163    }
164}