|
6 | 6 | """ |
7 | 7 |
|
8 | 8 | import reflex as rx |
| 9 | +from reflex.event import EventType |
9 | 10 | from reflex.experimental.client_state import ClientStateVar |
10 | 11 |
|
11 | 12 | import reflex_ui as ui |
|
14 | 15 | demo_form_error_message = ClientStateVar.create("demo_form_error_message", "") |
15 | 16 | demo_form_open_cs = ClientStateVar.create("demo_form_open", False) |
16 | 17 |
|
| 18 | +PERSONAL_EMAIL_PROVIDERS = r"^(?!.*@(gmail|outlook|hotmail|yahoo|icloud|aol|protonmail|mail|yandex|zoho|live|msn|me|mac|googlemail)\.com$|.*@(yahoo|outlook|hotmail)\.co\.uk$|.*@yahoo\.ca$|.*@yahoo\.co\.in$|.*@proton\.me$).*$" |
| 19 | + |
| 20 | + |
| 21 | +def get_element_value(element_id: str) -> str: |
| 22 | + """Get the value of an element by ID.""" |
| 23 | + return f"document.getElementById('{element_id}')?.value" |
| 24 | + |
17 | 25 |
|
18 | 26 | def check_if_company_email(email: str) -> bool: |
19 | 27 | """Check if an email address is from a company domain (not a personal email provider). |
@@ -62,6 +70,22 @@ def check_if_default_value_is_selected(value: str) -> bool: |
62 | 70 | return bool(value.strip()) |
63 | 71 |
|
64 | 72 |
|
| 73 | +class DemoFormStateUI(rx.State): |
| 74 | + """State for handling demo form submissions and validation.""" |
| 75 | + |
| 76 | + @rx.event |
| 77 | + def validate_email(self, email: str): |
| 78 | + """Validate the email address.""" |
| 79 | + if not check_if_company_email(email): |
| 80 | + yield [ |
| 81 | + demo_form_error_message.push( |
| 82 | + "Please enter a valid company email - gmails, aol, me, etc are not allowed" |
| 83 | + ), |
| 84 | + ] |
| 85 | + else: |
| 86 | + yield demo_form_error_message.push("") |
| 87 | + |
| 88 | + |
65 | 89 | def input_field( |
66 | 90 | label: str, |
67 | 91 | placeholder: str, |
@@ -98,6 +122,51 @@ def input_field( |
98 | 122 | ) |
99 | 123 |
|
100 | 124 |
|
| 125 | +def validation_input_field( |
| 126 | + label: str, |
| 127 | + placeholder: str, |
| 128 | + name: str, |
| 129 | + type: str = "text", |
| 130 | + required: bool = False, |
| 131 | + pattern: str | None = None, |
| 132 | + on_blur: EventType[()] | None = None, |
| 133 | + id: str = "", |
| 134 | +) -> rx.Component: |
| 135 | + """Create a labeled input field component. |
| 136 | +
|
| 137 | + Args: |
| 138 | + label: The label text to display above the input |
| 139 | + placeholder: Placeholder text for the input |
| 140 | + name: The name attribute for the input field |
| 141 | + type: The input type (text, email, tel, etc.) |
| 142 | + pattern: Regex pattern for input validation |
| 143 | + required: Whether the field is required |
| 144 | + on_blur: Event handler for when the input is blurred |
| 145 | + id: The ID attribute for the input field |
| 146 | +
|
| 147 | + Returns: |
| 148 | + A Reflex component containing the labeled input field |
| 149 | + """ |
| 150 | + return rx.el.div( |
| 151 | + rx.el.label( |
| 152 | + label + (" *" if required else ""), |
| 153 | + class_name="block text-sm font-medium text-secondary-12", |
| 154 | + ), |
| 155 | + ui.input( |
| 156 | + placeholder=placeholder, |
| 157 | + id=id, |
| 158 | + name=name, |
| 159 | + type=type, |
| 160 | + required=required, |
| 161 | + max_length=255, |
| 162 | + pattern=pattern, |
| 163 | + class_name="w-full", |
| 164 | + on_blur=on_blur, |
| 165 | + ), |
| 166 | + class_name="flex flex-col gap-1.5", |
| 167 | + ) |
| 168 | + |
| 169 | + |
101 | 170 | def text_area_field( |
102 | 171 | label: str, placeholder: str, name: str, required: bool = False |
103 | 172 | ) -> rx.Component: |
@@ -190,7 +259,18 @@ def demo_form(**props) -> rx.Component: |
190 | 259 | input_field("Last name", "Smith", "last_name", "text", True), |
191 | 260 | class_name="grid grid-cols-2 gap-4", |
192 | 261 | ), |
193 | | - input_field( "Business Email", "[email protected]", "email", "email", True), |
| 262 | + validation_input_field( |
| 263 | + "Business Email", |
| 264 | + |
| 265 | + "email", |
| 266 | + "email", |
| 267 | + True, |
| 268 | + PERSONAL_EMAIL_PROVIDERS, |
| 269 | + id="user_email", |
| 270 | + on_blur=DemoFormStateUI.validate_email( |
| 271 | + rx.Var(get_element_value("user_email")) |
| 272 | + ), |
| 273 | + ), |
194 | 274 | rx.el.div( |
195 | 275 | input_field("Job title", "CTO", "job_title", "text", True), |
196 | 276 | input_field("Company name", "Pynecone, Inc.", "company_name", "text", True), |
@@ -296,6 +376,9 @@ def demo_form_dialog(trigger: rx.Component | None, **props) -> rx.Component: |
296 | 376 | ), |
297 | 377 | open=demo_form_open_cs.value, |
298 | 378 | on_open_change=demo_form_open_cs.set_value, |
| 379 | + on_open_change_complete=[ |
| 380 | + rx.call_function(demo_form_error_message.set_value("")) |
| 381 | + ], |
299 | 382 | class_name=class_name, |
300 | 383 | **props, |
301 | 384 | ) |
0 commit comments