Completa UI e test del form contatti.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -7,7 +7,7 @@ module Public
|
|||||||
def create
|
def create
|
||||||
result = Contacts::SubmitInquiry.call(params: inquiry_params, ip: request.remote_ip)
|
result = Contacts::SubmitInquiry.call(params: inquiry_params, ip: request.remote_ip)
|
||||||
|
|
||||||
if result.ok?
|
if result.ok
|
||||||
redirect_to public_contatti_path, notice: t("flash.contacts.sent")
|
redirect_to public_contatti_path, notice: t("flash.contacts.sent")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<%= render "shared/meta_tags" %>
|
<%= render "shared/meta_tags" %>
|
||||||
<%= yield :head %>
|
<%= yield :head %>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer">
|
||||||
<link rel="stylesheet" href="/marketing.css?v=67">
|
<link rel="stylesheet" href="/marketing.css?v=68">
|
||||||
</head>
|
</head>
|
||||||
<body data-confirm-i18n='<%= raw confirm_dialog_i18n_json %>'<% if MatchLiveTv.google_analytics_configured? %> data-ga-id="<%= MatchLiveTv.google_analytics_measurement_id %>"<% end %>>
|
<body data-confirm-i18n='<%= raw confirm_dialog_i18n_json %>'<% if MatchLiveTv.google_analytics_configured? %> data-ga-id="<%= MatchLiveTv.google_analytics_measurement_id %>"<% end %>>
|
||||||
<%= render "shared/cookie_banner" %>
|
<%= render "shared/cookie_banner" %>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<title><%= content_for?(:title) ? yield(:title) : "Match Live TV" %></title>
|
<title><%= content_for?(:title) ? yield(:title) : "Match Live TV" %></title>
|
||||||
<%= render "shared/meta_tags" %>
|
<%= render "shared/meta_tags" %>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer">
|
||||||
<link rel="stylesheet" href="/marketing.css?v=67">
|
<link rel="stylesheet" href="/marketing.css?v=68">
|
||||||
<link rel="stylesheet" href="/live.css?v=26">
|
<link rel="stylesheet" href="/live.css?v=26">
|
||||||
<%= yield :head %>
|
<%= yield :head %>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -3381,3 +3381,87 @@ a.replay-archive__thumb:hover {
|
|||||||
border-color: #e53935;
|
border-color: #e53935;
|
||||||
background: rgba(229, 57, 53, 0.16);
|
background: rgba(229, 57, 53, 0.16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contacts-hero h1 {
|
||||||
|
max-width: 22ch;
|
||||||
|
}
|
||||||
|
.contacts-hero__meta {
|
||||||
|
margin: 0;
|
||||||
|
color: #888;
|
||||||
|
font-size: 0.92rem;
|
||||||
|
}
|
||||||
|
.contacts-channels {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
.contacts-channels .feature-card h2 {
|
||||||
|
margin: 0 0 8px;
|
||||||
|
font-size: 1.05rem;
|
||||||
|
}
|
||||||
|
.contacts-channels__email {
|
||||||
|
margin: 12px 0 0;
|
||||||
|
}
|
||||||
|
.contacts-channels__email a {
|
||||||
|
color: #e53935;
|
||||||
|
font-weight: 600;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
.contacts-company__details {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
text-align: center;
|
||||||
|
color: #ccc;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
.contacts-form-panel {
|
||||||
|
max-width: 640px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: #14141c;
|
||||||
|
border: 1px solid #2a2a36;
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 28px 24px;
|
||||||
|
}
|
||||||
|
.contacts-form-panel h2 { margin: 0 0 10px; }
|
||||||
|
.contacts-form-panel__lead {
|
||||||
|
margin: 0 0 20px;
|
||||||
|
color: #aaa;
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
.contacts-form textarea {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px 14px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #3d3d4a;
|
||||||
|
background: #1c1c26;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-family: inherit;
|
||||||
|
resize: vertical;
|
||||||
|
min-height: 140px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.contacts-form textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #e53935;
|
||||||
|
box-shadow: 0 0 0 2px rgba(229, 57, 53, 0.25);
|
||||||
|
}
|
||||||
|
.contacts-form .btn-primary {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 8px;
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
.contacts-hp {
|
||||||
|
position: absolute;
|
||||||
|
left: -10000px;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
@media (max-width: 999px) {
|
||||||
|
.contacts-channels {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
RSpec.describe ContactMailer, type: :mailer do
|
||||||
|
it "invia la richiesta commerciale al supporto con reply-to" do
|
||||||
|
mail = described_class.inquiry(
|
||||||
|
name: "Anna Bianchi",
|
||||||
|
email: "anna@test.it",
|
||||||
|
club_name: "ASD Test",
|
||||||
|
topic: "commercial",
|
||||||
|
message: "Serve un piano per due palestre."
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(mail.to).to eq([MatchLiveTv.support_email])
|
||||||
|
expect(mail.reply_to).to eq(["anna@test.it"])
|
||||||
|
expect(mail.subject).to include("Anna Bianchi")
|
||||||
|
expect(mail.body.encoded).to include("ASD Test")
|
||||||
|
expect(mail.body.encoded).to include("due palestre")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "invia la richiesta privacy all'indirizzo privacy" do
|
||||||
|
mail = described_class.inquiry(
|
||||||
|
name: "Luca Verdi",
|
||||||
|
email: "luca@test.it",
|
||||||
|
club_name: "",
|
||||||
|
topic: "privacy",
|
||||||
|
message: "Chiedo la cancellazione dei dati."
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(mail.to).to eq([MatchLiveTv.privacy_controller_email])
|
||||||
|
expect(mail.body.encoded).to include(I18n.t("mailers.contact.club_none", locale: :it))
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
RSpec.describe "Public contacts page", type: :request do
|
||||||
|
let(:valid_params) do
|
||||||
|
{
|
||||||
|
name: "Mario Rossi",
|
||||||
|
email: "mario@test.it",
|
||||||
|
club_name: "Volley Club",
|
||||||
|
topic: "commercial",
|
||||||
|
message: "Vorremmo un preventivo per tre squadre della società.",
|
||||||
|
accept_privacy: "1"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "è pubblica, indicizzabile e mostra i recapiti" do
|
||||||
|
get public_contatti_path
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:ok)
|
||||||
|
expect(response.body).to include(I18n.t("pages.contacts.title", locale: :it))
|
||||||
|
expect(response.body).to include(MatchLiveTv.support_email)
|
||||||
|
expect(response.body).to include(MatchLiveTv.privacy_controller_email)
|
||||||
|
expect(response.body).to include(MatchLiveTv.privacy_controller_name)
|
||||||
|
expect(response.body).to include(MatchLiveTv.privacy_controller_address)
|
||||||
|
expect(response.body).to include('rel="canonical"')
|
||||||
|
expect(response.body).to include(public_contatti_path)
|
||||||
|
expect(response.body).to include(public_support_path)
|
||||||
|
expect(response.body).to include(public_faq_path)
|
||||||
|
expect(response.body).to include(public_signup_path)
|
||||||
|
expect(response.body).not_to include("translation missing")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "appare nel footer del sito, non nel chrome App Store" do
|
||||||
|
get root_path
|
||||||
|
expect(response.body).to include(public_contatti_path)
|
||||||
|
|
||||||
|
get public_support_path
|
||||||
|
expect(response.body).not_to include(public_contatti_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "collega il CTA Prezzi alla pagina contatti" do
|
||||||
|
load Rails.root.join("db/seeds/plans.rb")
|
||||||
|
get public_prezzi_path
|
||||||
|
|
||||||
|
expect(response.body).to include(public_contatti_path)
|
||||||
|
expect(response.body).not_to include("mailto:info@matchlivetv.it")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "include /contatti nella sitemap e reindirizza /contact" do
|
||||||
|
get "/sitemap.xml"
|
||||||
|
expect(response).to have_http_status(:ok)
|
||||||
|
expect(response.body).to include("#{MatchLiveTv.app_public_url.chomp('/')}/contatti")
|
||||||
|
|
||||||
|
get "/contact"
|
||||||
|
expect(response).to redirect_to("/contatti")
|
||||||
|
end
|
||||||
|
|
||||||
|
{
|
||||||
|
"it" => "Contatti",
|
||||||
|
"en" => "Contact",
|
||||||
|
"fr" => "Contact",
|
||||||
|
"de" => "Kontakt",
|
||||||
|
"es" => "Contacto"
|
||||||
|
}.each do |locale, heading|
|
||||||
|
it "renderizza correttamente in #{locale} senza translation missing" do
|
||||||
|
cookies[:mltv_locale] = locale
|
||||||
|
get public_contatti_path
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:ok)
|
||||||
|
expect(response.body).to include(heading)
|
||||||
|
expect(response.body).not_to include("translation missing")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "invia la mail commerciale a info@ con reply-to del mittente" do
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
|
||||||
|
expect {
|
||||||
|
post public_contatti_path, params: valid_params
|
||||||
|
}.to change { ActionMailer::Base.deliveries.size }.by(1)
|
||||||
|
|
||||||
|
expect(response).to redirect_to(public_contatti_path)
|
||||||
|
expect(flash[:notice]).to eq(I18n.t("flash.contacts.sent", locale: :it))
|
||||||
|
|
||||||
|
mail = ActionMailer::Base.deliveries.last
|
||||||
|
expect(mail.to).to eq([MatchLiveTv.support_email])
|
||||||
|
expect(mail.reply_to).to eq(["mario@test.it"])
|
||||||
|
expect(mail.subject).to include("Mario Rossi")
|
||||||
|
expect(mail.body.encoded).to include("Volley Club")
|
||||||
|
expect(mail.body.encoded).to include("tre squadre")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "invia le richieste privacy all'email privacy" do
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
|
||||||
|
post public_contatti_path, params: valid_params.merge(topic: "privacy")
|
||||||
|
|
||||||
|
mail = ActionMailer::Base.deliveries.last
|
||||||
|
expect(mail.to).to eq([MatchLiveTv.privacy_controller_email])
|
||||||
|
expect(mail.subject).to include("privacy")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "non invia mail se il honeypot è compilato, ma risponde come successo" do
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
|
||||||
|
expect {
|
||||||
|
post public_contatti_path, params: valid_params.merge(website: "http://spam.test")
|
||||||
|
}.not_to change { ActionMailer::Base.deliveries.size }
|
||||||
|
|
||||||
|
expect(response).to redirect_to(public_contatti_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "rifiuta un modulo incompleto" do
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
|
||||||
|
post public_contatti_path, params: valid_params.merge(name: "", accept_privacy: "1")
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unprocessable_entity)
|
||||||
|
expect(ActionMailer::Base.deliveries).to be_empty
|
||||||
|
expect(flash[:alert]).to eq(I18n.t("flash.contacts.invalid", locale: :it))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "rifiuta senza consenso privacy" do
|
||||||
|
post public_contatti_path, params: valid_params.merge(accept_privacy: "0")
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unprocessable_entity)
|
||||||
|
expect(flash[:alert]).to eq(I18n.t("flash.contacts.privacy_required", locale: :it))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "limita gli invii ripetuti dallo stesso IP" do
|
||||||
|
previous = Rails.cache
|
||||||
|
Rails.cache = ActiveSupport::Cache::MemoryStore.new
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
|
||||||
|
Contacts::SubmitInquiry::LIMIT.times do
|
||||||
|
post public_contatti_path, params: valid_params
|
||||||
|
expect(response).to redirect_to(public_contatti_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
post public_contatti_path, params: valid_params.merge(email: "altro@test.it")
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:too_many_requests)
|
||||||
|
expect(flash[:alert]).to eq(I18n.t("flash.contacts.throttled", locale: :it))
|
||||||
|
expect(ActionMailer::Base.deliveries.size).to eq(Contacts::SubmitInquiry::LIMIT)
|
||||||
|
ensure
|
||||||
|
Rails.cache = previous
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user