Skip to content

Commit

Permalink
save as draft
Browse files Browse the repository at this point in the history
  • Loading branch information
maria-j-k committed Dec 10, 2024
1 parent e6c77a6 commit 1cdb55e
Show file tree
Hide file tree
Showing 17 changed files with 352 additions and 144 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Please view this file on the master branch, on stable branches it's out of date.
## [3.58.0]

### Added
- Add save as draft feature to offers form (@maria-j-k, @jarekzet)

### Changed

Expand Down
88 changes: 88 additions & 0 deletions app/assets/stylesheets/_bootstrap-customizations.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6496,6 +6496,94 @@ abbr[title] {
}
}

.modal-overlay {
background: $custom-26;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
position: relative;
height: 100vh;
width: 100%;
}

.exit-popup {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;

.modal-header {
border: none;
padding: 25px 25px 10px;

.modal-title {
font-size: 22px;
}
}

.modal-content {
width: 600px;
background: $home-card-bg;
border-radius: 14px;
font-size: 16px;
box-shadow: $popup-shadow;
border: 1px solid $popup-border;
}

.modal-body {
padding: 20px 25px;

label {
font-weight: 600;
margin-top: 15px;
}

input {
border-radius: 8px;
min-height: 53px;
font-size: 1rem;
height: calc(1.5em + 1.4rem + 2px);
padding: 0.7rem 1rem;
}
}

.modal-footer {
border: none;
padding: 0 25px 35px;

.buttons-row {
margin-top: 15px;
width: 100%;

.btn-sm {
font-size: 18px;
font-weight: 600;
color: $custom-16;
padding: 15px 60px;
background: $custom-25;
float: left;

&:hover {
color: $custom-16 !important;
}

&.btn-primary {
color: $palette-white;
float: right;
background: $custom-16;

&:hover {
color: $palette-white !important;
}
}
}
}
}
}

.bordered-box {
width: 100%;
min-height: 300px;
Expand Down
2 changes: 2 additions & 0 deletions app/assets/stylesheets/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,5 @@ $custom-22: #e5e5e5;
$custom-22: #000723;
$custom-23: #fafbfd;
$custom-24: rgba(145, 158, 231, 0.19);
$custom-25: #f8f8ff;
$custom-26: rgb(0, 0, 0, 0.4);
28 changes: 25 additions & 3 deletions app/controllers/backoffice/services/offers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,26 @@ class Backoffice::Services::OffersController < Backoffice::ApplicationController
before_action :load_form_data, only: %i[fetch_subtypes]
after_action :reindex_offer, only: %i[create update destroy]

helper_method :exit_title, :save_as_draft_title, :save_title

def new
@offer = Offer.new(service: @service)
authorize(@offer)
end

def create
template = offer_template
save_as_draft = params[:commit] == "Save as Draft"
template = save_as_draft ? offer_draft_template : offer_template
authorize(template)

@offer = Offer::Create.call(template)
if save_as_draft
template.name = params["name"]
@offer = Offer::CreateAsDraft.call(template)
redirect_to backoffice_service_path(@service), notice: "New offer created successfully"
return
else
@offer = Offer::Create.call(template)
end

if @offer.persisted?
redirect_to backoffice_service_path(@service), notice: "New offer created successfully"
Expand All @@ -34,8 +44,15 @@ def edit
end

def update
save_as_draft = params[:commit] == "Save as Draft"
template = permitted_attributes(Offer)
if Offer::Update.call(@offer, transform_attributes(template, @service))

if save_as_draft
template[:name] = params["name"]
Offer::UpdateAsDraft.call(@offer, transform_attributes(template, @service))
redirect_to backoffice_service_path(@service), notice: "Offer updated successfully and drafted"
nil
elsif Offer::Update.call(@offer, transform_attributes(template, @service))
redirect_to backoffice_service_path(@service), notice: "Offer updated successfully"
else
render :edit, status: :bad_request
Expand Down Expand Up @@ -70,6 +87,11 @@ def offer_template
Offer.new(temp.merge(service: @service, status: :published))
end

def offer_draft_template
temp = transform_attributes(permitted_attributes(Offer), @service)
Offer.new(temp.merge(service: @service, status: :draft))
end

def transform_attributes(template, service)
template["service_id"] = service.id

Expand Down
7 changes: 7 additions & 0 deletions app/inputs/custom_input.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true
class CustomInput < SimpleForm::Inputs::StringInput
def input(wrapper_options = nil)
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
template.text_field_tag(attribute_name, nil, merged_input_options)
end
end
15 changes: 15 additions & 0 deletions app/javascript/controllers/exit_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
static targets = ["modal", "modalNameInput", "formNameInput"];

connect() {
console.log("exit modal controller connected");
}

showModal(event) {
event.preventDefault();
this.modalTarget.classList.remove("d-none");
this.modalNameInputTarget.value = this.formNameInputTarget.value;
}
}
3 changes: 3 additions & 0 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ application.register("datasource", DatasourceController);
import DetailsLoaderController from "./details_loader_controller";
application.register("details-loader", DetailsLoaderController);

import ExitController from "./exit_controller";
application.register("exit", ExitController);

import ExternalController from "./external_controller";
application.register("external", ExternalController);

Expand Down
4 changes: 2 additions & 2 deletions app/models/attribute.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def config_schema
{ type: "null" }
end

def self.from_json(json)
def self.from_json(json, to_validate: true)
JSON::Validator.validate!(ATTRIBUTE_SCHEMA, json)

case json["type"]
Expand Down Expand Up @@ -131,7 +131,7 @@ def self.from_json(json)
attr.config = json["config"]
attr.description = json["description"]
attr.value = json["value"] unless json["value"].blank?
attr.validate_value_type!
attr.validate_value_type! if to_validate
attr
end

Expand Down
16 changes: 10 additions & 6 deletions app/models/offer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ def should_index?
belongs_to :primary_oms, class_name: "OMS", optional: true
has_many :project_items, dependent: :restrict_with_error

before_validation :set_iid
after_initialize :set_iid
before_validation :set_internal
before_validation :set_oms_details
before_validation :sanitize_oms_params
Expand All @@ -56,17 +58,19 @@ def should_index?
belongs_to :offer_type, class_name: "Vocabulary::ServiceCategory", optional: true
belongs_to :offer_subtype, class_name: "Vocabulary::ServiceCategory", optional: true

validate :set_iid, on: :create
with_options unless: :draft? do
validate :proper_oms?, if: -> { primary_oms.present? }
validates :oms_params, absence: true, if: -> { current_oms.blank? }
validate :check_oms_params, if: -> { current_oms.present? }
validate :same_order_type_as_in_service, if: -> { service&.order_type.present? }
end

validate :check_main_bundles, if: -> { draft? }
validates :service, presence: true
validates :iid, presence: true, numericality: true
validates :order_url, mp_url: true, if: :order_url?

validate :primary_oms_exists?, if: -> { primary_oms_id.present? }
validate :proper_oms?, if: -> { primary_oms.present? }
validates :oms_params, absence: true, if: -> { current_oms.blank? }
validate :check_oms_params, if: -> { current_oms.present? }
validate :check_main_bundles, if: -> { draft? }
validate :same_order_type_as_in_service, if: -> { service&.order_type.present? }

before_destroy :check_main_bundles

Expand Down
4 changes: 2 additions & 2 deletions app/models/offer/parameters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ module Offer::Parameters
extend ActiveSupport::Concern

included do
validates_associated :parameters
validates_associated :parameters, unless: :draft?
serialize :parameters, coder: Parameter::Array
end

def attributes
(parameters || []).map { |param| Attribute.from_json(param.dump) }
(parameters || []).map { |param| Attribute.from_json(param.dump, to_validate: !draft?) }
end

def parameters_attributes=(attrs)
Expand Down
10 changes: 10 additions & 0 deletions app/services/offer/create_as_draft.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

class Offer::CreateAsDraft < Offer::ApplicationService
def call
@offer.save(validate: false)
@service.reindex
@offer.reindex
@offer
end
end
23 changes: 23 additions & 0 deletions app/services/offer/update_as_draft.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true
class Offer::UpdateAsDraft < Offer::ApplicationService
def initialize(offer, params)
super(offer)
@params = params
end

def call
public_before = @offer.published?
@offer.status = "draft"
effective_params = @offer.service.offers.published.size == 1 ? @params : @params.merge(default: false)

if effective_params["primary_oms_id"] && OMS.find(effective_params["primary_oms_id"])&.custom_params.blank?
effective_params["oms_params"] = {}
end
@offer.assign_attributes(effective_params)
@offer.save(validate: false)
unbundle! if public_before
@offer.service.reindex

@offer.valid?
end
end
19 changes: 19 additions & 0 deletions app/views/backoffice/services/offers/_exit_modal.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.exit-popup.d-none{ role: "document", "data-exit-target": "modal" }
.modal-overlay
.modal-content
.modal-header
%h3#popup-modal-title.modal-title
Exit offer editor
.modal-body
%p
= _("Name your draft to save your offer draft and complete the configuration later.")
= f.input :name,
as: :custom,
input_html: { class: "form-control-lg", "data-exit-target": "modalNameInput"}
.modal-footer
.buttons-row
= link_to _("Exit without saving"),
backoffice_service_path(service),
class: "btn-sm btn-secondary",
"data-action": "click->exit#saveDraft"
= f.button :submit, "Save as draft", class: "btn-sm btn-primary"
8 changes: 5 additions & 3 deletions app/views/backoffice/services/offers/_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
https://www.figma.com/file/0F53l8h6P2Q7TpzLuFZ7qX/
Offers%3A-Adding-and-Editing?type=design&node-id=2-73&mode=design&t=F215vnzstlg4yUqR-0
= simple_form_for offer_form_source_module, html: { data: {controller: "offer", "offer-target": "form",
= simple_form_for offer_form_source_module, html: { data: {controller: "offer exit", "offer-target": "form",
"service-id": service.id, "offer-id": offer&.id || "new" }} do |f|
= f.hidden_field :from, value: local_assigns[:from]

Expand Down Expand Up @@ -42,12 +42,14 @@
.d-none{ data: { "offer-target": "section", section: "summary" } }
-# Render summary section here, from the backend
.row.new-offer-form-controls
.row.new-offer-form-controls{ "data-controller": "favourite" }
= render "backoffice/services/offers/exit_modal", offer: offer, f: f, service: service
.col-4
.btn.btn-back.d-none{ data: { action: "click->offer#prevSection", "offer-target": "prevButton" } }
<- Back
.col-4.text-right
= link_to _("Exit"), backoffice_service_path(service), class: "btn btn-back"
.btn.btn-back{ data: { action: "click->exit#showModal" } }
Exit
.col-4.text-right
.btn.btn-primary{ data: { action: "click->offer#nextSection", "offer-target": "nextButton" } }
Next ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
.col-lg-7.pl-0
%h4 Offer Description
.offer-section-wrapper
= f.input :name, input_html: { class: "form-control-lg" }
= f.input :name, input_html: { class: "form-control-lg", "data-exit-target": "formNameInput" }
= f.input :description, input_html: { rows: 10 }
= f.input :tag_list, input_html: { value: offer&.tag_list&.to_s, data: { choice: true } }
.bottom-tip
Expand Down
22 changes: 12 additions & 10 deletions spec/models/attribute/quantity_price_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@
RSpec.describe Attribute::QuantityPrice, backend: true do
let(:price) do
Attribute.from_json(
"id" => "id6",
"label" => "Label",
"description" => "Description",
"type" => "quantity_price",
"value_type" => "integer",
"config" => {
"start_price" => 100,
"step_price" => 1,
"currency" => "EUR",
"max" => 3
{
"id" => "id6",
"label" => "Label",
"description" => "Description",
"type" => "quantity_price",
"value_type" => "integer",
"config" => {
"start_price" => 100,
"step_price" => 1,
"currency" => "EUR",
"max" => 3
}
}
)
end
Expand Down
Loading

0 comments on commit 1cdb55e

Please sign in to comment.