diff options
Diffstat (limited to 'src/model/property_groups')
-rw-r--r-- | src/model/property_groups/address.rs | 155 | ||||
-rw-r--r-- | src/model/property_groups/mod.rs | 5 | ||||
-rw-r--r-- | src/model/property_groups/name.rs | 150 | ||||
-rw-r--r-- | src/model/property_groups/organizational.rs | 121 | ||||
-rw-r--r-- | src/model/property_groups/other_identification.rs | 117 | ||||
-rw-r--r-- | src/model/property_groups/telephone.rs | 147 |
6 files changed, 695 insertions, 0 deletions
diff --git a/src/model/property_groups/address.rs b/src/model/property_groups/address.rs new file mode 100644 index 0000000..00bca0b --- /dev/null +++ b/src/model/property_groups/address.rs @@ -0,0 +1,155 @@ +use crate::model::input_fields::VCardPropertyInputField; +use crate::model::*; + +#[derive(Clone, Debug, PartialEq)] +pub struct Address { + pub post_office_box: String, + pub extension: String, + pub street: String, + pub locality: String, + pub region: String, + pub code: String, + pub country: String, + pub work: bool, + pub home: bool, +} + +#[derive(Clone, PartialEq)] +pub enum AddressMsg { + UpdatePostOfficeBox(String), + UpdateExtension(String), + UpdateStreet(String), + UpdateLocality(String), + UpdateRegion(String), + UpdateCode(String), + UpdateCountry(String), + ToggleWork, + ToggleHome, + + Generate, +} + +impl VCardPropertyInputGroupObject<AddressMsg> for Address { + fn new() -> Self { + Self { + post_office_box: String::new(), + extension: String::new(), + street: String::new(), + locality: String::new(), + region: String::new(), + code: String::new(), + country: String::new(), + work: false, + home: false, + } + } + fn get_title(&self) -> String { + "Address".to_string() + } + fn get_input_fields( + &self, + link: &ComponentLink<PropertyGroupInputComponent<Self, AddressMsg>>, + ) -> Vec<VCardPropertyInputField> { + let typ = String::from("text"); + vec![ + VCardPropertyInputField::Text { + label: "Post Office Box".to_string(), + id: Some("post_office_box".to_string()), + placeholder: None, + oninput: link.callback(|e: InputData| AddressMsg::UpdatePostOfficeBox(e.value)), + value: self.post_office_box.clone(), + typ: typ.clone(), + }, + VCardPropertyInputField::Text { + label: "Extension".to_string(), + id: Some("extension".to_string()), + placeholder: None, + oninput: link.callback(|e: InputData| AddressMsg::UpdateExtension(e.value)), + value: self.extension.clone(), + typ: typ.clone(), + }, + VCardPropertyInputField::Text { + label: "Street".to_string(), + id: Some("street".to_string()), + placeholder: None, + oninput: link.callback(|e: InputData| AddressMsg::UpdateStreet(e.value)), + value: self.street.clone(), + typ: typ.clone(), + }, + VCardPropertyInputField::Text { + label: "Locality".to_string(), + id: Some("locality".to_string()), + placeholder: None, + oninput: link.callback(|e: InputData| AddressMsg::UpdateLocality(e.value)), + value: self.locality.clone(), + typ: typ.clone(), + }, + VCardPropertyInputField::Text { + label: "Region".to_string(), + id: Some("region".to_string()), + placeholder: None, + oninput: link.callback(|e: InputData| AddressMsg::UpdateRegion(e.value)), + value: self.region.clone(), + typ: typ.clone(), + }, + VCardPropertyInputField::Text { + label: "Code".to_string(), + id: Some("code".to_string()), + placeholder: None, + oninput: link.callback(|e: InputData| AddressMsg::UpdateCode(e.value)), + value: self.code.clone(), + typ: typ.clone(), + }, + VCardPropertyInputField::Text { + label: "Country".to_string(), + id: Some("country".to_string()), + placeholder: None, + oninput: link.callback(|e: InputData| AddressMsg::UpdateCountry(e.value)), + value: self.country.clone(), + typ, + }, + VCardPropertyInputField::CheckBox { + label: "Work".to_string(), + id: Some("work".to_string()), + onclick: link.callback(|_: MouseEvent| AddressMsg::ToggleWork), + value: self.work, + }, + VCardPropertyInputField::CheckBox { + label: "Home".to_string(), + id: Some("home".to_string()), + onclick: link.callback(|_: MouseEvent| AddressMsg::ToggleHome), + value: self.home, + }, + ] + } + fn update( + &mut self, + props: InputProps<Self, AddressMsg>, + msg: <PropertyGroupInputComponent<Self, AddressMsg> as yew::Component>::Message, + ) -> bool { + match msg { + AddressMsg::UpdatePostOfficeBox(b) => self.post_office_box = b, + AddressMsg::UpdateExtension(e) => self.extension = e, + AddressMsg::UpdateStreet(s) => self.street = s, + AddressMsg::UpdateLocality(l) => self.locality = l, + AddressMsg::UpdateRegion(r) => self.region = r, + AddressMsg::UpdateCode(p) => self.code = p, + AddressMsg::UpdateCountry(c) => self.country = c, + AddressMsg::ToggleWork => self.work = !self.work, + AddressMsg::ToggleHome => self.home = !self.home, + AddressMsg::Generate => { + props.generated.emit(self.clone()); + } + }; + true + } + fn is_empty(&self) -> bool { + self.post_office_box.is_empty() + && self.extension.is_empty() + && self.street.is_empty() + && self.locality.is_empty() + && self.region.is_empty() + && self.code.is_empty() + && self.country.is_empty() + } +} diff --git a/src/model/property_groups/mod.rs b/src/model/property_groups/mod.rs new file mode 100644 index 0000000..3bfc9f3 --- /dev/null +++ b/src/model/property_groups/mod.rs @@ -0,0 +1,5 @@ +pub mod address; +pub mod name; +pub mod organizational; +pub mod other_identification; +pub mod telephone; diff --git a/src/model/property_groups/name.rs b/src/model/property_groups/name.rs new file mode 100644 index 0000000..eb0d9da --- /dev/null +++ b/src/model/property_groups/name.rs @@ -0,0 +1,150 @@ +use crate::model::input_fields::VCardPropertyInputField; +use crate::model::*; + +/// Type that represents a vcard `name` property +/// +/// # Examples +/// ``` +/// # use bcard_wasm_webapp::viewmodel::name::Name; +/// # use crate::bcard_wasm_webapp::viewmodel::VCardPropertyInputObject; +/// let mut name = Name::new(); +/// name.prefix = String::from("Sir"); +/// name.first_name = String::from("Arthur"); +/// name.middle_name = String::from("Charles"); +/// name.last_name = String::from("Clarke"); +/// name.suffix = String::from("CBE FRAS"); +/// +/// assert_eq!(name.generate_fn(), String::from("Sir Arthur Charles Clarke, CBE FRAS")); +/// ``` +#[derive(Clone, Debug, PartialEq)] +pub struct Name { + pub prefix: String, + pub first_name: String, + pub middle_name: String, + pub last_name: String, + pub suffix: String, +} + +#[derive(Clone, PartialEq)] +pub enum NameMsg { + UpdatePrefix(String), + UpdateFirstName(String), + UpdateMiddleName(String), + UpdateLastName(String), + UpdateSuffix(String), + + Generate, +} + +impl VCardPropertyInputGroupObject<NameMsg> for Name { + fn new() -> Self { + Self { + prefix: String::new(), + first_name: String::new(), + middle_name: String::new(), + last_name: String::new(), + suffix: String::new(), + } + } + fn get_title(&self) -> String { + "Name".to_string() + } + fn get_input_fields( + &self, + link: &ComponentLink<PropertyGroupInputComponent<Self, NameMsg>>, + ) -> std::vec::Vec<VCardPropertyInputField> { + let typ = String::from("text"); + vec![ + VCardPropertyInputField::Text { + label: "Prefix".to_string(), + id: Some("prefix".to_string()), + placeholder: Some("Sir".to_string()), + oninput: link.callback(|e: InputData| NameMsg::UpdatePrefix(e.value)), + value: self.prefix.clone(), + typ: typ.clone(), + }, + VCardPropertyInputField::Text { + label: "First Name".to_string(), + id: Some("first_name".to_string()), + placeholder: Some("Arthur".to_string()), + oninput: link.callback(|e: InputData| NameMsg::UpdateFirstName(e.value)), + value: self.first_name.clone(), + typ: typ.clone(), + }, + VCardPropertyInputField::Text { + label: "Middle Name".to_string(), + id: Some("middle_name".to_string()), + placeholder: Some("Charles".to_string()), + oninput: link.callback(|e: InputData| NameMsg::UpdateMiddleName(e.value)), + value: self.middle_name.clone(), + typ: typ.clone(), + }, + VCardPropertyInputField::Text { + label: "Last Name".to_string(), + id: Some("last_name".to_string()), + placeholder: Some("Clarke".to_string()), + oninput: link.callback(|e: InputData| NameMsg::UpdateLastName(e.value)), + value: self.last_name.clone(), + typ: typ.clone(), + }, + VCardPropertyInputField::Text { + label: "Suffix".to_string(), + id: Some("suffix".to_string()), + placeholder: Some("CBE FRAS".to_string()), + oninput: link.callback(|e: InputData| NameMsg::UpdateSuffix(e.value)), + value: self.suffix.clone(), + typ, + }, + ] + } + fn update( + &mut self, + props: InputProps<Self, NameMsg>, + msg: <PropertyGroupInputComponent<Self, NameMsg> as yew::Component>::Message, + ) -> bool { + match msg { + NameMsg::UpdatePrefix(p) => self.prefix = p, + NameMsg::UpdateFirstName(f) => self.first_name = f, + NameMsg::UpdateMiddleName(m) => self.middle_name = m, + NameMsg::UpdateLastName(l) => self.last_name = l, + NameMsg::UpdateSuffix(s) => self.suffix = s, + NameMsg::Generate => { + props.generated.emit(self.clone()); + } + }; + true + } + fn is_empty(&self) -> bool { + self.prefix.is_empty() + && self.first_name.is_empty() + && self.middle_name.is_empty() + && self.last_name.is_empty() + && self.suffix.is_empty() + } +} + +impl Name { + pub fn generate_fn(&self) -> String { + let mut full_name = String::new(); + + full_name.push_str(&self.prefix); + if !self.first_name.is_empty() { + full_name.push_str(" "); + full_name.push_str(&self.first_name); + } + if !self.middle_name.is_empty() { + full_name.push_str(" "); + full_name.push_str(&self.middle_name); + } + if !self.last_name.is_empty() { + full_name.push_str(" "); + full_name.push_str(&self.last_name); + } + if !self.suffix.is_empty() { + full_name.push_str(", "); + full_name.push_str(&self.suffix); + } + + full_name + } +} diff --git a/src/model/property_groups/organizational.rs b/src/model/property_groups/organizational.rs new file mode 100644 index 0000000..1d6ccf2 --- /dev/null +++ b/src/model/property_groups/organizational.rs @@ -0,0 +1,121 @@ +use crate::model::input_fields::VCardPropertyInputField; +use crate::model::*; + +#[derive(Clone, Debug, PartialEq)] +pub struct Organizational { + pub org: String, + pub logo: Option<File>, + pub title: String, + pub role: String, + pub member: String, + pub related: String, +} + +#[derive(Clone, PartialEq)] +pub enum OrganizationalMsg { + UpdateOrg(String), + UpdateLogo(Option<File>), + UpdateTitle(String), + UpdateRole(String), + UpdateMember(String), + UpdateRelated(String), + + Generate, +} + +impl VCardPropertyInputGroupObject<OrganizationalMsg> for Organizational { + fn new() -> Self { + Self { + org: String::new(), + logo: None, + title: String::new(), + role: String::new(), + member: String::new(), + related: String::new(), + } + } + fn get_title(&self) -> std::string::String { + "Organizational".to_string() + } + fn get_input_fields( + &self, + link: &yew::html::Scope<PropertyGroupInputComponent<Self, OrganizationalMsg>>, + ) -> std::vec::Vec<VCardPropertyInputField> { + let typ = String::from("text"); + vec![ + VCardPropertyInputField::Text { + label: "Organisation".to_string(), + id: Some("org".to_string()), + placeholder: None, + oninput: link.callback(|e: InputData| OrganizationalMsg::UpdateOrg(e.value)), + value: self.org.clone(), + typ: typ.clone(), + }, + VCardPropertyInputField::File { + // TODO: Add Upload for logo + label: "Logo".to_string(), + name: "logo".to_string(), + callback: link.callback(|file: Option<File>| OrganizationalMsg::UpdateLogo(file)), + value: self.logo.clone(), + }, + VCardPropertyInputField::Text { + label: "Title".to_string(), + id: Some("title".to_string()), + placeholder: None, + oninput: link.callback(|e: InputData| OrganizationalMsg::UpdateTitle(e.value)), + value: self.title.clone(), + typ: typ.clone(), + }, + VCardPropertyInputField::Text { + label: "Role".to_string(), + id: Some("role".to_string()), + placeholder: None, + oninput: link.callback(|e: InputData| OrganizationalMsg::UpdateRole(e.value)), + value: self.role.clone(), + typ: typ.clone(), + }, + VCardPropertyInputField::Text { + label: "Member".to_string(), + id: Some("member".to_string()), + placeholder: None, + oninput: link.callback(|e: InputData| OrganizationalMsg::UpdateMember(e.value)), + value: self.member.clone(), + typ: typ.clone(), + }, + VCardPropertyInputField::Text { + label: "Related".to_string(), + id: Some("related".to_string()), + placeholder: None, + oninput: link.callback(|e: InputData| OrganizationalMsg::UpdateRelated(e.value)), + value: self.related.clone(), + typ: typ, + }, + ] + } + fn update( + &mut self, + props: InputProps<Self, OrganizationalMsg>, + msg: <PropertyGroupInputComponent<Self, OrganizationalMsg> as yew::Component>::Message, + ) -> bool { + match msg { + OrganizationalMsg::UpdateOrg(o) => self.org = o, + OrganizationalMsg::UpdateLogo(l) => self.logo = l, + OrganizationalMsg::UpdateTitle(t) => self.title = t, + OrganizationalMsg::UpdateRole(r) => self.role = r, + OrganizationalMsg::UpdateMember(m) => self.member = m, + OrganizationalMsg::UpdateRelated(r) => self.related = r, + OrganizationalMsg::Generate => { + props.generated.emit(self.clone()); + } + }; + true + } + fn is_empty(&self) -> bool { + self.org.is_empty() + && self.logo.is_none() + && self.title.is_empty() + && self.role.is_empty() + && self.member.is_empty() + && self.related.is_empty() + } +} diff --git a/src/model/property_groups/other_identification.rs b/src/model/property_groups/other_identification.rs new file mode 100644 index 0000000..ca48375 --- /dev/null +++ b/src/model/property_groups/other_identification.rs @@ -0,0 +1,117 @@ +use crate::model::input_fields::VCardPropertyInputField; +use crate::model::*; + +/// Type that represents the vcard `anniversary` and `birthday` properties. +#[derive(Clone, Debug, PartialEq)] +pub struct OtherIdentification { + pub nickname: String, + pub photo: Option<File>, + pub birthday: String, + pub anniversary: String, + pub gender: String, +} + +#[derive(Clone, PartialEq)] +pub enum OtherIdentificationMsg { + UpdateNickname(String), + UpdatePhoto(Option<File>), + UpdateBirthday(String), + UpdateAnniversary(String), + UpdateGender(String), + + Generate, + + Nope, +} + +impl VCardPropertyInputGroupObject<OtherIdentificationMsg> for OtherIdentification { + fn new() -> Self { + Self { + nickname: String::new(), + photo: None, + birthday: String::new(), + anniversary: String::new(), + gender: String::new(), + } + } + fn get_title(&self) -> std::string::String { + "Other Identification Properties".to_string() + } + fn get_input_fields( + &self, + link: &yew::html::Scope<PropertyGroupInputComponent<Self, OtherIdentificationMsg>>, + ) -> std::vec::Vec<VCardPropertyInputField> { + vec![ + VCardPropertyInputField::Text { + label: String::from("Nickname"), + id: Some(String::from("nickname")), + placeholder: None, + oninput: link + .callback(|e: InputData| OtherIdentificationMsg::UpdateNickname(e.value)), + value: self.nickname.clone(), + typ: String::from("text"), + }, + VCardPropertyInputField::File { + label: String::from("Photo"), + name: String::from("photo"), + callback: link + .callback(|file: Option<File>| OtherIdentificationMsg::UpdatePhoto(file)), + value: self.photo.clone(), + }, + VCardPropertyInputField::Text { + label: "Birthday".to_string(), + id: Some("birthday".to_string()), + placeholder: None, + oninput: link + .callback(|e: InputData| OtherIdentificationMsg::UpdateBirthday(e.value)), + value: self.birthday.clone(), + typ: String::from("date"), + }, + VCardPropertyInputField::Text { + label: "Anniversary".to_string(), + id: Some("anniversary".to_string()), + placeholder: None, + oninput: link + .callback(|e: InputData| OtherIdentificationMsg::UpdateAnniversary(e.value)), + value: self.anniversary.clone(), + typ: String::from("date"), + }, + VCardPropertyInputField::Select { + label: String::from("Gender"), + id: Some(String::from("gender")), + options: vec![ + (String::from(""), String::from("Select one")), + (String::from("M"), String::from("Male")), + (String::from("F"), String::from("Female")), + (String::from("O"), String::from("Other")), + (String::from("N"), String::from("Not applicable")), + (String::from("U"), String::from("Unknown")), + ], + onchange: link.callback(|c: ChangeData| match c { + ChangeData::Select(v) => OtherIdentificationMsg::UpdateGender(v.value()), + _ => OtherIdentificationMsg::Nope, + }), + value: self.gender.clone(), + }, + ] + } + fn update( + &mut self, + props: InputProps<Self, OtherIdentificationMsg>, + msg: <PropertyGroupInputComponent<Self, OtherIdentificationMsg> as yew::Component>::Message, + ) -> bool { + match msg { + OtherIdentificationMsg::UpdateNickname(n) => self.nickname = n, + OtherIdentificationMsg::UpdatePhoto(p) => self.photo = p, + OtherIdentificationMsg::UpdateBirthday(b) => self.birthday = b, + OtherIdentificationMsg::UpdateAnniversary(a) => self.anniversary = a, + OtherIdentificationMsg::UpdateGender(g) => self.gender = g, + OtherIdentificationMsg::Generate => props.generated.emit(self.clone()), + OtherIdentificationMsg::Nope => (), + }; + true + } + fn is_empty(&self) -> bool { + self.anniversary.is_empty() && self.birthday.is_empty() + } +} diff --git a/src/model/property_groups/telephone.rs b/src/model/property_groups/telephone.rs new file mode 100644 index 0000000..03de4ee --- /dev/null +++ b/src/model/property_groups/telephone.rs @@ -0,0 +1,147 @@ +use crate::model::input_fields::VCardPropertyInputField; +use crate::model::*; + +#[derive(Clone, Debug, PartialEq)] +pub struct Telephone { + pub number: String, + pub work: bool, + pub home: bool, + pub text: bool, + pub voice: bool, + pub fax: bool, + pub cell: bool, + pub video: bool, + pub pager: bool, + pub text_phone: bool, +} + +#[derive(Clone, PartialEq)] +pub enum TelephoneMsg { + UpdateNumber(String), + ToggleWork, + ToggleHome, + ToggleText, + ToggleVoice, + ToggleFax, + ToggleCell, + ToggleVideo, + TogglePager, + ToggleTextPhone, + + Generate, +} + +impl VCardPropertyInputGroupObject<TelephoneMsg> for Telephone { + fn new() -> Self { + Self { + number: String::new(), + work: false, + home: false, + text: false, + voice: false, + fax: false, + cell: false, + video: false, + pager: false, + text_phone: false, + } + } + fn get_title(&self) -> String { + "Telephone".to_string() + } + fn get_input_fields( + &self, + link: &ComponentLink<PropertyGroupInputComponent<Self, TelephoneMsg>>, + ) -> Vec<VCardPropertyInputField> { + let typ = String::from("tel"); + vec![ + VCardPropertyInputField::Text { + label: "Number".to_string(), + id: Some("number".to_string()), + placeholder: None, + oninput: link.callback(|e: InputData| TelephoneMsg::UpdateNumber(e.value)), + value: self.number.clone(), + typ, + }, + VCardPropertyInputField::CheckBox { + label: "Work".to_string(), + id: Some("work".to_string()), + onclick: link.callback(|_: MouseEvent| TelephoneMsg::ToggleWork), + value: self.work, + }, + VCardPropertyInputField::CheckBox { + label: "Home".to_string(), + id: Some("home".to_string()), + onclick: link.callback(|_: MouseEvent| TelephoneMsg::ToggleHome), + value: self.home, + }, + VCardPropertyInputField::CheckBox { + label: "Text".to_string(), + id: Some("text".to_string()), + onclick: link.callback(|_: MouseEvent| TelephoneMsg::ToggleText), + value: self.text, + }, + VCardPropertyInputField::CheckBox { + label: "Voice".to_string(), + id: Some("voice".to_string()), + onclick: link.callback(|_: MouseEvent| TelephoneMsg::ToggleVoice), + value: self.voice, + }, + VCardPropertyInputField::CheckBox { + label: "Fax".to_string(), + id: Some("fax".to_string()), + onclick: link.callback(|_: MouseEvent| TelephoneMsg::ToggleFax), + value: self.fax, + }, + VCardPropertyInputField::CheckBox { + label: "Cell".to_string(), + id: Some("cell".to_string()), + onclick: link.callback(|_: MouseEvent| TelephoneMsg::ToggleCell), + value: self.cell, + }, + VCardPropertyInputField::CheckBox { + label: "Video".to_string(), + id: Some("video".to_string()), + onclick: link.callback(|_: MouseEvent| TelephoneMsg::ToggleVideo), + value: self.video, + }, + VCardPropertyInputField::CheckBox { + label: "Pager".to_string(), + id: Some("pager".to_string()), + onclick: link.callback(|_: MouseEvent| TelephoneMsg::TogglePager), + value: self.pager, + }, + VCardPropertyInputField::CheckBox { + label: "Text Phone".to_string(), + id: Some("text_phone".to_string()), + onclick: link.callback(|_: MouseEvent| TelephoneMsg::ToggleTextPhone), + value: self.text_phone, + }, + ] + } + fn update( + &mut self, + props: InputProps<Self, TelephoneMsg>, + msg: <PropertyGroupInputComponent<Self, TelephoneMsg> as yew::Component>::Message, + ) -> bool { + match msg { + TelephoneMsg::UpdateNumber(n) => self.number = n, + TelephoneMsg::ToggleWork => self.work = !self.work, + TelephoneMsg::ToggleHome => self.home = !self.home, + TelephoneMsg::ToggleText => self.text = !self.text, + TelephoneMsg::ToggleVoice => self.voice = !self.voice, + TelephoneMsg::ToggleFax => self.fax = !self.fax, + TelephoneMsg::ToggleCell => self.cell = !self.cell, + TelephoneMsg::ToggleVideo => self.video = !self.video, + TelephoneMsg::TogglePager => self.pager = !self.pager, + TelephoneMsg::ToggleTextPhone => self.text_phone = !self.text_phone, + TelephoneMsg::Generate => { + props.generated.emit(self.clone()); + } + }; + true + } + fn is_empty(&self) -> bool { + self.number.is_empty() + } +} |