From 801a041404f018efc92101daf9be9cce9c8ce48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20Landstr=C3=B6m?= Date: Fri, 12 Jul 2024 06:45:44 +0000 Subject: [PATCH] Merged in feat/best-friend-hero (pull request #338) Feat(SW-170): Update overview hero Approved-by: Christel Westerberg --- components/Icons/Copy.tsx | 36 +++++++++ components/MyPages/AccountPage/Content.tsx | 4 + .../MyPages/AccountPage/Webview/Content.tsx | 12 +-- .../Blocks/Benefits/NextLevel/index.tsx | 6 +- .../Blocks/Overview/Buttons/CopyButton.tsx | 28 ++++--- .../Overview/Buttons/copybutton.module.css | 5 ++ .../Overview/Friend/Hero/hero.module.css | 21 +++++ .../Blocks/Overview/Friend/Hero/hero.ts | 7 ++ .../Overview/Friend/Hero/heroVariants.ts | 15 ++++ .../Blocks/Overview/Friend/Hero/index.tsx | 7 ++ .../index.tsx | 2 +- .../membershipLevel.module.css | 0 .../Overview/Friend/MemershipNumber/index.tsx | 34 ++++++++ .../membershipNumber.module.css | 37 +++++++++ .../MemershipNumber/membershipNumber.ts | 11 +++ .../membershipNumberVariants.ts | 15 ++++ .../Blocks/Overview/Friend/friend.module.css | 11 +-- .../MyPages/Blocks/Overview/Friend/index.tsx | 32 ++++---- .../Overview/Stats/ExpiringPoints/index.tsx | 24 ++++++ .../Blocks/Overview/Stats/NextLevel/index.tsx | 50 ------------ .../Stats/NextLevel/nextLevel.module.css | 13 --- .../Points/Container/container.module.css | 14 ++++ .../Overview/Stats/Points/Container/index.tsx | 5 ++ .../Stats/Points/PointsColumn/index.tsx | 79 +++++++++++++++++++ .../PointsColumn/pointsColumn.module.css | 5 ++ .../Blocks/Overview/Stats/Points/index.tsx | 48 ++++++----- .../Stats/Points/totalPoints.module.css | 11 --- .../MyPages/Blocks/Overview/Stats/index.tsx | 8 +- components/MyPages/Blocks/Overview/index.tsx | 8 +- .../Blocks/Overview/overview.module.css | 14 ---- .../Points/CurrentPointsBalance/index.tsx | 2 +- .../Blocks/Points/Overview/Points/index.tsx | 55 +++++++++++++ .../MyPages/Blocks/Points/Overview/index.tsx | 39 +++++++++ .../Points/Overview/overview.module.css | 9 +++ .../Divider/divider.module.css | 4 + .../TempDesignSystem/Divider/variants.ts | 1 + i18n/dictionaries/da.json | 14 +++- i18n/dictionaries/de.json | 14 +++- i18n/dictionaries/en.json | 14 +++- i18n/dictionaries/fi.json | 14 +++- i18n/dictionaries/no.json | 14 +++- i18n/dictionaries/sv.json | 14 +++- server/routers/user/output.ts | 2 + .../{membershipLevel.ts => membership.ts} | 4 + types/components/myPages/myPage/enums.ts | 1 + types/components/myPages/points.ts | 16 ++++ utils/membershipLevel.ts | 12 +-- utils/user.ts | 7 ++ 48 files changed, 595 insertions(+), 203 deletions(-) create mode 100644 components/Icons/Copy.tsx create mode 100644 components/MyPages/Blocks/Overview/Buttons/copybutton.module.css create mode 100644 components/MyPages/Blocks/Overview/Friend/Hero/hero.module.css create mode 100644 components/MyPages/Blocks/Overview/Friend/Hero/hero.ts create mode 100644 components/MyPages/Blocks/Overview/Friend/Hero/heroVariants.ts create mode 100644 components/MyPages/Blocks/Overview/Friend/Hero/index.tsx rename components/MyPages/Blocks/Overview/Friend/{MemberShipLevel => MembershipLevel}/index.tsx (97%) rename components/MyPages/Blocks/Overview/Friend/{MemberShipLevel => MembershipLevel}/membershipLevel.module.css (100%) create mode 100644 components/MyPages/Blocks/Overview/Friend/MemershipNumber/index.tsx create mode 100644 components/MyPages/Blocks/Overview/Friend/MemershipNumber/membershipNumber.module.css create mode 100644 components/MyPages/Blocks/Overview/Friend/MemershipNumber/membershipNumber.ts create mode 100644 components/MyPages/Blocks/Overview/Friend/MemershipNumber/membershipNumberVariants.ts create mode 100644 components/MyPages/Blocks/Overview/Stats/ExpiringPoints/index.tsx delete mode 100644 components/MyPages/Blocks/Overview/Stats/NextLevel/index.tsx delete mode 100644 components/MyPages/Blocks/Overview/Stats/NextLevel/nextLevel.module.css create mode 100644 components/MyPages/Blocks/Overview/Stats/Points/Container/container.module.css create mode 100644 components/MyPages/Blocks/Overview/Stats/Points/Container/index.tsx create mode 100644 components/MyPages/Blocks/Overview/Stats/Points/PointsColumn/index.tsx create mode 100644 components/MyPages/Blocks/Overview/Stats/Points/PointsColumn/pointsColumn.module.css delete mode 100644 components/MyPages/Blocks/Overview/Stats/Points/totalPoints.module.css create mode 100644 components/MyPages/Blocks/Points/Overview/Points/index.tsx create mode 100644 components/MyPages/Blocks/Points/Overview/index.tsx create mode 100644 components/MyPages/Blocks/Points/Overview/overview.module.css rename types/components/myPages/{membershipLevel.ts => membership.ts} (67%) create mode 100644 types/components/myPages/points.ts diff --git a/components/Icons/Copy.tsx b/components/Icons/Copy.tsx new file mode 100644 index 000000000..05a5268a5 --- /dev/null +++ b/components/Icons/Copy.tsx @@ -0,0 +1,36 @@ +import { iconVariants } from "./variants" + +import type { IconProps } from "@/types/components/icon" + +export default function CopyIcon({ className, color, ...props }: IconProps) { + const classNames = iconVariants({ className, color }) + return ( + + + + + + + + + ) +} diff --git a/components/MyPages/AccountPage/Content.tsx b/components/MyPages/AccountPage/Content.tsx index a3f150aa4..aa73adceb 100644 --- a/components/MyPages/AccountPage/Content.tsx +++ b/components/MyPages/AccountPage/Content.tsx @@ -10,6 +10,8 @@ import SoonestStays from "@/components/MyPages/Blocks/Stays/Soonest" import UpcomingStays from "@/components/MyPages/Blocks/Stays/Upcoming" import { removeMultipleSlashes } from "@/utils/url" +import PointsOverview from "../Blocks/Points/Overview" + import { AccountPageContentProps, ContentProps, @@ -23,6 +25,8 @@ function DynamicComponent({ component, props }: AccountPageContentProps) { switch (component) { case DynamicContentComponents.membership_overview: return + case DynamicContentComponents.points_overview: + return case DynamicContentComponents.previous_stays: return case DynamicContentComponents.soonest_stays: diff --git a/components/MyPages/AccountPage/Webview/Content.tsx b/components/MyPages/AccountPage/Webview/Content.tsx index 61b91c437..45899a42f 100644 --- a/components/MyPages/AccountPage/Webview/Content.tsx +++ b/components/MyPages/AccountPage/Webview/Content.tsx @@ -8,6 +8,7 @@ import CurrentBenefitsBlock from "../../Blocks/Benefits/CurrentLevel" import NextLevelBenefitsBlock from "../../Blocks/Benefits/NextLevel" import CurrentPointsBalance from "../../Blocks/Points/CurrentPointsBalance" import EarnAndBurn from "../../Blocks/Points/EarnAndBurn" +import PointsOverview from "../../Blocks/Points/Overview" import { AccountPageContentProps, @@ -21,14 +22,9 @@ import { function DynamicComponent({ component, props }: AccountPageContentProps) { switch (component) { case DynamicContentComponents.membership_overview: - return ( - - ) + return + case DynamicContentComponents.points_overview: + return case DynamicContentComponents.current_benefits: return case DynamicContentComponents.next_benefits: diff --git a/components/MyPages/Blocks/Benefits/NextLevel/index.tsx b/components/MyPages/Blocks/Benefits/NextLevel/index.tsx index 151ef6412..4503c4d0d 100644 --- a/components/MyPages/Blocks/Benefits/NextLevel/index.tsx +++ b/components/MyPages/Blocks/Benefits/NextLevel/index.tsx @@ -8,7 +8,6 @@ import SectionHeader from "@/components/Section/Header" import SectionLink from "@/components/Section/Link" import Chip from "@/components/TempDesignSystem/Chip" import Grids from "@/components/TempDesignSystem/Grids" -import BiroScript from "@/components/TempDesignSystem/Text/BiroScript" import Body from "@/components/TempDesignSystem/Text/Body" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import { getIntl } from "@/i18n" @@ -30,9 +29,8 @@ export default async function NextLevelBenefitsBlock({ return null } const nextLevel = getMembershipLevelObject( - user.memberships[0].membershipLevel as MembershipLevelEnum, - lang, - "nextLevel" + user.memberships[0].nextLevel as MembershipLevelEnum, + lang ) if (!nextLevel) { // TODO: handle this case, when missing or when user is top level? diff --git a/components/MyPages/Blocks/Overview/Buttons/CopyButton.tsx b/components/MyPages/Blocks/Overview/Buttons/CopyButton.tsx index fac1a8976..274a3ab5b 100644 --- a/components/MyPages/Blocks/Overview/Buttons/CopyButton.tsx +++ b/components/MyPages/Blocks/Overview/Buttons/CopyButton.tsx @@ -1,25 +1,27 @@ "use client" -import Image from "@/components/Image" +import CopyIcon from "@/components/Icons/Copy" import Button from "@/components/TempDesignSystem/Button" -import { getMembership } from "@/utils/user" -import type { User } from "@/types/user" +import styles from "./copybutton.module.css" -export default function CopyButton({ memberships }: Pick) { +import type { CopyButtonProps } from "@/types/components/myPages/membership" + +export default function CopyButton({ membershipNumber }: CopyButtonProps) { function handleCopy() { - const membership = getMembership(memberships) - console.log(`COPIED! (${membership ? membership.membershipNumber : "N/A"})`) + navigator.clipboard.writeText(membershipNumber) } return ( - ) } diff --git a/components/MyPages/Blocks/Overview/Buttons/copybutton.module.css b/components/MyPages/Blocks/Overview/Buttons/copybutton.module.css new file mode 100644 index 000000000..7d3d03bc4 --- /dev/null +++ b/components/MyPages/Blocks/Overview/Buttons/copybutton.module.css @@ -0,0 +1,5 @@ +.button { + display: flex; + justify-content: center; + align-items: center; +} diff --git a/components/MyPages/Blocks/Overview/Friend/Hero/hero.module.css b/components/MyPages/Blocks/Overview/Friend/Hero/hero.module.css new file mode 100644 index 000000000..7e6af67c8 --- /dev/null +++ b/components/MyPages/Blocks/Overview/Friend/Hero/hero.module.css @@ -0,0 +1,21 @@ +.hero { + border-radius: var(--Corner-radius-xLarge); + display: grid; + gap: var(--Spacing-x2); + grid-template-columns: 1fr; + padding: var(--Spacing-x7) var(--Spacing-x6); +} + +.burgundy { + background-color: var(--Scandic-Brand-Burgundy); +} + +.red { + background-color: var(--Scandic-Brand-Scandic-Red); +} + +@media screen and (min-width: 768px) { + .hero { + grid-template-columns: 1fr 1fr; + } +} diff --git a/components/MyPages/Blocks/Overview/Friend/Hero/hero.ts b/components/MyPages/Blocks/Overview/Friend/Hero/hero.ts new file mode 100644 index 000000000..e672e9de2 --- /dev/null +++ b/components/MyPages/Blocks/Overview/Friend/Hero/hero.ts @@ -0,0 +1,7 @@ +import { VariantProps } from "class-variance-authority" + +import { heroVariants } from "./heroVariants" + +export interface HeroProps + extends Omit, "color">, + VariantProps {} diff --git a/components/MyPages/Blocks/Overview/Friend/Hero/heroVariants.ts b/components/MyPages/Blocks/Overview/Friend/Hero/heroVariants.ts new file mode 100644 index 000000000..324fb46aa --- /dev/null +++ b/components/MyPages/Blocks/Overview/Friend/Hero/heroVariants.ts @@ -0,0 +1,15 @@ +import { cva } from "class-variance-authority" + +import styles from "./hero.module.css" + +export const heroVariants = cva(styles.hero, { + variants: { + color: { + burgundy: styles.burgundy, + red: styles.red, + }, + }, + defaultVariants: { + color: "red", + }, +}) diff --git a/components/MyPages/Blocks/Overview/Friend/Hero/index.tsx b/components/MyPages/Blocks/Overview/Friend/Hero/index.tsx new file mode 100644 index 000000000..3ec3083ba --- /dev/null +++ b/components/MyPages/Blocks/Overview/Friend/Hero/index.tsx @@ -0,0 +1,7 @@ +import { HeroProps } from "./hero" +import { heroVariants } from "./heroVariants" + +export default function Hero({ className, color, children }: HeroProps) { + const classNames = heroVariants({ className, color }) + return
{children}
+} diff --git a/components/MyPages/Blocks/Overview/Friend/MemberShipLevel/index.tsx b/components/MyPages/Blocks/Overview/Friend/MembershipLevel/index.tsx similarity index 97% rename from components/MyPages/Blocks/Overview/Friend/MemberShipLevel/index.tsx rename to components/MyPages/Blocks/Overview/Friend/MembershipLevel/index.tsx index 38fe367e0..07d4743ee 100644 --- a/components/MyPages/Blocks/Overview/Friend/MemberShipLevel/index.tsx +++ b/components/MyPages/Blocks/Overview/Friend/MembershipLevel/index.tsx @@ -12,7 +12,7 @@ import { import styles from "./membershipLevel.module.css" -import type { MembershipLevelProps } from "@/types/components/myPages/membershipLevel" +import type { MembershipLevelProps } from "@/types/components/myPages/membership" export default function MembershipLevel({ level }: MembershipLevelProps) { switch (level) { diff --git a/components/MyPages/Blocks/Overview/Friend/MemberShipLevel/membershipLevel.module.css b/components/MyPages/Blocks/Overview/Friend/MembershipLevel/membershipLevel.module.css similarity index 100% rename from components/MyPages/Blocks/Overview/Friend/MemberShipLevel/membershipLevel.module.css rename to components/MyPages/Blocks/Overview/Friend/MembershipLevel/membershipLevel.module.css diff --git a/components/MyPages/Blocks/Overview/Friend/MemershipNumber/index.tsx b/components/MyPages/Blocks/Overview/Friend/MemershipNumber/index.tsx new file mode 100644 index 000000000..4b4538420 --- /dev/null +++ b/components/MyPages/Blocks/Overview/Friend/MemershipNumber/index.tsx @@ -0,0 +1,34 @@ +import Caption from "@/components/TempDesignSystem/Text/Caption" +import { getIntl } from "@/i18n" + +import CopyButton from "../../Buttons/CopyButton" +import { MembershipNumberProps } from "./membershipNumber" +import { membershipNumberVariants } from "./membershipNumberVariants" + +import styles from "./membershipNumber.module.css" + +export default async function MembershipNumber({ + className, + color, + membership, +}: MembershipNumberProps) { + const { formatMessage } = await getIntl() + const classNames = membershipNumberVariants({ className, color }) + + return ( +
+ + {formatMessage({ id: "Membership ID" })} + {": "} + + + + {membership.membershipNumber ?? "N/A"} + + {membership && ( + + )} + +
+ ) +} diff --git a/components/MyPages/Blocks/Overview/Friend/MemershipNumber/membershipNumber.module.css b/components/MyPages/Blocks/Overview/Friend/MemershipNumber/membershipNumber.module.css new file mode 100644 index 000000000..47f8f2334 --- /dev/null +++ b/components/MyPages/Blocks/Overview/Friend/MemershipNumber/membershipNumber.module.css @@ -0,0 +1,37 @@ +.membershipContainer { + align-items: center; + background: var(--Scandic-Brand-Burgundy); + border-radius: var(--Corner-radius-Small); + display: grid; + grid-template-columns: 1fr; + justify-items: center; + padding: var(--Spacing-x1) var(--Spacing-x7) 0 var(--Spacing-x7); +} + +.icon { + display: flex; + align-items: center; + flex-direction: row; + justify-content: center; + padding-left: var(--Spacing-x2); +} + +.burgundy { + background-color: var(--Main-Brand-Burgundy); +} + +.red { + background-color: var(--Scandic-Brand-Scandic-Red); +} + +@media screen and (min-width: 768px) { + .membershipContainer { + grid-template-columns: auto auto; + padding: 0 0 0 var(--Spacing-x2); + gap: var(--Spacing-x-half); + } + + .icon { + padding-left: 0; + } +} diff --git a/components/MyPages/Blocks/Overview/Friend/MemershipNumber/membershipNumber.ts b/components/MyPages/Blocks/Overview/Friend/MemershipNumber/membershipNumber.ts new file mode 100644 index 000000000..71d6cf3db --- /dev/null +++ b/components/MyPages/Blocks/Overview/Friend/MemershipNumber/membershipNumber.ts @@ -0,0 +1,11 @@ +import { VariantProps } from "class-variance-authority" + +import { membershipNumberVariants } from "./membershipNumberVariants" + +import { User } from "@/types/user" + +export interface MembershipNumberProps + extends Omit, "color">, + VariantProps { + membership: User["memberships"][number] +} diff --git a/components/MyPages/Blocks/Overview/Friend/MemershipNumber/membershipNumberVariants.ts b/components/MyPages/Blocks/Overview/Friend/MemershipNumber/membershipNumberVariants.ts new file mode 100644 index 000000000..7cdd28a27 --- /dev/null +++ b/components/MyPages/Blocks/Overview/Friend/MemershipNumber/membershipNumberVariants.ts @@ -0,0 +1,15 @@ +import { cva } from "class-variance-authority" + +import styles from "./membershipNumber.module.css" + +export const membershipNumberVariants = cva(styles.membershipContainer, { + variants: { + color: { + burgundy: styles.burgundy, + red: styles.red, + }, + }, + defaultVariants: { + color: "burgundy", + }, +}) diff --git a/components/MyPages/Blocks/Overview/Friend/friend.module.css b/components/MyPages/Blocks/Overview/Friend/friend.module.css index f103b1a53..13e7f9641 100644 --- a/components/MyPages/Blocks/Overview/Friend/friend.module.css +++ b/components/MyPages/Blocks/Overview/Friend/friend.module.css @@ -9,7 +9,7 @@ .header { display: flex; flex-direction: column; - gap: var(--Spacing-x1); + gap: var(--Spacing-x2); } .levelLabel { @@ -35,14 +35,7 @@ background: var(--Scandic-Brand-Burgundy); border-radius: var(--Corner-radius-Small); display: grid; - gap: var(--Spacing-x1); grid-template-columns: 1fr; justify-items: center; - padding: var(--Spacing-x1) var(--Spacing-x2); -} - -@media screen and (min-width: 768px) { - .membershipContainer { - grid-template-columns: auto auto; - } + padding: var(--Spacing-x1) var(--Spacing-x7) 0 var(--Spacing-x7); } diff --git a/components/MyPages/Blocks/Overview/Friend/index.tsx b/components/MyPages/Blocks/Overview/Friend/index.tsx index f723fdc1a..b1c41884a 100644 --- a/components/MyPages/Blocks/Overview/Friend/index.tsx +++ b/components/MyPages/Blocks/Overview/Friend/index.tsx @@ -1,30 +1,39 @@ import { membershipLevels } from "@/constants/membershipLevels" -import BiroScript from "@/components/TempDesignSystem/Text/BiroScript" -import Caption from "@/components/TempDesignSystem/Text/Caption" +import Body from "@/components/TempDesignSystem/Text/Body" import Title from "@/components/TempDesignSystem/Text/Title" import { getIntl } from "@/i18n" -import { getMembership } from "@/utils/user" +import { getMembership, isHighestMembership } from "@/utils/user" -import MembershipLevel from "./MemberShipLevel" +import { MembershipNumberProps } from "./MemershipNumber/membershipNumber" +import MembershipLevel from "./MembershipLevel" +import MembershipNumber from "./MemershipNumber" import styles from "./friend.module.css" import type { UserProps } from "@/types/components/myPages/user" -export default async function Friend({ user }: UserProps) { +export default async function Friend({ + user, + color, +}: UserProps & Pick) { const { formatMessage } = await getIntl() const membership = getMembership(user.memberships) if (!membership?.membershipLevel) { return null } + const isHighestLevel = isHighestMembership(membership.membershipLevel) return (
- - {formatMessage({ id: "Current level" })}: - + + {formatMessage( + isHighestLevel + ? { id: "Highest level" } + : { id: "Your current level" } + )} + {membership ? ( {user.name} -
- - {formatMessage({ id: "Membership ID" })}:{" "} - {membership ? membership.membershipNumber : "N/A"} - -
+
) diff --git a/components/MyPages/Blocks/Overview/Stats/ExpiringPoints/index.tsx b/components/MyPages/Blocks/Overview/Stats/ExpiringPoints/index.tsx new file mode 100644 index 000000000..fe6b59fa1 --- /dev/null +++ b/components/MyPages/Blocks/Overview/Stats/ExpiringPoints/index.tsx @@ -0,0 +1,24 @@ +import Body from "@/components/TempDesignSystem/Text/Body" +import { getIntl } from "@/i18n" +import { getMembership } from "@/utils/user" + +import type { UserProps } from "@/types/components/myPages/user" + +export default async function ExpiringPoints({ user }: UserProps) { + const { formatMessage } = await getIntl() + const membership = getMembership(user.memberships) + // TODO - add correct points when available from API + if (!membership /* || !membership.expiringPoints*/) { + // TODO: handle this case? + return null + } + + return ( +
+ + {membership.currentPoints} {formatMessage({ id: "points expiring by" })}{" "} + {membership.expirationDate} + +
+ ) +} diff --git a/components/MyPages/Blocks/Overview/Stats/NextLevel/index.tsx b/components/MyPages/Blocks/Overview/Stats/NextLevel/index.tsx deleted file mode 100644 index 056ecf5f3..000000000 --- a/components/MyPages/Blocks/Overview/Stats/NextLevel/index.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import BiroScript from "@/components/TempDesignSystem/Text/BiroScript" -import Body from "@/components/TempDesignSystem/Text/Body" -import Title from "@/components/TempDesignSystem/Text/Title" -import { getIntl } from "@/i18n" -import { getMembershipLevelObject } from "@/utils/membershipLevel" -import { getMembership } from "@/utils/user" - -import styles from "./nextLevel.module.css" - -import type { UserProps } from "@/types/components/myPages/user" -import type { LangParams } from "@/types/params" - -export default async function NextLevel({ - user, - lang, -}: UserProps & LangParams) { - const { formatMessage } = await getIntl() - const membership = getMembership(user.memberships) - - if (!membership?.membershipLevel) { - // TODO: handle this case? - return null - } - - const nextLevel = getMembershipLevelObject( - membership.membershipLevel, - lang, - "nextLevel" - ) - if (!nextLevel) { - // TODO: already at top level, no next level exists - return null - } - return ( -
- - {formatMessage({ id: "Next level" })}: - - - {nextLevel?.name || "N/A"} - <BiroScript>{formatMessage({ id: "Coming up" })}!</BiroScript> - -
- ) -} diff --git a/components/MyPages/Blocks/Overview/Stats/NextLevel/nextLevel.module.css b/components/MyPages/Blocks/Overview/Stats/NextLevel/nextLevel.module.css deleted file mode 100644 index ee4800d29..000000000 --- a/components/MyPages/Blocks/Overview/Stats/NextLevel/nextLevel.module.css +++ /dev/null @@ -1,13 +0,0 @@ -.nextLevel { - align-items: center; - display: grid; - grid-template-columns: 1fr; -} - -@media screen and (min-width: 768px) { - .nextLevel { - gap: var(--Spacing-x1); - grid-template-columns: auto auto; - justify-content: center; - } -} diff --git a/components/MyPages/Blocks/Overview/Stats/Points/Container/container.module.css b/components/MyPages/Blocks/Overview/Stats/Points/Container/container.module.css new file mode 100644 index 000000000..df2bf9472 --- /dev/null +++ b/components/MyPages/Blocks/Overview/Stats/Points/Container/container.module.css @@ -0,0 +1,14 @@ +.points { + display: grid; + gap: var(--Spacing-x5); + text-wrap: balance; +} + +@media screen and (min-width: 768px) { + .points { + grid-template-rows: auto auto auto; + grid-template-columns: 1fr 1fr; + row-gap: 0; + column-gap: var(--Spacing-x2); + } +} diff --git a/components/MyPages/Blocks/Overview/Stats/Points/Container/index.tsx b/components/MyPages/Blocks/Overview/Stats/Points/Container/index.tsx new file mode 100644 index 000000000..a3a7856ee --- /dev/null +++ b/components/MyPages/Blocks/Overview/Stats/Points/Container/index.tsx @@ -0,0 +1,5 @@ +import styles from "./container.module.css" + +export default function PointsContainer({ children }: React.PropsWithChildren) { + return
{children}
+} diff --git a/components/MyPages/Blocks/Overview/Stats/Points/PointsColumn/index.tsx b/components/MyPages/Blocks/Overview/Stats/Points/PointsColumn/index.tsx new file mode 100644 index 000000000..ba9fef66a --- /dev/null +++ b/components/MyPages/Blocks/Overview/Stats/Points/PointsColumn/index.tsx @@ -0,0 +1,79 @@ +import Body from "@/components/TempDesignSystem/Text/Body" +import Title from "@/components/TempDesignSystem/Text/Title" +import { getIntl } from "@/i18n" + +import styles from "./pointsColumn.module.css" + +import type { + NightsColumn, + PointsColumn, + PointsColumnProps, +} from "@/types/components/myPages/points" + +export const YourPointsColumn = ({ points }: PointsColumn) => + PointsColumn({ + points, + title: "Your points", + subtitle: "as of today", + }) + +export const NextLevelPointsColumn = ({ + points, + subtitleParam, +}: PointsColumn) => + PointsColumn({ + points, + title: "Points needed to level up", + subtitleParam, + subtitle: "next level:", + }) + +export const StayOnLevelColumn = ({ points, subtitleParam }: PointsColumn) => + PointsColumn({ + points, + title: "Points needed to stay on level", + subtitleParam, + subtitle: "by", + }) + +export const NextLevelNightsColumn = ({ + nights, + subtitleParam, +}: NightsColumn) => + PointsColumn({ + nights, + title: "Nights needed to level up", + subtitleParam, + subtitle: "by", + }) + +async function PointsColumn({ + points, + nights, + title, + subtitle, + subtitleParam, +}: PointsColumnProps) { + const { formatMessage } = await getIntl() + + return ( +
+ + {formatMessage({ + id: title, + })} + + + {points ?? nights ?? "N/A"} + + + {formatMessage({ id: subtitle })} {subtitleParam} + +
+ ) +} diff --git a/components/MyPages/Blocks/Overview/Stats/Points/PointsColumn/pointsColumn.module.css b/components/MyPages/Blocks/Overview/Stats/Points/PointsColumn/pointsColumn.module.css new file mode 100644 index 000000000..57e6e06ff --- /dev/null +++ b/components/MyPages/Blocks/Overview/Stats/Points/PointsColumn/pointsColumn.module.css @@ -0,0 +1,5 @@ +@media screen and (min-width: 768px) { + .firstRow { + align-content: flex-end; + } +} diff --git a/components/MyPages/Blocks/Overview/Stats/Points/index.tsx b/components/MyPages/Blocks/Overview/Stats/Points/index.tsx index 5f55bca7b..9d968b3ea 100644 --- a/components/MyPages/Blocks/Overview/Stats/Points/index.tsx +++ b/components/MyPages/Blocks/Overview/Stats/Points/index.tsx @@ -1,34 +1,30 @@ -import Body from "@/components/TempDesignSystem/Text/Body" -import Title from "@/components/TempDesignSystem/Text/Title" -import { getIntl } from "@/i18n" +import { MembershipLevelEnum } from "@/constants/membershipLevels" + +import { getMembershipLevelObject } from "@/utils/membershipLevel" import { getMembership } from "@/utils/user" -import styles from "./totalPoints.module.css" +import PointsContainer from "./Container" +import { NextLevelPointsColumn, YourPointsColumn } from "./PointsColumn" -import type { UserProps } from "@/types/components/myPages/user" +import { UserProps } from "@/types/components/myPages/user" +import { LangParams } from "@/types/params" -export default async function Points({ user }: UserProps) { - const { formatMessage } = await getIntl() +export default async function Points({ user, lang }: UserProps & LangParams) { const membership = getMembership(user.memberships) + const nextLevel = getMembershipLevelObject( + membership?.nextLevel as MembershipLevelEnum, + lang + ) + return ( -
-
- - {formatMessage({ id: "Total Points" })} - - - {membership ? membership.currentPoints : "N/A"} - -
-
- - {formatMessage({ id: "Points until next level" })} - {/* TODO */} - - - {membership ? membership.currentPoints : "N/A"} - -
-
+ + + {nextLevel && ( + + )} + ) } diff --git a/components/MyPages/Blocks/Overview/Stats/Points/totalPoints.module.css b/components/MyPages/Blocks/Overview/Stats/Points/totalPoints.module.css deleted file mode 100644 index 7bc8663cb..000000000 --- a/components/MyPages/Blocks/Overview/Stats/Points/totalPoints.module.css +++ /dev/null @@ -1,11 +0,0 @@ -.points { - display: grid; - gap: var(--Spacing-x2); - grid-template-columns: 1fr; -} - -@media screen and (min-width: 768px) { - .points { - grid-template-columns: 1fr 1fr; - } -} diff --git a/components/MyPages/Blocks/Overview/Stats/index.tsx b/components/MyPages/Blocks/Overview/Stats/index.tsx index 9be45ac3a..e66579fb7 100644 --- a/components/MyPages/Blocks/Overview/Stats/index.tsx +++ b/components/MyPages/Blocks/Overview/Stats/index.tsx @@ -1,6 +1,6 @@ import Divider from "@/components/TempDesignSystem/Divider" -import NextLevel from "./NextLevel" +import ExpiringPoints from "./ExpiringPoints" import Points from "./Points" import styles from "./stats.module.css" @@ -11,9 +11,9 @@ import type { LangParams } from "@/types/params" export default function Stats({ user, lang }: UserProps & LangParams) { return (
- - - + + +
) } diff --git a/components/MyPages/Blocks/Overview/index.tsx b/components/MyPages/Blocks/Overview/index.tsx index d9008147d..aa1040b9d 100644 --- a/components/MyPages/Blocks/Overview/index.tsx +++ b/components/MyPages/Blocks/Overview/index.tsx @@ -5,6 +5,7 @@ import SectionHeader from "@/components/Section/Header" import SectionLink from "@/components/Section/Link" import Divider from "@/components/TempDesignSystem/Divider" +import Hero from "./Friend/Hero" import Friend from "./Friend" import Stats from "./Stats" @@ -23,14 +24,15 @@ export default async function Overview({ if (!user) { return null } + return ( -
- + + -
+
) diff --git a/components/MyPages/Blocks/Overview/overview.module.css b/components/MyPages/Blocks/Overview/overview.module.css index 80093743d..1dd9b754f 100644 --- a/components/MyPages/Blocks/Overview/overview.module.css +++ b/components/MyPages/Blocks/Overview/overview.module.css @@ -1,12 +1,3 @@ -.overview { - background-color: var(--Scandic-Brand-Scandic-Red); - border-radius: var(--Corner-radius-xLarge); - display: grid; - gap: var(--Spacing-x2); - grid-template-columns: 1fr; - padding: var(--Spacing-x7) var(--Spacing-x6); -} - .divider { padding-top: var(--Spacing-x2); } @@ -25,11 +16,6 @@ } @media screen and (min-width: 768px) { - .overview { - gap: var(--Spacing-x2); - grid-template-columns: 1fr 1fr; - } - .divider { display: none; } diff --git a/components/MyPages/Blocks/Points/CurrentPointsBalance/index.tsx b/components/MyPages/Blocks/Points/CurrentPointsBalance/index.tsx index d1ff4a7b1..d92caceef 100644 --- a/components/MyPages/Blocks/Points/CurrentPointsBalance/index.tsx +++ b/components/MyPages/Blocks/Points/CurrentPointsBalance/index.tsx @@ -25,7 +25,7 @@ async function CurrentPointsBalance({
-

{`${formatMessage({ id: "Total Points" })}*`}

+

{`${formatMessage({ id: "Your points" })}*`}

{`${formatMessage({ id: "Points" })}: ${membership ? membership.currentPoints : "N/A"}`}

diff --git a/components/MyPages/Blocks/Points/Overview/Points/index.tsx b/components/MyPages/Blocks/Points/Overview/Points/index.tsx new file mode 100644 index 000000000..78c2da3a5 --- /dev/null +++ b/components/MyPages/Blocks/Points/Overview/Points/index.tsx @@ -0,0 +1,55 @@ +import { + MembershipLevelEnum, + membershipLevels, +} from "@/constants/membershipLevels" + +import PointsContainer from "@/components/MyPages/Blocks/Overview/Stats/Points/Container" +import { + NextLevelNightsColumn, + NextLevelPointsColumn, + StayOnLevelColumn, + YourPointsColumn, +} from "@/components/MyPages/Blocks/Overview/Stats/Points/PointsColumn" +import { getMembershipLevelObject } from "@/utils/membershipLevel" +import { getMembership } from "@/utils/user" + +import { UserProps } from "@/types/components/myPages/user" +import { LangParams } from "@/types/params" + +/* TODO */ +export default async function Points({ user, lang }: UserProps & LangParams) { + const membership = getMembership(user.memberships) + const nextLevel = getMembershipLevelObject( + membership?.nextLevel as MembershipLevelEnum, + lang + ) + + return ( + + + {nextLevel && ( + <> + {membership?.currentPoints ? ( + + ) : ( + <> + + {nextLevel?.level === membershipLevels.L7 && ( + + )} + + )} + + )} + + ) +} diff --git a/components/MyPages/Blocks/Points/Overview/index.tsx b/components/MyPages/Blocks/Points/Overview/index.tsx new file mode 100644 index 000000000..0bd594352 --- /dev/null +++ b/components/MyPages/Blocks/Points/Overview/index.tsx @@ -0,0 +1,39 @@ +import { serverClient } from "@/lib/trpc/server" + +import SectionContainer from "@/components/Section/Container" +import SectionHeader from "@/components/Section/Header" +import SectionLink from "@/components/Section/Link" +import Divider from "@/components/TempDesignSystem/Divider" + +import Friend from "../../Overview/Friend" +import Hero from "../../Overview/Friend/Hero" +import Stats from "../../Overview/Stats" + +import styles from "./overview.module.css" + +import type { AccountPageComponentProps } from "@/types/components/myPages/myPage/accountPage" +import type { LangParams } from "@/types/params" + +export default async function PointsOverview({ + link, + subtitle, + title, + lang, +}: AccountPageComponentProps & LangParams) { + const user = await serverClient().user.get() + if (!user) { + return null + } + + return ( + + + + + + + + + + ) +} diff --git a/components/MyPages/Blocks/Points/Overview/overview.module.css b/components/MyPages/Blocks/Points/Overview/overview.module.css new file mode 100644 index 000000000..35c8c607a --- /dev/null +++ b/components/MyPages/Blocks/Points/Overview/overview.module.css @@ -0,0 +1,9 @@ +.divider { + padding-top: var(--Spacing-x2); +} + +@media screen and (min-width: 768px) { + .divider { + display: none; + } +} diff --git a/components/TempDesignSystem/Divider/divider.module.css b/components/TempDesignSystem/Divider/divider.module.css index e4031ab65..80dac16d0 100644 --- a/components/TempDesignSystem/Divider/divider.module.css +++ b/components/TempDesignSystem/Divider/divider.module.css @@ -13,6 +13,10 @@ border-bottom-color: var(--Scandic-Brand-Burgundy); } +.pale { + border-bottom-color: var(--Primary-Dark-On-Surface-Text); +} + .peach { border-bottom-color: var(--Primary-Light-On-Surface-Divider); } diff --git a/components/TempDesignSystem/Divider/variants.ts b/components/TempDesignSystem/Divider/variants.ts index 2bb604bf5..9c11e2c5a 100644 --- a/components/TempDesignSystem/Divider/variants.ts +++ b/components/TempDesignSystem/Divider/variants.ts @@ -10,6 +10,7 @@ export const dividerVariants = cva(styles.divider, { beige: styles.beige, white: styles.white, subtle: styles.subtle, + pale: styles.pale, }, opacity: { 100: styles.opacity100, diff --git a/i18n/dictionaries/da.json b/i18n/dictionaries/da.json index 462e7cca1..ffafd9b1b 100644 --- a/i18n/dictionaries/da.json +++ b/i18n/dictionaries/da.json @@ -5,11 +5,13 @@ "All rooms comes with standard amenities": "Alle værelser er udstyret med standardfaciliteter", "Already a friend?": "Allerede en ven?", "Arrival date": "Ankomstdato", + "as of today": "fra idag", "As our": "Som vores", "As our Close Friend": "Som vores nære ven", "At the hotel": "På hotellet", "Book": "Bestil", "Booking number": "Bestillingsnummer", + "by": "inden", "Cancel": "Afbestille", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Tjek de kreditkort, der er gemt på din profil. Betal med et gemt kort, når du er logget ind for en mere jævn weboplevelse.", "Choose room": "Vælg rum", @@ -24,7 +26,7 @@ "Could not find requested resource": "Kunne ikke finde den anmodede ressource", "Country": "Land", "Country code": "Landekode", - "Current level": "Nuværende niveau", + "Your current level": "Dit nuværende niveau", "Current password": "Nuværende kodeord", "characters": "tegn", "Date of Birth": "Fødselsdato", @@ -41,6 +43,7 @@ "From": "Fra", "Get inspired": "Blive inspireret", "Go back to overview": "Gå tilbage til oversigten", + "Highest level": "Højeste niveau", "How it works": "Hvordan det virker", "Join Scandic Friends": "Tilmeld dig Scandic Friends", "Language": "Sprog", @@ -60,12 +63,13 @@ "My wishes": "Mine ønsker", "New password": "Nyt kodeord", "Next": "Næste", - "Next level": "Næste niveau", + "next level:": "Næste niveau:", "No content published": "Intet indhold offentliggjort", "No transactions available": "Ingen tilgængelige transaktioner", "Not found": "Ikke fundet", "night": "nat", "nights": "nætter", + "Nights needed to level up": "Nætter nødvendige for at komme i niveau", "number": "nummer", "On your journey": "På din rejse", "Open": "Åben", @@ -77,9 +81,10 @@ "Please enter a valid phone number": "Indtast venligst et gyldigt telefonnummer", "Points": "Points", "Points may take up to 10 days to be displayed.": "Det kan tage op til 10 dage at få vist point.", - "Points until next level": "Point indtil næste niveau", + "Points needed to level up": "Point nødvendige for at komme i niveau", + "Points needed to stay on level": "Point nødvendige for at holde sig på niveau", + "points expiring by": "point udløber den", "Previous victories": "Tidligere sejre", - "points until next level": "point indtil næste niveau", "Read more": "Læs mere", "Read more about the hotel": "Læs mere om hotellet", "Retype new password": "Gentag den nye adgangskode", @@ -95,6 +100,7 @@ "Street": "Gade", "special character": "speciel karakter", "Total Points": "Samlet antal point", + "Your points": "Dine pointer", "Transaction date": "Overførselsdato", "Transactions": "Transaktioner", "Tripadvisor reviews": "{rating} ({count} anmeldelser på Tripadvisor)", diff --git a/i18n/dictionaries/de.json b/i18n/dictionaries/de.json index 2d9bf6d6e..9021dfdec 100644 --- a/i18n/dictionaries/de.json +++ b/i18n/dictionaries/de.json @@ -5,11 +5,13 @@ "All rooms comes with standard amenities": "Alle Zimmer sind mit den üblichen Annehmlichkeiten ausgestattet", "Already a friend?": "Schon ein Freund?", "Arrival date": "Ankunftsdatum", + "as of today": "Ab heute", "As our": "Als unsere", "As our Close Friend": "Als unser enger Freund", "At the hotel": "Im Hotel", "Book": "Buch", "Booking number": "Buchungsnummer", + "by": "bis", "Cancel": "Stornieren", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Sehen Sie sich die in Ihrem Profil gespeicherten Kreditkarten an. Bezahlen Sie mit einer gespeicherten Karte, wenn Sie angemeldet sind, für ein reibungsloseres Web-Erlebnis.", "Choose room": "Zimmer wählen", @@ -24,7 +26,7 @@ "Could not find requested resource": "Die angeforderte Ressource konnte nicht gefunden werden.", "Country": "Land", "Country code": "Landesvorwahl", - "Current level": "Aktuelles Level", + "Your current level": "Ihr aktuelles Level", "Current password": "Aktuelles Passwort", "characters": "figuren", "Date of Birth": "Geburtsdatum", @@ -41,6 +43,7 @@ "From": "Fromm", "Get inspired": "Lass dich inspirieren", "Go back to overview": "Zurück zur Übersicht", + "Highest level": "Höchstes Level", "How it works": "Wie es funktioniert", "Join Scandic Friends": "Treten Sie Scandic Friends bei", "Language": "Sprache", @@ -60,12 +63,13 @@ "My wishes": "Meine Wünsche", "New password": "Neues Kennwort", "Next": "Nächste", - "Next level": "Nächste Ebene", + "next level:": "Nächste Ebene:", "No content published": "Kein Inhalt veröffentlicht", "No transactions available": "Keine Transaktionen verfügbar", "Not found": "Nicht gefunden", "night": "nacht", "nights": "nächte", + "Nights needed to level up": "Nächte, die zum Levelaufstieg benötigt werden", "number": "nummer", "On your journey": "Auf deiner Reise", "Open": "Offen", @@ -77,9 +81,10 @@ "Please enter a valid phone number": "Bitte geben Sie eine gültige Telefonnummer ein", "Points": "Punkte", "Points may take up to 10 days to be displayed.": "Es kann bis zu 10 Tage dauern, bis Punkte angezeigt werden.", - "Points until next level": "Punkte bis zum nächsten Level", + "Points needed to level up": "Punkte, die zum Levelaufstieg benötigt werden", + "Points needed to stay on level": "Erforderliche Punkte, um auf diesem Niveau zu bleiben", + "points expiring by": "punkte verfallen bis zum", "Previous victories": "Bisherige Siege", - "points until next level": "punkte bis zum nächsten Level", "Read more": "Mehr lesen", "Read more about the hotel": "Lesen Sie mehr über das Hotel", "Retype new password": "Neues Passwort erneut eingeben", @@ -95,6 +100,7 @@ "Street": "Straße", "special character": "sonderzeichen", "Total Points": "Gesamtpunktzahl", + "Your points": "Deine Punkte", "Transaction date": "Transaktionsdatum", "Transactions": "Transaktionen", "Tripadvisor reviews": "{rating} ({count} Bewertungen auf Tripadvisor)", diff --git a/i18n/dictionaries/en.json b/i18n/dictionaries/en.json index 2b3ebf24d..78b517806 100644 --- a/i18n/dictionaries/en.json +++ b/i18n/dictionaries/en.json @@ -5,11 +5,13 @@ "All rooms comes with standard amenities": "All rooms comes with standard amenities", "Already a friend?": "Already a friend?", "Arrival date": "Arrival date", + "as of today": "as of today", "As our": "As our", "As our Close Friend": "As our Close Friend", "At the hotel": "At the hotel", "Book": "Book", "Booking number": "Booking number", + "by": "by", "Cancel": "Cancel", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.", "Choose room": "Choose room", @@ -24,7 +26,7 @@ "Could not find requested resource": "Could not find requested resource", "Country": "Country", "Country code": "Country code", - "Current level": "Current level", + "Your current level": "Your current level", "Current password": "Current password", "characters": "characters", "Date of Birth": "Date of Birth", @@ -46,6 +48,7 @@ "hotelPages.rooms.roomCard.person": "person", "hotelPages.rooms.roomCard.persons": "persons", "hotelPages.rooms.roomCard.seeRoomDetails": "See room details", + "Highest level": "Highest level", "How it works": "How it works", "Join Scandic Friends": "Join Scandic Friends", "Language": "Language", @@ -65,12 +68,13 @@ "My wishes": "My wishes", "New password": "New password", "Next": "Next", - "Next level": "Next level", + "next level:": "next level:", "No content published": "No content published", "No transactions available": "No transactions available", "Not found": "Not found", "night": "night", "nights": "nights", + "Nights needed to level up": "Nights needed to level up", "number": "number", "On your journey": "On your journey", "Open": "Open", @@ -82,9 +86,10 @@ "Please enter a valid phone number": "Please enter a valid phone number", "Points": "Points", "Points may take up to 10 days to be displayed.": "Points may take up to 10 days to be displayed.", - "Points until next level": "Points until next level", + "Points needed to level up": "Points needed to level up", + "Points needed to stay on level": "Points needed to stay on level", + "points expiring by": "points expiring by", "Previous victories": "Previous victories", - "points until next level": "points until next level", "Read more": "Read more", "Read more about the hotel": "Read more about the hotel", "Retype new password": "Retype new password", @@ -100,6 +105,7 @@ "Street": "Street", "special character": "special character", "Total Points": "Total Points", + "Your points": "Your points", "Transaction date": "Transaction date", "Transactions": "Transactions", "Tripadvisor reviews": "{rating} ({count} reviews on Tripadvisor)", diff --git a/i18n/dictionaries/fi.json b/i18n/dictionaries/fi.json index d9b7a37ae..5e834587b 100644 --- a/i18n/dictionaries/fi.json +++ b/i18n/dictionaries/fi.json @@ -5,11 +5,13 @@ "All rooms comes with standard amenities": "Kaikissa huoneissa on perusmukavuudet", "Already a friend?": "Oletko jo ystävä?", "Arrival date": "Saapumispäivä", + "as of today": "tästä päivästä lähtien", "As our": "Kuin meidän", "As our Close Friend": "Läheisenä ystävänämme", "At the hotel": "Hotellissa", "Book": "Kirja", "Booking number": "Varausnumero", + "by": "mennessä", "Cancel": "Peruuttaa", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Tarkista profiiliisi tallennetut luottokortit. Maksa tallennetulla kortilla kirjautuneena, jotta verkkokokemus on sujuvampi.", "Choose room": "Valitse huone", @@ -24,7 +26,7 @@ "Could not find requested resource": "Pyydettyä resurssia ei löytynyt", "Country": "Maa", "Country code": "Maatunnus", - "Current level": "Nykyinen taso", + "Your current level": "Nykyinen tasosi", "Current password": "Nykyinen salasana", "characters": "hahmoja", "Date of Birth": "Syntymäaika", @@ -41,6 +43,7 @@ "From": "From", "Get inspired": "Inspiroidu", "Go back to overview": "Palaa yleiskatsaukseen", + "Highest level": "Korkein taso", "How it works": "Kuinka se toimii", "Join Scandic Friends": "Liity Scandic Friends", "Language": "Kieli", @@ -60,12 +63,13 @@ "My wishes": "Toiveeni", "New password": "Uusi salasana", "Next": "Seuraava", - "Next level": "Seuraava taso", + "next level:": "Seuraava taso:", "No content published": "Ei julkaistua sisältöä", "No transactions available": "Ei tapahtumia saatavilla", "Not found": "Ei löydetty", "night": "yö", "nights": "yöt", + "Nights needed to level up": "Yöt, joita tarvitaan tasolle", "number": "määrä", "On your journey": "Matkallasi", "Open": "Avata", @@ -77,9 +81,10 @@ "Please enter a valid phone number": "Ole hyvä ja näppäile voimassaoleva puhelinnumero", "Points": "Pisteet", "Points may take up to 10 days to be displayed.": "Pisteiden näyttäminen voi kestää jopa 10 päivää.", - "Points until next level": "Pisteitä seuraavalle tasolle", + "Points needed to level up": "Pisteitä tarvitaan tasolle pääsemiseksi", + "Points needed to stay on level": "Tällä tasolla pysymiseen tarvittavat pisteet", + "points expiring by": "pisteet vanhenevat viimeistään", "Previous victories": "Edelliset voitot", - "points until next level": "pisteitä seuraavalle tasolle", "Read more": "Lue lisää", "Read more about the hotel": "Lue lisää hotellista", "Retype new password": "Kirjoita uusi salasana uudelleen", @@ -95,6 +100,7 @@ "Street": "Katu", "special character": "erikoishahmo", "Total Points": "Kokonaispisteet", + "Your points": "Sinun pisteesi", "Transaction date": "Tapahtuman päivämäärä", "Transactions": "Tapahtumat", "Tripadvisor reviews": "{rating} ({count} arvostelua TripAdvisorissa)", diff --git a/i18n/dictionaries/no.json b/i18n/dictionaries/no.json index 2dfd04ba8..4fdb6f3ad 100644 --- a/i18n/dictionaries/no.json +++ b/i18n/dictionaries/no.json @@ -5,11 +5,13 @@ "All rooms comes with standard amenities": "Alle rommene har standard fasiliteter", "Already a friend?": "Allerede en venn?", "Arrival date": "Ankomstdato", + "as of today": "per idag", "As our": "Som vår", "As our Close Friend": "Som vår nære venn", "At the hotel": "På hotellet", "Book": "Bok", "Booking number": "Bestillingsnummer", + "by": "innen", "Cancel": "Avbryt", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Sjekk ut kredittkortene som er lagret på profilen din. Betal med et lagret kort når du er pålogget for en jevnere nettopplevelse.", "Choose room": "Velg rom", @@ -24,7 +26,7 @@ "Could not find requested resource": "Kunne ikke finne den forespurte ressursen", "Country": "Land", "Country code": "Landskode", - "Current level": "Nåværende nivå", + "Your current level": "Ditt nåværende nivå", "Current password": "Nåværende passord", "characters": "tegn", "Date of Birth": "Fødselsdato", @@ -41,6 +43,7 @@ "From": "Fra", "Get inspired": "Bli inspirert", "Go back to overview": "Gå tilbake til oversikten", + "Highest level": "Høyeste nivå", "How it works": "Hvordan det fungerer", "Join Scandic Friends": "Bli med i Scandic Friends", "Language": "Språk", @@ -60,12 +63,13 @@ "My wishes": "Mine ønsker", "New password": "Nytt passord", "Next": "Neste", - "Next level": "Neste nivå", + "next level:": "Neste nivå:", "No content published": "Ingen innhold publisert", "No transactions available": "Ingen transaksjoner tilgjengelig", "Not found": "Ikke funnet", "night": "natt", "nights": "netter", + "Nights needed to level up": "Netter som trengs for å komme opp i nivå", "number": "antall", "On your journey": "På reisen din", "Open": "Åpen", @@ -77,9 +81,10 @@ "Please enter a valid phone number": "Vennligst oppgi et gyldig telefonnummer", "Points": "Poeng", "Points may take up to 10 days to be displayed.": "Det kan ta opptil 10 dager før poeng vises.", - "Points until next level": "Poeng til neste nivå", + "Points needed to level up": "Poeng som trengs for å komme opp i nivå", + "Points needed to stay on level": "Poeng som trengs for å holde seg på nivå", + "points expiring by": "poeng utløper innen", "Previous victories": "Tidligere seire", - "points until next level": "poeng til neste nivå", "Read more": "Les mer", "Read more about the hotel": "Les mer om hotellet", "Retype new password": "Skriv inn nytt passord på nytt", @@ -95,6 +100,7 @@ "Street": "Gate", "special character": "spesiell karakter", "Total Points": "Totale poeng", + "Your points": "Dine poeng", "Transaction date": "Transaksjonsdato", "Transactions": "Transaksjoner", "Tripadvisor reviews": "{rating} ({count} anmeldelser på Tripadvisor)", diff --git a/i18n/dictionaries/sv.json b/i18n/dictionaries/sv.json index e8e2d2260..88c001d26 100644 --- a/i18n/dictionaries/sv.json +++ b/i18n/dictionaries/sv.json @@ -5,11 +5,13 @@ "All rooms comes with standard amenities": "Alla rum har standardbekvämligheter", "Already a friend?": "Redan en vän?", "Arrival date": "Ankomstdatum", + "as of today": "från och med idag", "As our": "Som vår", "As our Close Friend": "Som vår nära vän", "At the hotel": "På hotellet", "Book": "Boka", "Booking number": "Bokningsnummer", + "by": "innan", "Cancel": "Avbryt", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Kolla in kreditkorten som sparats i din profil. Betala med ett sparat kort när du är inloggad för en smidigare webbupplevelse.", "Choose room": "Välj rum", @@ -24,7 +26,7 @@ "Could not find requested resource": "Det gick inte att hitta den begärda resursen", "Country": "Land", "Country code": "Landskod", - "Current level": "Nuvarande nivå", + "Your current level": "Din nuvarande nivå", "Current password": "Nuvarande lösenord", "characters": "tecken", "Date of Birth": "Födelsedatum", @@ -41,6 +43,7 @@ "From": "Från", "Get inspired": "Bli inspirerad", "Go back to overview": "Gå tillbaka till översikten", + "Highest level": "Högsta nivå", "How it works": "Hur det fungerar", "hotelPages.rooms.title": "Rum", "hotelPages.rooms.roomCard.person": "person", @@ -64,12 +67,13 @@ "My wishes": "Mina önskningar", "New password": "Nytt lösenord", "Next": "Nästa", - "Next level": "Nästa nivå", + "next level:": "Nästa nivå:", "No content published": "Inget innehåll publicerat", "No transactions available": "Inga transaktioner tillgängliga", "Not found": "Hittades inte", "night": "natt", "nights": "nätter", + "Nights needed to level up": "Nätter som behövs för att gå upp i nivå", "number": "nummer", "On your journey": "På din resa", "Open": "Öppna", @@ -81,9 +85,10 @@ "Please enter a valid phone number": "Var vänlig och ange ett giltigt telefonnummer", "Points": "Poäng", "Points may take up to 10 days to be displayed.": "Det kan ta upp till 10 dagar innan poäng visas.", - "Points until next level": "Poäng till nästa nivå", + "Points needed to level up": "Poäng som behövs för att gå upp i nivå", + "Points needed to stay on level": "Poäng som behövs för att hålla sig på nivå", + "points expiring by": "poäng förfaller till", "Previous victories": "Tidigare segrar", - "points until next level": "poäng till nästa nivå", "Read more": "Läs mer", "Read more about the hotel": "Läs mer om hotellet", "Retype new password": "Upprepa nytt lösenord", @@ -99,6 +104,7 @@ "Street": "Gata", "special character": "speciell karaktär", "Total Points": "Total poäng", + "Your points": "Dina poäng", "Transaction date": "Transaktionsdatum", "Transactions": "Transaktioner", "Tripadvisor reviews": "{rating} ({count} recensioner på Tripadvisor)", diff --git a/server/routers/user/output.ts b/server/routers/user/output.ts index 5a6638d0b..0ee142386 100644 --- a/server/routers/user/output.ts +++ b/server/routers/user/output.ts @@ -25,6 +25,8 @@ export const getUserSchema = z.object({ membershipLevel: z.nativeEnum(MembershipLevelEnum).optional(), memberSince: z.string(), membershipType: z.string(), + nextLevel: z.string().optional(), + pointsRequiredToNextlevel: z.number().optional(), }) ), phoneNumber: z.string().optional(), diff --git a/types/components/myPages/membershipLevel.ts b/types/components/myPages/membership.ts similarity index 67% rename from types/components/myPages/membershipLevel.ts rename to types/components/myPages/membership.ts index ae458ba79..ce352511f 100644 --- a/types/components/myPages/membershipLevel.ts +++ b/types/components/myPages/membership.ts @@ -3,3 +3,7 @@ import { membershipLevels } from "@/constants/membershipLevels" export type MembershipLevelProps = { level: membershipLevels } + +export type CopyButtonProps = { + membershipNumber: string +} diff --git a/types/components/myPages/myPage/enums.ts b/types/components/myPages/myPage/enums.ts index 5385bc1ac..294944620 100644 --- a/types/components/myPages/myPage/enums.ts +++ b/types/components/myPages/myPage/enums.ts @@ -1,5 +1,6 @@ export enum DynamicContentComponents { membership_overview = "membership_overview", + points_overview = "points_overview", soonest_stays = "soonest_stays", previous_stays = "previous_stays", upcoming_stays = "upcoming_stays", diff --git a/types/components/myPages/points.ts b/types/components/myPages/points.ts new file mode 100644 index 000000000..95d8486e5 --- /dev/null +++ b/types/components/myPages/points.ts @@ -0,0 +1,16 @@ +interface PointsOrNightColumn { + title?: string + subtitle?: string + subtitleParam?: string +} + +export interface PointsColumn extends PointsOrNightColumn { + points: number | undefined + nights?: never +} +export interface NightsColumn extends PointsOrNightColumn { + points?: never + nights: number | undefined +} + +export type PointsColumnProps = PointsColumn | NightsColumn diff --git a/utils/membershipLevel.ts b/utils/membershipLevel.ts index aa7d54135..2c1420a7f 100644 --- a/utils/membershipLevel.ts +++ b/utils/membershipLevel.ts @@ -8,13 +8,9 @@ import levelsData from "@/components/Loyalty/Blocks/DynamicContent/LoyaltyLevels export function getMembershipLevelObject( membershipLevel: MembershipLevelEnum, - lang: Lang, - level: "currentLevel" | "nextLevel" = "currentLevel" + lang: Lang ) { - let levelNumber = membershipLevels[membershipLevel] - if (level === "nextLevel") { - levelNumber += 1 - } - - return levelsData[lang].levels.find((level) => level.level === levelNumber) + return levelsData[lang].levels.find( + (level) => level.level === membershipLevels[membershipLevel] + ) } diff --git a/utils/user.ts b/utils/user.ts index 57f4e3e16..25157fc80 100644 --- a/utils/user.ts +++ b/utils/user.ts @@ -1,5 +1,6 @@ import { z } from "zod" +import { MembershipLevelEnum } from "@/constants/membershipLevels" import { getMembershipCardsSchema } from "@/server/routers/user/output" import { User } from "@/types/user" @@ -29,6 +30,12 @@ export function getMembershipCards( }) } +export function isHighestMembership( + membershipLevel: MembershipLevelEnum | undefined +) { + return membershipLevel == MembershipLevelEnum.L7 +} + export function getInitials( firstName: User["firstName"], lastName: User["lastName"]