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.
- checksums.yaml +4 -4
- data/app/assets/builds/bundle.css +8665 -6069
- data/app/assets/builds/bundle.css.map +3 -3
- data/app/assets/builds/bundle.js +37877 -27557
- data/app/assets/builds/bundle.js.map +4 -4
- data/app/assets/builds/styles.css +6328 -5031
- data/app/assets/builds/styles.css.map +3 -3
- data/app/javascript/react/components/Accountpage/AccountInfo.jsx +2 -1
- data/app/javascript/react/components/AddNewProperty/CommonLayout.jsx +0 -2
- data/app/javascript/react/components/AddNewProperty/Description.jsx +51 -52
- data/app/javascript/react/components/AddNewProperty/Details.jsx +212 -129
- data/app/javascript/react/components/AddNewProperty/Images.jsx +122 -45
- data/app/javascript/react/components/AddNewProperty/Location.jsx +21 -14
- data/app/javascript/react/components/AddNewProperty/Room.jsx +639 -548
- data/app/javascript/react/components/AvatarDropdown/AvatarDropDown.jsx +9 -1
- data/app/javascript/react/components/FacilitiesSection/Facilities.jsx +18 -0
- data/app/javascript/react/components/FixedNavbar/FixedNav.jsx +20 -14
- data/app/javascript/react/components/HeroSectionDesign/BookingForm.jsx +136 -88
- data/app/javascript/react/components/HeroSectionDesign/MyPropertiesListing.jsx +79 -69
- data/app/javascript/react/components/Layout/Layout.js +8 -1
- data/app/javascript/react/components/Listing-stay-Detail/ApartmentCard.jsx +3 -3
- data/app/javascript/react/components/Listing-stay-Detail/BookingModal.jsx +167 -122
- data/app/javascript/react/components/Listing-stay-Detail/CardManager.jsx +285 -0
- data/app/javascript/react/components/Listing-stay-Detail/CheckoutForm.jsx +147 -84
- data/app/javascript/react/components/Listing-stay-Detail/ListingStayDetailPage.jsx +1 -7
- data/app/javascript/react/components/Listing-stay-Detail/PropertiesPage.jsx +464 -0
- data/app/javascript/react/components/MobileNav/MobileMenu.jsx +1 -4
- data/app/javascript/react/components/PropertyListing/MyProperties.jsx +45 -44
- data/app/javascript/react/components/PropertyListing/StayBooking/BookingDetails.jsx +4 -4
- data/app/javascript/react/components/PropertyListing/StayBooking/MyBooking.jsx +41 -29
- data/app/javascript/react/components/StayCard/StayCard.jsx +5 -3
- data/app/javascript/react/packs/index.jsx +1 -0
- data/app/javascript/react/packs/routes/Route.jsx +18 -1
- data/app/javascript/react/pages/Home.jsx +6 -4
- data/app/javascript/react/redux/slices/PropertySlice/PropertySlice.jsx +21 -21
- data/app/javascript/react/redux/slices/PropertySlice/Searchslice.jsx +53 -6
- data/app/javascript/react/redux/slices/UserSlice/UserSlice.jsx +1 -0
- data/app/javascript/react/shared/Avatar/Avatar.jsx +5 -8
- data/app/javascript/react/shared/Button/SecondryButton.jsx +9 -0
- data/app/javascript/react/shared/Loader.jsx +13 -0
- data/app/javascript/react/shared/Pagination.jsx +53 -0
- data/app/javascript/react/shared/Schema/FormSchema +143 -0
- data/app/javascript/react/styles/BookingDetails.scss +1 -0
- data/app/javascript/react/styles/CardManager.scss +608 -0
- data/app/javascript/react/styles/Loader.scss +30 -0
- data/app/javascript/react/styles/Pagination.scss +33 -0
- data/app/javascript/react/styles/PropertiesPage.scss +0 -4
- data/app/javascript/react/styles/RenderSection.scss +1 -0
- data/app/javascript/react/styles/accountpage.scss +3 -0
- data/app/javascript/react/styles/application.scss +13 -1
- data/app/javascript/react/styles/bookingform.scss +56 -28
- data/app/javascript/react/styles/buttonSecondry.scss +24 -0
- data/app/javascript/react/styles/checkbox.scss +34 -35
- data/app/javascript/react/styles/commonlayout.scss +7 -2
- data/app/javascript/react/styles/commonpage.scss +5 -1
- data/app/javascript/react/styles/description.scss +3 -0
- data/app/javascript/react/styles/facilities.scss +2 -1
- data/app/javascript/react/styles/fixednavbar.scss +8 -0
- data/app/javascript/react/styles/listingstaydetailpage.scss +5 -0
- data/app/javascript/react/styles/mobilemenu.scss +0 -1
- data/app/javascript/react/styles/mybooking.scss +20 -0
- data/app/javascript/react/styles/myproperty.scss +26 -0
- data/app/javascript/react/styles/propertydetailscard.scss +265 -267
- data/app/javascript/react/styles/react-datepicker/react-datepicker.css +869 -0
- data/app/javascript/react/styles/room.scss +13 -8
- data/app/javascript/react/utils/helpers/ToastErros.js +12 -0
- data/db/migrate/20250627101451_add_role_to_stay_users.rb +5 -0
- data/lib/stay_commerce/frontend/version.rb +1 -1
- metadata +15 -5
- data/app/javascript/react/components/HeroSectionDesign/PropertiesPage.jsx +0 -122
- data/app/javascript/react/shared/DateField/CustomDatePicker.jsx +0 -69
- 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
|
-
|
49
|
-
onSubmit: (values, { setSubmitting, resetForm }) => {
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
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
|
-
}
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
-
|
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());
|
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
|
-
|
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
|
53
|
+
console.error("Error loading property details:", error);
|
79
54
|
})
|
80
|
-
.finally(() =>
|
55
|
+
.finally(() => {
|
56
|
+
setLoading(false);
|
57
|
+
});
|
81
58
|
} else {
|
82
|
-
|
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
|
87
|
-
|
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
|
-
|
90
|
-
|
91
|
-
|
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
|
-
|
115
|
-
|
151
|
+
setFieldValue("additionalRules", filtered);
|
152
|
+
if (!String(id).startsWith("temp_")) {
|
153
|
+
setDeletedRuleIds((prev) => [...prev, id]);
|
154
|
+
}
|
116
155
|
|
117
|
-
|
118
|
-
|
119
|
-
|
156
|
+
setIsEdit({ state: false, itemId: null });
|
157
|
+
setNewRuleInput("");
|
158
|
+
};
|
120
159
|
|
121
|
-
|
122
|
-
|
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
|
-
|
127
|
-
|
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
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
{
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
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
|
-
|
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
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
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="
|
207
|
-
|
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
|
-
{
|
305
|
+
{isSubmitting ? "Saving..." : "Save"}
|
210
306
|
</ButtonPrimary>
|
211
307
|
</div>
|
212
|
-
</
|
213
|
-
|
214
|
-
|
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>
|