stay_commerce 0.1.11 → 0.1.13
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/javascripts/stay/admin/property.js +8 -8
- data/app/controllers/concerns/stay/image_resizer_concern.rb +44 -0
- data/app/controllers/devise/api/tokens_controller.rb +0 -4
- data/app/controllers/stay/admin/properties_controller.rb +1 -0
- data/app/controllers/stay/admin/rooms_controller.rb +2 -2
- data/app/controllers/stay/api/v1/amenities_controller.rb +38 -6
- data/app/controllers/stay/api/v1/features_controller.rb +32 -6
- data/app/controllers/stay/api/v1/properties_controller.rb +1 -0
- data/app/controllers/stay/api/v1/property_categories_controller.rb +43 -5
- data/app/controllers/stay/api/v1/property_types_controller.rb +32 -9
- data/app/controllers/stay/users/registrations_controller.rb +7 -0
- data/app/controllers/stay/users/sessions_controller.rb +7 -0
- data/app/helpers/stay/application_helper.rb +44 -14
- data/app/models/stay/property.rb +4 -3
- data/app/models/stay/property_category.rb +2 -1
- data/app/models/stay/property_type.rb +3 -3
- data/app/models/stay/room_type.rb +3 -2
- data/app/serializers/credit_card_serializer.rb +0 -3
- data/app/serializers/feature_serializer.rb +3 -0
- data/app/serializers/property_category_serializer.rb +1 -5
- data/app/serializers/property_listing_serializer.rb +1 -1
- data/app/serializers/property_serializer.rb +2 -2
- data/app/serializers/property_type_serializer.rb +1 -5
- data/app/serializers/room_serializer.rb +1 -1
- data/app/serializers/user_serializer.rb +2 -9
- data/app/views/stay/admin/properties/index.html.erb +60 -60
- data/app/views/stay/admin/rooms/index.html.erb +51 -52
- data/app/views/stay/admin/users/show.html.erb +6 -3
- data/db/migrate/20250407101335_add_field_to_stay_users.rb +7 -0
- data/lib/stay/version.rb +1 -1
- metadata +5 -3
- data/app/serializers/property_feature_serializer.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8ab666ef6621d55e7d2aac249f86d0ea9e2c0ccb902bda7de026a5013181372
|
4
|
+
data.tar.gz: 432b2ded3073a63f4757e7721dec5c9e21203f3a51377382f23eb5a503650d52
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d046d3c8f75dc3e92614d66d991770d3d03a606458aec4c81fc3a3a9108fc1d2c5f8e45aea562cc8d62b50d55b8f9325949a16451daf41683ef59e33f20a0014
|
7
|
+
data.tar.gz: aa34ce806d5e6f5300f7386f359dcc57d25e1920a869b2181e327710480cd88007846930e378dc2e77256e2b528dd784ddbf1c5b46a545c368c92c8b3853e66c
|
@@ -25,13 +25,13 @@ $(document).ready(function() {
|
|
25
25
|
const roomTypeField = document.getElementById('room_type_field');
|
26
26
|
const propertyCategoryData = document.getElementById('property-category-data');
|
27
27
|
|
28
|
-
|
28
|
+
const roomTypesByCategory = JSON.parse(propertyCategoryData.getAttribute('data-room-types'));
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
30
|
+
window.updateRoomType = function(selectedCategoryId) {
|
31
|
+
if (roomTypesByCategory[selectedCategoryId]) {
|
32
|
+
roomTypeField.value = roomTypesByCategory[selectedCategoryId];
|
33
|
+
} else {
|
34
|
+
roomTypeField.value = '';
|
35
|
+
}
|
36
|
+
};
|
37
37
|
});
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Stay
|
3
|
+
module ImageResizerConcern
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
before_action :resize_image, only: %i[update create]
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def resize_image
|
13
|
+
image_params = resize_param_name
|
14
|
+
return unless image_params
|
15
|
+
|
16
|
+
Array(image_params).each do |image_param|
|
17
|
+
next unless image_param.respond_to?(:tempfile)
|
18
|
+
|
19
|
+
content_type = Marcel::MimeType.for(image_param.tempfile)
|
20
|
+
|
21
|
+
next unless content_type&.start_with?("image")
|
22
|
+
|
23
|
+
begin
|
24
|
+
ImageProcessing::MiniMagick
|
25
|
+
.source(image_param.tempfile)
|
26
|
+
.quality(85)
|
27
|
+
.call(destination: image_param.tempfile.path)
|
28
|
+
rescue StandardError => e
|
29
|
+
Rails.logger.error "Image processing failed: #{e.message}"
|
30
|
+
next
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def resize_param_name
|
36
|
+
case controller_name
|
37
|
+
when "properties"
|
38
|
+
params[:property][:place_images] || params[:property][:cover_image]
|
39
|
+
else
|
40
|
+
params[:attachment]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -27,12 +27,10 @@ module Devise
|
|
27
27
|
token = service.success
|
28
28
|
|
29
29
|
call_devise_trackable!(token.resource_owner)
|
30
|
-
|
31
30
|
token_response = Devise::Api::Responses::TokenResponse.new(request, token: token, action: __method__)
|
32
31
|
Devise.api.config.after_successful_sign_up.call(token.resource_owner, token, request)
|
33
32
|
assign_role(token.resource_owner) if token.resource_owner
|
34
33
|
data = ActiveModelSerializers::SerializableResource.new(token.resource_owner, serializer: UserSerializer).as_json
|
35
|
-
UserMailer.welcome_email(token.resource_owner).deliver_later if token.resource_owner
|
36
34
|
return render json: { access_token: token_response&.token.access_token, success: true }, status: token_response.status
|
37
35
|
end
|
38
36
|
|
@@ -157,8 +155,6 @@ module Devise
|
|
157
155
|
def assign_role(user)
|
158
156
|
role = Stay::Role.find_by(name: params[:type])
|
159
157
|
user.role_users.create(role_id: role&.id) if role.present?
|
160
|
-
token = Random.hex(16)
|
161
|
-
user.update(confirmation_token: token)
|
162
158
|
end
|
163
159
|
|
164
160
|
def sign_in_params
|
@@ -5,7 +5,7 @@ module Stay
|
|
5
5
|
before_action :set_room, only: %i[show edit update destroy]
|
6
6
|
|
7
7
|
def index
|
8
|
-
@rooms = @property.rooms
|
8
|
+
@rooms = @property.rooms.page(params[:page]).per(10)
|
9
9
|
end
|
10
10
|
|
11
11
|
def show
|
@@ -51,7 +51,7 @@ module Stay
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def room_params
|
54
|
-
params.require(:room).permit(:property_id, :max_guests, :price_per_month, :room_type_id, :booking_start, :booking_end, :description,
|
54
|
+
params.require(:room).permit(:property_id, :max_guests, :price_per_month, :room_type_id, :booking_start, :booking_end, :description, :name,
|
55
55
|
:size, :bed_type_id, :status, amenity_ids: [], feature_ids: [], room_images: [],
|
56
56
|
room_amenities_attributes: [ :id, :amenity_id, :_destroy ],
|
57
57
|
room_features_attributes: [ :id, :name, :feature_id, :_destroy ],
|
@@ -1,13 +1,45 @@
|
|
1
1
|
class Stay::Api::V1::AmenitiesController < ApplicationController
|
2
|
-
before_action :authenticate_devise_api_token!
|
3
|
-
|
4
2
|
def property
|
5
|
-
amenities = Stay::Amenity.
|
6
|
-
|
3
|
+
amenities = Stay::Amenity.property
|
4
|
+
|
5
|
+
if amenities.exists?
|
6
|
+
render json: {
|
7
|
+
success: true,
|
8
|
+
data: ActiveModelSerializers::SerializableResource.new(amenities, each_serializer: AmenitySerializer)
|
9
|
+
}, status: :ok
|
10
|
+
else
|
11
|
+
render json: {
|
12
|
+
success: false,
|
13
|
+
message: "No property amenities found"
|
14
|
+
}, status: :not_found
|
15
|
+
end
|
16
|
+
rescue => e
|
17
|
+
render json: {
|
18
|
+
success: false,
|
19
|
+
error: "Failed to fetch property amenities",
|
20
|
+
message: e.message
|
21
|
+
}, status: :internal_server_error
|
7
22
|
end
|
8
23
|
|
9
24
|
def room
|
10
|
-
amenities = Stay::Amenity.
|
11
|
-
|
25
|
+
amenities = Stay::Amenity.room
|
26
|
+
|
27
|
+
if amenities.exists?
|
28
|
+
render json: {
|
29
|
+
success: true,
|
30
|
+
data: ActiveModelSerializers::SerializableResource.new(amenities, each_serializer: AmenitySerializer)
|
31
|
+
}, status: :ok
|
32
|
+
else
|
33
|
+
render json: {
|
34
|
+
success: false,
|
35
|
+
message: "No room amenities found"
|
36
|
+
}, status: :not_found
|
37
|
+
end
|
38
|
+
rescue => e
|
39
|
+
render json: {
|
40
|
+
success: false,
|
41
|
+
error: "Failed to fetch room amenities",
|
42
|
+
message: e.message
|
43
|
+
}, status: :internal_server_error
|
12
44
|
end
|
13
45
|
end
|
@@ -3,19 +3,45 @@ class Stay::Api::V1::FeaturesController < Stay::BaseApiController
|
|
3
3
|
|
4
4
|
def property
|
5
5
|
features = Stay::Feature.property
|
6
|
-
|
7
|
-
|
6
|
+
|
7
|
+
if features.exists?
|
8
|
+
render json: {
|
9
|
+
success: true,
|
10
|
+
data: ActiveModelSerializers::SerializableResource.new(features, each_serializer: FeatureSerializer)
|
11
|
+
}, status: :ok
|
8
12
|
else
|
9
|
-
render json: {
|
13
|
+
render json: {
|
14
|
+
success: false,
|
15
|
+
message: "No property features found"
|
16
|
+
}, status: :not_found
|
10
17
|
end
|
18
|
+
rescue => e
|
19
|
+
render json: {
|
20
|
+
success: false,
|
21
|
+
error: "Failed to fetch property features",
|
22
|
+
message: e.message
|
23
|
+
}, status: :internal_server_error
|
11
24
|
end
|
12
25
|
|
13
26
|
def room
|
14
27
|
features = Stay::Feature.room
|
15
|
-
|
16
|
-
|
28
|
+
|
29
|
+
if features.exists?
|
30
|
+
render json: {
|
31
|
+
success: true,
|
32
|
+
data: ActiveModelSerializers::SerializableResource.new(features, each_serializer: FeatureSerializer)
|
33
|
+
}, status: :ok
|
17
34
|
else
|
18
|
-
render json: {
|
35
|
+
render json: {
|
36
|
+
success: false,
|
37
|
+
message: "No room features found"
|
38
|
+
}, status: :not_found
|
19
39
|
end
|
40
|
+
rescue => e
|
41
|
+
render json: {
|
42
|
+
success: false,
|
43
|
+
error: "Failed to fetch room features",
|
44
|
+
message: e.message
|
45
|
+
}, status: :internal_server_error
|
20
46
|
end
|
21
47
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
class Stay::Api::V1::PropertiesController < Stay::BaseApiController
|
2
|
+
include Stay::ImageResizerConcern
|
2
3
|
before_action :authenticate_devise_api_token!
|
3
4
|
before_action :set_property, only: [ :show, :update, :destroy ]
|
4
5
|
before_action :check_create_access, only: [ :create, :update ]
|
@@ -2,13 +2,51 @@ class Stay::Api::V1::PropertyCategoriesController < Stay::BaseApiController
|
|
2
2
|
before_action :authenticate_devise_api_token!
|
3
3
|
|
4
4
|
def index
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
categories = Stay::PropertyCategory.all
|
6
|
+
|
7
|
+
if categories.exists?
|
8
|
+
serialized_data = ActiveModelSerializers::SerializableResource.new(categories, each_serializer: PropertyCategorySerializer)
|
9
|
+
render json: {
|
10
|
+
data: serialized_data,
|
11
|
+
message: "Property categories found",
|
12
|
+
success: true
|
13
|
+
}, status: :ok
|
14
|
+
else
|
15
|
+
render json: {
|
16
|
+
data: [],
|
17
|
+
message: "No property categories found",
|
18
|
+
success: false
|
19
|
+
}, status: :not_found
|
20
|
+
end
|
21
|
+
rescue => e
|
22
|
+
render json: {
|
23
|
+
error: "Failed to fetch property categories",
|
24
|
+
message: e.message,
|
25
|
+
success: false
|
26
|
+
}, status: :internal_server_error
|
8
27
|
end
|
9
28
|
|
10
29
|
def show
|
11
|
-
|
12
|
-
|
30
|
+
category = Stay::PropertyCategory.find_by(id: params[:id])
|
31
|
+
|
32
|
+
if category.present?
|
33
|
+
render json: {
|
34
|
+
data: PropertyCategorySerializer.new(category),
|
35
|
+
message: "Property category found",
|
36
|
+
success: true
|
37
|
+
}, status: :ok
|
38
|
+
else
|
39
|
+
render json: {
|
40
|
+
data: {},
|
41
|
+
message: "Property category not found",
|
42
|
+
success: false
|
43
|
+
}, status: :not_found
|
44
|
+
end
|
45
|
+
rescue => e
|
46
|
+
render json: {
|
47
|
+
error: "Failed to fetch property category",
|
48
|
+
message: e.message,
|
49
|
+
success: false
|
50
|
+
}, status: :internal_server_error
|
13
51
|
end
|
14
52
|
end
|
@@ -3,13 +3,13 @@ class Stay::Api::V1::PropertyTypesController < Stay::BaseApiController
|
|
3
3
|
|
4
4
|
def index
|
5
5
|
property_types = Stay::PropertyType.all
|
6
|
-
|
7
|
-
if property_types.
|
6
|
+
|
7
|
+
if property_types.exists?
|
8
8
|
serialized_data = ActiveModelSerializers::SerializableResource.new(property_types, each_serializer: PropertyTypeSerializer)
|
9
|
-
|
9
|
+
|
10
10
|
render json: {
|
11
11
|
data: serialized_data,
|
12
|
-
message: "
|
12
|
+
message: "Property types found",
|
13
13
|
success: true
|
14
14
|
}, status: :ok
|
15
15
|
else
|
@@ -17,14 +17,37 @@ class Stay::Api::V1::PropertyTypesController < Stay::BaseApiController
|
|
17
17
|
data: [],
|
18
18
|
message: "No property types found",
|
19
19
|
success: false
|
20
|
-
}, status: :
|
20
|
+
}, status: :not_found
|
21
21
|
end
|
22
|
+
rescue => e
|
23
|
+
render json: {
|
24
|
+
error: "Failed to fetch property types",
|
25
|
+
message: e.message,
|
26
|
+
success: false
|
27
|
+
}, status: :internal_server_error
|
22
28
|
end
|
23
|
-
|
24
29
|
|
25
30
|
def show
|
26
|
-
|
27
|
-
|
28
|
-
|
31
|
+
type = Stay::PropertyType.find_by(id: params[:id])
|
32
|
+
|
33
|
+
if type.present?
|
34
|
+
render json: {
|
35
|
+
data: PropertyTypeSerializer.new(type),
|
36
|
+
message: "Property type found",
|
37
|
+
success: true
|
38
|
+
}, status: :ok
|
39
|
+
else
|
40
|
+
render json: {
|
41
|
+
data: {},
|
42
|
+
message: "Property type not found",
|
43
|
+
success: false
|
44
|
+
}, status: :not_found
|
45
|
+
end
|
46
|
+
rescue => e
|
47
|
+
render json: {
|
48
|
+
error: "Failed to fetch property type",
|
49
|
+
message: e.message,
|
50
|
+
success: false
|
51
|
+
}, status: :internal_server_error
|
29
52
|
end
|
30
53
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Stay::Users::RegistrationsController < Devise::RegistrationsController
|
4
|
+
before_action :redirects
|
5
|
+
|
4
6
|
# before_action :configure_sign_up_params, only: [:create]
|
5
7
|
# before_action :configure_account_update_params, only: [:update]
|
6
8
|
|
@@ -59,4 +61,9 @@ class Stay::Users::RegistrationsController < Devise::RegistrationsController
|
|
59
61
|
# def after_inactive_sign_up_path_for(resource)
|
60
62
|
# super(resource)
|
61
63
|
# end
|
64
|
+
private
|
65
|
+
|
66
|
+
def redirects
|
67
|
+
redirect_to "/admin/login"
|
68
|
+
end
|
62
69
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Stay::Users::SessionsController < Devise::SessionsController
|
4
|
+
before_action :redirects
|
4
5
|
# before_action :configure_sign_in_params, only: [:create]
|
5
6
|
|
6
7
|
# GET /resource/sign_in
|
@@ -24,4 +25,10 @@ class Stay::Users::SessionsController < Devise::SessionsController
|
|
24
25
|
# def configure_sign_in_params
|
25
26
|
# devise_parameter_sanitizer.permit(:sign_in, keys: [:attribute])
|
26
27
|
# end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def redirects
|
32
|
+
redirect_to "/admin/login"
|
33
|
+
end
|
27
34
|
end
|
@@ -3,8 +3,38 @@ module Stay
|
|
3
3
|
include CurrencyHelper
|
4
4
|
ICON_SIZE = 14
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
def badge_class(state)
|
7
|
+
case state
|
8
|
+
when "approved"
|
9
|
+
"green"
|
10
|
+
when "rejected"
|
11
|
+
"red"
|
12
|
+
when "accepted"
|
13
|
+
"orange"
|
14
|
+
when "confirmed"
|
15
|
+
"green"
|
16
|
+
when "booking_request"
|
17
|
+
"orange"
|
18
|
+
when "invoice_sent"
|
19
|
+
"orange"
|
20
|
+
when "canceled"
|
21
|
+
"red"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def icon_class(state)
|
26
|
+
case state
|
27
|
+
when "approved"
|
28
|
+
"icon-check-circle"
|
29
|
+
when "rejected"
|
30
|
+
"icon-times-circle"
|
31
|
+
else
|
32
|
+
"icon-exclamation-circle"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def svg_icon(name:, classes: "", width:, height:)
|
37
|
+
if name.ends_with?(".svg")
|
8
38
|
icon_name = File.basename(name, File.extname(name))
|
9
39
|
inline_svg_tag "#{icon_name}.svg", class: "icon-#{icon_name} #{classes}", size: "#{width}px*#{height}px"
|
10
40
|
else
|
@@ -14,8 +44,8 @@ module Stay
|
|
14
44
|
|
15
45
|
def active_badge(condition, options = {})
|
16
46
|
label = options[:label]
|
17
|
-
label ||= condition ? I18n.t(
|
18
|
-
css_class = condition ?
|
47
|
+
label ||= condition ? I18n.t("admin.say_yes") : I18n.t("admin.say_no")
|
48
|
+
css_class = condition ? "badge-active" : "badge-inactive"
|
19
49
|
|
20
50
|
content_tag(:small, class: "badge badge-pill #{css_class}") do
|
21
51
|
label
|
@@ -25,16 +55,16 @@ module Stay
|
|
25
55
|
def link_to_with_icon(icon_name, text, url, options = {})
|
26
56
|
options[:class] = (options[:class].to_s + " icon-link with-tip action-#{icon_name}").strip
|
27
57
|
options[:title] = text if options[:no_text]
|
28
|
-
text = options[:no_text] ?
|
58
|
+
text = options[:no_text] ? "" : content_tag(:span, text)
|
29
59
|
options.delete(:no_text)
|
30
60
|
options[:width] ||= ICON_SIZE
|
31
61
|
options[:height] ||= ICON_SIZE
|
32
62
|
if icon_name
|
33
|
-
icon = if icon_name.ends_with?(
|
63
|
+
icon = if icon_name.ends_with?(".svg")
|
34
64
|
svg_icon(name: icon_name, classes: "#{'mr-2' unless text.empty?} icon icon-#{icon_name}", width: options[:width], height: options[:height])
|
35
|
-
|
36
|
-
content_tag(:span,
|
37
|
-
|
65
|
+
else
|
66
|
+
content_tag(:span, "", class: "#{'mr-2' unless text.empty?} icon icon-#{icon_name}")
|
67
|
+
end
|
38
68
|
text = "#{icon} #{text}"
|
39
69
|
end
|
40
70
|
link_to(text.html_safe, url, options)
|
@@ -43,17 +73,17 @@ module Stay
|
|
43
73
|
def button_to_with_icon(icon_name, text, url, options = {})
|
44
74
|
options[:class] = (options[:class].to_s + " icon-link with-tip action-#{icon_name}").strip
|
45
75
|
options[:title] = text if options[:no_text]
|
46
|
-
text = options[:no_text] ?
|
76
|
+
text = options[:no_text] ? "" : content_tag(:span, text)
|
47
77
|
options.delete(:no_text)
|
48
78
|
options[:width] ||= ICON_SIZE
|
49
79
|
options[:height] ||= ICON_SIZE
|
50
80
|
|
51
81
|
if icon_name
|
52
|
-
icon = if icon_name.ends_with?(
|
82
|
+
icon = if icon_name.ends_with?(".svg")
|
53
83
|
svg_icon(name: icon_name, classes: "#{'mr-2' unless text.empty?} icon icon-#{icon_name}", width: options[:width], height: options[:height])
|
54
|
-
|
55
|
-
content_tag(:span,
|
56
|
-
|
84
|
+
else
|
85
|
+
content_tag(:span, "", class: "#{'mr-2' unless text.empty?} icon icon-#{icon_name}")
|
86
|
+
end
|
57
87
|
text = "#{icon} #{text}".html_safe
|
58
88
|
end
|
59
89
|
|
data/app/models/stay/property.rb
CHANGED
@@ -2,6 +2,7 @@ module Stay
|
|
2
2
|
class Property < ApplicationRecord
|
3
3
|
ACTIVE_STATUS = "active".freeze
|
4
4
|
APPROVED = "approved".freeze
|
5
|
+
PROPERTY = "property".freeze
|
5
6
|
include Rails.application.routes.url_helpers
|
6
7
|
include CurrencyHelper
|
7
8
|
include Stay::ControllerHelpers::Currency
|
@@ -29,15 +30,15 @@ module Stay
|
|
29
30
|
has_many :prices, through: :rooms
|
30
31
|
has_many :line_items, through: :variants_including_master
|
31
32
|
has_many :bookings
|
32
|
-
belongs_to :property_category, class_name: "Stay::PropertyCategory"
|
33
|
+
belongs_to :property_category, class_name: "Stay::PropertyCategory"
|
33
34
|
belongs_to :property_type, class_name: "Stay::PropertyType"
|
34
35
|
has_many :property_amenities, class_name: "Stay::PropertyAmenity", dependent: :destroy
|
35
|
-
has_many :
|
36
|
+
has_many :property_type_amenities, -> { where(amenity_type: PROPERTY) }, through: :property_amenities, source: :amenity, class_name: "Stay::Amenity"
|
36
37
|
has_many :additional_rules, class_name: "Stay::AdditionalRule", dependent: :destroy
|
37
38
|
has_many :property_house_rules, class_name: "Stay::PropertyHouseRule", dependent: :destroy
|
38
39
|
has_many :house_rules, through: :property_house_rules, class_name: "Stay::HouseRule"
|
39
40
|
has_many :property_features, class_name: "Stay::PropertyFeature", dependent: :destroy
|
40
|
-
has_many :
|
41
|
+
has_many :property_type_features,-> { where(feature_type: PROPERTY) },through: :property_features,source: :feature, class_name: "Stay::Feature"
|
41
42
|
has_many :property_taxes, class_name: "Stay::PropertyTax", dependent: :destroy
|
42
43
|
has_many :taxes, through: :property_taxes, class_name: "Stay::Tax"
|
43
44
|
has_many :store_properties, class_name: "Stay::StoreProperty", dependent: :destroy
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Stay
|
2
2
|
class PropertyCategory < ApplicationRecord
|
3
3
|
has_many :properties, class_name: "Stay::Property", dependent: :nullify
|
4
|
-
validates :name, presence: true, uniqueness: { case_sensitive: false },
|
4
|
+
validates :name, presence: true, uniqueness: { case_sensitive: false },
|
5
|
+
format: { without: /_/, message: "must not contain underscores" }
|
5
6
|
end
|
6
7
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Stay
|
2
2
|
class PropertyType < ApplicationRecord
|
3
|
-
validates :name, presence: true, uniqueness: { case_sensitive: false },
|
3
|
+
validates :name, presence: true, uniqueness: { case_sensitive: false },
|
4
|
+
format: { without: /_/, message: "must not contain underscores" }
|
4
5
|
|
5
|
-
|
6
|
-
has_many :properties
|
6
|
+
has_many :properties, class_name: "Stay::Property", dependent: :nullify
|
7
7
|
def self.ransackable_attributes(auth_object = nil)
|
8
8
|
%w[id name created_at updated_at]
|
9
9
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
module Stay
|
2
2
|
class RoomType < ApplicationRecord
|
3
|
-
has_many :rooms, class_name: "Stay::Room"
|
3
|
+
has_many :rooms, class_name: "Stay::Room", dependent: :destroy
|
4
4
|
|
5
|
-
validates :name, presence: true, uniqueness: { case_sensitive: false },
|
5
|
+
validates :name, presence: true, uniqueness: { case_sensitive: false },
|
6
|
+
format: { without: /_/, message: "must not contain underscores" }
|
6
7
|
end
|
7
8
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class PropertyListingSerializer < ActiveModel::Serializer
|
2
2
|
attributes :id, :title, :price_per_month, :place_images, :total_rooms,
|
3
3
|
:availability_end, :availability_start, :extra_guest, :latitude,
|
4
|
-
:longitude, :address, :city, :state, :country, :active, :property_state
|
4
|
+
:longitude, :address, :city, :state, :country, :active, :property_state, :slug
|
5
5
|
|
6
6
|
belongs_to :property_category, Serializer: :PropertyCategorySerializer
|
7
7
|
belongs_to :property_type, Serializer: :PropertyTypeSerializer
|
@@ -12,11 +12,11 @@ class PropertySerializer < ActiveModel::Serializer
|
|
12
12
|
belongs_to :user
|
13
13
|
|
14
14
|
def amenities
|
15
|
-
ActiveModelSerializers::SerializableResource.new(object.
|
15
|
+
ActiveModelSerializers::SerializableResource.new(object.property_type_amenities, each_serializer: AmenitySerializer)
|
16
16
|
end
|
17
17
|
|
18
18
|
def features
|
19
|
-
ActiveModelSerializers::SerializableResource.new(object.
|
19
|
+
ActiveModelSerializers::SerializableResource.new(object.property_type_features, each_serializer: FeatureSerializer)
|
20
20
|
end
|
21
21
|
|
22
22
|
def is_shared_property
|
@@ -16,7 +16,7 @@ class RoomSerializer < ActiveModel::Serializer
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def features
|
19
|
-
ActiveModelSerializers::SerializableResource.new(object.features.distinct, each_serializer:
|
19
|
+
ActiveModelSerializers::SerializableResource.new(object.features.distinct, each_serializer: FeatureSerializer)
|
20
20
|
end
|
21
21
|
|
22
22
|
def room_images
|
@@ -1,7 +1,8 @@
|
|
1
1
|
class UserSerializer < ActiveModel::Serializer
|
2
2
|
include Rails.application.routes.url_helpers
|
3
|
+
|
3
4
|
attributes :id, :email, :first_name, :full_name, :last_name, :phone, :gender, :is_user, :is_host, :date_of_birth,
|
4
|
-
:image, :
|
5
|
+
:image, :image_file_name, :about_me, :country, :country_code
|
5
6
|
|
6
7
|
def full_name
|
7
8
|
object.full_name
|
@@ -23,14 +24,6 @@ class UserSerializer < ActiveModel::Serializer
|
|
23
24
|
object.profile_image.url || nil
|
24
25
|
end
|
25
26
|
|
26
|
-
def whatsapp_notification
|
27
|
-
object&.preferences.present? ? object&.preferences["whatsapp_notification"]: false
|
28
|
-
end
|
29
|
-
|
30
|
-
def sms_notification
|
31
|
-
object&.preferences.present? ? object&.preferences["sms_notification"]: false
|
32
|
-
end
|
33
|
-
|
34
27
|
def image_file_name
|
35
28
|
object.profile_image&.filename&.to_s || nil
|
36
29
|
end
|
@@ -2,81 +2,81 @@
|
|
2
2
|
<div class="card-header">
|
3
3
|
<div class="row align-items-center">
|
4
4
|
<div class="col-sm-6 col-12 mb-4 mb-sm-0">
|
5
|
-
|
6
|
-
<h1 class="h3 mb-0 ls-tight">Properties</h1>
|
5
|
+
<h1 class="h3 mb-0 ls-tight">Properties</h1>
|
7
6
|
</div>
|
8
7
|
<div class="col-sm-6 col-12 text-sm-end">
|
9
|
-
|
8
|
+
<div class="mx-n1">
|
10
9
|
<%= link_to new_admin_property_path, class:"btn d-inline-flex btn-sm btn-primary mx-1" do %>
|
11
|
-
|
10
|
+
<span class=" pe-2">
|
12
11
|
<i class="bi bi-plus"></i>
|
13
|
-
|
14
|
-
|
12
|
+
</span>
|
13
|
+
<span>Create New</span>
|
15
14
|
<%end%>
|
16
|
-
|
15
|
+
</div>
|
17
16
|
</div>
|
18
17
|
<div class="row g-3 mt-4">
|
19
|
-
<div class="col-
|
18
|
+
<div class="col-3 mt-6">
|
20
19
|
<%= search_form_for @q, url: admin_properties_path, method: :get, local: true, class: "input-group" do |f| %>
|
21
|
-
<%= f.search_field :title_cont, placeholder: "Search by
|
20
|
+
<%= f.search_field :title_cont, placeholder: "Search by Name", class: "form-control" %>
|
22
21
|
<%= f.submit "Search", class: "btn btn-primary" %>
|
23
22
|
<% end %>
|
24
23
|
</div>
|
25
|
-
|
24
|
+
<div class="col-9 d-flex justify-content-end">
|
25
|
+
<%= form_with url: admin_properties_path, method: :get, local: true, class: "row g-3 align-items-center" do |f| %>
|
26
|
+
<div class="col-auto mt-4">
|
27
|
+
<%= f.label :status, "Filter", class: "form-label" %>
|
28
|
+
<%= f.select :property_state, options_for_select([["All", ""], ["Waiting for Approval", "waiting_for_approval"], ["Approved", "approved"], ["Rejected", "rejected"]], params[:property_state]), {}, class: "form-select" %>
|
29
|
+
</div>
|
30
|
+
<div class="col-auto">
|
31
|
+
<%= f.submit "Filter", class: "btn btn-primary mt-3" %>
|
32
|
+
</div>
|
33
|
+
<% end %>
|
34
|
+
</div>
|
35
|
+
</div>
|
26
36
|
</div>
|
27
37
|
</div>
|
28
38
|
<div class="table-responsive">
|
29
|
-
<table class="table table-hover table-nowrap">
|
39
|
+
<table class="table table-hover table-nowrap text-center align-middle">
|
30
40
|
<thead class="table-light">
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
<% end %>
|
70
|
-
</td>
|
71
|
-
</tr>
|
72
|
-
<% end %>
|
73
|
-
</tbody>
|
74
|
-
</table>
|
75
|
-
</div>
|
76
|
-
</div>
|
77
|
-
<div class="card-footer border-0 py-5">
|
78
|
-
<span class="text-muted text-sm">Showing <%= @properties.count > 0 ? @properties.count : 0%> items out of <%= @properties.count||0%> results found</span>
|
41
|
+
<tr>
|
42
|
+
<th scope="col">Sr.No</th>
|
43
|
+
<th scope="col">Title</th>
|
44
|
+
<th scope="col">Availability Start</th>
|
45
|
+
<th scope="col">Availability End</th>
|
46
|
+
<th scope="col">Status</th>
|
47
|
+
<th scope="col">Action</th>
|
48
|
+
</tr>
|
49
|
+
</thead>
|
50
|
+
<tbody>
|
51
|
+
<% @properties.each_with_index do |property, index| %>
|
52
|
+
<tr>
|
53
|
+
<td><%= index + 1 %></td>
|
54
|
+
<td><%= property.title %></td>
|
55
|
+
<td><%= property.availability_start && property.availability_start.strftime("%b %d, %Y") %></td>
|
56
|
+
<td><%= property.availability_end && property.availability_end.strftime("%b %d, %Y") %></td>
|
57
|
+
<td style = "color: <%= badge_class(property.property_state) %>">
|
58
|
+
<%= property.property_state.humanize %>
|
59
|
+
<span class="badge badge-lg badge-dot">
|
60
|
+
<i class="<%= icon_class(property.property_state) %>"></i>
|
61
|
+
</span>
|
62
|
+
</td>
|
63
|
+
<td class="d-flex justify-content-center">
|
64
|
+
<%= link_to edit_admin_property_path(property), class: 'btn d-inline-flex btn-sm btn-neutral mx-1' do %>
|
65
|
+
<i class="bi bi-pencil"></i>
|
66
|
+
<% end %>
|
67
|
+
<%= link_to admin_property_path(property), class: 'btn d-inline-flex btn-sm btn-neutral mx-1' do %>
|
68
|
+
<i class="bi bi-eye"></i>
|
69
|
+
<% end %>
|
70
|
+
<%= button_to admin_property_path(property), method: :delete, data: { turbo_method: :delete, turbo_confirm: 'Are you sure?' }, class: 'btn btn-sm btn-neutral mx-1 text-danger-hover' do %>
|
71
|
+
<i class="bi bi-trash"></i>
|
72
|
+
<% end %>
|
73
|
+
</td>
|
74
|
+
</tr>
|
75
|
+
<% end %>
|
76
|
+
</tbody>
|
77
|
+
</table>
|
78
|
+
</div>
|
79
79
|
</div>
|
80
80
|
<div class="d-flex justify-content-center">
|
81
|
-
|
81
|
+
<%= paginate @properties %>
|
82
82
|
</div>
|
@@ -2,68 +2,67 @@
|
|
2
2
|
<div class="card-header">
|
3
3
|
<div class="row align-items-center">
|
4
4
|
<div class="col-sm-6 col-12 mb-4 mb-sm-0">
|
5
|
-
|
6
|
-
|
5
|
+
<!-- Title -->
|
6
|
+
<h1 class="h3 mb-0 ls-tight">Rooms</h1>
|
7
7
|
</div>
|
8
8
|
<!-- Actions -->
|
9
9
|
<div class="col-sm-6 col-12 text-sm-end">
|
10
|
-
|
10
|
+
<div class="mx-n1">
|
11
11
|
<%= link_to new_admin_property_room_path(@property), class:"btn d-inline-flex btn-sm btn-primary mx-1" do %>
|
12
|
-
|
12
|
+
<span class=" pe-2">
|
13
13
|
<i class="bi bi-plus"></i>
|
14
|
-
|
15
|
-
|
14
|
+
</span>
|
15
|
+
<span>Create New</span>
|
16
16
|
<%end%>
|
17
|
-
|
17
|
+
</div>
|
18
18
|
</div>
|
19
19
|
</div>
|
20
20
|
</div>
|
21
21
|
<div class="table-responsive">
|
22
22
|
<table class="table table-hover table-nowrap">
|
23
23
|
<thead class="table-light">
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
</table>
|
64
|
-
</div>
|
65
|
-
|
66
|
-
<div class="card-footer border-0 py-5">
|
67
|
-
<span class="text-muted text-sm">Showing 10 items out of 250 results found</span>
|
24
|
+
<tr>
|
25
|
+
<th scope="col">Image</th>
|
26
|
+
<th scope="col">Max Guests</th>
|
27
|
+
<th scope="col">Price Per Night</th>
|
28
|
+
<th scope="col">Room Type</th>
|
29
|
+
<th scope="col">Booking Start</th>
|
30
|
+
<th scope="col">Booking End</th>
|
31
|
+
<th scope="col">Status</th>
|
32
|
+
<th scope="col">Action</th>
|
33
|
+
<th></th>
|
34
|
+
</tr>
|
35
|
+
</thead>
|
36
|
+
<tbody>
|
37
|
+
<% @rooms.each do |room| %>
|
38
|
+
<tr>
|
39
|
+
<td>
|
40
|
+
<%= image_tag main_app.url_for(room.room_images.first.url), size: "25x25" if room.room_images.attached? %>
|
41
|
+
</td>
|
42
|
+
<td><%= room.max_guests %></td>
|
43
|
+
<td><%= currency_symbol(current_currency) %> <%= room.price_per_month %></td>
|
44
|
+
<td><%= room.room_type&.name %></td>
|
45
|
+
<td><%= room.booking_start&.strftime("%b %d, %Y")%></td>
|
46
|
+
<td><%= room.booking_end&.strftime("%b %d, %Y")%></td>
|
47
|
+
<td><%= room.status%></td>
|
48
|
+
<td class="text-end d-flex justify-content-end">
|
49
|
+
<%= link_to edit_admin_property_room_path(@property, room), class: 'btn d-inline-flex btn-sm btn-neutral mx-1' do %>
|
50
|
+
<i class="bi bi-pencil">Edit</i>
|
51
|
+
<% end %>
|
52
|
+
<%= link_to admin_property_room_path(@property, room), class: 'btn d-inline-flex btn-sm btn-neutral mx-1' do %>
|
53
|
+
<i class="bi bi-eye">View</i>
|
54
|
+
<% end %>
|
55
|
+
<%= button_to admin_property_room_path(@property, room), method: :delete, data: { turbo_method: :delete, turbo_confirm: 'Are you sure?' }, class: 'btn btn-sm btn-neutral mx-1 text-danger-hover' do %>
|
56
|
+
<i class="bi bi-trash">Destroy</i>
|
57
|
+
<% end %>
|
58
|
+
</td>
|
59
|
+
</tr>
|
60
|
+
<% end %>
|
61
|
+
</tbody>
|
62
|
+
</table>
|
68
63
|
</div>
|
69
|
-
</div>
|
64
|
+
</div>
|
65
|
+
<div class="d-flex justify-content-center">
|
66
|
+
<%= paginate @rooms %>
|
67
|
+
</div>
|
68
|
+
|
@@ -6,12 +6,15 @@
|
|
6
6
|
<h2 class="text-xl font-semibold mb-0">User Details</h2>
|
7
7
|
</div>
|
8
8
|
<div class="card-body">
|
9
|
-
|
9
|
+
<%if @user.profile_image.attached?%>
|
10
|
+
<p><strong>Profile Image: </strong><%= image_tag main_app.url_for(@user.profile_image), size: "100x100", class: "mt-2" %></p>
|
11
|
+
<%end%>
|
12
|
+
<p><strong>Full Name: </strong><%= @user.full_name %></p>
|
10
13
|
<p><strong>Email: </strong><%= @user.email %></p>
|
11
14
|
<p><strong>Phone: </strong><%= @user.phone %></p>
|
12
|
-
<p><strong>Date of Birth: </strong><%= @user.date_of_birth %></p>
|
15
|
+
<p><strong>Date of Birth: </strong><%= @user.date_of_birth&.strftime("%b %d, %Y") %></p>
|
13
16
|
<p><strong>Gender: </strong><%= @user.gender %></p>
|
14
|
-
<p><strong>
|
17
|
+
<p><strong>Role: </strong><%= @user.stay_roles.map(&:name).join(", ").capitalize %></p>
|
15
18
|
<div class="d-flex mt-4 p-4 justify-content-center">
|
16
19
|
<%= link_to 'Edit', edit_admin_user_path(@user), class: 'btn btn-warning me-3' %>
|
17
20
|
<%= link_to 'Back', admin_users_path, class: 'btn btn-secondary' %>
|
data/lib/stay/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stay_commerce
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- w3villa-vikaspal
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-04-
|
11
|
+
date: 2025-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -479,6 +479,7 @@ files:
|
|
479
479
|
- app/assets/stylesheets/stay/webpixels.css
|
480
480
|
- app/channels/chat_channel.rb
|
481
481
|
- app/controllers/concerns/stay/booking_validations.rb
|
482
|
+
- app/controllers/concerns/stay/image_resizer_concern.rb
|
482
483
|
- app/controllers/concerns/stay/stripe_concern.rb
|
483
484
|
- app/controllers/devise/api/tokens_controller.rb
|
484
485
|
- app/controllers/stay/admin/addresses_controller.rb
|
@@ -610,13 +611,13 @@ files:
|
|
610
611
|
- app/serializers/cancellation_policy_serializer.rb
|
611
612
|
- app/serializers/chat_serializer.rb
|
612
613
|
- app/serializers/credit_card_serializer.rb
|
614
|
+
- app/serializers/feature_serializer.rb
|
613
615
|
- app/serializers/house_rules_serializer.rb
|
614
616
|
- app/serializers/invoice_serializer.rb
|
615
617
|
- app/serializers/last_5_messages_serializer.rb
|
616
618
|
- app/serializers/line_item_serializer.rb
|
617
619
|
- app/serializers/message_serializer.rb
|
618
620
|
- app/serializers/property_category_serializer.rb
|
619
|
-
- app/serializers/property_feature_serializer.rb
|
620
621
|
- app/serializers/property_listing_serializer.rb
|
621
622
|
- app/serializers/property_serializer.rb
|
622
623
|
- app/serializers/property_type_serializer.rb
|
@@ -935,6 +936,7 @@ files:
|
|
935
936
|
- db/migrate/20241205092943_create_friendly_id_slugs.rb
|
936
937
|
- db/migrate/20241217044817_add_deleted_atto_stay_property.rb
|
937
938
|
- db/migrate/20241230064432_modify_property_category_on_properties.rb
|
939
|
+
- db/migrate/20250407101335_add_field_to_stay_users.rb
|
938
940
|
- db/seeds.rb
|
939
941
|
- lib/stay.rb
|
940
942
|
- lib/stay/controller_helpers/currency.rb
|