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..6438acb7 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 = getPreferences();
+
return (
+ {!preferences.wrapped2025Hidden && (
+
+ )}
{
+ // eslint-disable-next-line @typescript-eslint/require-await
+ 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 (
+
+
+
+ {/* eslint-disable-next-line @typescript-eslint/no-misused-promises */}
+
+
+
+ );
+};
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..a1c11bf1 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,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";
return {
dayRange: defaultDayRange ?? DEFAULT_DAY_RANGE,
smoothCharts,
maxTimeUnit: maxTimeUnit as unknown as TimeUnit,
+ wrapped2025Hidden,
};
};