feat(WEB-170): edit profile view

This commit is contained in:
Simon Emanuelsson
2024-04-11 18:51:38 +02:00
parent 82e4d40203
commit 9396b2c3d5
114 changed files with 3642 additions and 2171 deletions

View File

@@ -1,114 +1,16 @@
export const breadcrumbs = {
"/my-pages": [
{
title: "My Pages"
}
title: "My Pages",
},
],
"/my-pages/profile": [
{
href: "/my-pages",
title: "My Pages"
title: "My Pages",
},
{
title: "My Profile",
},
],
}
export const challenges = {
journeys: [
{
tag: "After work queen",
title: "Try 3 Hotel Bars, Pocket 200 Points",
},
{
tag: "Dine & Shine",
title: "Visit 3 scandic Restaurants, Earn 150 Points",
},
],
victories: [
{
tag: "Capital Explorer",
title: "Stay in 3 scandic hotels, in three Capitals, Gain 2000 Points",
},
{
tag: "Friends Feast",
title: "Dine with 3 Buddies, Snag a Free Breakfast",
},
{
tag: "Eco Warrior",
title: "Choose Green, Get 500 Points",
},
],
}
export const shortcuts = [
{
href: "#",
title: "My Benefit",
},
{
href: "#",
title: "Program overview",
},
// {
// href: "#",
// title: "Scandic Friends shop",
// },
// {
// href: "#",
// title: "Fire and safety",
// },
// {
// href: "#",
// title: "Our sustainability work",
// },
// {
// href: "#",
// title: "How you earn points",
// },
// {
// href: "#",
// title: "How you use points",
// },
// {
// href: "#",
// title: "Missing points",
// },
// {
// href: "#",
// title: "Our term and conditions",
// },
]
export const stays = [
{
dateArrive: new Date("04 27 2024"),
dateDepart: new Date("04 28 2024"),
guests: 2,
hotel: "Scandic Helsinki Hub",
},
{
dateArrive: new Date("05 27 2024"),
dateDepart: new Date("05 28 2024"),
guests: 2,
hotel: "Scandic Örebro Central",
},
{
dateArrive: new Date("06 27 2024"),
dateDepart: new Date("06 28 2024"),
guests: 2,
hotel: "Scandic Oslo City",
},
]
export const extendedUser = {
journeys: challenges.journeys,
membershipId: 30812404844732,
nights: 14,
points: 20720,
qualifyingPoints: 5000,
shortcuts,
stays,
victories: challenges.victories,
}

View File

@@ -8,53 +8,11 @@ import Sidebar from "@/components/MyPages/Sidebar"
import styles from "./layout.module.css"
import type { LangParams, LayoutArgs } from "@/types/params"
import { request } from "@/lib/graphql/request"
import {
GetNavigationMyPagesData,
NavigationItem,
MenuItem,
PageLink,
PageLinkEnum,
} from "@/types/requests/myPages/navigation"
import { GetNavigationMyPages } from "@/lib/graphql/Query/NavigationMyPages.graphql"
function getURL(node: PageLink) {
switch (node.__typename) {
case PageLinkEnum.ContentPage:
return node.web.url
case PageLinkEnum.AccountPage:
case PageLinkEnum.LoyaltyPage:
return node.url
}
}
function mapMenuItems(navigationItems: NavigationItem[]) {
return navigationItems.map(({ item }): MenuItem => {
const { node } = item.pageConnection.edges[0]
return {
uid: node.system.uid,
url: getURL(node),
linkText: item.link_text || node.title,
subItems: item.sub_items ? mapMenuItems(item.sub_items) : null,
}
})
}
export default async function MyPagesLayout({
children,
params,
}: React.PropsWithChildren<LayoutArgs<LangParams>>) {
const response = await request<GetNavigationMyPagesData>(
GetNavigationMyPages,
{
locale: params.lang,
}
)
// navigation_my_pages is of type Single, hence the hard [0]
const navigation = response.data.all_navigation_my_pages.items[0]
const menuItems = mapMenuItems(navigation.items)
return (
<div
className={`${firaMono.variable} ${firaSans.variable} ${styles.layout}`}
@@ -62,7 +20,7 @@ export default async function MyPagesLayout({
<Header lang={params.lang} />
<Breadcrumbs breadcrumbs={breadcrumbs} lang={params.lang} />
<div className={styles.content}>
<Sidebar menuItems={menuItems} />
<Sidebar lang={params.lang} />
{children}
</div>
</div>

View File

@@ -1,7 +1,6 @@
import { _ } from "@/lib/translation"
import { serverClient } from "@/lib/trpc/server"
import { extendedUser } from "./_constants"
import MaxWidth from "@/components/MaxWidth"
import Overview from "@/components/MyPages/Blocks/Overview"
import Shortcuts from "@/components/MyPages/Blocks/Shortcuts"
@@ -12,19 +11,15 @@ import styles from "./page.module.css"
import type { LangParams, PageArgs } from "@/types/params"
export default async function MyPage({ params }: PageArgs<LangParams>) {
const data = await serverClient().user.get()
const user = {
...data,
...extendedUser,
}
const user = await serverClient().user.get()
return (
<MaxWidth className={styles.blocks} tag="main">
<Overview user={user} />
<UpcomingStays lang={params.lang} stays={user.stays} />
<Shortcuts
shortcuts={user.shortcuts}
title="Handy Shortcuts"
subtitle="The community at your fingertips"
subtitle={_("The community at your fingertips")}
title={_("Handy Shortcuts")}
/>
</MaxWidth>
)

View File

@@ -0,0 +1,5 @@
import CommunicationPreferences from "@/components/MyProfile/CommunicationPreferences"
export default function Communication() {
return <CommunicationPreferences />
}

View File

@@ -0,0 +1,3 @@
export default function Default() {
return null
}

View File

@@ -0,0 +1,5 @@
import CreditCards from "@/components/MyProfile/CreditCards"
export default function CreditCardSlot() {
return <CreditCards />
}

View File

@@ -1,3 +1,3 @@
export default function DefaultEdit() {
export default function Default() {
return null
}

View File

@@ -1,10 +1,3 @@
import Button from "@/components/TempDesignSystem/Button";
export default function EditProfile() {
return (
<>
<Button form="edit-profile" type="reset">Cancel</Button>
<Button form="edit-profile" type="submit">Save</Button>
</>
)
export default function Default() {
return null
}

View File

@@ -0,0 +1,38 @@
"use client"
import { _ } from "@/lib/translation"
import { profile } from "@/constants/routes/myPages"
import { useProfileStore } from "@/stores/edit-profile"
import Button from "@/components/TempDesignSystem/Button"
import Link from "@/components/TempDesignSystem/Link"
import type { LangParams, PageArgs } from "@/types/params"
export default function EditProfile({ params }: PageArgs<LangParams>) {
const isPending = useProfileStore((store) => store.pending)
const isValid = useProfileStore((store) => store.valid)
return (
<>
<Button
aria-label="Cancel"
asChild
bgcolor="white"
form="edit-profile"
size="small"
type="reset"
>
<Link href={profile[params.lang]}>{_("Cancel")}</Link>
</Button>
<Button
bgcolor="quarternary"
disabled={!isValid || isPending}
form="edit-profile"
size="small"
type="submit"
weight="regular"
>
{_("Save")}
</Button>
</>
)
}

View File

@@ -0,0 +1,3 @@
export default function Page() {
return null
}

View File

@@ -0,0 +1,3 @@
export default function Default() {
return null
}

View File

@@ -0,0 +1,5 @@
import MembershipCard from "@/components/MyProfile/MembershipCard"
export default function MembershipCardSlot() {
return <MembershipCard />
}

View File

@@ -0,0 +1,3 @@
export default function Default() {
return null
}

View File

@@ -0,0 +1,5 @@
import Password from "@/components/MyProfile/Password"
export default function PasswordSlot() {
return <Password />
}

View File

@@ -0,0 +1,3 @@
export default function Default() {
return null
}

View File

@@ -0,0 +1,3 @@
export default function Default() {
return null
}

View File

@@ -0,0 +1,8 @@
import { serverClient } from "@/lib/trpc/server"
import EditProfile from "@/components/MyProfile/Profile/Edit"
export default async function EditProfileSlot() {
const user = await serverClient().user.get()
return <EditProfile user={user} />
}

View File

@@ -0,0 +1,8 @@
import { serverClient } from "@/lib/trpc/server"
import Profile from "@/components/MyProfile/Profile"
export default async function ProfileInfo() {
const user = await serverClient().user.get()
return <Profile user={user} />
}

View File

@@ -1,11 +0,0 @@
import Modal from "@/components/Modal";
export default function VerifyCode() {
return (
<Modal>
<Modal.Header>
<Modal.Title>Verify Code</Modal.Title>
</Modal.Header>
</Modal>
)
}

View File

@@ -1,22 +1,3 @@
import Button from "@/components/TempDesignSystem/Button";
import Link from "@/components/TempDesignSystem/Link";
import styles from "./view.module.css"
import type { LangParams, PageArgs } from "@/types/params";
export default function ProfileView({ params }: PageArgs<LangParams>) {
return (
<Button
asChild
bgcolor="quarternary"
className={styles.btn}
size="small"
weight="regular"
>
<Link href={`/${params.lang}/my-pages/profile/verify`}>
Edit
</Link>
</Button>
)
export default function Default() {
return null
}

View File

@@ -0,0 +1,3 @@
export default function Default() {
return null
}

View File

@@ -0,0 +1,15 @@
import { _ } from "@/lib/translation"
import { profileEdit } from "@/constants/routes/myPages"
import Button from "@/components/TempDesignSystem/Button"
import Link from "@/components/TempDesignSystem/Link"
import type { LangParams, PageArgs } from "@/types/params"
export default function ProfileView({ params }: PageArgs<LangParams>) {
return (
<Button asChild bgcolor="quarternary" size="small" weight="regular">
<Link href={profileEdit[params.lang]}>{_("Edit")}</Link>
</Button>
)
}

View File

@@ -1,3 +0,0 @@
.btn {
position: absolute;
}

View File

@@ -0,0 +1,3 @@
export default function Default() {
return null
}

View File

@@ -0,0 +1,5 @@
import Wishes from "@/components/MyProfile/Wishes"
export default function WishesSlot() {
return <Wishes />
}

View File

@@ -0,0 +1,3 @@
export default function EditPage() {
return null
}

View File

@@ -0,0 +1,23 @@
.page {
display: grid;
gap: 3rem;
}
.btns {
align-items: center;
display: flex;
gap: 1rem;
justify-content: flex-end;
position: absolute;
right: 0;
/* Creates the 16px gap from design */
top: -1.6rem;
/* Moves itself to top of container to avoid calc */
transform: translateY(-100%);
}
.cards {
display: grid;
gap: 0.4rem;
grid-template-columns: 1fr 1fr;
}

View File

@@ -1,16 +1,33 @@
type ProfileLayoutProps = React.PropsWithChildren<{
edit: React.ReactNode
verifyCode: React.ReactNode
view: React.ReactNode
}>
import MaxWidth from "@/components/MaxWidth"
export default function ProfileLayout({ children, edit, verifyCode, view }: ProfileLayoutProps) {
import styles from "./layout.module.css"
import type { ProfileLayoutProps } from "@/types/components/myPages/myProfile/layout"
export default function ProfileLayout({
communication,
creditCards,
edit,
membershipCard,
password,
profile,
view,
wishes,
}: React.PropsWithChildren<ProfileLayoutProps>) {
return (
<>
{edit}
{view}
{children}
{verifyCode}
</>
<MaxWidth className={styles.page} tag="main">
<div className={styles.btns}>
{edit}
{view}
</div>
{profile}
<section className={styles.cards}>
{communication}
{wishes}
{membershipCard}
{creditCards}
{password}
</section>
</MaxWidth>
)
}

View File

@@ -1,10 +0,0 @@
.page {
display: grid;
gap: 3rem;
}
.cards {
display: grid;
gap: 0.4rem;
grid-template-columns: 1fr 1fr;
}

View File

@@ -1,36 +0,0 @@
import { serverClient } from "@/lib/trpc/server";
import { extendedUser } from "../_constants";
import CommunicationPreferences from "@/components/MyProfile/CommunicationPreferences";
import CreditCards from "@/components/MyProfile/CreditCards";
import MaxWidth from "@/components/MaxWidth";
import MembershipCard from "@/components/MyProfile/MembershipCard";
import Password from "@/components/MyProfile/Password";
import Profile from "@/components/MyProfile/Profile";
import Wishes from "@/components/MyProfile/Wishes";
import styles from "./page.module.css"
import Modal from "@/components/Modal";
export default async function MyProfile() {
const data = await serverClient().user.get()
const user = {
...data,
...extendedUser,
}
return (
<MaxWidth className={styles.page} tag="main">
<Modal>
<h1>HALLÅ ELLER!?!</h1>
</Modal>
<Profile user={user} />
<section className={styles.cards}>
<CommunicationPreferences />
<Wishes />
<MembershipCard />
<CreditCards />
<Password />
</section>
</MaxWidth>
)
}

View File

@@ -1,9 +0,0 @@
export default function VerifyPage() {
return (
<section>
<header>
<h1>Verify that code already!</h1>
</header>
</section>
)
}