diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cea3e33d5..bc09fe086 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,16 @@ name: CI on: push: + pull_request: + branches: + - develop + - master + types: + - closed + + release: + types: [published] + jobs: rubocop: runs-on: ubuntu-latest @@ -50,7 +60,10 @@ jobs: with: ruby-version: 3.3.5 bundler-cache: true - + + - name: Update packages + run: sudo apt-get update + - name: Install system dependencies run: | sudo apt-get update @@ -58,8 +71,8 @@ jobs: - uses: actions/setup-node@v1 with: - node-version: '14.x' - registry-url: 'https://registry.npmjs.org' + node-version: "14.x" + registry-url: "https://registry.npmjs.org" - uses: nanasess/setup-chromedriver@master @@ -81,3 +94,40 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} json-path: tmp/rspec_results.json if: always() + + deploy-to-staging: + needs: rspec + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true + steps: + - uses: actions/checkout@v2 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.3.5 + bundler-cache: true + + - uses: miloserdow/capistrano-deploy@v3 + with: + target: staging + deploy_key: ${{ secrets.STAGING_KEY_PASSWORD }} + enc_rsa_key_pth: config/credentials/staging_deploy_id_ed25519_enc + + deploy-to-production: + needs: rspec + runs-on: ubuntu-latest + if: github.event_name == 'release' && github.event.action == 'published' + steps: + - uses: actions/checkout@v2 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.3.5 + bundler-cache: true + + - uses: miloserdow/capistrano-deploy@v3 + with: + target: production + deploy_key: ${{ secrets.PROD_DEPLOY_KEY }} diff --git a/.rubocop.yml b/.rubocop.yml index 51dec8a54..0d435ded4 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -18,7 +18,7 @@ inherit_gem: AllCops: SuggestExtensions: true NewCops: enable - TargetRubyVersion: 3.0.6 + TargetRubyVersion: 3.2 Layout/SpaceInsideHashLiteralBraces: Enabled: true diff --git a/README.md b/README.md index d1bb70b38..0f6a65d4f 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ The latest version from the release branch 'master' is automatically deployed to - Bootstrap ## Clone - + $ `git clone https://github.com/ita-social-projects/ZeroWaste.git` ## Local setup diff --git a/app/assets/images/pad_scales.png b/app/assets/images/pad_scales.png new file mode 100644 index 000000000..bae343088 Binary files /dev/null and b/app/assets/images/pad_scales.png differ diff --git a/app/assets/images/pads_bought.png b/app/assets/images/pads_bought.png new file mode 100644 index 000000000..7a864b55a Binary files /dev/null and b/app/assets/images/pads_bought.png differ diff --git a/app/assets/images/pads_to_buy.png b/app/assets/images/pads_to_buy.png new file mode 100644 index 000000000..0fcf41cda Binary files /dev/null and b/app/assets/images/pads_to_buy.png differ diff --git a/app/assets/stylesheets/application.tailwind.css b/app/assets/stylesheets/application.tailwind.css index f73f37afc..9a85acf0b 100644 --- a/app/assets/stylesheets/application.tailwind.css +++ b/app/assets/stylesheets/application.tailwind.css @@ -10,5 +10,6 @@ @import "/components/pagination"; @import "/components/breadcrumbs.scss"; @import "/components/description_block"; +@import "/components/showpage_calculator"; @import "/utilities/custom-utilities"; @import "/pages/under_construction" diff --git a/app/assets/stylesheets/components/showpage_calculator.css b/app/assets/stylesheets/components/showpage_calculator.css new file mode 100644 index 000000000..c106a4e6e --- /dev/null +++ b/app/assets/stylesheets/components/showpage_calculator.css @@ -0,0 +1,21 @@ +@layer components { + .main-show-container { + @apply flex flex-col bg-white rounded-lg shadow-md w-full p-6 text-left mt-4; + } + + .back-arrow { + @apply rounded mb-4 px-2 flex items-center; + } + + .calc-details { + @apply flex flex-col mb-4 px-2; + } + + .showpage-buttons { + @apply flex justify-start w-full space-x-4; + } + + .showpage-text { + @apply text-slate-600 text-sm; + } +} diff --git a/app/assets/stylesheets/pages/calculator.scss b/app/assets/stylesheets/pages/calculator.scss index 0dede5e06..1c8178664 100644 --- a/app/assets/stylesheets/pages/calculator.scss +++ b/app/assets/stylesheets/pages/calculator.scss @@ -16,6 +16,28 @@ font-style: normal; transition: transform 0.5s ease-in-out; max-width: 300px; + @include transition(all 0.5s ease-in-out); + + &:hover { + background-color: $matte_lime_green; + } +} + +.btn-nonito { + font-size: 14px; + letter-spacing: 2px; + text-transform: uppercase; + font-weight: 400; + font-family: "Nunito", sans-serif; + font-style: normal; +} + +.dynamic-text-color { + color: var(--calculator-color); +} + +.dynamic-background-color { + background-color: var(--calculator-color); } #calc { @@ -61,6 +83,11 @@ margin-right: 0px; } +.calculator-field { + background-color: $light_gray !important; + border: 0; +} + .flex-item { display: flex; flex-wrap: wrap; diff --git a/app/assets/stylesheets/pages/feature_flags.scss b/app/assets/stylesheets/pages/feature_flags.scss index a68714537..53a8ce168 100644 --- a/app/assets/stylesheets/pages/feature_flags.scss +++ b/app/assets/stylesheets/pages/feature_flags.scss @@ -41,7 +41,6 @@ } input[type="submit"] { - background-color: $success; border: none; border-radius: 4px; color: #fff; @@ -49,11 +48,6 @@ input[type="submit"] { font-size: 16px; padding: 10px; min-width: 110px; - @include transition(all 0.5s ease-in-out); - - &:hover { - background-color: $matte_lime_green; - } } .btn-grey { diff --git a/app/controllers/account/calculators_controller.rb b/app/controllers/account/calculators_controller.rb index 4a1cd4b6a..c4d6bb1a5 100644 --- a/app/controllers/account/calculators_controller.rb +++ b/app/controllers/account/calculators_controller.rb @@ -2,10 +2,9 @@ class Account::CalculatorsController < Account::BaseController load_and_authorize_resource + before_action :check_constructor_flipper def index - render "shared/under_construction" unless Rails.env.local? - @q = collection.ransack(params[:q]) @calculators = @q.result.page(params[:page]) end @@ -95,4 +94,10 @@ def updater @calculator.update(calculator_params) end end + + def check_constructor_flipper + return if Flipper[:constructor_status].enabled? + + raise ActionController::RoutingError, "Constructor flipper is disabled" + end end diff --git a/app/controllers/account/users_controller.rb b/app/controllers/account/users_controller.rb index e36afe64d..4fc589e74 100644 --- a/app/controllers/account/users_controller.rb +++ b/app/controllers/account/users_controller.rb @@ -6,6 +6,7 @@ class Account::UsersController < Account::BaseController layout "account" before_action :set_paper_trail_whodunnit + before_action :blocking_admin, only: :update load_and_authorize_resource @@ -71,6 +72,16 @@ def user_params prms end + def blocking_admin + @user = resource + + return if params.dig(:user, :blocked).blank? || !@user.admin? + + flash[:alert] = t("errors.messages.blocked_user_cannot_be_admin") + + redirect_to account_users_path + end + def collection User.ordered_by_email end diff --git a/app/controllers/api/v1/pad_calculators_controller.rb b/app/controllers/api/v1/pad_calculators_controller.rb new file mode 100644 index 000000000..659282f88 --- /dev/null +++ b/app/controllers/api/v1/pad_calculators_controller.rb @@ -0,0 +1,20 @@ +class Api::V1::PadCalculatorsController < ApplicationController + def calculate + @validation = MhcCalculatorValidator.new(params) + + if @validation.valid? + calc_service = Calculators::PadUsageService.new( + user_age: params[:user_age], + menstruation_age: params[:menstruation_age], + menopause_age: params[:menopause_age], + average_menstruation_cycle_duration: params[:average_menstruation_cycle_duration], + pads_per_cycle: params[:pads_per_cycle], + pad_category: params[:pad_category] + ) + + render json: calc_service.calculate, status: :ok + else + render json: { errors: @validation.errors }, status: :unprocessable_entity + end + end +end diff --git a/app/controllers/calculators_controller.rb b/app/controllers/calculators_controller.rb index 8e87d0e92..a6b025e2c 100644 --- a/app/controllers/calculators_controller.rb +++ b/app/controllers/calculators_controller.rb @@ -3,6 +3,9 @@ class CalculatorsController < ApplicationController before_action :authenticate_user!, only: :receive_recomendations + before_action :check_constructor_flipper, only: [:index, :show, :calculate] + before_action :check_mhc_flipper, only: :mhc_calculator + def index if Flipper[:show_calculators_list].enabled? @q = collection.ransack(params[:q]) @@ -14,6 +17,8 @@ def index def show @calculator = resource + add_breadcrumb t("breadcrumbs.home"), root_path + add_breadcrumb @calculator.name end def calculate @@ -37,6 +42,11 @@ def calculator end end + def mhc_calculator + add_breadcrumb t("breadcrumbs.home"), root_path + add_breadcrumb t(".mhc_calculator.calculator_name") + end + def receive_recomendations current_user.toggle(:receive_recomendations) current_user.save @@ -51,4 +61,16 @@ def collection def resource collection.friendly.find(params[:slug]) end + + def check_constructor_flipper + return if Flipper[:constructor_status].enabled? + + raise ActionController::RoutingError, "Constructor flipper is disabled" + end + + def check_mhc_flipper + return if Flipper[:mhc_calculator_status].enabled? + + raise ActionController::RoutingError, "Mhc calculator flipper is disabled" + end end diff --git a/app/helpers/calculators_helper.rb b/app/helpers/calculators_helper.rb index 7d3236c88..1ce08246d 100644 --- a/app/helpers/calculators_helper.rb +++ b/app/helpers/calculators_helper.rb @@ -31,6 +31,15 @@ def link_to_external(text:, url:, **options) end end + def mhc_calculator_items + [{ image: "pads_bought.png", data_target: "padsUsed", unit: t(".pieces"), text: t(".bought_products") }, + "arrow", + { image: "pads_to_buy.png", data_target: "padsToBeUsed", unit: t(".pieces"), text: t(".will_buy_products") }, + { image: "money_spent_2.png", data_target: "moneySpent", unit: t(".unit"), text: t(".money_spent") }, + "arrow", + { image: "money_to_spent_2.png", data_target: "moneyWillBeSpent", unit: t(".unit"), text: t(".money_will_be_spent") }] + end + def new_calculator_items [{ image: "diapers_bought_2.png", data_target: "diapersUsed", unit: t(".pieces"), text_target: "boughtDiapersPluralize", text: t(".bought_diapers", count: 0) }, "arrow", diff --git a/app/javascript/controllers/constructors_form_indexing_controller.js b/app/javascript/controllers/constructors_form_indexing_controller.js new file mode 100644 index 000000000..9e5677b96 --- /dev/null +++ b/app/javascript/controllers/constructors_form_indexing_controller.js @@ -0,0 +1,26 @@ +import { Controller } from "@hotwired/stimulus" + +// Connects to data-controller="constructors-form-indexing" +export default class extends Controller { + static targets = ["index"]; + + afterInsert(event) { + const fieldsets = this.element.querySelectorAll(":scope > .nested-fields"); + const span = fieldsets[fieldsets.length - 1].querySelector("[data-constructors-form-indexing-target='index']") + + if (span) { + span.textContent = `${fieldsets.length}`; + } + } + + afterRemove(event) { + const fieldsets = this.element.querySelectorAll(":scope > .nested-fields"); + + fieldsets.forEach((fieldset, index) => { + const span = fieldset.querySelector("[data-constructors-form-indexing-target='index']"); + if (span) { + span.textContent = `${index + 1}`; + } + }); + } +} diff --git a/app/javascript/controllers/mhc_calculator_controller.js b/app/javascript/controllers/mhc_calculator_controller.js new file mode 100644 index 000000000..dc7e0f3ad --- /dev/null +++ b/app/javascript/controllers/mhc_calculator_controller.js @@ -0,0 +1,71 @@ +import { Controller } from "@hotwired/stimulus"; +import { FetchRequest } from "@rails/request.js"; + +export default class extends Controller { + static targets = ["userAge", "menstruationAge", "menopauseAge", "averageMenstruationCycleDuration", "padsPerCycle", "padCategory"]; + static outlets = ["pad-results"]; + static values = { + url: { + type: String, + default: "en/api/v1/pad_calculators", + } + }; + + submit(e) { + e.preventDefault(); + + let formData = { + user_age: parseInt(this.userAgeTarget.value), + menstruation_age: parseInt(this.menstruationAgeTarget.value), + menopause_age: parseInt(this.menopauseAgeTarget.value), + average_menstruation_cycle_duration: parseInt(this.averageMenstruationCycleDurationTarget.value), + pads_per_cycle: parseInt(this.padsPerCycleTarget.value), + pad_category: this.padCategoryTarget.value + }; + + const request = new FetchRequest("POST", this.urlValue, { + responseKind: "json", + body: JSON.stringify(formData), + }); + + this.sendRequest(request); + } + + async sendRequest(request) { + const response = await request.perform(); + const result = await response.json; + + this.clearErrors() + + if (response.ok) { + this.padResultsOutlet.showResults(result); + } else if (response.statusCode == 422) { + this.showErrors(result.errors); + } + } + + showErrors(errors) { + Object.keys(errors).forEach(errorKey => { + const targetKey = errorKey.replace(/_([a-z])/g, (match, letter) => letter.toUpperCase()); + const feedbackDiv = document.createElement('div'); + + feedbackDiv.className = 'invalid-feedback'; + feedbackDiv.textContent = errors[errorKey]; + + this[`${targetKey}Target`].classList.add("is-invalid"); + this[`${targetKey}Target`].insertAdjacentElement('afterend', feedbackDiv); + }); + } + + clearErrors(){ + this.constructor.targets.forEach(targetKey => { + const targetElement = this[`${targetKey}Target`]; + targetElement.classList.remove("is-invalid"); + + const feedbackDiv = targetElement.nextElementSibling; + if (feedbackDiv && feedbackDiv.classList.contains('invalid-feedback')) { + feedbackDiv.remove(); + } + }); + } +} diff --git a/app/javascript/controllers/pad_results_controller.js b/app/javascript/controllers/pad_results_controller.js new file mode 100644 index 000000000..a998666df --- /dev/null +++ b/app/javascript/controllers/pad_results_controller.js @@ -0,0 +1,21 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ + "padsUsed", + "padsToBeUsed", + "moneySpent", + "moneyWillBeSpent" + ]; + + showResults(data) { + let result = data; + + this.moneySpentTarget.innerHTML = Math.ceil(result.already_used_products_cost); + this.moneyWillBeSpentTarget.innerHTML = Math.ceil(result.products_to_be_used_cost); + this.padsUsedTarget.innerHTML = Math.ceil(result.already_used_products); + this.padsToBeUsedTarget.innerHTML = Math.ceil(result.products_to_be_used); + + this.element.scrollIntoView({ behavior: "smooth" }); + } +} diff --git a/app/javascript/controllers/price_form_controller.js b/app/javascript/controllers/price_form_controller.js index 9ecdf8479..8e2262e64 100644 --- a/app/javascript/controllers/price_form_controller.js +++ b/app/javascript/controllers/price_form_controller.js @@ -13,6 +13,7 @@ export default class extends Controller { this.priceInputTargets.forEach(input => { input.addEventListener('input', this.validatePriceInput.bind(this)); + input.addEventListener('keydown', this.restrictDecimalInput.bind(this)); }); } @@ -57,4 +58,13 @@ export default class extends Controller { target.style.borderColor = ""; } } + + restrictDecimalInput(event) { + const target = event.target; + const inputValue = target.value; + + if (inputValue.includes('.') && inputValue.split('.')[1].length >= 2 && !["Backspace", "Delete"].includes(event.key)) { + event.preventDefault(); + } + } } diff --git a/app/javascript/controllers/results_controller.js b/app/javascript/controllers/results_controller.js index 2fc4578ed..f66dbcc75 100644 --- a/app/javascript/controllers/results_controller.js +++ b/app/javascript/controllers/results_controller.js @@ -20,5 +20,7 @@ export default class extends Controller { this.willBuyDiapersPluralizeTarget.innerHTML = result.to_be_diapers_amount_pluralize; this.boughtDiapersPluralizeTarget.innerHTML = result.used_diapers_amount_pluralize; + + this.element.scrollIntoView({ behavior: "smooth" }); } } diff --git a/app/models/formula.rb b/app/models/formula.rb index 66b8217bd..872682229 100644 --- a/app/models/formula.rb +++ b/app/models/formula.rb @@ -22,6 +22,8 @@ # fk_rails_... (calculator_id => calculators.id) # class Formula < ApplicationRecord + include Translatable + belongs_to :calculator PRIORITY_RANGE = 0..10 @@ -34,4 +36,6 @@ class Formula < ApplicationRecord validates :priority, numericality: { greater_than_or_equal_to: 0 } scope :ordered_by_priority, -> { order(:priority) } + + translates :label, :unit end diff --git a/app/services/calculators/calculation_service.rb b/app/services/calculators/calculation_service.rb index 081092b0f..e888d1f47 100644 --- a/app/services/calculators/calculation_service.rb +++ b/app/services/calculators/calculation_service.rb @@ -10,7 +10,7 @@ def perform @calculator.formulas.map do |formula| result = @dentaku.evaluate(formula.expression, @inputs) - { label: formula.en_label, result: result } + { label: formula.label, result: result, unit: formula.unit } end end end diff --git a/app/services/calculators/pad_usage_service.rb b/app/services/calculators/pad_usage_service.rb new file mode 100644 index 000000000..5de628434 --- /dev/null +++ b/app/services/calculators/pad_usage_service.rb @@ -0,0 +1,52 @@ +class Calculators::PadUsageService + attr_accessor :user_age, :menstruation_age, :menopause_age, + :average_menstruation_cycle_duration, + :pads_per_cycle, :pad_category + + PAD_PRICES = { + budget: 2, + average: 4, + premium: 7 + } + + def initialize(user_age:, menstruation_age:, menopause_age:, average_menstruation_cycle_duration:, + pads_per_cycle:, pad_category:) + @user_age = user_age + @menstruation_age = menstruation_age + @menopause_age = menopause_age || 48.7 + @average_menstruation_cycle_duration = average_menstruation_cycle_duration + @pads_per_cycle = pads_per_cycle + @pad_category = (pad_category || :budget).to_sym + end + + def calculate + { + already_used_products:, + already_used_products_cost:, + products_to_be_used:, + products_to_be_used_cost: + } + end + + private + + def already_used_products + menstruations_from_age_range(menstruation_age, user_age) * pads_per_cycle + end + + def products_to_be_used + menstruations_from_age_range(user_age, menopause_age) * pads_per_cycle + end + + def already_used_products_cost + already_used_products * PAD_PRICES[pad_category] + end + + def products_to_be_used_cost + products_to_be_used * PAD_PRICES[pad_category] + end + + def menstruations_from_age_range(from_age, till_age) + (till_age - from_age) * (365 / average_menstruation_cycle_duration) + end +end diff --git a/app/validators/mhc_calculator_validator.rb b/app/validators/mhc_calculator_validator.rb new file mode 100644 index 000000000..cd5e21bfe --- /dev/null +++ b/app/validators/mhc_calculator_validator.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +class MhcCalculatorValidator + attr_reader :params, :errors + + def initialize(params) + @params = params + @errors = {} + end + + def valid? + validate_user_age + validate_menstruation_age + validate_menopause_age + validate_average_menstruation_cycle_duration + validate_pads_per_cycle + validate_pad_category + + errors.empty? + end + + private + + def validate_user_age + presence_valid?(:user_age) + end + + def validate_menstruation_age + presence_valid?(:menstruation_age) + end + + def validate_menopause_age + presence_valid?(:menopause_age) + end + + def validate_average_menstruation_cycle_duration + presence_valid?(:average_menstruation_cycle_duration) + end + + def validate_pads_per_cycle + presence_valid?(:pads_per_cycle) + end + + def validate_pad_category + presence_valid?(:pad_category) + end + + def presence_valid?(param) + return true if @params[param].present? + + @errors[param] = I18n.t("calculators.errors.presence_error_msg", field: I18n.t("calculators.mhc_calculator.form.#{param}")) + + false + end +end diff --git a/app/views/account/calculators/partials/_category_fields.html.erb b/app/views/account/calculators/partials/_category_fields.html.erb index b90a7a26d..ab81bb659 100644 --- a/app/views/account/calculators/partials/_category_fields.html.erb +++ b/app/views/account/calculators/partials/_category_fields.html.erb @@ -1,7 +1,10 @@ -
- <%= f.input :en_name, label: "Category Name:" %> - <%= f.input :uk_name, label: "Uk Category Name:" %> - <%= f.input :price, label: "Category Price:" %> - - <%= link_to_remove_association "- Remove Category", f, class: "text-red-500 underline" %> -
+
+ Category 1 +
+ <%= f.input :en_name, label: "Category Name:" %> + <%= f.input :uk_name, label: "Uk Category Name:" %> + <%= f.input :price, label: "Category Price:" %> + + <%= link_to_remove_association "- Remove Category", f, class: "text-red-500 underline" %> +
+
diff --git a/app/views/account/calculators/partials/_field_fields.html.erb b/app/views/account/calculators/partials/_field_fields.html.erb index 2df9d0d8e..3c86bf24b 100644 --- a/app/views/account/calculators/partials/_field_fields.html.erb +++ b/app/views/account/calculators/partials/_field_fields.html.erb @@ -1,21 +1,32 @@ -
- <%= f.input :en_label, label: "Field Label:" %> - <%= f.input :uk_label, label: "Uk Field Label:" %> - <%= f.input :var_name, label: "Variable Name:" %> - <%= f.input( - :kind, - collection: Field.kinds.keys.map { |key| [key.humanize, key] }, - prompt: "Select Field Type", - label: "Field Type:", - input_html: { data: { field_type_target: "fieldTypeSelect" } } - ) %> +
+ Field 1 + +
+ <%= f.input :en_label, label: "Field Label:" %> + <%= f.input :uk_label, label: "Uk Field Label:" %> + <%= f.input :var_name, label: "Variable Name:" %> + <%= f.input( + :kind, + collection: Field.kinds.keys.map { |key| [key.humanize, key] }, + prompt: "Select Field Type", + label: "Field Type:", + input_html: { data: { field_type_target: "fieldTypeSelect" } } + ) %> - - <%= link_to_remove_association "- Remove Field", f, class: "text-red-500 underline" %> -
+ + <%= link_to_remove_association "- Remove Field", f, class: "text-red-500 underline" %> +
+ diff --git a/app/views/account/calculators/partials/_form.html.erb b/app/views/account/calculators/partials/_form.html.erb index 781d15c5d..438b34288 100644 --- a/app/views/account/calculators/partials/_form.html.erb +++ b/app/views/account/calculators/partials/_form.html.erb @@ -1,27 +1,36 @@ <%= simple_form_for(@calculator, url: account_calculators_path) do |f| %>
- <%= f.input :en_name, label: "Calculator Name:", class: 'form-control' %> - <%= f.input :uk_name, label: "Uk Calculator Name:", class: 'form-control' %> +
+ Calculator + <%= f.input :en_name, label: "Calculator Name:", class: 'form-control' %> + <%= f.input :uk_name, label: "Uk Calculator Name:", class: 'form-control' %> +
- <%= f.simple_fields_for :formulas do |formula_fields| %> - <%= render "account/calculators/partials/formula_fields", f: formula_fields %> - <% end %> - +
+ <%= f.simple_fields_for :formulas do |formula_fields| %> + <%= render "account/calculators/partials/formula_fields", f: formula_fields %> + <% end %> + +
- <%= f.simple_fields_for :fields do |field_fields| %> - <%= render "account/calculators/partials/field_fields", f: field_fields %> - <% end %> - +
+ <%= f.simple_fields_for :fields do |field_fields| %> + <%= render "account/calculators/partials/field_fields", f: field_fields %> + <% end %> + +
diff --git a/app/views/account/calculators/partials/_formula_fields.html.erb b/app/views/account/calculators/partials/_formula_fields.html.erb index c0519a2df..d4870167c 100644 --- a/app/views/account/calculators/partials/_formula_fields.html.erb +++ b/app/views/account/calculators/partials/_formula_fields.html.erb @@ -1,11 +1,13 @@ -
- <%= f.input :en_label, label: "Formula Label:" %> - <%= f.input :uk_label, label: "Uk Formula Label:" %> - <%= f.input :priority, collection: Formula::PRIORITY_RANGE, wrapper: :custom_vertical_select %> - <%= f.input :expression, label: "Formula Expression:" %> +
+ Formula 1 +
+ <%= f.input :en_label, label: "Formula Label:" %> + <%= f.input :uk_label, label: "Uk Formula Label:" %> + <%= f.input :priority, collection: Formula::PRIORITY_RANGE, wrapper: :custom_vertical_select %> + <%= f.input :expression, label: "Formula Expression:" %> + <%= f.input :uk_unit, label: "Uk Unit Label:" %> + <%= f.input :en_unit, label: "Unit Label:" %> - <%= f.input :uk_unit, label: "Uk Unit Label:" %> - <%= f.input :en_unit, label: "Unit Label:" %> - - <%= link_to_remove_association "- Remove Formula", f, class: "text-red-500 underline" %> -
+ <%= link_to_remove_association "- Remove Formula", f, class: "text-red-500 underline" %> +
+ diff --git a/app/views/account/calculators/show.html.erb b/app/views/account/calculators/show.html.erb new file mode 100644 index 000000000..9a6fdaaa9 --- /dev/null +++ b/app/views/account/calculators/show.html.erb @@ -0,0 +1,29 @@ +
+ <%= link_to account_calculators_path, class: "back-arrow" do %> + <%= inline_svg "icons/arrow-left.svg", class: "z-1 mr-2 mb-0.5" %> + <%= t('buttons.back') %> + <% end %> + +
+ <%= t('.name') %>: +

<%= @calculator.name %>

+
+ +
+ <%= t('.slug') %>: +

<%= @calculator.slug %>

+
+ +
+ <%= link_to t('.edit'), + edit_account_calculator_path(@calculator.slug, locale: I18n.locale), + class: "btn btn-green" %> + + <%= button_to account_calculator_path(@calculator.slug, locale: I18n.locale), + method: :delete, + data: { turbo_confirm: t('.confirm_delete') }, + class: "btn btn-danger" do %> + <%= t('.delete') %> + <% end %> +
+
diff --git a/app/views/account/categories/new.html.erb b/app/views/account/categories/new.html.erb index f9f6156d6..1bdd33494 100644 --- a/app/views/account/categories/new.html.erb +++ b/app/views/account/categories/new.html.erb @@ -1,15 +1,3 @@ -<%= simple_form_for @category, url: { action: "create" }, html: { novalidate: false } do |f| %> -
-
- <%= f.input :uk_name, class: "form-control col-sm-11" %> - <%= f.input :en_name, class: "form-control col-sm-11" %> - <%= f.input :priority, collection: Category::PRIORITY_RANGE, wrapper: :custom_vertical_select %> -
-
-
- <%= f.submit t(".form.create_category_button"), class: "btn btn-green me-2" %> - <%= link_to account_categories_path, class: "btn btn-danger d-flex align-items-center justify-content-center" do %> - <%= t("buttons.cancel") %> - <% end %> -
-<% end %> +
+ <%= render "account/categories/partials/new/form", category: @category %> +
diff --git a/app/views/account/categories/new.turbo_stream.erb b/app/views/account/categories/new.turbo_stream.erb new file mode 100644 index 000000000..0de8de8e1 --- /dev/null +++ b/app/views/account/categories/new.turbo_stream.erb @@ -0,0 +1,4 @@ +<%= turbo_stream.replace( + dom_id(@category, :form), + partial: "account/categories/partials/new/form", + locals: {category: @category}) %> diff --git a/app/views/account/categories/partials/new/_form.html.erb b/app/views/account/categories/partials/new/_form.html.erb new file mode 100644 index 000000000..f0ad59de7 --- /dev/null +++ b/app/views/account/categories/partials/new/_form.html.erb @@ -0,0 +1,15 @@ +<%= simple_form_for @category, url: { action: "create" }, html: { id: dom_id(category, :form) } do |f| %> +
+
+ <%= f.input :uk_name, class: "form-control col-sm-11" %> + <%= f.input :en_name, class: "form-control col-sm-11" %> + <%= f.input :priority, collection: Category::PRIORITY_RANGE, wrapper: :custom_vertical_select %> +
+
+
+ <%= f.submit t("account.categories.new.form.create_category_button"), class: "btn btn-green me-2" %> + <%= link_to account_categories_path, class: "btn btn-danger d-flex align-items-center justify-content-center" do %> + <%= t("buttons.cancel") %> + <% end %> +
+<% end %> diff --git a/app/views/account/shared/_navigation.html.erb b/app/views/account/shared/_navigation.html.erb index 1df545e99..575b45bf9 100644 --- a/app/views/account/shared/_navigation.html.erb +++ b/app/views/account/shared/_navigation.html.erb @@ -10,6 +10,11 @@ <%= link_to t("layouts.navigation.calculate"), calculator_path, class: "tab-main-page" %> <% end %> +
  • + <% if Flipper[:mhc_calculator_status].enabled? %> + <%= link_to t("layouts.navigation.mhc_calculator"), mhc_calculator_path, class: "tab-main-page" %> + <% end %> +
  • <%= link_to t("layouts.navigation.about_us"), about_path, class: "tab-main-page" %>
  • @@ -18,7 +23,7 @@ <% if user_signed_in? && current_user.admin? %>
  • - <%= link_to t("layouts.navigation.admin"), account_calculators_path, class: "tab-main-page" %> + <%= link_to t("layouts.navigation.admin"), edit_account_site_setting_path, class: "tab-main-page" %>
  • <% end %> <% if user_signed_in? %> diff --git a/app/views/account/users/index.html.erb b/app/views/account/users/index.html.erb index 588018bc4..77d2448f3 100644 --- a/app/views/account/users/index.html.erb +++ b/app/views/account/users/index.html.erb @@ -38,10 +38,12 @@ <%= link_to icon("fa-solid", "eye"), account_user_path(id: user.id) %> <%= link_to icon("fa-solid", "edit"), edit_account_user_path(id: user.id) %> - <%= button_to account_user_path(id: user, user: toggle_block_param(user)), - method: :patch, - data: { turbo_confirm: toggle_confirm(user) } do %> - <%= icon("fa-solid", toggle_class(user)) %> + <% unless user.admin? %> + <%= button_to account_user_path(id: user, user: toggle_block_param(user)), + method: :patch, + data: { turbo_confirm: toggle_confirm(user) } do %> + <%= icon("fa-solid", toggle_class(user)) %> + <% end %> <% end %> diff --git a/app/views/calculators/mhc_calculator.erb b/app/views/calculators/mhc_calculator.erb new file mode 100644 index 000000000..16cd4d748 --- /dev/null +++ b/app/views/calculators/mhc_calculator.erb @@ -0,0 +1,93 @@ +
    +

    <%= t(".calculator_name") %>

    +
    + <%= simple_form_for(:pad, url: "#", html: { class: "simple_form_calculator", + data: { controller: "mhc-calculator", + mhc_calculator_url_value: api_v1_pad_calculators_url, + mhc_calculator_pad_results_outlet: ".result" } }) do |form| %> +
    + +
    + <%= label_tag "child_product_category", t(".form.user_age") %> +
    + + <%= form.input_field :user_age, + type: "number", + class: "form_fild price_select rounded w-100 form-control mb-0", + data: { mhc_calculator_target: "userAge" } %> + +
    + <%= label_tag "child_product_category", t(".form.menstruation_age") %> +
    + + <%= form.input_field :menstruation_age, + type: "number", + class: "form_fild price_select rounded w-100 form-control mb-0 ", + data: { mhc_calculator_target: "menstruationAge" } %> + +
    + <%= label_tag "child_product_category", t(".form.menopause_age") %> +
    + + <%= form.input_field :menopause_age, + type: "number", + class: "form_fild price_select rounded w-100 form-control mb-0", + data: { mhc_calculator_target: "menopauseAge" } %> + +
    + <%= label_tag "child_product_category", t(".form.average_menstruation_cycle_duration") %> +
    + + <%= form.input_field :average_menstruation_cycle_duration, + type: "number", + class: "form_fild price_select rounded w-100 form-control mb-0", + data: { mhc_calculator_target: "averageMenstruationCycleDuration" } %> + +
    + <%= label_tag "child_product_category", t(".form.pads_per_cycle") %> +
    + + <%= form.input_field :pads_per_cycle, + type: "number", + class: "form_fild price_select rounded w-100 form-control mb-0", + data: { mhc_calculator_target: "padsPerCycle" } %> + +
    + <%= label_tag "child_product_category", t(".form.pad_category") %> +
    + + <%= form.input_field :product_category, + collection: [[t(".form.budgetary"), :budget], [t(".form.average"), :average], [t(".form.premium"), :premium]], + selected: "Budget", + class: "form_fild price_select rounded w-100 form-control mb-0", + data: { mhc_calculator_target: "padCategory" } %> + + <%= form.submit t("calculators.buttons.calculate"), + class: "calculate-btn result-btn mt-6", + data: { action: "mhc-calculator#submit" } %> +
    + <% end %> + + <%= image_tag "pad_scales.png", class: "scales_img", alt: "Scales" %> +
    +
    + +
    + <% mhc_calculator_items.each do |item| %> + <% if item == "arrow" %> +
    + <%= image_tag "icons/vector_5.png", class: "vector", alt: "horizontal arrow" %> + <%= image_tag "icons/vector_2.png", class: "vector-mobile", alt: "vertical arrow" %> +
    + <% else %> +
    + <%= image_tag item[:image], class: "img-margin", alt: "icon" %> +

    0

    +

    <%= item[:unit] %>

    +

    <%= item[:text] %>

    +
    + <% end %> + <% end %> +
    + +<%= render "layouts/mhc_description_block" %> diff --git a/app/views/calculators/partials/_calculation_results.html.erb b/app/views/calculators/partials/_calculation_results.html.erb index 72c1d9215..14199c497 100644 --- a/app/views/calculators/partials/_calculation_results.html.erb +++ b/app/views/calculators/partials/_calculation_results.html.erb @@ -1,14 +1,22 @@ -

    Calculation Results

    -
    - <% results.each do |result| %> -
    -

    - <%= result[:label] %> -

    - = -

    - <%= result[:result] %> -

    -
    - <% end %> +<%# TODO: Delete this and use user provided value%> +<% formula_image = "money_to_spent_2.png" %> + +
    +

    Calculation Results

    +
    + <% results.each do |result| %> +
    + <%= image_tag "#{formula_image}", class: "img-margin", alt: "icon" %> +

    + <%= result[:result] %> +

    +

    + <%= result[:unit] %> +

    +

    + <%= result[:label] %> +

    +
    + <% end %> +
    diff --git a/app/views/calculators/partials/show/_constructor_calculator_description.erb b/app/views/calculators/partials/show/_constructor_calculator_description.erb new file mode 100644 index 000000000..fed35215a --- /dev/null +++ b/app/views/calculators/partials/show/_constructor_calculator_description.erb @@ -0,0 +1,8 @@ +<%# TODO: Delete this if %> +<% if false %> +
    +
    + <%# TODO: ADD text here %> +
    +
    +<% end %> diff --git a/app/views/calculators/show.html.erb b/app/views/calculators/show.html.erb index 489f4f024..82295fe22 100644 --- a/app/views/calculators/show.html.erb +++ b/app/views/calculators/show.html.erb @@ -1,21 +1,40 @@ -
    -

    Calculator <%= @calculator.name %>


    +<%# TODO: Delete this and use user provided value %> +<% color = "#088F8F" %> - <%= form_with url: calculate_calculator_path(@calculator) do |form| %> - <% @calculator.fields.each do |field| %> -
    -

    <%= form.label field.var_name, field.label %>

    - <% if field.kind == 'number' %> - <%= form.number_field "inputs[#{field.var_name}]", placeholder: field.label %> - <% else %> - <%= form.select "inputs[#{field.var_name}]", options_from_collection_for_select(field.categories, :price, :name) %> - <% end %> -

    +<%# TODO: Delete this and use user provided value %> +<% calculator_image = "scales.png" %> + +
    +
    +

    Calculator <%= @calculator.name %> <%= @text %>

    +
    + + <%= form_with html: { class: "simple_form_calculator"}, url: calculate_calculator_path(@calculator) do |form| %> +
    + <% @calculator.fields.each do |field| %> +
    <%= form.label field.var_name, field.label %>
    + <% if field.kind == 'number' %> +
    + <%= form.number_field "inputs[#{field.var_name}]", + placeholder: field.label, + class: "required rounded w-100 calculator-field" + %> +
    + <% else %> + <%= form.select "inputs[#{field.var_name}]", + options_from_collection_for_select(field.categories, :price, :name), + {}, + class: "flex-row rounded flex-item w-100 form_fild calculator-field" %> + <% end %> + <% end %> + <%= form.submit "Calculate", class: "btn-nonito result-btn dynamic-background-color" %> +
    <% end %> -
    - <%= form.submit "Calculate", class: "bg-blue-500 text-white font-semibold px-4 py-2 rounded hover:bg-blue-700" %> + <%= image_tag calculator_image, class: "scales_img", alt: t(".image_alt") %>
    - <% end %> +
    <%= turbo_frame_tag "calc-results" %>
    + +<%= render "calculators/partials/show/constructor_calculator_description" %> diff --git a/app/views/layouts/_account_navbar.html.erb b/app/views/layouts/_account_navbar.html.erb index 35774f393..f3cac3796 100644 --- a/app/views/layouts/_account_navbar.html.erb +++ b/app/views/layouts/_account_navbar.html.erb @@ -8,13 +8,15 @@