feat(WEB-250): overview hero final ui

This commit is contained in:
Simon Emanuelsson
2024-05-24 10:13:24 +02:00
parent f884383c3c
commit 16b817f469
164 changed files with 6262 additions and 990 deletions
@@ -5,7 +5,7 @@ import { serverClient } from "@/lib/trpc/server"
import Header from "@/components/MyPages/Blocks/Header"
import CardGrid from "@/components/TempDesignSystem/CardGrid"
import Title from "@/components/Title"
import Title from "@/components/TempDesignSystem/Title"
import levelsData from "../data"
@@ -2,6 +2,7 @@
display: grid;
gap: 1.5rem;
}
.cardContainer {
display: grid;
gap: 0.4rem;
@@ -15,6 +16,7 @@
margin: 0;
font-size: 2rem;
}
.card {
text-decoration: none;
display: flex;
@@ -31,7 +33,8 @@
.level {
font-size: var(--typography-Script-Mobile-fontSize, 18px);
font-weight: var(--typography-Script-Mobile-fontWeight);
font-style: italic; /* font-family: var(--ff-biro-script-plus); */
font-style: italic;
/* font-family: var(--ff-biro-script-plus); */
}
.cardSubtitle {
@@ -47,7 +50,7 @@
text-decoration: none;
}
@media screen and (min-width: 950px) {
@media screen and (min-width: 1367px) {
.cardContainer {
grid-template-columns: 1fr 1fr 1fr;
}
@@ -100,13 +100,13 @@
display: none;
}
@media screen and (max-width: 950px) {
@media screen and (max-width: 1366px) {
.victory:first-of-type {
grid-row: 1 / -1;
}
}
@media screen and (min-width: 950px) {
@media screen and (min-width: 1367px) {
.challenges {
gap: 2.6rem 1.5rem;
grid-template-areas:
@@ -1,5 +1,7 @@
import { _ } from "@/lib/translation"
import Image from "@/components/Image"
import Title from "@/components/Title"
import Title from "@/components/TempDesignSystem/Title"
import styles from "./challenges.module.css"
@@ -9,13 +11,11 @@ export default function Challenges({ journeys, victories }: ChallengesProps) {
return (
<section className={styles.challenges}>
<header className={styles.header}>
<Title level="h2" uppercase>
Your Challenges Conquer & Earn!
</Title>
<Title level="h2">{_("Your Challenges Conquer & Earn!")}</Title>
</header>
<section className={styles.section}>
<header>
<Title level="h3">On your journey</Title>
<Title level="h3">{_("On your journey")}</Title>
</header>
<section className={styles.journeys}>
{journeys.map((journey) => (
@@ -28,7 +28,7 @@ export default function Challenges({ journeys, victories }: ChallengesProps) {
</section>
<aside className={styles.aside}>
<header>
<Title level="h3">Previous victories</Title>
<Title level="h3">{_("Previous victories")}</Title>
</header>
<section className={styles.victories}>
{victories.map((victory) => (
@@ -1,20 +1,20 @@
.header {
display: grid;
grid-template-areas:
"title link"
"subtitle subtitle";
grid-template-columns: 1fr max-content;
gap: 1.5rem;
gap: var(--Spacing-x1);
grid-template-columns: 1fr auto;
}
.title {
grid-area: title;
grid-column: 1/2;
grid-row: 1/2;
}
.link {
grid-area: link;
grid-column: 2/-1;
grid-row: 1/2;
}
.subtitle {
grid-area: subtitle;
grid-column: 1/-1;
grid-row: 2;
}
+24 -29
View File
@@ -1,37 +1,32 @@
import Link from "next/link"
import Title from "@/components/Title"
import Link from "@/components/TempDesignSystem/Link"
import Subtitle from "@/components/TempDesignSystem/Subtitle"
import Title from "@/components/TempDesignSystem/Title"
import styles from "./header.module.css"
import type { HeaderProps } from "@/types/components/myPages/stays/title"
export default function Header({ title, subtitle, link }: HeaderProps) {
export default function Header({
link,
subtitle,
title,
topTitle = false,
}: HeaderProps) {
return (
<>
<header className={styles.header}>
{title && (
<Title
as="h3"
level="h2"
className={styles.title}
weight="medium"
uppercase
>
{title}
</Title>
)}
{link && (
<Link className={styles.link} href={link.href}>
{link.text}
</Link>
)}
{subtitle && (
<Title as="h5" weight="regular" className={styles.subtitle}>
{subtitle}
</Title>
)}
</header>
</>
<header className={styles.header}>
<Title
as={topTitle ? "h2" : "h3"}
className={styles.title}
level={topTitle ? "h1" : "h2"}
>
{title}
</Title>
{link && (
<Link className={styles.link} href={link.href}>
{link.text}
</Link>
)}
<Subtitle className={styles.subtitle}>{subtitle}</Subtitle>
</header>
)
}
@@ -1,4 +1,4 @@
@media screen and (max-width: 950px) {
@media screen and (max-width: 1366px) {
.membershipBtn {
display: none;
}
@@ -2,67 +2,61 @@
align-items: center;
display: flex;
flex-direction: column;
gap: var(--Spacing-x4);
justify-content: center;
}
.header {
display: flex;
flex-direction: column;
}
.levelLabel {
position: relative;
transform: rotate(-13deg) translate(0px, -15px);
}
.level {
color: var(--some-black-color, #000);
/* font-family: var(--ff-biro-script-plus); */
font-size: 2.1rem;
font-weight: 400;
letter-spacing: 4%;
line-height: 3.6rem;
margin: 0;
height: 105px;
width: 219px;
}
.name {
color: var(--some-black-color, #111);
/* font-family: var(--ff-brandon-text); */
font-size: 2.8rem;
font-weight: 900;
letter-spacing: -3%;
line-height: 2.8rem;
margin: 0;
text-transform: uppercase;
text-align: center;
}
.membership {
align-items: center;
display: flex;
flex-direction: column;
gap: var(--Spacing-x2);
justify-content: center;
}
.membershipContainer {
align-items: center;
display: flex;
gap: 0.8rem;
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);
}
.membershipId {
color: var(--some-black-color, #1e1e1e);
font-family: var(--ff-fira-mono);
font-size: 1.5rem;
font-weight: 500;
letter-spacing: 6%;
line-height: 1.8rem;
color: var(--Scandic-Brand-Pale-Peach);
/* TODO: Not yet exported by the design team, change to variable l8r */
font-family: var(--ff-fira-mono, "fira mono");
font-size: 14px;
font-weight: 400;
letter-spacing: 0.168px;
line-height: 140%;
margin: 0;
}
@media screen and (max-width: 950px) {
.friend {
gap: 1.2rem;
}
.level {
transform: translate(-60%, 40%) rotate(-20deg);
}
}
@media screen and (min-width: 950px) {
.friend {
justify-self: flex-end;
}
.image {
margin-bottom: 2.6rem;
margin-top: 1.1rem;
}
.name {
margin-bottom: 1.2rem;
@media screen and (min-width: 768px) {
.membershipContainer {
grid-template-columns: auto auto;
}
}
@@ -1,25 +1,32 @@
import Image from "@/components/Image"
import { _ } from "@/lib/translation"
import { GoodFriend } from "@/components/Levels"
import BiroScript from "@/components/TempDesignSystem/BiroScript"
import Title from "@/components/TempDesignSystem/Title"
import styles from "./friend.module.css"
import type { FriendProps } from "@/types/components/myPages/myPage/friend"
import type { UserProps } from "@/types/components/myPages/user"
export default function Friend({ user }: FriendProps) {
export default function Friend({ user }: UserProps) {
return (
<section className={styles.friend}>
<p className={styles.level}>Current level:</p>
<Image
alt="Good Friend"
className={styles.image}
height={70}
src="/_static/icons/good-friend.svg"
width={228}
/>
<h3 className={styles.name}>{user.name}</h3>
<div className={styles.membershipContainer}>
<p className={styles.membershipId}>
{user.membership ? user.membership.membershipNumber : "N/A"}
</p>
<header className={styles.header}>
<BiroScript className={styles.levelLabel} color="pale">
Current level:
</BiroScript>
<GoodFriend className={styles.level} color="pale" />
</header>
<div className={styles.membership}>
<Title className={styles.name} color="pale" level="h3">
{user.name}
</Title>
<div className={styles.membershipContainer}>
<p className={styles.membershipId}>{_("Membership ID:")}</p>
<p className={styles.membershipId}>
{user.membership ? user.membership.membershipNumber : "N/A"}
</p>
</div>
</div>
</section>
)
@@ -0,0 +1,5 @@
import styles from "./label.module.css"
export default function Label({ children }: React.PropsWithChildren) {
return <span className={styles.label}>{children}</span>
}
@@ -0,0 +1,9 @@
.label {
color: var(--Scandic-Brand-Pale-Peach);
font-family: var(--typography-Body-Regular-fontFamily);
font-size: var(--typography-Body-Regular-fontSize);
font-weight: var(--typography-Body-Regular-fontWeight);
letter-spacing: var(--typography-Body-Regular-letterSpacing);
line-height: var(--typography-Body-Regular-lineHeight);
margin: 0;
}
@@ -0,0 +1,22 @@
import { _ } from "@/lib/translation"
import BiroScript from "@/components/TempDesignSystem/BiroScript"
import Title from "@/components/TempDesignSystem/Title"
import Label from "../Label"
import styles from "./nextLevel.module.css"
import type { UserProps } from "@/types/components/myPages/user"
export default function NextLevel({}: UserProps) {
return (
<section>
<Label>{_("Next level")}:</Label>
<Title className={styles.nextLevel} color="pale" level="h3">
{_("Close friend")}
<BiroScript>{_("Coming up")}!</BiroScript>
</Title>
</section>
)
}
@@ -0,0 +1,12 @@
.nextLevel {
align-items: center;
display: grid;
grid-template-columns: 1fr;
}
@media screen and (min-width: 768px) {
.nextLevel {
gap: var(--Spacing-x1);
grid-template-columns: 1fr auto;
}
}
@@ -0,0 +1,26 @@
import Title from "@/components/TempDesignSystem/Title"
import Label from "../Label"
import styles from "./totalPoints.module.css"
import type { UserProps } from "@/types/components/myPages/user"
export default function Points({ user }: UserProps) {
return (
<section className={styles.points}>
<article>
<Label>Total Points</Label>
<Title color="pale" level="h2">
{user.membership ? user.membership.currentPoints : "N/A"}
</Title>
</article>
<article>
<Label>Points until next level</Label>
<Title color="pale" level="h2">
{user.membership ? user.membership.currentPoints : "N/A"}
</Title>
</article>
</section>
)
}
@@ -0,0 +1,11 @@
.points {
display: grid;
gap: var(--Spacing-x2);
grid-template-columns: 1fr;
}
@media screen and (min-width: 768px) {
.points {
grid-template-columns: 1fr 1fr;
}
}
@@ -1,21 +0,0 @@
import Divider from "@/components/TempDesignSystem/Divider"
import Title from "../Title"
import styles from "./progress.module.css"
export default function Progress() {
return (
<section className={styles.progress}>
<header className={styles.header}>
<Title>14 680 points until next level</Title>
<Title>Progress</Title>
</header>
<Divider className={styles.divider} variant="dotted" />
<div className={styles.container}>
<p className={styles.nextLevel}>14 680 points until next level</p>
<p className={styles.target}>Close friend</p>
</div>
</section>
)
}
@@ -1,62 +0,0 @@
.header :first-child {
display: none;
}
.divider {
display: none;
}
.container {
align-items: baseline;
display: flex;
gap: 0.7rem;
}
.nextLevel {
color: var(--some-black-color, #000);
/* font-family: var(--ff-brandon-text); */
font-size: 1.2rem;
font-weight: 400;
letter-spacing: 0.6%;
margin: 0;
}
.target {
color: var(--some-black-color, #000);
/* font-family: var(--ff-biro-script-plus); */
font-size: 1.8rem;
font-weight: 400;
letter-spacing: 4%;
margin: 0;
}
@media screen and (max-width: 950px) {
.progress {
display: grid;
gap: 0.2rem;
}
}
@media screen and (min-width: 950px) {
.header :first-child {
display: block;
}
.header :nth-child(2n) {
display: none;
}
.divider {
display: block;
margin: 0.3rem 0 1.2rem;
}
.nextLevel {
display: none;
}
.target {
font-size: 1.8rem;
line-height: 3rem;
}
}
@@ -1,5 +0,0 @@
import styles from "./title.module.css"
export default function Title({ children }: React.PropsWithChildren) {
return <h4 className={styles.title}>{children}</h4>
}
@@ -1,16 +0,0 @@
.title {
color: var(--some-grey-color, #000);
/* font-family: var(--ff-brandon-text); */
font-size: 1.5rem;
font-weight: 500;
letter-spacing: 0.6%;
line-height: 1.7rem;
margin: 0;
}
@media screen and (min-width: 950px) {
.title {
color: var(--some-grey-color, #4f4f4f);
font-size: 1.2rem;
}
}
@@ -1,19 +0,0 @@
import Divider from "@/components/TempDesignSystem/Divider"
import Title from "../Title"
import styles from "./totalPoints.module.css"
import type { TotalPointsProps } from "@/types/components/myPages/myPage/totalPoints"
export default function TotalPoints({ user }: TotalPointsProps) {
return (
<div>
<Title>Total Points</Title>
<Divider className={styles.divider} variant="dotted" />
<p className={styles.points}>
{user.membership ? user.membership.currentPoints : "N/A"}
</p>
</div>
)
}
@@ -1,20 +0,0 @@
.divider {
margin-bottom: 1rem;
margin-top: 0.3rem;
}
.points {
color: var(--some-black-color, #111);
/* font-family: var(--ff-brandon-text); */
font-size: 3.7rem;
font-weight: 900;
letter-spacing: -3%;
line-height: 3.7rem;
margin: 0;
}
@media screen and (min-width: 950px) {
.divider {
margin-bottom: 1.2rem;
}
}
@@ -1,15 +1,18 @@
import Progress from "./Progress"
import TotalPoints from "./TotalPoints"
import Divider from "@/components/TempDesignSystem/Divider"
import NextLevel from "./NextLevel"
import Points from "./Points"
import styles from "./stats.module.css"
import type { StatsProps } from "@/types/components/myPages/myPage/stats"
import type { UserProps } from "@/types/components/myPages/user"
export default function Stats({ user }: StatsProps) {
export default function Stats({ user }: UserProps) {
return (
<section className={styles.stats}>
<TotalPoints user={user} />
<Progress />
<Points user={user} />
<Divider variant="default" />
<NextLevel user={user} />
</section>
)
}
@@ -1,13 +1,11 @@
.stats {
display: flex;
flex-direction: column;
gap: 0.7rem;
align-content: center;
display: grid;
gap: var(--Spacing-x2);
}
@media screen and (min-width: 950px) {
@media screen and (min-width: 1367px) {
.stats {
gap: 1.4rem;
justify-content: center;
max-width: 32rem;
gap: var(--Spacing-x4);
}
}
+10 -11
View File
@@ -1,28 +1,27 @@
import { serverClient } from "@/lib/trpc/server"
import Title from "@/components/Title"
import Divider from "@/components/TempDesignSystem/Divider"
import Header from "../Header"
import Friend from "./Friend"
import Stats from "./Stats"
import styles from "./overview.module.css"
import type { OverviewProps } from "@/types/components/myPages/myPage/overview"
import type { AccountPageComponentProps } from "@/types/components/myPages/myPage/accountPage"
export default async function Overview({ title }: OverviewProps) {
export default async function Overview({
link,
subtitle,
title,
}: AccountPageComponentProps) {
const user = await serverClient().user.get()
return (
<section className={styles.container}>
<header>
{title && (
<Title as="h3" level="h2" uppercase className={styles.title}>
{title}
</Title>
)}
</header>
<Header link={link} subtitle={subtitle} title={title} topTitle />
<section className={styles.overview}>
<Friend user={user} />
<Divider className={styles.divider} />
<Stats user={user} />
</section>
</section>
@@ -4,43 +4,38 @@
}
.overview {
background-color: var(--Scandic-Brand-Scandic-Red);
border-radius: var(--Corner-radius-xLarge);
display: grid;
gap: 1.7rem;
gap: var(--Spacing-x2);
grid-template-columns: 1fr;
padding: var(--Spacing-x7) var(--Spacing-x6);
}
@media screen and (max-width: 950px) {
.divider {
padding-top: var(--Spacing-x2);
}
@media screen and (max-width: 767px) {
.container {
/* Full-width override styling */
left: 50%;
margin-left: -50vw;
margin-right: -50vw;
padding: 0 2rem 3.6rem;
padding: 0 var(--Spacing-x2);
position: relative;
right: 50%;
width: 100dvw;
}
}
@media screen and (min-width: 950px) {
@media screen and (min-width: 768px) {
.overview {
background-color: var(--some-grey-color, #f2f2f2);
border-radius: 0.8rem;
gap: 4rem;
gap: var(--Spacing-x2);
grid-template-columns: 1fr 1fr;
justify-content: center;
left: unset;
margin-left: unset;
margin-right: unset;
padding: 3.5rem 2rem;
position: static;
right: unset;
width: 100%;
}
}
@media screen and (min-width: 1100px) {
.overview {
gap: 10rem;
min-height: 35rem;
.divider {
display: none;
}
}
+5 -16
View File
@@ -1,7 +1,7 @@
import Link from "next/link"
import Image from "@/components/Image"
import Title from "@/components/Title"
import Link from "@/components/TempDesignSystem/Link"
import Header from "../Header"
import styles from "./shortcuts.module.css"
@@ -9,23 +9,12 @@ import type { ShortcutsProps } from "@/types/components/myPages/myPage/shortcuts
export default function Shortcuts({
shortcuts,
title,
subtitle,
title,
}: ShortcutsProps) {
return (
<section className={styles.shortcuts}>
<header className={styles.header}>
<Title
as="h3"
level="h2"
weight={"medium"}
className={styles.title}
uppercase
>
{title}
</Title>
<p className={styles.subtitle}>{subtitle}</p>
</header>
<Header link={undefined} subtitle={subtitle} title={title} />
<section className={styles.links}>
{shortcuts.map((shortcut) => (
<Link
@@ -2,7 +2,8 @@
display: grid;
gap: 2rem;
}
@media screen and (min-width: 950px) {
@media screen and (min-width: 1367px) {
.container {
gap: 3.5rem;
}
@@ -1,13 +1,13 @@
import { _ } from "@/lib/translation"
import Title from "@/components/Title"
import Title from "@/components/TempDesignSystem/Title"
import styles from "./emptyPreviousStays.module.css"
export default function EmptyPreviousStaysBlock() {
return (
<section className={styles.container}>
<Title level="h3" as="h5" uppercase>
<Title as="h5" level="h3">
{_("You have no previous stays.")}
</Title>
</section>
@@ -12,8 +12,7 @@ import ShowMoreButton from "../ShowMoreButton"
import StayCard from "../StayCard"
import EmptyPreviousStaysBlock from "./EmptyPreviousStays"
import { AccountPageComponentProps } from "@/types/components/myPages/myPage/accountPage"
import type { Page } from "@/types/components/myPages/stays/page"
import type { AccountPageComponentProps } from "@/types/components/myPages/myPage/accountPage"
export default function PreviousStays({
lang,
@@ -25,7 +24,7 @@ export default function PreviousStays({
trpc.user.stays.previous.useInfiniteQuery(
{},
{
getNextPageParam: (lastPage: Page) => lastPage.nextCursor,
getNextPageParam: (lastPage) => lastPage.nextCursor,
}
)
@@ -1,24 +1,23 @@
import Link from "next/link"
import { _ } from "@/lib/translation"
import Button from "@/components/TempDesignSystem/Button"
import Title from "@/components/Title"
import Link from "@/components/TempDesignSystem/Link"
import Title from "@/components/TempDesignSystem/Title"
import styles from "./emptyUpcomingStays.module.css"
export default function EmptyUpcomingStaysBlock() {
return (
<section className={styles.container}>
<Title level="h3" as="h5" uppercase>
{_(" You have no upcoming stays.")}
<Title as="h5" level="h3">
{_("You have no upcoming stays.")}
<span className={styles.grayTitle}>
{" "}
{_("Where should you go next?")}
</span>
</Title>
<Button intent="primary" asChild type="button">
<Link className={styles.link} href={"#"} key="getInspired">
<Link className={styles.link} href="#" key="getInspired">
{_("Get inspired")}
</Link>
</Button>
@@ -20,7 +20,7 @@ export default async function SoonestStays({
const { data: stays } = await serverClient().user.stays.upcoming({ limit: 3 })
return (
<MaxWidth className={styles.container} tag="section">
<section className={styles.container}>
<Header title={title} subtitle={subtitle} link={link} />
{stays.length ? (
<CardGrid>
@@ -35,6 +35,6 @@ export default async function SoonestStays({
) : (
<EmptyUpcomingStaysBlock />
)}
</MaxWidth>
</section>
)
}
@@ -3,7 +3,7 @@ import { Calendar } from "react-feather"
import { dt } from "@/lib/dt"
import Image from "@/components/Image"
import Title from "@/components/Title"
import Title from "@/components/TempDesignSystem/Title"
import styles from "./stay.module.css"
@@ -29,13 +29,7 @@ export default function StayCard({ stay, lang }: StayCardProps) {
height={240}
/>
<footer className={styles.footer}>
<Title
as="h5"
level="h3"
weight="semiBold"
uppercase
className={styles.hotel}
>
<Title as="h5" className={styles.hotel} level="h3">
{hotelInformation.hotelName}
</Title>
<div className={styles.date}>
@@ -1,24 +1,23 @@
import Link from "next/link"
import { _ } from "@/lib/translation"
import Button from "@/components/TempDesignSystem/Button"
import Title from "@/components/Title"
import Link from "@/components/TempDesignSystem/Link"
import Title from "@/components/TempDesignSystem/Title"
import styles from "./emptyUpcomingStays.module.css"
export default function EmptyUpcomingStaysBlock() {
return (
<section className={styles.container}>
<Title level="h3" as="h5" uppercase>
{_(" You have no upcoming stays.")}
<Title as="h5" level="h3">
{_("You have no upcoming stays.")}
<span className={styles.grayTitle}>
{" "}
{_("Where should you go next?")}
</span>
</Title>
<Button intent="primary" asChild type="button">
<Link className={styles.link} href={"#"} key="getInspired">
<Link className={styles.link} href="#" key="getInspired">
{_("Get inspired")}
</Link>
</Button>
@@ -13,8 +13,7 @@ import ShowMoreButton from "../ShowMoreButton"
import StayCard from "../StayCard"
import EmptyUpcomingStaysBlock from "./EmptyUpcomingStays"
import { AccountPageComponentProps } from "@/types/components/myPages/myPage/accountPage"
import type { Page } from "@/types/components/myPages/stays/page"
import type { AccountPageComponentProps } from "@/types/components/myPages/myPage/accountPage"
export default function UpcomingStays({
lang,
@@ -26,7 +25,7 @@ export default function UpcomingStays({
trpc.user.stays.upcoming.useInfiniteQuery(
{ limit: 6 },
{
getNextPageParam: (lastPage: Page) => lastPage.nextCursor,
getNextPageParam: (lastPage) => lastPage.nextCursor,
}
)