Skip to content

Commit 023d703

Browse files
GDSNewtChrisBAshton
authored andcommitted
WIP: Social media links
1 parent 73753eb commit 023d703

9 files changed

Lines changed: 165 additions & 2 deletions

File tree

app/models/concerns/standard_edition/has_block_content.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ module StandardEdition::HasBlockContent
77
def block_content=(value)
88
value_to_merge = (value || {}).to_h.deep_stringify_keys
99
merged_value = (self[:block_content] || {}).deep_merge(value_to_merge)
10-
super(merged_value)
10+
11+
normalised = StandardEdition::BlockContent.new(type_instance.schema)
12+
normalised.assign_attributes(merged_value)
13+
14+
@block_content = normalised # keep the memoized object in sync (optional but nice)
15+
super(normalised.to_h)
1116
end
1217

1318
def block_content
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module ConfigurableContentBlocks
2+
class DefaultArray
3+
attr_reader :block_factory
4+
5+
def initialize(block_factory)
6+
@block_factory = block_factory
7+
end
8+
9+
def to_partial_path
10+
"admin/configurable_content_blocks/default_array"
11+
end
12+
end
13+
end

app/models/configurable_content_blocks/factory.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ def build_block(block)
99
"default_string" => ->(_page) { ConfigurableContentBlocks::DefaultString.new },
1010
"govspeak" => ->(page) { ConfigurableContentBlocks::Govspeak.new(page.images, page.attachments) },
1111
"default_date" => ->(_page) { ConfigurableContentBlocks::DefaultDate.new },
12+
"social_media_service_select" => ->(_page) { ConfigurableContentBlocks::SocialMediaServiceSelect.new },
1213
"image_select" => ->(page) { ConfigurableContentBlocks::ImageSelect.new(page.valid_images) },
1314
"lead_image_select" => ->(page) { ConfigurableContentBlocks::LeadImageSelect.new(page.valid_lead_images, default_lead_image: page.default_lead_image, placeholder_image_url: page.placeholder_image_url) },
1415
"default_object" => ->(_page) { ConfigurableContentBlocks::DefaultObject.new(self) },
16+
"default_array" => ->(_page) { ConfigurableContentBlocks::DefaultArray.new(self) },
1517
}.freeze
1618

1719
raise "Block #{block} is not defined" if blocks[block].nil?
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module ConfigurableContentBlocks
2+
class SocialMediaServiceSelect
3+
attr_reader :services
4+
5+
def initialize
6+
@services = SocialMediaService.all
7+
end
8+
9+
def to_partial_path
10+
"admin/configurable_content_blocks/social_media_service_select"
11+
end
12+
end
13+
end

app/models/configurable_document_types/topical_event.json

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@
2323
"block": "default_date"
2424
}
2525
}
26+
},
27+
"social_media_links": {
28+
"title": "Social media accounts",
29+
"block": "default_array",
30+
"fields": {
31+
"social_media_service_id": {
32+
"title": "Service",
33+
"block": "social_media_service_select"
34+
},
35+
"url": {
36+
"title": "URL",
37+
"block": "default_string"
38+
}
39+
}
2640
}
2741
}
2842
}
@@ -37,6 +51,17 @@
3751
},
3852
"end_date": {
3953
"type": "date"
54+
},
55+
"social_media_links": {
56+
"type": "array",
57+
"attributes": {
58+
"social_media_service_id": {
59+
"type": "integer"
60+
},
61+
"url": {
62+
"type": "string"
63+
}
64+
}
4065
}
4166
},
4267
"validations": {
@@ -67,7 +92,8 @@
6792
"publishing_api": {
6893
"body": "govspeak",
6994
"start_date": "rfc3339_date",
70-
"end_date": "rfc3339_date"
95+
"end_date": "rfc3339_date",
96+
"social_media_links": "social_media_links"
7197
}
7298
},
7399
"associations": [

app/models/standard_edition/block_content.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ def attributes=(values)
2727
setter = "#{key}="
2828
if nested_schema["type"] == "date"
2929
public_send(setter, pre_validate_date_attribute(key, values[key]))
30+
elsif nested_schema["type"] == "array"
31+
#  Convert
32+
# { "0" => { "foo" => "bar" }, "1" => { "delete_me" => "something", "_destroy" => "1" } }
33+
# to
34+
# [ { "foo" => "bar" } ]
35+
vals = values[key].is_a?(Hash) ? values[key].values : values[key]
36+
public_send(setter, vals.reject { |h| h["_destroy"] == "1" })
3037
else
3138
public_send(setter, values[key])
3239
end
@@ -74,6 +81,8 @@ def attributes_class_for(attribute_config)
7481
case property_schema["type"]
7582
when "object"
7683
attribute key
84+
when "array"
85+
attribute key
7786
else
7887
attribute key, property_schema["type"].to_sym
7988
end

app/presenters/publishing_api/payload_builder/block_content.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,21 @@ def lead_image(attribute)
8080
url: item.placeholder_image_url,
8181
}
8282
end
83+
84+
def social_media_links(attribute)
85+
content = item.block_content&.public_send(attribute)
86+
return [] if content.blank?
87+
88+
content.map do |item|
89+
# `item` looks something like `{"url"=>"foo", "social_media_service_id"=>"3"}`
90+
service = SocialMediaService.find(item["social_media_service_id"].to_i)
91+
{
92+
title: service.name,
93+
service_type: service.name.parameterize, # "Google Plus" => "google-plus"
94+
href: item["url"],
95+
}
96+
end
97+
end
8398
end
8499
end
85100
end
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<% required ||= false
2+
content ||= {}
3+
translated_content ||= {}
4+
right_to_left ||= false
5+
errors ||= []
6+
required_attributes ||= []
7+
element_properties = schema.fetch("fields") %>
8+
9+
<%
10+
render_fields = ->(social_media_link, index) do
11+
element_fields = capture do
12+
element_properties.each do |property_key, property_schema|
13+
block = default_array.block_factory.build_block(property_schema["block"])
14+
%>
15+
<%= render block, {
16+
schema: property_schema,
17+
content: social_media_link[property_key],
18+
# TODO: support translations
19+
# translated_content: social_media_link[property_key],
20+
path: ConfigurableContentBlocks::Path.new(["social_media_links", index, property_key]),
21+
required: required_attributes.include?(property_key),
22+
required_attributes: property_schema["block"] == "default_array" ? required_attributes : [],
23+
right_to_left: right_to_left,
24+
errors: errors,
25+
} %>
26+
<%
27+
end # element_properties.each loop
28+
end # element_fields = capture
29+
end # render_fields definition
30+
%>
31+
32+
<%= render "govuk_publishing_components/components/fieldset",
33+
{ legend_text: "#{schema['title']}#{required ? ' (required)' : ''}",
34+
heading_size: "l",
35+
id: path.form_control_id } do %>
36+
<%
37+
# TODO: make the array key (`social_media_links`) dynamic
38+
items = content["social_media_links"].map.with_index do |social_media_link, index|
39+
# raise path.form_control_name.inspect # "edition[block_content][social_media_links]"
40+
{
41+
fields: render_fields.call(social_media_link, index),
42+
destroy_checkbox: render("govuk_publishing_components/components/checkboxes", {
43+
name: "#{path.form_control_name}[#{index}][_destroy]",
44+
items: [{ label: "Remove", value: "1" }],
45+
}),
46+
}
47+
end
48+
%>
49+
50+
<%= render "govuk_publishing_components/components/add_another", {
51+
fieldset_legend: schema["title"],
52+
add_button_text: "Add another",
53+
empty_fields: true,
54+
items: items,
55+
empty: render_fields.call({}, items.length),
56+
} %>
57+
<% end %>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<% required = required || false %>
2+
<% translated_content = translated_content || nil %>
3+
<% select_options = [
4+
{
5+
text: "No social media service selected",
6+
value: "",
7+
},
8+
] + social_media_service_select.services.map do |service|
9+
{
10+
text: service.name,
11+
value: service.id,
12+
selected: service.id == (translated_content || content).to_i,
13+
}
14+
end %>
15+
<% errors = errors || [] %>
16+
<%= render "govuk_publishing_components/components/select", {
17+
id: path.form_control_id,
18+
label: schema["title"] + (required ? " (required)" : ""),
19+
name: path.form_control_name,
20+
options: select_options,
21+
hint: schema["description"],
22+
error_items: errors_for(errors, path.validation_error_attribute.to_sym),
23+
} %>

0 commit comments

Comments
 (0)