1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
extern crate console_error_panic_hook;
use crate::pdfgen;
use wasm_bindgen::prelude::*;
use js_sys;
use yew::prelude::*;
use vcard::{VCard, VCardError};
use std::panic;
fn init() {
panic::set_hook(Box::new(console_error_panic_hook::hook));
}
pub struct Form {
link: ComponentLink<Self>,
error: Option<String>,
formatted_name: String,
generated_vcard: Option<String>,
}
pub enum Msg {
UpdateFormattedName(String),
GenerateVCard,
Nope,
}
impl Component for Form {
type Message = Msg;
type Properties = ();
fn create(_props: Self::Properties, link: ComponentLink<Self>) -> Self {
Self { link, error: None, formatted_name: String::new(), generated_vcard: None }
}
fn update(&mut self, msg: Self::Message) -> ShouldRender {
match msg {
Msg::UpdateFormattedName(value) => self.formatted_name = String::from(value),
Msg::GenerateVCard => {
match self.generate_vcard() {
Ok(vcard) => self.generated_vcard = Some(vcard.to_string()),
Err(VCardError::FormatError(err)) => self.error = Some(err.to_string()),
Err(VCardError::EmptyFormatName) => self.error = Some(String::from("A VCard should have at least one formatted name.")),
};
}
Msg::Nope => (),
};
true
}
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
false
}
fn view(&self) -> Html {
let formatted_name_input = self.link.callback(|e: ChangeData|
match e {
ChangeData::Value(v) => Msg::UpdateFormattedName(v),
_ => Msg::Nope,
}
);
html!{
<div id="form" >
{ self.render_error() }
<label for="formatted_name">{ "Formatted Name" }</label>
<input type="text" id="formatted_name" onchange=formatted_name_input/>
<input id="prefix"/>
<input id="first_name"/>
<input id="middle_name"/>
<input id="last_name"/>
<input id="suffix"/>
<button id="generate-vcard" class="button primary small" onclick=self.link.callback(|_| Msg::GenerateVCard)>{ "Generate VCard" }</button>
{ self.render_pdf() } { self.render_vcard() }
</div>
}
}
}
impl Form {
fn generate_vcard(&self) -> Result<VCard, VCardError> {
match VCard::from_formatted_name_str(&self.formatted_name) {
Ok(vcard) => Ok(vcard),
Err(err) => Err(err),
}
}
fn render_error(&self) -> Html {
if self.error.is_some() {
html!{
<div class="alert danger">
<p>{ self.error.as_ref().unwrap() }</p>
</div>
}
} else {
html!{}
}
}
fn render_pdf(&self) -> Html {
let raw = pdfgen::genpdf();
let data = base64::encode(&raw);
let uri_component: String = js_sys::encode_uri_component(&data).into();
let href = format!{"data:application/pdf;base64,{}", uri_component };
html!{
<a href=href download="demo.pdf" class="button success small" >
{ "Download PDF" }
</a>
}
}
fn render_vcard(&self) -> Html {
if self.generated_vcard.is_some() {
let data = base64::encode(self.generated_vcard.as_ref().unwrap());
let uri_component: String = js_sys::encode_uri_component(&data).into();
let href = format!("data:text/vcard;base64,{}", uri_component);
html!{
<a href=href download=format!("{}.vcs",self.formatted_name) class="button success small">
{ "Download vCard" }
</a>
}
} else {
html!{}
}
}
}
#[wasm_bindgen(start)]
pub fn run_app() {
init();
App::<Form>::new().mount_to_body();
}
|