From 5cdaddf8b1bd8bc8d465db16884cf9464402f36d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20R=C3=A9?= Date: Wed, 29 Apr 2026 18:54:36 +0400 Subject: [PATCH] Store cookie durations as max_age_seconds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the free-form duration TEXT column with a nullable max_age_seconds INTEGER on both cookies and cookie_patterns tables. The SDK detector now sends raw seconds instead of humanized strings, eliminating locale-dependent comparisons in the pattern merge worker. Humanization happens at display time in the widget and console UI. Signed-off-by: Émile Ré --- .../CookieBannerConsentRecordPage.tsx | 6 +- .../cookies/_components/AddCookieRow.tsx | 37 ++++++---- .../cookies/_components/CategorySection.tsx | 18 ++--- .../cookies/_components/DurationInput.tsx | 73 +++++++++++++++++++ .../cookies/_components/EditCookieRow.tsx | 40 ++++++---- packages/cookie-banner/src/client.ts | 2 +- .../src/components/cookie-list.ts | 13 +++- packages/cookie-banner/src/cookie-utils.ts | 18 ++--- packages/cookie-banner/src/detector.ts | 10 +-- packages/helpers/src/duration.ts | 33 +++++++++ packages/helpers/src/index.ts | 1 + pkg/cookiebanner/service.go | 53 +++++++------- pkg/cookiebanner/worker.go | 32 +++++--- pkg/coredata/cookie.go | 26 +++---- pkg/coredata/cookie_category.go | 6 +- pkg/coredata/cookie_pattern.go | 26 +++---- pkg/coredata/migrations/20260429T135250Z.sql | 19 +++++ .../api/console/v1/cookie_banner_resolvers.go | 10 +-- .../console/v1/graphql/cookie_banner.graphql | 8 +- .../api/console/v1/types/cookie_pattern.go | 16 ++-- pkg/server/api/cookiebanner/v1/handler.go | 12 +-- 21 files changed, 308 insertions(+), 151 deletions(-) create mode 100644 apps/console/src/pages/organizations/cookie-banners/configuration/cookies/_components/DurationInput.tsx create mode 100644 packages/helpers/src/duration.ts create mode 100644 pkg/coredata/migrations/20260429T135250Z.sql diff --git a/apps/console/src/pages/organizations/cookie-banners/configuration/consent-records/CookieBannerConsentRecordPage.tsx b/apps/console/src/pages/organizations/cookie-banners/configuration/consent-records/CookieBannerConsentRecordPage.tsx index a3d01adc3..f426cd04b 100644 --- a/apps/console/src/pages/organizations/cookie-banners/configuration/consent-records/CookieBannerConsentRecordPage.tsx +++ b/apps/console/src/pages/organizations/cookie-banners/configuration/consent-records/CookieBannerConsentRecordPage.tsx @@ -12,7 +12,7 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -import { formatDate } from "@probo/helpers"; +import { formatDate, humanizeSeconds } from "@probo/helpers"; import { useTranslate } from "@probo/i18n"; import { Badge, Breadcrumb, Card, PageHeader, PropertyRow } from "@probo/ui"; import { useMemo } from "react"; @@ -49,7 +49,7 @@ export const cookieBannerConsentRecordPageQuery = graphql` kind cookies { name - duration + maxAgeSeconds description } } @@ -217,7 +217,7 @@ export default function CookieBannerConsentRecordPage({ {cookie.name} - {cookie.duration} + {humanizeSeconds(cookie.maxAgeSeconds ?? null)} {cookie.description} diff --git a/apps/console/src/pages/organizations/cookie-banners/configuration/cookies/_components/AddCookieRow.tsx b/apps/console/src/pages/organizations/cookie-banners/configuration/cookies/_components/AddCookieRow.tsx index 2f7a0f71b..315f7ded7 100644 --- a/apps/console/src/pages/organizations/cookie-banners/configuration/cookies/_components/AddCookieRow.tsx +++ b/apps/console/src/pages/organizations/cookie-banners/configuration/cookies/_components/AddCookieRow.tsx @@ -17,6 +17,7 @@ import { Button, Input, Td, Tr } from "@probo/ui"; import { useState } from "react"; import type { CookieEntry } from "./CategorySection"; +import { DurationInput, toMaxAgeSeconds } from "./DurationInput"; interface AddCookieRowProps { isUpdating: boolean; @@ -30,39 +31,47 @@ export function AddCookieRow({ onCancel, }: AddCookieRowProps) { const { __ } = useTranslate(); - const [form, setForm] = useState({ - name: "", - duration: "", - description: "", - }); + const [name, setName] = useState(""); + const [durationValue, setDurationValue] = useState(""); + const [durationUnit, setDurationUnit] = useState("days"); + const [description, setDescription] = useState(""); + + const handleSave = () => { + onSave({ + name, + maxAgeSeconds: toMaxAgeSeconds(durationValue, durationUnit), + description, + }); + }; return ( setForm({ ...form, name: e.target.value })} + value={name} + onChange={e => setName(e.target.value)} placeholder={__("Cookie name")} /> - setForm({ ...form, duration: e.target.value })} - placeholder={__("e.g. 1 year")} + setForm({ ...form, description: e.target.value })} + value={description} + onChange={e => setDescription(e.target.value)} placeholder={__("Description")} />