adui_dioxus/components/
result.rs1use crate::components::icon::{Icon, IconKind};
2use dioxus::prelude::*;
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6pub enum ResultStatus {
7 Success,
8 Info,
9 Warning,
10 Error,
11 NotFound,
12 Forbidden,
13 ServerError,
14}
15
16impl ResultStatus {
17 fn as_class(&self) -> &'static str {
18 match self {
19 ResultStatus::Success => "adui-result-success",
20 ResultStatus::Info => "adui-result-info",
21 ResultStatus::Warning => "adui-result-warning",
22 ResultStatus::Error => "adui-result-error",
23 ResultStatus::NotFound => "adui-result-404",
24 ResultStatus::Forbidden => "adui-result-403",
25 ResultStatus::ServerError => "adui-result-500",
26 }
27 }
28
29 fn icon_kind(&self) -> IconKind {
30 match self {
31 ResultStatus::Success => IconKind::Check,
32 ResultStatus::Error | ResultStatus::ServerError => IconKind::Close,
33 ResultStatus::Warning | ResultStatus::Forbidden | ResultStatus::NotFound => {
34 IconKind::Info
35 }
36 ResultStatus::Info => IconKind::Info,
37 }
38 }
39}
40
41#[derive(Props, Clone, PartialEq)]
43pub struct ResultProps {
44 #[props(optional)]
46 pub status: Option<ResultStatus>,
47 #[props(optional)]
49 pub icon: Option<Element>,
50 #[props(optional)]
52 pub title: Option<Element>,
53 #[props(optional)]
55 pub sub_title: Option<Element>,
56 #[props(optional)]
58 pub extra: Option<Element>,
59 #[props(optional)]
61 pub class: Option<String>,
62 #[props(optional)]
64 pub style: Option<String>,
65 pub children: Option<Element>,
67}
68
69#[component]
71pub fn Result(props: ResultProps) -> Element {
72 let ResultProps {
73 status,
74 icon,
75 title,
76 sub_title,
77 extra,
78 class,
79 style,
80 children,
81 } = props;
82
83 let status_value = status.unwrap_or(ResultStatus::Info);
84
85 let mut class_list = vec![
86 "adui-result".to_string(),
87 status_value.as_class().to_string(),
88 ];
89 if let Some(extra_class) = class {
90 class_list.push(extra_class);
91 }
92 let class_attr = class_list.join(" ");
93 let style_attr = style.unwrap_or_default();
94
95 let icon_node = icon.map(Some).unwrap_or_else(|| {
96 Some(rsx!(Icon {
97 kind: status_value.icon_kind(),
98 size: 40.0,
99 }))
100 });
101
102 rsx! {
103 div { class: "{class_attr}", style: "{style_attr}",
104 if let Some(node) = icon_node {
105 div { class: "adui-result-icon", {node} }
106 }
107 if let Some(t) = title {
108 div { class: "adui-result-title", {t} }
109 }
110 if let Some(st) = sub_title {
111 div { class: "adui-result-subtitle", {st} }
112 }
113 if let Some(extra_node) = extra {
114 div { class: "adui-result-extra", {extra_node} }
115 }
116 if let Some(content) = children {
117 div { class: "adui-result-content", {content} }
118 }
119 }
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 #[test]
128 fn result_status_class_mapping_is_stable() {
129 assert_eq!(ResultStatus::Success.as_class(), "adui-result-success");
130 assert_eq!(ResultStatus::Info.as_class(), "adui-result-info");
131 assert_eq!(ResultStatus::Warning.as_class(), "adui-result-warning");
132 assert_eq!(ResultStatus::Error.as_class(), "adui-result-error");
133 assert_eq!(ResultStatus::NotFound.as_class(), "adui-result-404");
134 assert_eq!(ResultStatus::Forbidden.as_class(), "adui-result-403");
135 assert_eq!(ResultStatus::ServerError.as_class(), "adui-result-500");
136 }
137
138 #[test]
139 fn result_status_icon_mapping() {
140 assert_eq!(ResultStatus::Success.icon_kind(), IconKind::Check);
141 assert_eq!(ResultStatus::Info.icon_kind(), IconKind::Info);
142 assert_eq!(ResultStatus::Warning.icon_kind(), IconKind::Info);
143 assert_eq!(ResultStatus::Error.icon_kind(), IconKind::Close);
144 assert_eq!(ResultStatus::NotFound.icon_kind(), IconKind::Info);
145 assert_eq!(ResultStatus::Forbidden.icon_kind(), IconKind::Info);
146 assert_eq!(ResultStatus::ServerError.icon_kind(), IconKind::Close);
147 }
148
149 #[test]
150 fn result_status_all_variants() {
151 let variants = [
152 ResultStatus::Success,
153 ResultStatus::Info,
154 ResultStatus::Warning,
155 ResultStatus::Error,
156 ResultStatus::NotFound,
157 ResultStatus::Forbidden,
158 ResultStatus::ServerError,
159 ];
160 for variant in variants.iter() {
161 let class = variant.as_class();
162 assert!(!class.is_empty());
163 assert!(class.starts_with("adui-result-"));
164 let icon = variant.icon_kind();
165 let _ = format!("{:?}", icon);
167 }
168 }
169
170 #[test]
171 fn result_status_equality() {
172 assert_eq!(ResultStatus::Success, ResultStatus::Success);
173 assert_eq!(ResultStatus::Info, ResultStatus::Info);
174 assert_ne!(ResultStatus::Success, ResultStatus::Error);
175 assert_ne!(ResultStatus::NotFound, ResultStatus::Forbidden);
176 }
177
178 #[test]
179 fn result_status_clone() {
180 let original = ResultStatus::Warning;
181 let cloned = original;
182 assert_eq!(original, cloned);
183 assert_eq!(original.as_class(), cloned.as_class());
184 assert_eq!(original.icon_kind(), cloned.icon_kind());
185 }
186
187 #[test]
188 fn result_props_defaults() {
189 }
192
193 #[test]
194 fn result_status_debug() {
195 let status = ResultStatus::ServerError;
196 let debug_str = format!("{:?}", status);
197 assert!(debug_str.contains("ServerError"));
198 }
199}