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 abd6033db..c0e6036b0 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 @@ -49,6 +49,7 @@ export const cookieBannerConsentRecordPageQuery = graphql` kind cookies { name + trackerType maxAgeSeconds description } @@ -235,7 +236,7 @@ export default function CookieBannerConsentRecordPage({ {cookie.name} - {humanizeSeconds(cookie.maxAgeSeconds ?? null)} + {humanizeSeconds(cookie.maxAgeSeconds ?? null, cookie.trackerType)} {cookie.description} diff --git a/apps/console/src/pages/organizations/cookie-banners/configuration/display/_components/CategorySection.tsx b/apps/console/src/pages/organizations/cookie-banners/configuration/display/_components/CategorySection.tsx index dd8911da9..506a16fd1 100644 --- a/apps/console/src/pages/organizations/cookie-banners/configuration/display/_components/CategorySection.tsx +++ b/apps/console/src/pages/organizations/cookie-banners/configuration/display/_components/CategorySection.tsx @@ -795,7 +795,7 @@ export function CategorySection({ categoryKey, connectionId }: CategorySectionPr })()} - {humanizeSeconds(pattern.maxAgeSeconds ?? null)} + {humanizeSeconds(pattern.maxAgeSeconds ?? null, pattern.trackerType)}
diff --git a/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/_components/TrackerPatternPropertiesSection.tsx b/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/_components/TrackerPatternPropertiesSection.tsx index 7a71c4a56..f342cbf03 100644 --- a/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/_components/TrackerPatternPropertiesSection.tsx +++ b/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/_components/TrackerPatternPropertiesSection.tsx @@ -161,7 +161,7 @@ export function TrackerPatternPropertiesSection({ - {humanizeSeconds(pattern.maxAgeSeconds ?? null)} + {humanizeSeconds(pattern.maxAgeSeconds ?? null, pattern.trackerType)} {pattern.description && ( diff --git a/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/_components/TrackerPatternRow.tsx b/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/_components/TrackerPatternRow.tsx index 54ed0c506..f6539abe3 100644 --- a/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/_components/TrackerPatternRow.tsx +++ b/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/_components/TrackerPatternRow.tsx @@ -28,7 +28,6 @@ import { } from "@probo/ui"; import { useState } from "react"; import { graphql, useFragment, useMutation } from "react-relay"; -import { ConnectionHandler } from "relay-runtime"; import type { TrackerPatternRowDeleteMutation } from "#/__generated__/core/TrackerPatternRowDeleteMutation.graphql"; import type { TrackerPatternRowFragment$key } from "#/__generated__/core/TrackerPatternRowFragment.graphql"; @@ -94,6 +93,8 @@ const movePatternMutation = graphql` id cookieCategory { id + name + kind } } cookieBanner { @@ -214,17 +215,6 @@ export function TrackerPatternRow({ patternKey, connectionId }: TrackerPatternRo targetCookieCategoryId: targetCategoryId, }, }, - updater(store) { - const payload = store.getRootField("moveTrackerPatternToCategory"); - if (!payload?.getLinkedRecord("trackerPattern")) { - return; - } - - const conn = store.get(connectionId); - if (conn) { - ConnectionHandler.deleteNode(conn, pattern.id); - } - }, onCompleted(_, errors) { if (errors?.length) { toast({ title: __("Error"), description: errors[0].message, variant: "error" }); @@ -392,7 +382,7 @@ export function TrackerPatternRow({ patternKey, connectionId }: TrackerPatternRo
- {humanizeSeconds(pattern.maxAgeSeconds ?? null)} + {humanizeSeconds(pattern.maxAgeSeconds ?? null, pattern.trackerType)} {pattern.lastMatchedAt diff --git a/packages/cookie-banner/src/components/cookie-list.ts b/packages/cookie-banner/src/components/cookie-list.ts index ed318a04c..fe833458a 100644 --- a/packages/cookie-banner/src/components/cookie-list.ts +++ b/packages/cookie-banner/src/components/cookie-list.ts @@ -52,8 +52,8 @@ export class ProboCookieList extends ProboElement { if (!this.template) return; const duration = cookie.max_age_seconds != null - ? humanizeDuration(cookie.max_age_seconds, lang) - : humanizeDuration(0, lang); + ? humanizeDuration(cookie.max_age_seconds, lang, cookie.tracker_type) + : humanizeDuration(0, lang, cookie.tracker_type); const type = getTrackerTypeLabel(cookie.tracker_type); diff --git a/packages/cookie-banner/src/cookie-utils.ts b/packages/cookie-banner/src/cookie-utils.ts index de94a09eb..31c479d2d 100644 --- a/packages/cookie-banner/src/cookie-utils.ts +++ b/packages/cookie-banner/src/cookie-utils.ts @@ -13,6 +13,16 @@ // PERFORMANCE OF THIS SOFTWARE. import { interpolate } from "./i18n"; +import type { TrackerType } from "./types"; + +// Tracker types whose data persists until explicitly cleared. When such a +// tracker has no max-age, its lifetime is "persistent" rather than "session" +// (cookies and session storage are cleared when the session/tab ends). +const PERSISTENT_TRACKER_TYPES: ReadonlySet = new Set([ + "LOCAL_STORAGE", + "INDEXED_DB", + "CACHE_STORAGE", +]); interface DurationTexts { [key: string]: string; @@ -35,6 +45,7 @@ const durationTextsByLanguage: Record = { duration_second_one: "{{count}} second", duration_second_other: "{{count}} seconds", duration_session: "session", + duration_persistent: "persistent", }, fr: { duration_year_one: "{{count}} an", @@ -52,6 +63,7 @@ const durationTextsByLanguage: Record = { duration_second_one: "{{count}} seconde", duration_second_other: "{{count}} secondes", duration_session: "session", + duration_persistent: "persistant", }, de: { duration_year_one: "{{count}} Jahr", @@ -69,6 +81,7 @@ const durationTextsByLanguage: Record = { duration_second_one: "{{count}} Sekunde", duration_second_other: "{{count}} Sekunden", duration_session: "Sitzung", + duration_persistent: "dauerhaft", }, es: { duration_year_one: "{{count}} año", @@ -86,6 +99,7 @@ const durationTextsByLanguage: Record = { duration_second_one: "{{count}} segundo", duration_second_other: "{{count}} segundos", duration_session: "sesión", + duration_persistent: "persistente", }, }; @@ -107,9 +121,17 @@ const DURATION_UNITS: [number, string, number][] = [ [1, "duration_second", 0], ]; -export function humanizeDuration(seconds: number, lang?: string): string { +export function humanizeDuration( + seconds: number, + lang?: string, + trackerType?: TrackerType, +): string { const texts = getDurationTexts(lang); - if (seconds <= 0) return texts.duration_session; + if (seconds <= 0) { + return trackerType && PERSISTENT_TRACKER_TYPES.has(trackerType) + ? texts.duration_persistent + : texts.duration_session; + } let remaining = seconds; const parts: string[] = []; diff --git a/packages/helpers/src/duration.ts b/packages/helpers/src/duration.ts index f8d5cf229..2f1c2cf77 100644 --- a/packages/helpers/src/duration.ts +++ b/packages/helpers/src/duration.ts @@ -22,8 +22,24 @@ export const DURATION_UNITS: { value: string; label: string; singular: string; s { value: "years", label: "years", singular: "year", seconds: 31536000, snap: 21 * 24 * 3600 }, ] as const; -export function humanizeSeconds(seconds: number | null): string { - if (seconds === null || seconds <= 0) return "session"; +// Tracker types whose data persists until explicitly cleared. When such a +// tracker has no max-age, its lifetime is "persistent" rather than "session" +// (cookies and session storage are cleared when the session/tab ends). +const PERSISTENT_TRACKER_TYPES = new Set([ + "LOCAL_STORAGE", + "INDEXED_DB", + "CACHE_STORAGE", +]); + +export function humanizeSeconds( + seconds: number | null, + trackerType?: string | null, +): string { + if (seconds === null || seconds <= 0) { + return trackerType && PERSISTENT_TRACKER_TYPES.has(trackerType) + ? "persistent" + : "session"; + } let remaining = seconds; const parts: string[] = [];