From 25e5c044f496959e1a18554c017432baee3d3d2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eetu=20M=C3=A4enp=C3=A4=C3=A4?= Date: Mon, 22 Dec 2025 00:32:09 +0200 Subject: [PATCH 1/2] feat: add banner to show Testaustime Wrapped 2025 --- public/locales/en/common.json | 3 +- public/locales/fi/common.json | 3 +- src/app/[locale]/page.module.css | 3 +- src/app/[locale]/page.tsx | 7 ++++ .../WrappedBanner/WrappedBanner.tsx | 34 +++++++++++++++++++ .../WrappedBanner/styles.module.css | 32 +++++++++++++++++ src/utils/constants.ts | 1 + src/utils/cookieUtils.ts | 3 ++ 8 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 src/components/WrappedBanner/WrappedBanner.tsx create mode 100644 src/components/WrappedBanner/styles.module.css diff --git a/public/locales/en/common.json b/public/locales/en/common.json index bdb4b2f2..62e8f1c5 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -318,5 +318,6 @@ "badges": { "admin": "Admin", "you": "You" - } + }, + "wrappedText": "Testaustime Wrapped has arrived! See what you accomplished in the year 2025:" } diff --git a/public/locales/fi/common.json b/public/locales/fi/common.json index f7883eac..759908dd 100644 --- a/public/locales/fi/common.json +++ b/public/locales/fi/common.json @@ -318,5 +318,6 @@ "badges": { "admin": "Ylläpitäjä", "you": "Sinä" - } + }, + "wrappedText": "Testaustime Wrapped on saapunut! Katso, mitä sait aikaan vuonna 2025:" } diff --git a/src/app/[locale]/page.module.css b/src/app/[locale]/page.module.css index bf4e7f52..e7f1cca3 100644 --- a/src/app/[locale]/page.module.css +++ b/src/app/[locale]/page.module.css @@ -11,8 +11,9 @@ .dashboardContainer { height: calc(100% - 36px - 50px - 80px); display: flex; + gap: 2rem; flex-wrap: wrap; - flex-direction: row; + flex-direction: stretch; align-content: flex-start; justify-content: flex-start; align-items: flex-start; diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx index 1b277020..d107300c 100644 --- a/src/app/[locale]/page.tsx +++ b/src/app/[locale]/page.tsx @@ -13,6 +13,8 @@ import { getOwnActivityData, } from "../../api/usersApi"; import { redirect } from "next/navigation"; +import { WrappedBanner } from "../../components/WrappedBanner/WrappedBanner"; +import { getPreferences } from "../../utils/cookieUtils"; export default async function MainPage({ params: { locale }, @@ -50,8 +52,13 @@ export default async function MainPage({ throw new Error(JSON.stringify(currentActivity)); } + const preferences = await getPreferences(); + return (
+ {!preferences.wrapped2025Hidden && ( + + )} { + async function closeBanner() { + "use server"; + cookies().set(wrapped2025CookieName, "true", { + path: "/", + httpOnly: true, + expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365), + sameSite: "strict", + }); + } + + return ( +
+ +
+
+ + + +
+
+
+ ); +}; diff --git a/src/components/WrappedBanner/styles.module.css b/src/components/WrappedBanner/styles.module.css new file mode 100644 index 00000000..9d8481e6 --- /dev/null +++ b/src/components/WrappedBanner/styles.module.css @@ -0,0 +1,32 @@ +.container { + display: flex; + + flex: 1; + padding: 16px; + background-color: #b7defb; + color: #1a1a1a; + border: 4px solid #5b87a8; + border-radius: 8px; +} + +.left { + display: flex; + flex-direction: column; + flex: 1; + align-items: flex-start; +} + +.right { + display: flex; + justify-content: center; + align-items: center; +} + +.text { + margin: 0; +} + +.link { + color: #1c3a64; + font-weight: bold; +} diff --git a/src/utils/constants.ts b/src/utils/constants.ts index dff4e945..326e9cfb 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -3,6 +3,7 @@ export const languageCookieName = "NEXT_LOCALE"; export const colorSchemeCookieName = "testaustime-color-scheme"; export const defaultDayRangeCookieName = "testaustime-default-day-range"; export const maxTimeUnitCookieName = "testaustime-max-time-unit"; +export const wrapped2025CookieName = "testaustime-wrapped-2025-closed"; export const DEFAULT_DAY_RANGE = "week"; export const DEFAULT_MAX_TIME_UNIT = "h"; diff --git a/src/utils/cookieUtils.ts b/src/utils/cookieUtils.ts index 78723268..73be8bf0 100644 --- a/src/utils/cookieUtils.ts +++ b/src/utils/cookieUtils.ts @@ -5,6 +5,7 @@ import { smoothChartsCookieName, maxTimeUnitCookieName, DEFAULT_MAX_TIME_UNIT, + wrapped2025CookieName, } from "./constants"; import { isDayRange, TimeUnit } from "./dateUtils"; @@ -19,10 +20,12 @@ export const getPreferences = () => { (cookies().get(smoothChartsCookieName)?.value || "true") === "true"; const maxTimeUnit = cookies().get(maxTimeUnitCookieName)?.value || DEFAULT_MAX_TIME_UNIT; + const wrapped2025Hidden = cookies().get(wrapped2025CookieName)?.value === "true" return { dayRange: defaultDayRange ?? DEFAULT_DAY_RANGE, smoothCharts, maxTimeUnit: maxTimeUnit as unknown as TimeUnit, + wrapped2025Hidden }; }; From 78508fdf02194b433bd5d108947a1e8ce51cb037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eetu=20M=C3=A4enp=C3=A4=C3=A4?= Date: Mon, 22 Dec 2025 00:37:51 +0200 Subject: [PATCH 2/2] style: I love Prettier and Eslint --- src/app/[locale]/page.tsx | 2 +- src/components/WrappedBanner/WrappedBanner.tsx | 2 ++ src/utils/cookieUtils.ts | 5 +++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx index d107300c..6438acb7 100644 --- a/src/app/[locale]/page.tsx +++ b/src/app/[locale]/page.tsx @@ -52,7 +52,7 @@ export default async function MainPage({ throw new Error(JSON.stringify(currentActivity)); } - const preferences = await getPreferences(); + const preferences = getPreferences(); return (
diff --git a/src/components/WrappedBanner/WrappedBanner.tsx b/src/components/WrappedBanner/WrappedBanner.tsx index c43a3640..3b977a76 100644 --- a/src/components/WrappedBanner/WrappedBanner.tsx +++ b/src/components/WrappedBanner/WrappedBanner.tsx @@ -4,6 +4,7 @@ import { cookies } from "next/headers"; import { wrapped2025CookieName } from "../../utils/constants"; export const WrappedBanner = ({ text }: { text: string }) => { + // eslint-disable-next-line @typescript-eslint/require-await async function closeBanner() { "use server"; cookies().set(wrapped2025CookieName, "true", { @@ -23,6 +24,7 @@ export const WrappedBanner = ({ text }: { text: string }) => {
+ {/* eslint-disable-next-line @typescript-eslint/no-misused-promises */}
diff --git a/src/utils/cookieUtils.ts b/src/utils/cookieUtils.ts index 73be8bf0..a1c11bf1 100644 --- a/src/utils/cookieUtils.ts +++ b/src/utils/cookieUtils.ts @@ -20,12 +20,13 @@ export const getPreferences = () => { (cookies().get(smoothChartsCookieName)?.value || "true") === "true"; const maxTimeUnit = cookies().get(maxTimeUnitCookieName)?.value || DEFAULT_MAX_TIME_UNIT; - const wrapped2025Hidden = cookies().get(wrapped2025CookieName)?.value === "true" + const wrapped2025Hidden = + cookies().get(wrapped2025CookieName)?.value === "true"; return { dayRange: defaultDayRange ?? DEFAULT_DAY_RANGE, smoothCharts, maxTimeUnit: maxTimeUnit as unknown as TimeUnit, - wrapped2025Hidden + wrapped2025Hidden, }; };