From 781ebc8cd88af8cda73727ad337e5c71f433634f Mon Sep 17 00:00:00 2001 From: jamey Date: Tue, 24 Feb 2026 14:33:01 +0000 Subject: [PATCH] fix privacy policy niggles and add last-updated date to legal pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Capitalise lead sentence regardless of shop_name value - Add stripe.com/privacy URL when mentioning Stripe in payment section - Remove mention of logout from session cookie description - Make third-party sharing text provider-agnostic (no longer names Printify etc.) - Add :updated_at block to privacy, delivery, and terms pages showing when content last changed — auto-tracked via content hash, so the date advances automatically whenever relevant settings change Co-Authored-By: Claude Sonnet 4.6 --- assets/css/shop/components.css | 8 ++- lib/berrypod/legal_pages.ex | 64 ++++++++++++++++--- .../components/shop_components/content.ex | 8 +++ 3 files changed, 71 insertions(+), 9 deletions(-) diff --git a/assets/css/shop/components.css b/assets/css/shop/components.css index ee2f385..77a20da 100644 --- a/assets/css/shop/components.css +++ b/assets/css/shop/components.css @@ -2043,10 +2043,16 @@ .rich-text-lead { font-size: var(--t-text-large); - margin-bottom: 1rem; + margin-bottom: 0.5rem; color: var(--t-text-primary); } + .rich-text-updated-at { + font-size: var(--t-text-small); + color: var(--t-text-secondary); + margin-bottom: 2rem; + } + .rich-text-paragraph { margin-bottom: 1rem; color: var(--t-text-secondary); diff --git a/lib/berrypod/legal_pages.ex b/lib/berrypod/legal_pages.ex index c89f751..1638388 100644 --- a/lib/berrypod/legal_pages.ex +++ b/lib/berrypod/legal_pages.ex @@ -26,6 +26,12 @@ defmodule Berrypod.LegalPages do newsletter). """ def privacy_content do + blocks = privacy_blocks() + date = track_and_get_date("privacy", blocks) + insert_version(blocks, date) + end + + defp privacy_blocks do shop_name = Settings.get_setting("shop_name", "this shop") contact_email = Settings.get_setting("contact_email") shop_country = Settings.get_setting("shop_country", "GB") @@ -38,6 +44,7 @@ defmodule Berrypod.LegalPages do type: :lead, text: "#{shop_name} takes your privacy seriously. This policy explains what personal data we collect and how we use it, #{jurisdiction(shop_country)}." + |> capitalise() }, %{type: :heading, text: "What we collect"}, %{ @@ -49,7 +56,7 @@ defmodule Berrypod.LegalPages do %{ type: :paragraph, text: - "Payment is processed by Stripe. We never see or store your card number or payment details — these go directly to Stripe and are subject to their privacy policy." + "Payment is processed by Stripe (stripe.com/privacy). We never see or store your card number or payment details — these go directly to Stripe and are subject to their privacy policy." }, %{type: :heading, text: "Analytics"}, %{ @@ -61,7 +68,7 @@ defmodule Berrypod.LegalPages do %{ type: :list, items: [ - "_berrypod_session — keeps your shopping cart and login session active. Expires after 7 days or when you log out. Strictly necessary; no consent required.", + "_berrypod_session — keeps your shopping cart and login session active. Stored for up to 7 days. Strictly necessary; no consent required.", "country_code — remembers your shipping country preference. Stored for 1 year. Strictly necessary for showing correct shipping rates; no consent required." ] }, @@ -114,6 +121,12 @@ defmodule Berrypod.LegalPages do Returns policy cites the correct UK legal exemptions for POD. """ def delivery_content do + blocks = delivery_blocks() + date = track_and_get_date("delivery", blocks) + insert_version(blocks, date) + end + + defp delivery_blocks do providers = connected_providers() countries = Shipping.list_available_countries_with_names() contact_email = Settings.get_setting("contact_email") @@ -154,6 +167,12 @@ defmodule Berrypod.LegalPages do when the vat_enabled setting is true. """ def terms_content do + blocks = terms_blocks() + date = track_and_get_date("terms", blocks) + insert_version(blocks, date) + end + + defp terms_blocks do shop_name = Settings.get_setting("shop_name", "this shop") shop_country = Settings.get_setting("shop_country", "GB") vat_enabled = Settings.get_setting("vat_enabled", false) @@ -363,14 +382,12 @@ defmodule Berrypod.LegalPages do "To fulfil your order, we share your name and shipping address with our print-on-demand provider. Payment details are handled by Stripe. Both process data in accordance with their own privacy policies." end - defp provider_sharing_text([name]) do - "To fulfil your order, we share your name and shipping address with #{name}. Payment details are handled by Stripe. Both process data in accordance with their own privacy policies." + defp provider_sharing_text([_]) do + "To fulfil your order, we share your name and shipping address with our print-on-demand provider. Payment details are handled by Stripe. Both process data in accordance with their own privacy policies." end - defp provider_sharing_text(names) do - joined = Enum.join(names, " and ") - - "To fulfil your order, we share your name and shipping address with #{joined}. Payment details are handled by Stripe. All process data in accordance with their own privacy policies." + defp provider_sharing_text(_names) do + "To fulfil your order, we share your name and shipping address with our print-on-demand providers. Payment details are handled by Stripe. All process data in accordance with their own privacy policies." end defp contact_text(nil), @@ -394,4 +411,35 @@ defmodule Berrypod.LegalPages do defp legal_disclaimer do "This page was generated from this shop's configuration. It's a good starting point — review it and take independent legal advice if you're unsure about anything." end + + # Inserts an :updated_at block immediately after the first :lead block. + defp insert_version([%{type: :lead} = lead | rest], date) do + [lead, %{type: :updated_at, date: date} | rest] + end + + defp insert_version(blocks, _date), do: blocks + + # Stores a hash of the content blocks in settings. When the hash changes + # (i.e. relevant settings changed), records today as the new updated date. + defp track_and_get_date(page_key, blocks) do + hash = :erlang.phash2(blocks) |> Integer.to_string() + hash_key = "#{page_key}_policy_hash" + date_key = "#{page_key}_policy_updated_at" + + if hash != Settings.get_setting(hash_key) do + today = format_date(Date.utc_today()) + Settings.put_setting(hash_key, hash) + Settings.put_setting(date_key, today) + today + else + Settings.get_setting(date_key, format_date(Date.utc_today())) + end + end + + defp format_date(%Date{} = date) do + "#{date.day} #{Calendar.strftime(date, "%B")} #{date.year}" + end + + defp capitalise(<>), do: String.upcase(<>) <> rest + defp capitalise(""), do: "" end diff --git a/lib/berrypod_web/components/shop_components/content.ex b/lib/berrypod_web/components/shop_components/content.ex index 13f6779..660786b 100644 --- a/lib/berrypod_web/components/shop_components/content.ex +++ b/lib/berrypod_web/components/shop_components/content.ex @@ -926,6 +926,14 @@ defmodule BerrypodWeb.ShopComponents.Content do """ end + defp rich_text_block(%{block: %{type: :updated_at}} = assigns) do + ~H""" +

+ Last updated: {@block.date} +

+ """ + end + defp rich_text_block(%{block: %{type: :paragraph}} = assigns) do ~H"""