stay_commerce-frontend 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/builds/bundle.css +8665 -6069
  3. data/app/assets/builds/bundle.css.map +3 -3
  4. data/app/assets/builds/bundle.js +37877 -27557
  5. data/app/assets/builds/bundle.js.map +4 -4
  6. data/app/assets/builds/styles.css +6328 -5031
  7. data/app/assets/builds/styles.css.map +3 -3
  8. data/app/javascript/react/components/Accountpage/AccountInfo.jsx +2 -1
  9. data/app/javascript/react/components/AddNewProperty/CommonLayout.jsx +0 -2
  10. data/app/javascript/react/components/AddNewProperty/Description.jsx +51 -52
  11. data/app/javascript/react/components/AddNewProperty/Details.jsx +212 -129
  12. data/app/javascript/react/components/AddNewProperty/Images.jsx +122 -45
  13. data/app/javascript/react/components/AddNewProperty/Location.jsx +21 -14
  14. data/app/javascript/react/components/AddNewProperty/Room.jsx +639 -548
  15. data/app/javascript/react/components/AvatarDropdown/AvatarDropDown.jsx +9 -1
  16. data/app/javascript/react/components/FacilitiesSection/Facilities.jsx +18 -0
  17. data/app/javascript/react/components/FixedNavbar/FixedNav.jsx +20 -14
  18. data/app/javascript/react/components/HeroSectionDesign/BookingForm.jsx +136 -88
  19. data/app/javascript/react/components/HeroSectionDesign/MyPropertiesListing.jsx +79 -69
  20. data/app/javascript/react/components/Layout/Layout.js +8 -1
  21. data/app/javascript/react/components/Listing-stay-Detail/ApartmentCard.jsx +3 -3
  22. data/app/javascript/react/components/Listing-stay-Detail/BookingModal.jsx +167 -122
  23. data/app/javascript/react/components/Listing-stay-Detail/CardManager.jsx +285 -0
  24. data/app/javascript/react/components/Listing-stay-Detail/CheckoutForm.jsx +147 -84
  25. data/app/javascript/react/components/Listing-stay-Detail/ListingStayDetailPage.jsx +1 -7
  26. data/app/javascript/react/components/Listing-stay-Detail/PropertiesPage.jsx +464 -0
  27. data/app/javascript/react/components/MobileNav/MobileMenu.jsx +1 -4
  28. data/app/javascript/react/components/PropertyListing/MyProperties.jsx +45 -44
  29. data/app/javascript/react/components/PropertyListing/StayBooking/BookingDetails.jsx +4 -4
  30. data/app/javascript/react/components/PropertyListing/StayBooking/MyBooking.jsx +41 -29
  31. data/app/javascript/react/components/StayCard/StayCard.jsx +5 -3
  32. data/app/javascript/react/packs/index.jsx +1 -0
  33. data/app/javascript/react/packs/routes/Route.jsx +18 -1
  34. data/app/javascript/react/pages/Home.jsx +6 -4
  35. data/app/javascript/react/redux/slices/PropertySlice/PropertySlice.jsx +21 -21
  36. data/app/javascript/react/redux/slices/PropertySlice/Searchslice.jsx +53 -6
  37. data/app/javascript/react/redux/slices/UserSlice/UserSlice.jsx +1 -0
  38. data/app/javascript/react/shared/Avatar/Avatar.jsx +5 -8
  39. data/app/javascript/react/shared/Button/SecondryButton.jsx +9 -0
  40. data/app/javascript/react/shared/Loader.jsx +13 -0
  41. data/app/javascript/react/shared/Pagination.jsx +53 -0
  42. data/app/javascript/react/shared/Schema/FormSchema +143 -0
  43. data/app/javascript/react/styles/BookingDetails.scss +1 -0
  44. data/app/javascript/react/styles/CardManager.scss +608 -0
  45. data/app/javascript/react/styles/Loader.scss +30 -0
  46. data/app/javascript/react/styles/Pagination.scss +33 -0
  47. data/app/javascript/react/styles/PropertiesPage.scss +0 -4
  48. data/app/javascript/react/styles/RenderSection.scss +1 -0
  49. data/app/javascript/react/styles/accountpage.scss +3 -0
  50. data/app/javascript/react/styles/application.scss +13 -1
  51. data/app/javascript/react/styles/bookingform.scss +56 -28
  52. data/app/javascript/react/styles/buttonSecondry.scss +24 -0
  53. data/app/javascript/react/styles/checkbox.scss +34 -35
  54. data/app/javascript/react/styles/commonlayout.scss +7 -2
  55. data/app/javascript/react/styles/commonpage.scss +5 -1
  56. data/app/javascript/react/styles/description.scss +3 -0
  57. data/app/javascript/react/styles/facilities.scss +2 -1
  58. data/app/javascript/react/styles/fixednavbar.scss +8 -0
  59. data/app/javascript/react/styles/listingstaydetailpage.scss +5 -0
  60. data/app/javascript/react/styles/mobilemenu.scss +0 -1
  61. data/app/javascript/react/styles/mybooking.scss +20 -0
  62. data/app/javascript/react/styles/myproperty.scss +26 -0
  63. data/app/javascript/react/styles/propertydetailscard.scss +265 -267
  64. data/app/javascript/react/styles/react-datepicker/react-datepicker.css +869 -0
  65. data/app/javascript/react/styles/room.scss +13 -8
  66. data/app/javascript/react/utils/helpers/ToastErros.js +12 -0
  67. data/db/migrate/20250627101451_add_role_to_stay_users.rb +5 -0
  68. data/lib/stay_commerce/frontend/version.rb +1 -1
  69. metadata +15 -5
  70. data/app/javascript/react/components/HeroSectionDesign/PropertiesPage.jsx +0 -122
  71. data/app/javascript/react/shared/DateField/CustomDatePicker.jsx +0 -69
  72. data/app/javascript/react/styles/customdatepicker.scss +0 -120
@@ -18,6 +18,7 @@ import moment from "moment";
18
18
  const AccountInfo = () => {
19
19
  const dispatch = useDispatch();
20
20
  const { data: currentUser, loading } = useSelector((state) => state.user);
21
+ const user = useSelector((state) => state.user.data);
21
22
  const fileInputRef = React.useRef(null);
22
23
  useEffect(() => {
23
24
  if (currentUser) {
@@ -103,7 +104,7 @@ const AccountInfo = () => {
103
104
  className="avatar-wrapper"
104
105
  onClick={() => fileInputRef.current.click()}
105
106
  >
106
- <Avatar sizeClass="large-avatar" />
107
+ <Avatar sizeClass="large-avatar" userData={user} />
107
108
  </div>
108
109
 
109
110
  <input
@@ -10,8 +10,6 @@ const CommonLayout = ({ children, PropertyID }) => {
10
10
  navigate("/property-1");
11
11
  }
12
12
  }, [PropertyID, navigate]);
13
-
14
- // Define your steps
15
13
  const pathArray = [
16
14
  { path: 1, type: "Description", href: "/property-1" },
17
15
  { path: 2, type: "Images", href: "/property-2" },
@@ -17,6 +17,7 @@ import {
17
17
  import { useNavigate } from "react-router-dom";
18
18
  import { useParams } from "react-router-dom";
19
19
  import successHandler from "../../utils/helpers/SuccessHandler";
20
+ import { descriptionValidationSchemas } from "../../shared/Schema/FormSchema";
20
21
 
21
22
  const Description = () => {
22
23
  const dispatch = useDispatch();
@@ -38,62 +39,58 @@ const Description = () => {
38
39
  property_type_id: PropertyToEdit?.property_type?.id || "",
39
40
  country: PropertyToEdit?.country || "",
40
41
  address: PropertyToEdit?.address || "",
41
-
42
42
  description: PropertyToEdit?.description || "",
43
43
  };
44
44
 
45
45
  const formik = useFormik({
46
46
  initialValues,
47
47
  enableReinitialize: true,
48
- // validationSchema: descriptionValidationSchemas,
49
- onSubmit: (values, { setSubmitting, resetForm }) => {
50
- const payload = {
51
- title: values.title,
52
- property_category_id: values.property_category,
53
- property_type_id: values.property_type_id,
54
- address: values.address,
55
- state: values.state,
56
- country: values.country,
57
- description: values.description,
58
-
59
- ...(slug ? { id: slug } : {}),
60
- };
61
-
62
- setSubmitting(true);
63
-
64
- if (id) {
65
- if (isEditing) {
66
- dispatch(updateProperties({ property: payload }))
67
- .unwrap()
68
- .then((response) => {
69
- const newSlug = response?.property?.slug || slug;
70
- if (response?.success) {
71
- successHandler("Updated successfully");
72
- navigate(`/property-2/${newSlug}`);
73
- resetForm();
74
- }
75
- })
76
- .catch(console.error)
77
- .finally(() => setSubmitting(false));
78
- } else {
48
+ validationSchema: descriptionValidationSchemas,
49
+ onSubmit: async (values, { setSubmitting, resetForm }) => {
50
+ try {
51
+ const payload = {
52
+ title: values.title,
53
+ property_category_id: values.property_category,
54
+ property_type_id: values.property_type_id,
55
+ address: values.address,
56
+ country: values.country,
57
+ description: values.description,
58
+ ...(slug ? { id: slug } : {}),
59
+ };
60
+ setSubmitting(true);
61
+ setLoading(true);
62
+ if (id && isEditing) {
63
+ const response = await dispatch(
64
+ updateProperties({ property: payload })
65
+ ).unwrap();
66
+ const newSlug = response?.property?.slug || slug;
67
+ if (response?.success) {
68
+ successHandler("Updated successfully");
69
+ navigate(`/property-2/${newSlug}`);
70
+ resetForm();
71
+ } else {
72
+ console.error("Update failed:", response);
73
+ }
74
+ } else if (id && !isEditing) {
79
75
  navigate(`/property-2/${slug}`);
76
+ } else {
77
+ const response = await dispatch(
78
+ createProperties({ property: payload })
79
+ ).unwrap();
80
+ if (response?.success) {
81
+ successHandler("Created successfully");
82
+ dispatch(setId(response.property.id));
83
+ resetForm();
84
+ navigate(`/property-2/${response?.property?.slug}`);
85
+ } else {
86
+ console.error("Create failed:", response);
87
+ }
80
88
  }
81
- } else {
82
- dispatch(createProperties({ property: payload }))
83
- .unwrap()
84
- .then((response) => {
85
- if (response?.success) {
86
- successHandler("Created successfully");
87
- dispatch(setId(response.property.id));
88
- resetForm();
89
- navigate(`/property-2/${response?.property?.slug}`);
90
- }
91
- })
92
- .catch(console.error)
93
- .finally(() => {
94
- setLoading(false);
95
- setSubmitting(false);
96
- });
89
+ } catch (error) {
90
+ console.error("Submit error:", error);
91
+ } finally {
92
+ setLoading(false);
93
+ setSubmitting(false);
97
94
  }
98
95
  },
99
96
  });
@@ -102,7 +99,8 @@ const Description = () => {
102
99
 
103
100
  useEffect(() => {
104
101
  const currentFormValues = JSON.stringify(formik.values);
105
- setIsEditing(currentFormValues !== initialFormValues);
102
+ const hasChanged = currentFormValues !== initialFormValues;
103
+ setIsEditing(hasChanged);
106
104
  }, [formik.values, initialFormValues]);
107
105
 
108
106
  useEffect(() => {
@@ -111,7 +109,7 @@ const Description = () => {
111
109
  if (id) {
112
110
  dispatch(getallupdateProperties({ propertyId: id }));
113
111
  } else {
114
- dispatch(clearPropertyToEdit()); // 🧹 Clear old edit data
112
+ dispatch(clearPropertyToEdit());
115
113
  }
116
114
  }, [dispatch, id]);
117
115
 
@@ -213,12 +211,13 @@ const Description = () => {
213
211
  onBlur={formik.handleBlur}
214
212
  error={formik.touched.description && formik.errors.description}
215
213
  />
214
+
216
215
  <ButtonPrimary
217
216
  type="submit"
218
217
  className="submit-btn"
219
- disabled={loading}
218
+ disabled={loading || formik.isSubmitting}
220
219
  >
221
- {loading ? "Submitting..." : "Submit"}
220
+ {loading || formik.isSubmitting ? "Submitting..." : "Submit"}
222
221
  </ButtonPrimary>
223
222
  </form>
224
223
  </div>
@@ -1,6 +1,7 @@
1
1
  import React, { useState, useEffect } from "react";
2
2
  import { useLocation, useParams, useNavigate } from "react-router-dom";
3
3
  import { Formik } from "formik";
4
+ import * as Yup from "yup";
4
5
  import { useDispatch } from "react-redux";
5
6
  import CommonLayout from "./CommonLayout";
6
7
  import "../../styles/description.scss";
@@ -11,92 +12,128 @@ import {
11
12
  updateProperties,
12
13
  } from "../../redux/slices/PropertySlice/PropertySlice";
13
14
  import "../../styles/details.scss";
14
- import { useSelector } from "react-redux";
15
15
  import successHandler from "../../utils/helpers/SuccessHandler";
16
+ import { detailsvalidationSchema } from "../../shared/Schema/FormSchema";
17
+ import SecondryButton from "../../shared/Button/SecondryButton";
16
18
 
17
19
  const Details = () => {
18
20
  const dispatch = useDispatch();
19
21
  const navigate = useNavigate();
20
22
  const { slug } = useParams();
21
23
  const routeId = slug;
24
+
22
25
  const [isEdit, setIsEdit] = useState({ state: false, itemId: null });
23
26
  const [initialValues, setInitialValues] = useState({
24
27
  property_size: "",
25
28
  total_rooms: "",
26
29
  additionalRules: [],
27
30
  });
31
+ const [initialFormState, setInitialFormState] = useState(null);
28
32
  const [newRuleInput, setNewRuleInput] = useState("");
29
33
  const [deletedRuleIds, setDeletedRuleIds] = useState([]);
30
34
  const [loading, setLoading] = useState(true);
35
+ const [isEditing, setIsEditing] = useState(false);
36
+
31
37
  useEffect(() => {
32
38
  if (slug) {
33
39
  dispatch(getallupdateProperties({ propertyId: slug }))
34
40
  .unwrap()
35
41
  .then((response) => {
36
42
  if (response) {
37
- setInitialValues({
43
+ const values = {
38
44
  property_size: response.property_size || "",
39
45
  total_rooms: response.total_rooms || "",
40
46
  additionalRules: response.additional_rules || [],
41
- });
42
- }
43
- });
44
- }
45
- }, [dispatch, slug]);
46
-
47
- const submitHandler = (values, { setSubmitting }) => {
48
- const dirty =
49
- values.property_size !== initialValues.property_size ||
50
- values.total_rooms !== initialValues.total_rooms;
51
-
52
- const additional_rules_attributes = [
53
- ...values.additionalRules.map((rule) => ({
54
- id: String(rule.id).startsWith("temp_") ? undefined : rule.id,
55
- name: rule.name,
56
- })),
57
- ...deletedRuleIds.map((id) => ({ id, _destroy: true })),
58
- ];
59
-
60
- const payload = {
61
- id: slug,
62
- property_size: values.property_size,
63
- total_rooms: values.total_rooms,
64
- additional_rules_attributes,
65
- };
66
-
67
- if (dirty || additional_rules_attributes.length) {
68
- dispatch(updateProperties({ property: payload }))
69
- .unwrap()
70
- .then((response) => {
71
- if (response?.property) {
72
- successHandler("Updated successfully");
73
- setDeletedRuleIds([]);
74
- navigate(`/property-4/${slug}`);
47
+ };
48
+ setInitialValues(values);
49
+ setInitialFormState(JSON.stringify(values));
75
50
  }
76
51
  })
77
52
  .catch((error) => {
78
- console.error("Error in operation:", error);
53
+ console.error("Error loading property details:", error);
79
54
  })
80
- .finally(() => setSubmitting(false));
55
+ .finally(() => {
56
+ setLoading(false);
57
+ });
81
58
  } else {
82
- navigate(`/property-4/${slug}`);
59
+ setLoading(false);
83
60
  }
61
+ }, [dispatch, slug]);
62
+ const checkForChanges = (currentValues) => {
63
+ const currentState = JSON.stringify({
64
+ property_size: currentValues.property_size,
65
+ total_rooms: currentValues.total_rooms,
66
+ additionalRules: currentValues.additionalRules,
67
+ });
68
+ const hasFormChanges = currentState !== initialFormState;
69
+ const hasDeletedRules = deletedRuleIds.length > 0;
70
+ const hasChanges = hasFormChanges || hasDeletedRules;
71
+ setIsEditing(hasChanges);
72
+ return hasChanges;
84
73
  };
85
74
 
86
- const handleAddRule = (values, setFieldValue) => {
87
- if (newRuleInput.trim() === "") return;
75
+ const submitHandler = async (values, { setSubmitting }) => {
76
+ try {
77
+ setSubmitting(true);
78
+ const hasChanges = checkForChanges(values);
79
+ if (slug && hasChanges) {
80
+ const additional_rules_attributes = [
81
+ ...values.additionalRules.map((rule) => ({
82
+ id: String(rule.id).startsWith("temp_") ? undefined : rule.id,
83
+ name: rule.name,
84
+ })),
85
+ ...deletedRuleIds.map((id) => ({ id, _destroy: true })),
86
+ ];
88
87
 
89
- const newRule = {
90
- id: `temp_${Date.now()}`,
91
- name: newRuleInput,
92
- };
88
+ const payload = {
89
+ id: slug,
90
+ property_size: values.property_size,
91
+ total_rooms: values.total_rooms,
92
+ additional_rules_attributes,
93
+ };
94
+ const response = await dispatch(
95
+ updateProperties({ property: payload })
96
+ ).unwrap();
97
+ if (response?.property) {
98
+ successHandler("Updated successfully");
99
+ setDeletedRuleIds([]);
100
+ setInitialFormState(
101
+ JSON.stringify({
102
+ property_size: values.property_size,
103
+ total_rooms: values.total_rooms,
104
+ additionalRules: values.additionalRules,
105
+ })
106
+ );
107
+ navigate(`/property-4/${slug}`);
108
+ } else {
109
+ console.error("Update failed:", response);
110
+ }
111
+ } else if (slug && !hasChanges) {
112
+ navigate(`/property-4/${slug}`);
113
+ } else {
114
+ navigate(`/property-4/${slug}`);
115
+ }
116
+ } catch (error) {
117
+ console.error("Error in operation:", error);
118
+ } finally {
119
+ setSubmitting(false);
120
+ }
121
+ };
93
122
 
123
+ const handleAddRule = (values, setFieldValue) => {
124
+ if (newRuleInput.trim() === "") {
125
+ return;
126
+ }
94
127
  if (isEdit.state) {
95
128
  const updated = values.additionalRules.map((rule) =>
96
129
  rule.id === isEdit.itemId ? { ...rule, name: newRuleInput } : rule
97
130
  );
98
131
  setFieldValue("additionalRules", updated);
99
132
  } else {
133
+ const newRule = {
134
+ id: `temp_${Date.now()}`,
135
+ name: newRuleInput,
136
+ };
100
137
  setFieldValue("additionalRules", [...values.additionalRules, newRule]);
101
138
  }
102
139
 
@@ -111,21 +148,35 @@ const Details = () => {
111
148
 
112
149
  const handleDeleteRule = (id, values, setFieldValue) => {
113
150
  const filtered = values.additionalRules.filter((rule) => rule.id !== id);
114
- if (filtered.length > 0) {
115
- setFieldValue("additionalRules", filtered);
151
+ setFieldValue("additionalRules", filtered);
152
+ if (!String(id).startsWith("temp_")) {
153
+ setDeletedRuleIds((prev) => [...prev, id]);
154
+ }
116
155
 
117
- if (!String(id).startsWith("temp_")) {
118
- setDeletedRuleIds((prev) => [...prev, id]);
119
- }
156
+ setIsEdit({ state: false, itemId: null });
157
+ setNewRuleInput("");
158
+ };
120
159
 
121
- setIsEdit({ state: false, itemId: null });
122
- setNewRuleInput("");
123
- }
160
+ const handleFormSubmit = (handleSubmit, isValid, errors, values) => {
161
+ return (e) => {
162
+ e.preventDefault();
163
+ if (isValid) {
164
+ handleSubmit(e);
165
+ } else {
166
+ console.log("Form validation failed, not submitting");
167
+ }
168
+ };
124
169
  };
125
170
 
126
- useEffect(() => {
127
- setTimeout(() => setLoading(false), 1000);
128
- }, []);
171
+ if (loading) {
172
+ return (
173
+ <CommonLayout currentHref="/property-2" PropertyID={routeId}>
174
+ <div className="description-container">
175
+ <div>Loading...</div>
176
+ </div>
177
+ </CommonLayout>
178
+ );
179
+ }
129
180
 
130
181
  return (
131
182
  <CommonLayout currentHref="/property-2" PropertyID={routeId}>
@@ -135,6 +186,7 @@ const Details = () => {
135
186
  <Formik
136
187
  enableReinitialize
137
188
  initialValues={initialValues}
189
+ validationSchema={detailsvalidationSchema}
138
190
  onSubmit={submitHandler}
139
191
  >
140
192
  {({
@@ -146,85 +198,116 @@ const Details = () => {
146
198
  setFieldValue,
147
199
  isSubmitting,
148
200
  handleSubmit,
149
- }) => (
150
- <form onSubmit={handleSubmit} className="form-container">
151
- <FormField
152
- label="Property Size (sq ft)"
153
- name="property_size"
154
- type="number"
155
- placeholder="Enter property size"
156
- value={values.property_size}
157
- onChange={handleChange}
158
- onBlur={handleBlur}
159
- error={touched.property_size && errors.property_size}
160
- />
161
-
162
- <FormField
163
- label="Total Rooms"
164
- name="total_rooms"
165
- type="number"
166
- placeholder="Enter total rooms"
167
- value={values.total_rooms}
168
- onChange={handleChange}
169
- onBlur={handleBlur}
170
- error={touched.total_rooms && errors.total_rooms}
171
- />
172
-
173
- <div className="additional-rules">
174
- <h3>Additional Rules</h3>
175
- <div className="rules-list">
176
- {values.additionalRules.map((rule, index) => (
177
- <div className="rule-item" key={rule.id || index}>
178
- <span>{rule.name}</span>
179
- <div className="rule-actions">
180
- <button
181
- type="button"
182
- onClick={() => handleEditRule(rule)}
183
- >
184
- ✏️
185
- </button>
186
- <button
187
- type="button"
188
- onClick={() =>
189
- handleDeleteRule(rule.id, values, setFieldValue)
190
- }
191
- >
192
- 🗑️
193
- </button>
201
+ isValid,
202
+ setTouched,
203
+ }) => {
204
+ useEffect(() => {
205
+ if (initialFormState) {
206
+ checkForChanges(values);
207
+ }
208
+ }, [values, deletedRuleIds, initialFormState]);
209
+
210
+ return (
211
+ <form
212
+ onSubmit={handleFormSubmit(
213
+ handleSubmit,
214
+ isValid,
215
+ errors,
216
+ values
217
+ )}
218
+ className="form-container"
219
+ >
220
+ <FormField
221
+ label="Property Size (sq ft)"
222
+ name="property_size"
223
+ type="number"
224
+ placeholder="Enter property size"
225
+ value={values.property_size}
226
+ onChange={handleChange}
227
+ onBlur={handleBlur}
228
+ error={touched.property_size && errors.property_size}
229
+ />
230
+
231
+ <FormField
232
+ label="Total Rooms"
233
+ name="total_rooms"
234
+ type="number"
235
+ placeholder="Enter total rooms"
236
+ value={values.total_rooms}
237
+ onChange={handleChange}
238
+ onBlur={handleBlur}
239
+ error={touched.total_rooms && errors.total_rooms}
240
+ />
241
+
242
+ <div className="additional-rules">
243
+ <h3>Additional Rules</h3>
244
+ <div className="rules-list">
245
+ {values.additionalRules.map((rule, index) => (
246
+ <div className="rule-item" key={rule.id || index}>
247
+ <span>{rule.name}</span>
248
+ <div className="rule-actions">
249
+ <button
250
+ type="button"
251
+ onClick={() => handleEditRule(rule)}
252
+ >
253
+ ✏️
254
+ </button>
255
+ <button
256
+ type="button"
257
+ onClick={() =>
258
+ handleDeleteRule(rule.id, values, setFieldValue)
259
+ }
260
+ >
261
+ 🗑️
262
+ </button>
263
+ </div>
194
264
  </div>
195
- </div>
196
- ))}
265
+ ))}
266
+ </div>
267
+ <div className="rule-input-group">
268
+ <input
269
+ type="text"
270
+ placeholder="No smoking, no pets..."
271
+ value={newRuleInput}
272
+ onChange={(e) => setNewRuleInput(e.target.value)}
273
+ onKeyPress={(e) => {
274
+ if (e.key === "Enter") {
275
+ e.preventDefault();
276
+ handleAddRule(values, setFieldValue);
277
+ }
278
+ }}
279
+ />
280
+ <ButtonPrimary
281
+ type="button"
282
+ onClick={() => handleAddRule(values, setFieldValue)}
283
+ disabled={!newRuleInput.trim()}
284
+ >
285
+ {isEdit.state ? "Update Rule" : "Add Rule"}
286
+ </ButtonPrimary>
287
+ </div>
197
288
  </div>
198
- <div className="rule-input-group">
199
- <input
200
- type="text"
201
- placeholder="No smoking, no pets..."
202
- value={newRuleInput}
203
- onChange={(e) => setNewRuleInput(e.target.value)}
204
- />
289
+
290
+ <div className="actions">
291
+ <SecondryButton href={`/property-2/${slug}`}>
292
+ Go back
293
+ </SecondryButton>
205
294
  <ButtonPrimary
206
- type="button"
207
- onClick={() => handleAddRule(values, setFieldValue)}
295
+ type="submit"
296
+ className="submit-btn"
297
+ disabled={isSubmitting}
298
+ onClick={() => {
299
+ setTouched({
300
+ property_size: true,
301
+ total_rooms: true,
302
+ });
303
+ }}
208
304
  >
209
- {isEdit.state ? "Update Rule" : "Add Rule"}
305
+ {isSubmitting ? "Saving..." : "Save"}
210
306
  </ButtonPrimary>
211
307
  </div>
212
- </div>
213
-
214
- <div className="actions">
215
- <ButtonPrimary href={`/property-2/${slug}`}>
216
- Go back
217
- </ButtonPrimary>
218
- <ButtonPrimary
219
- type="submit"
220
- className="submit-btn"
221
- disabled={isSubmitting}
222
- >
223
- {isSubmitting ? "Saving..." : "Save"}
224
- </ButtonPrimary>
225
- </div>
226
- </form>
227
- )}
308
+ </form>
309
+ );
310
+ }}
228
311
  </Formik>
229
312
  </div>
230
313
  </CommonLayout>