diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 03aea123..3f1b316d 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -17,23 +17,38 @@
//= require cookieconsent.min
//= require newsletter_sign_up
//= require google_analytics
+//= require jscookie
-$(document).on('turbolinks:load', function () {
- // Initialize Cookie Bar
- window.cookieconsent.initialise({
- "palette": {
- "popup": {
- "background": "#1d1e21"
- },
- "button": {
- "background": "#4cae18"
- }
- },
- "theme": "classic",
- "content": {
- "message": "Tento web používa súbory cookie na poskytovanie služieb a analýzu webu. Používaním tohto webu vyjadrujete svoj súhlas s používaním súborov cookie.",
- "dismiss": "OK"
- },
- "showLink": false
- })
+$(document).on("turbolinks:load", function () {
+ // Initialize Cookie Bar
+ window.cookieconsent.initialise({
+ palette: {
+ popup: {
+ background: "#1d1e21",
+ },
+ button: {
+ background: "#4cae18",
+ },
+ },
+ theme: "classic",
+ content: {
+ message:
+ "Tento web používa súbory cookie na poskytovanie služieb a analýzu webu. Používaním tohto webu vyjadrujete svoj súhlas s používaním súborov cookie.",
+ dismiss: "OK",
+ },
+ showLink: false,
+ });
+
+ var activeTopicClose = document.querySelector(".js__active-topic-close");
+ if (activeTopicClose) {
+ activeTopicClose.addEventListener("click", function (e) {
+ e.preventDefault();
+ Cookies.set("current_topic", activeTopicClose.dataset.key, {
+ expires: 365,
+ });
+ document
+ .querySelector(".active-topic")
+ .classList.add("active-topic__hidden");
+ });
+ }
});
diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css
index b92d88e7..ef32652c 100644
--- a/app/assets/stylesheets/application.css
+++ b/app/assets/stylesheets/application.css
@@ -124,3 +124,44 @@
.notification-subscription-group .govuk-form-group:last-child {
margin-bottom: 0;
}
+
+.active-topic {
+ background-color: #F3F2F1;
+ padding: 20px 0;
+ font-size: 1rem;
+}
+
+.active-topic p ,
+.active-topic h1,
+.active-topic h2,
+.active-topic h3,
+.active-topic h4,
+.active-topic h5,
+.active-topic h6 {
+ margin: 10px 0;
+ font-size: 1rem;
+}
+
+.active-topic p:first-child {
+ margin-top: 0;
+}
+
+.active-topic p:last-child {
+ margin-bottom: 0;
+}
+
+.active-topic__inner {
+ display: grid;
+ grid-template-columns: 1fr 100px;
+ grid-gap: 30px;
+}
+
+.active-topic__hidden {
+ display: none;
+}
+
+@media (max-width: 767px) {
+ .active-topic__inner {
+ grid-template-columns: 1fr;
+ }
+}
diff --git a/app/controllers/admin/current_topics_controller.rb b/app/controllers/admin/current_topics_controller.rb
new file mode 100644
index 00000000..50974dfd
--- /dev/null
+++ b/app/controllers/admin/current_topics_controller.rb
@@ -0,0 +1,32 @@
+class Admin::CurrentTopicsController < Admin::AdminController
+ before_action :set_current_topic, only: [:show, :edit, :update]
+
+ def index
+ current_topic = CurrentTopic.last
+ return redirect_to edit_admin_current_topic_path(current_topic) if current_topic.present?
+ redirect_to new_admin_current_topic_path
+ end
+
+ def new
+ @current_topic = CurrentTopic.new
+ end
+
+ def create
+ @current_topic = CurrentTopic.new(current_topic_params)
+ @current_topic.save!
+ redirect_to admin_current_topics_url
+ end
+
+ def update
+ @current_topic.update!(current_topic_params)
+ redirect_to admin_current_topics_url
+ end
+
+ private def set_current_topic
+ @current_topic = CurrentTopic.find_by!(id: params[:id])
+ end
+
+ private def current_topic_params
+ params.require(:current_topic).permit(:body, :enabled)
+ end
+end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 5bd56adf..f1990038 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,5 +1,5 @@
class ApplicationController < ActionController::Base
- before_action :set_default_metadata
+ before_action :set_default_metadata, :set_active_current_topic
protected
@@ -46,4 +46,10 @@ def set_default_metadata
)
)
end
+
+ def set_active_current_topic
+ active_current_topic = CurrentTopic.active
+ return if active_current_topic.blank? || cookies[:current_topic] == active_current_topic.key
+ @active_current_topic = active_current_topic
+ end
end
diff --git a/app/models/current_topic.rb b/app/models/current_topic.rb
new file mode 100644
index 00000000..946579df
--- /dev/null
+++ b/app/models/current_topic.rb
@@ -0,0 +1,17 @@
+class CurrentTopic < ApplicationRecord
+
+ def key
+ Digest::MD5.hexdigest updated_at.to_s
+ end
+
+ def self.active
+ last_current_topic = self.last
+
+ return last_current_topic if last_current_topic.present? &&
+ last_current_topic.body.present? &&
+ last_current_topic.enabled == true
+
+ nil
+ end
+
+end
diff --git a/app/views/admin/current_topics/_form.html.erb b/app/views/admin/current_topics/_form.html.erb
new file mode 100644
index 00000000..3b43781b
--- /dev/null
+++ b/app/views/admin/current_topics/_form.html.erb
@@ -0,0 +1,30 @@
+<%= form_with(model: [:admin, current_topic], local: true, builder: AdminFormBuilder) do |form| %>
+
+
+
+ !
+
+ Pozor!
+ Každou aktualizáciou sa užívateľom vynuluje skrytie banneru.
+
+
+
+
+
+ <% if current_topic.errors.any? %>
+
+
<%= pluralize(current_topic.errors.count, "error") %> prohibited this current topic from being saved
+
+ <% end %>
+
+ <%= form.text_area :body, size: "60x12" %>
+ <%= form.check_box :enabled %>
+
+
+
+
+ <%= form.submit %>
+
+
+
+<% end %>
diff --git a/app/views/admin/current_topics/edit.html.erb b/app/views/admin/current_topics/edit.html.erb
new file mode 100644
index 00000000..6eb35bf8
--- /dev/null
+++ b/app/views/admin/current_topics/edit.html.erb
@@ -0,0 +1 @@
+<%= render 'form', current_topic: @current_topic %>
diff --git a/app/views/admin/current_topics/new.html.erb b/app/views/admin/current_topics/new.html.erb
new file mode 100644
index 00000000..6eb35bf8
--- /dev/null
+++ b/app/views/admin/current_topics/new.html.erb
@@ -0,0 +1 @@
+<%= render 'form', current_topic: @current_topic %>
diff --git a/app/views/components/_active_topic.html.erb b/app/views/components/_active_topic.html.erb
new file mode 100644
index 00000000..c5058ad0
--- /dev/null
+++ b/app/views/components/_active_topic.html.erb
@@ -0,0 +1,12 @@
+
+
+
+
+ <%= @active_current_topic.body.html_safe %>
+
+
+
+
+
diff --git a/app/views/layouts/admin.html.erb b/app/views/layouts/admin.html.erb
index 52969f56..24f6d6a3 100644
--- a/app/views/layouts/admin.html.erb
+++ b/app/views/layouts/admin.html.erb
@@ -57,6 +57,10 @@
+ <% klass = request.fullpath.include?(admin_current_topics_path) ? '--active' : '' %>
+
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 9259ec90..6a9441c4 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -45,6 +45,7 @@
<% if content_for?(:before_main_wrapper) %>
<%= yield(:before_main_wrapper) %>
<% else %>
+ <%= render 'components/active_topic' if @active_current_topic.present? %>
<%= yield(:before_content) %>
diff --git a/app/views/pages/index.html.erb b/app/views/pages/index.html.erb
index f3ffd790..20c22b62 100644
--- a/app/views/pages/index.html.erb
+++ b/app/views/pages/index.html.erb
@@ -2,6 +2,8 @@
<% content_for(:before_main_wrapper) do %>
<%= render 'searches/search_box' %>
+ <%= render 'components/active_topic' if @active_current_topic.present? %>
+
-
-
- <%#= link_to 'Zobraziť viac', '#', class: 'govuk-button', role: 'button', draggable: false %>
-
-
diff --git a/config/routes.rb b/config/routes.rb
index 2a685445..edbd2814 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -14,6 +14,7 @@
post :reposition, on: :collection
end
resources :apps, except: [:show]
+ resources :current_topics, except: [:show, :destroy]
resources :pages, except: [:show]
resources :journeys, except: [:show] do
resources :steps, except: [:show] do
diff --git a/db/migrate/20200919092214_create_current_topic.rb b/db/migrate/20200919092214_create_current_topic.rb
new file mode 100644
index 00000000..852c0ce8
--- /dev/null
+++ b/db/migrate/20200919092214_create_current_topic.rb
@@ -0,0 +1,9 @@
+class CreateCurrentTopic < ActiveRecord::Migration[6.0]
+ def change
+ create_table :current_topics do |t|
+ t.string :body
+ t.boolean :enabled
+ t.timestamps
+ end
+ end
+end
diff --git a/db/seeds.rb b/db/seeds.rb
index e2dbc8f0..a9ab4356 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -103,3 +103,9 @@
title: "Zaregistrujte sa na DPH",
type: "SimpleTask",
)
+
+CurrentTopic.create!(
+ key: 'Brexit',
+ value: 'A Brexit deal has been agreed but needs to be ratified',
+ enabled: true
+)
diff --git a/db/structure.sql b/db/structure.sql
index a1b28e2e..41068df5 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -261,6 +261,38 @@ CREATE TABLE public.ar_internal_metadata (
);
+--
+-- Name: current_topics; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.current_topics (
+ id bigint NOT NULL,
+ body character varying,
+ enabled boolean,
+ created_at timestamp(6) without time zone NOT NULL,
+ updated_at timestamp(6) without time zone NOT NULL
+);
+
+
+--
+-- Name: current_topics_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE public.current_topics_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+--
+-- Name: current_topics_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE public.current_topics_id_seq OWNED BY public.current_topics.id;
+
+
--
-- Name: journeys; Type: TABLE; Schema: public; Owner: -
--
@@ -723,6 +755,13 @@ ALTER SEQUENCE public.users_id_seq OWNED BY public.users.id;
ALTER TABLE ONLY public.apps ALTER COLUMN id SET DEFAULT nextval('public.apps_id_seq'::regclass);
+--
+-- Name: current_topics id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.current_topics ALTER COLUMN id SET DEFAULT nextval('public.current_topics_id_seq'::regclass);
+
+
--
-- Name: journeys id; Type: DEFAULT; Schema: public; Owner: -
--
@@ -823,6 +862,14 @@ ALTER TABLE ONLY public.ar_internal_metadata
ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key);
+--
+-- Name: current_topics current_topics_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.current_topics
+ ADD CONSTRAINT current_topics_pkey PRIMARY KEY (id);
+
+
--
-- Name: journeys journeys_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -1276,6 +1323,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20190915104202'),
('20191209121011'),
('20200316102804'),
-('20200316104715');
+('20200316104715'),
+('20200919092214');
diff --git a/spec/controllers/admin/current_topics_controller_spec.rb b/spec/controllers/admin/current_topics_controller_spec.rb
new file mode 100644
index 00000000..4afac56f
--- /dev/null
+++ b/spec/controllers/admin/current_topics_controller_spec.rb
@@ -0,0 +1,70 @@
+require 'rails_helper'
+
+RSpec.describe Admin::CurrentTopicsController, type: :controller do
+ include AdminAuthHelper
+
+ before(:each) do
+ admin_http_login
+ end
+
+ let(:valid_attributes) { build(:current_topic).attributes }
+ let(:valid_session) { {} }
+
+ describe "GET #index" do
+ it "redirects to new action when there is no existing record" do
+ get :index, params: {}, session: valid_session
+ expect(response).to redirect_to(new_admin_current_topic_path)
+ end
+
+ it "redirects to existing current topic action when there is already record" do
+ current_topic = create(:current_topic)
+ get :index, params: {}, session: valid_session
+ expect(response).to redirect_to(edit_admin_current_topic_path(current_topic) )
+ end
+ end
+
+ describe "GET #new" do
+ it "returns a success response" do
+ get :new, params: {}, session: valid_session
+ expect(response).to be_successful
+ end
+ end
+
+ describe "GET #edit" do
+ it "returns a success response" do
+ current_topic = create(:current_topic)
+ get :edit, params: {id: current_topic.to_param}, session: valid_session
+ expect(response).to be_successful
+ end
+ end
+
+ describe "POST #create" do
+ context "with valid params" do
+ it "creates a new CurrentTopic" do
+ expect {
+ post :create, params: { current_topic: valid_attributes }, session: valid_session
+ }.to change(CurrentTopic, :count).by(1)
+ expect(response).to redirect_to(admin_current_topics_url)
+ end
+ end
+ end
+
+ describe "PUT #update" do
+ context "with valid params" do
+ let(:new_attributes) {
+ {
+ body: 'Foo bar'
+ }
+ }
+
+ it "updates the requested page" do
+ current_topic = create(:current_topic)
+ put :update, params: {id: current_topic.to_param, current_topic: new_attributes}, session: valid_session
+ current_topic.reload
+ expect(current_topic.body).to eq 'Foo bar'
+ expect(response).to redirect_to(admin_current_topics_url)
+ end
+ end
+ end
+
+end
diff --git a/spec/factories/current_topic.rb b/spec/factories/current_topic.rb
new file mode 100644
index 00000000..77568593
--- /dev/null
+++ b/spec/factories/current_topic.rb
@@ -0,0 +1,6 @@
+FactoryBot.define do
+ factory :current_topic do
+ body { Faker::Lorem.paragraph(sentence_count: 10) }
+ enabled { true }
+ end
+end
diff --git a/spec/models/current_topic_spec.rb b/spec/models/current_topic_spec.rb
new file mode 100644
index 00000000..1bc8d44a
--- /dev/null
+++ b/spec/models/current_topic_spec.rb
@@ -0,0 +1,29 @@
+require 'rails_helper'
+
+RSpec.describe CurrentTopic, type: :model do
+
+ context 'active' do
+ it 'returns current active topic when enabled' do
+ current_topic = create(:current_topic)
+ active_current_topic = CurrentTopic.active
+ expect(active_current_topic).to eq current_topic
+ end
+
+ it 'returns nil when its not enabled' do
+ current_topic = create(:current_topic)
+ current_topic.enabled = false
+ current_topic.save!
+ active_current_topic = CurrentTopic.active
+ expect(active_current_topic).to eq nil
+ end
+
+ it 'returns nil when body is empty' do
+ current_topic = create(:current_topic)
+ current_topic.body = ""
+ current_topic.save!
+ active_current_topic = CurrentTopic.active
+ expect(active_current_topic).to eq nil
+ end
+ end
+
+end
diff --git a/vendor/assets/javascripts/jscookie.js b/vendor/assets/javascripts/jscookie.js
new file mode 100644
index 00000000..45e0f70f
--- /dev/null
+++ b/vendor/assets/javascripts/jscookie.js
@@ -0,0 +1,91 @@
+/*! js-cookie v3.0.0-rc.1 | MIT */
+!(function (e, t) {
+ "object" == typeof exports && "undefined" != typeof module
+ ? (module.exports = t())
+ : "function" == typeof define && define.amd
+ ? define(t)
+ : ((e = e || self),
+ (function () {
+ var n = e.Cookies,
+ r = (e.Cookies = t());
+ r.noConflict = function () {
+ return (e.Cookies = n), r;
+ };
+ })());
+})(this, function () {
+ "use strict";
+ function e(e) {
+ for (var t = 1; t < arguments.length; t++) {
+ var n = arguments[t];
+ for (var r in n) e[r] = n[r];
+ }
+ return e;
+ }
+ var t = {
+ read: function (e) {
+ return e.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent);
+ },
+ write: function (e) {
+ return encodeURIComponent(e).replace(
+ /%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,
+ decodeURIComponent
+ );
+ },
+ };
+ return (function n(r, o) {
+ function i(t, n, i) {
+ if ("undefined" != typeof document) {
+ "number" == typeof (i = e({}, o, i)).expires &&
+ (i.expires = new Date(Date.now() + 864e5 * i.expires)),
+ i.expires && (i.expires = i.expires.toUTCString()),
+ (t = encodeURIComponent(t)
+ .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)
+ .replace(/[()]/g, escape)),
+ (n = r.write(n, t));
+ var c = "";
+ for (var u in i)
+ i[u] &&
+ ((c += "; " + u), !0 !== i[u] && (c += "=" + i[u].split(";")[0]));
+ return (document.cookie = t + "=" + n + c);
+ }
+ }
+ return Object.create(
+ {
+ set: i,
+ get: function (e) {
+ if ("undefined" != typeof document && (!arguments.length || e)) {
+ for (
+ var n = document.cookie ? document.cookie.split("; ") : [],
+ o = {},
+ i = 0;
+ i < n.length;
+ i++
+ ) {
+ var c = n[i].split("="),
+ u = c.slice(1).join("=");
+ '"' === u[0] && (u = u.slice(1, -1));
+ try {
+ var f = t.read(c[0]);
+ if (((o[f] = r.read(u, f)), e === f)) break;
+ } catch (e) {}
+ }
+ return e ? o[e] : o;
+ }
+ },
+ remove: function (t, n) {
+ i(t, "", e({}, n, { expires: -1 }));
+ },
+ withAttributes: function (t) {
+ return n(this.converter, e({}, this.attributes, t));
+ },
+ withConverter: function (t) {
+ return n(e({}, this.converter, t), this.attributes);
+ },
+ },
+ {
+ attributes: { value: Object.freeze(o) },
+ converter: { value: Object.freeze(r) },
+ }
+ );
+ })(t, { path: "/" });
+});