diff options
Diffstat (limited to 'src/view.rs')
-rw-r--r-- | src/view.rs | 136 |
1 files changed, 108 insertions, 28 deletions
diff --git a/src/view.rs b/src/view.rs index 281cb63..8da1a6c 100644 --- a/src/view.rs +++ b/src/view.rs @@ -1,4 +1,6 @@ extern crate console_error_panic_hook; +use qrcodegen::QrCode; +use qrcodegen::QrCodeEcc; use crate::pdfgen; use wasm_bindgen::prelude::*; use js_sys; @@ -12,14 +14,17 @@ fn init() { pub struct Form { link: ComponentLink<Self>, - error: Option<String>, + error: Vec<String>, formatted_name: String, - generated_vcard: Option<String>, + vcard: Option<String>, + qr_code: Option<String>, } pub enum Msg { UpdateFormattedName(String), GenerateVCard, + GeneratePdf, + GenerateQrCode, Nope, } @@ -28,21 +33,42 @@ impl Component for Form { type Properties = (); fn create(_props: Self::Properties, link: ComponentLink<Self>) -> Self { - Self { link, error: None, formatted_name: String::new(), generated_vcard: None } + Self { link, error: vec![], formatted_name: String::new(), vcard: None, qr_code: None } } fn update(&mut self, msg: Self::Message) -> ShouldRender { + self.error.clear(); 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.")), + Ok(vcard) => self.vcard = Some(vcard.to_string()), + Err(VCardError::FormatError(err)) => self.error.push(err.to_string()), + Err(VCardError::EmptyFormatName) => self.error.push(String::from("A VCard should have at least one formatted name.")), }; } - Msg::Nope => (), + Msg::GeneratePdf => { + + } + Msg::GenerateQrCode => { + match self.generate_vcard() { + Ok(vcard) => self.vcard = Some(vcard.to_string()), + Err(VCardError::FormatError(err)) => self.error.push(err.to_string()), + Err(VCardError::EmptyFormatName) => self.error.push(String::from("A VCard should have at least one formatted name.")), + }; + if self.vcard.is_some() { + match QrCode::encode_text(self.vcard.as_ref().unwrap(), QrCodeEcc::Low) { + Ok(qr) => self.qr_code = Some(qr.to_svg_string(4)), + Err(_) => self.error.push(String::from("Sorry, VCard is too long!")), + }; + } + } + Msg::Nope => return false, }; + if self.error.len() > 0 { + self.vcard = None; + self.qr_code = None; + } true } @@ -52,26 +78,63 @@ impl Component for Form { fn view(&self) -> Html { - let formatted_name_input = self.link.callback(|e: ChangeData| + let formatted_name_input = self.link.batch_callback(|e: InputData| + vec![Msg::UpdateFormattedName(e.value), Msg::GenerateVCard] + ); + + let download_options = self.link.callback(|e: ChangeData| match e { - ChangeData::Value(v) => Msg::UpdateFormattedName(v), + ChangeData::Select(v) => match v.value().as_str() { + "vcard" => Msg::GenerateVCard, + "pdf" => Msg::GeneratePdf, + "qrcode" => Msg::GenerateQrCode, + _ => Msg::Nope, + }, _ => Msg::Nope, } ); html!{ - <div id="form" > + <div class="container"> + <div class="banner row"> + <div class="span twelve"> + <h4>{ "A Generator for vCards" }</h4> + <h5>{ "Supports generating vCards (.vcf), print-ready PDF business cards and QR Codes" }</h5> + </div> + </div> { 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> + <h4 class="explainer">{ "Name" }</h4> + <form class="row"> + <label for="formatted_name">{ "Formatted name: " }</label> + <input id="formatted_name" type="text" oninput=formatted_name_input/> + <br/> + <label for="prefix">{ "Prefix: " }</label> + <input id="prefix" type="text"/> + <br/> + <label for="first_name">{ "First name: " }</label> + <input id="first_name" type="text"/> + + <label for="middle_name">{ "Middle name: " }</label> + <input id="middle_name" type="text"/> + + <label for="last_name">{ "Last name: " }</label> + <input id="last_name" type="text"/> + <br/> + <label for="suffix">{ "Suffix: " }</label> + <input id="suffix" type="text"/> + </form> + <select id="download_options" onchange=download_options> + <option value="">{ "" }</option> + <option value="vcard">{ "VCard (.vcf)" }</option> + <option value="pdf">{ "Print-ready PDF" }</option> + <option value="qrcode">{ "QR Code" }</option> + </select> { self.render_pdf() } { self.render_vcard() } + + <div class="row"> + { self.render_qrcode() } + </div> </div> } } @@ -85,14 +148,18 @@ impl Form { } } 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!{} + html!{ + <> + { + for self.error.iter().map(|err| + html!{ + <div class="alert danger"> + <p>{ err }</p> + </div> + } + ) + } + </> } } fn render_pdf(&self) -> Html { @@ -108,8 +175,8 @@ impl Form { } } fn render_vcard(&self) -> Html { - if self.generated_vcard.is_some() { - let data = base64::encode(self.generated_vcard.as_ref().unwrap()); + if self.vcard.is_some() { + let data = base64::encode(self.vcard.as_ref().unwrap()); let uri_component: String = js_sys::encode_uri_component(&data).into(); let href = format!("data:text/vcard;base64,{}", uri_component); @@ -122,6 +189,19 @@ impl Form { html!{} } } + fn render_qrcode(&self) -> Html { + if self.qr_code.is_some() { + let data = base64::encode(self.qr_code.as_ref().unwrap()); + let uri_component: String = js_sys::encode_uri_component(&data).into(); + let src = format!("data:image/svg+xml;base64,{}", uri_component); + + html!{ + <img src=src alt="QR Code" width="200" height="200"/> + } + } else { + html!{} + } + } } |