feat(WEB-162): final design for my profile page
This commit is contained in:
committed by
Christel Westerberg
parent
a7b04df7b6
commit
5f3e417593
@@ -1,5 +1,5 @@
|
||||
.layout {
|
||||
background-color: var(--Scandic-Brand-Pale-Peach);
|
||||
background-color: var(--Scandic-Brand-Warm-White);
|
||||
display: grid;
|
||||
font-family: var(--typography-Body-Regular-fontFamily);
|
||||
gap: var(--Spacing-x3);
|
||||
|
||||
@@ -1,5 +1 @@
|
||||
import CommunicationPreferences from "@/components/MyProfile/CommunicationPreferences"
|
||||
|
||||
export default function Communication() {
|
||||
return <CommunicationPreferences />
|
||||
}
|
||||
export { default } from "../page"
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
.container {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x3);
|
||||
max-width: 510px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x1);
|
||||
}
|
||||
@@ -1,5 +1,31 @@
|
||||
import CommunicationPreferences from "@/components/MyProfile/CommunicationPreferences"
|
||||
import { ArrowRightIcon } from "@/components/Icons"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
export default function Communication() {
|
||||
return <CommunicationPreferences />
|
||||
import styles from "./page.module.css"
|
||||
|
||||
export default async function CommunicationSlot() {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<article className={styles.content}>
|
||||
<Subtitle>
|
||||
{formatMessage({ id: "My communication preferences" })}
|
||||
</Subtitle>
|
||||
<Body>
|
||||
{formatMessage({
|
||||
id: "Tell us what information and updates you'd like to receive, and how, by clicking the link below.",
|
||||
})}
|
||||
</Body>
|
||||
</article>
|
||||
<Link href="#" variant="icon">
|
||||
<ArrowRightIcon color="red" />
|
||||
<Body color="red" textTransform="underlined">
|
||||
{formatMessage({ id: "Add new card" })}
|
||||
</Body>
|
||||
</Link>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1 @@
|
||||
import CreditCards from "@/components/MyProfile/CreditCards"
|
||||
|
||||
export default function CreditCardSlot() {
|
||||
return <CreditCards />
|
||||
}
|
||||
export { default } from "../page"
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
.container {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x3);
|
||||
max-width: 510px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x1);
|
||||
}
|
||||
@@ -1,5 +1,29 @@
|
||||
import CreditCards from "@/components/MyProfile/CreditCards"
|
||||
import { PlusCircleIcon } from "@/components/Icons"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
export default function CreditCardSlot() {
|
||||
return <CreditCards />
|
||||
import styles from "./page.module.css"
|
||||
|
||||
export default async function CreditCardSlot() {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<article className={styles.content}>
|
||||
<Subtitle>{formatMessage({ id: "My credit cards" })}</Subtitle>
|
||||
<Body>
|
||||
{formatMessage({
|
||||
id: "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.",
|
||||
})}
|
||||
</Body>
|
||||
</article>
|
||||
<Link href="#" variant="icon">
|
||||
<PlusCircleIcon color="red" />
|
||||
<Body color="red" textTransform="underlined">
|
||||
{formatMessage({ id: "Add new card" })}
|
||||
</Body>
|
||||
</Link>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
"use client"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
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 { formatMessage } = useIntl()
|
||||
const isPending = useProfileStore((store) => store.pending)
|
||||
const isValid = useProfileStore((store) => store.valid)
|
||||
|
||||
const cancel = formatMessage({ id: "Cancel" })
|
||||
const save = formatMessage({ id: "Save" })
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
aria-label={cancel}
|
||||
asChild
|
||||
form="edit-profile"
|
||||
size="small"
|
||||
type="reset"
|
||||
>
|
||||
<Link href={profile[params.lang]}>{cancel}</Link>
|
||||
</Button>
|
||||
<Button
|
||||
aria-label={save}
|
||||
disabled={!isValid || isPending}
|
||||
form="edit-profile"
|
||||
size="small"
|
||||
type="submit"
|
||||
>
|
||||
{save}
|
||||
</Button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function Page() {
|
||||
return null
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import MembershipCard from "@/components/MyProfile/MembershipCard"
|
||||
|
||||
export default function MembershipCardSlot() {
|
||||
return <MembershipCard />
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import MembershipCard from "@/components/MyProfile/MembershipCard"
|
||||
|
||||
export default function MembershipCardSlot() {
|
||||
return <MembershipCard />
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import Password from "@/components/MyProfile/Password"
|
||||
|
||||
export default function PasswordSlot() {
|
||||
return <Password />
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import Password from "@/components/MyProfile/Password"
|
||||
|
||||
export default function PasswordSlot() {
|
||||
return <Password />
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
.container {
|
||||
background-color: var(--Scandic-Brand-Warm-White);
|
||||
border-radius: var(--Corner-radius-Large);
|
||||
display: grid;
|
||||
gap: var(--Spacing-x3);
|
||||
padding: var(--Spacing-x3);
|
||||
}
|
||||
|
||||
.header {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: var(--Spacing-x2);
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
button.btn {
|
||||
border: 1px solid var(--Base-Border-Subtle);
|
||||
}
|
||||
|
||||
.profile {
|
||||
display: flex;
|
||||
gap: var(--Spacing-x2);
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x-one-and-half) var(--Spacing-x7);
|
||||
grid-template-columns: auto auto;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x1);
|
||||
grid-template-columns: auto auto 1fr;
|
||||
}
|
||||
@@ -1,5 +1,96 @@
|
||||
import Profile from "@/components/MyProfile/Profile"
|
||||
// import { dt } from "@/lib/dt"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
export default function ProfileInfo() {
|
||||
return <Profile />
|
||||
import {
|
||||
EmailIcon,
|
||||
GlobeIcon,
|
||||
LocationIcon,
|
||||
LockIcon,
|
||||
PhoneIcon,
|
||||
} from "@/components/Icons"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
export default async function Profile() {
|
||||
const { formatMessage } = await getIntl()
|
||||
const user = await serverClient().user.get()
|
||||
if (!user) {
|
||||
return null
|
||||
}
|
||||
// const dob = dt(user.dateOfBirth).format("DD/MM/YYYY")
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<header className={styles.header}>
|
||||
<hgroup>
|
||||
<Title as="h4" color="red" level="h1">
|
||||
{user.name}
|
||||
</Title>
|
||||
<Title as="h4" color="burgundy" level="h2">
|
||||
{user.dateOfBirth}
|
||||
</Title>
|
||||
</hgroup>
|
||||
<Button className={styles.btn} size="large" theme="primaryStrong">
|
||||
{formatMessage({ id: "Edit profile" })}
|
||||
</Button>
|
||||
</header>
|
||||
<Divider color="burgundy" opacity={8} />
|
||||
<section className={styles.profile}>
|
||||
<article className={styles.info}>
|
||||
<div className={styles.item}>
|
||||
<LocationIcon color="burgundy" />
|
||||
<Body color="burgundy" textTransform="bold">
|
||||
{formatMessage({ id: "Address" })}
|
||||
</Body>
|
||||
<Body color="burgundy">
|
||||
{user.address.streetAddress
|
||||
? `${user.address.streetAddress}, `
|
||||
: ""}
|
||||
{user.address.city ? `${user.address.city}, ` : ""}
|
||||
{user.address.country ? `${user.address.country}` : ""}
|
||||
{!user.address.streetAddress &&
|
||||
!user.address.city &&
|
||||
!user.address.country
|
||||
? "N/A"
|
||||
: null}
|
||||
</Body>
|
||||
</div>
|
||||
<div className={styles.item}>
|
||||
<EmailIcon color="burgundy" />
|
||||
<Body color="burgundy" textTransform="bold">
|
||||
{formatMessage({ id: "Email" })}
|
||||
</Body>
|
||||
<Body color="burgundy">{user.email}</Body>
|
||||
</div>
|
||||
<div className={styles.item}>
|
||||
<PhoneIcon color="burgundy" />
|
||||
<Body color="burgundy" textTransform="bold">
|
||||
{formatMessage({ id: "Phone number" })}
|
||||
</Body>
|
||||
<Body color="burgundy">{user.phoneNumber}</Body>
|
||||
</div>
|
||||
<div className={styles.item}>
|
||||
<GlobeIcon color="burgundy" />
|
||||
<Body color="burgundy" textTransform="bold">
|
||||
{formatMessage({ id: "Language" })}
|
||||
</Body>
|
||||
<Body color="burgundy">{user.language}</Body>
|
||||
</div>
|
||||
</article>
|
||||
<aside>
|
||||
<div className={styles.item}>
|
||||
<LockIcon color="burgundy" />
|
||||
<Body color="burgundy" textTransform="bold">
|
||||
{formatMessage({ id: "Password" })}
|
||||
</Body>
|
||||
<Body color="burgundy">**********</Body>
|
||||
</div>
|
||||
</aside>
|
||||
</section>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function Default() {
|
||||
return null
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function Default() {
|
||||
return null
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function EditPage() {
|
||||
return null
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { profileEdit } from "@/constants/routes/myPages"
|
||||
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function ProfileView({ params }: PageArgs<LangParams>) {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<Button asChild size="small">
|
||||
<Link href={profileEdit[params.lang]}>
|
||||
{formatMessage({ id: "Edit" })}
|
||||
</Link>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import Wishes from "@/components/MyProfile/Wishes"
|
||||
|
||||
export default function WishesSlot() {
|
||||
return <Wishes />
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import Wishes from "@/components/MyProfile/Wishes"
|
||||
|
||||
export default function WishesSlot() {
|
||||
return <Wishes />
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import "../profileLayout.css"
|
||||
|
||||
export default function EditProfilePage() {
|
||||
return null
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import MaxWidth from "@/components/MaxWidth"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
|
||||
import type { ProfileLayoutProps } from "@/types/components/myPages/myProfile/layout"
|
||||
|
||||
@@ -6,28 +6,17 @@ export default function ProfileLayout({
|
||||
children,
|
||||
communication,
|
||||
creditCards,
|
||||
edit,
|
||||
membershipCard,
|
||||
password,
|
||||
profile,
|
||||
view,
|
||||
wishes,
|
||||
}: React.PropsWithChildren<ProfileLayoutProps>) {
|
||||
return (
|
||||
<MaxWidth className="profile-page" tag="main">
|
||||
<div className="profile-btns">
|
||||
{edit}
|
||||
{view}
|
||||
</div>
|
||||
{profile}
|
||||
<main>
|
||||
{children}
|
||||
<section className="profile-cards">
|
||||
{communication}
|
||||
{wishes}
|
||||
{membershipCard}
|
||||
<section className="profile-layout">
|
||||
{profile}
|
||||
{creditCards}
|
||||
{password}
|
||||
<Divider color="burgundy" opacity={8} />
|
||||
{communication}
|
||||
</section>
|
||||
</MaxWidth>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,26 +2,10 @@
|
||||
* Due to css import issues with parallell routes we are forced to
|
||||
* use a regular css file and import it in the page.tsx
|
||||
*/
|
||||
.profile-page {
|
||||
.profile-layout {
|
||||
background-color: var(--Main-Grey-White);
|
||||
border-radius: var(--Corner-radius-xLarge);
|
||||
display: grid;
|
||||
gap: 3rem;
|
||||
}
|
||||
|
||||
.profile-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%);
|
||||
}
|
||||
|
||||
.profile-cards {
|
||||
display: grid;
|
||||
gap: 0.4rem;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--Spacing-x4);
|
||||
padding: var(--Spacing-x3);
|
||||
}
|
||||
|
||||
17
app/[lang]/(live)/@languageSwitcher/[...paths]/page.tsx
Normal file
17
app/[lang]/(live)/@languageSwitcher/[...paths]/page.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import Desktop from "@/components/Current/Header/LanguageSwitcher/Desktop"
|
||||
import Mobile from "@/components/Current/Header/LanguageSwitcher/Mobile"
|
||||
|
||||
export default async function LanguageSwitcher() {
|
||||
const data = await serverClient().contentstack.languageSwitcher.get()
|
||||
if (!data) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Desktop currentLanguage={data.lang} urls={data.urls} />
|
||||
<Mobile currentLanguage={data.lang} urls={data.urls} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
3
app/[lang]/(live)/@languageSwitcher/default.tsx
Normal file
3
app/[lang]/(live)/@languageSwitcher/default.tsx
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function DefaultLanguageSwitcher() {
|
||||
return null
|
||||
}
|
||||
@@ -72,6 +72,14 @@
|
||||
src: url(/_static/fonts/fira-sans/medium.woff2) format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: "fira sans";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url(/_static/fonts/fira-sans/Medium.woff2) format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: "fira sans";
|
||||
|
||||
@@ -2,7 +2,11 @@ import { iconVariants } from "./variants"
|
||||
|
||||
import type { IconProps } from "@/types/components/icon"
|
||||
|
||||
export default function ArrowRight({ className, color, ...props }: IconProps) {
|
||||
export default function ArrowRightIcon({
|
||||
className,
|
||||
color,
|
||||
...props
|
||||
}: IconProps) {
|
||||
const classNames = iconVariants({ className, color })
|
||||
return (
|
||||
<svg
|
||||
|
||||
40
components/Icons/Cellphone.tsx
Normal file
40
components/Icons/Cellphone.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import { iconVariants } from "./variants"
|
||||
|
||||
import type { IconProps } from "@/types/components/icon"
|
||||
|
||||
export default function CellphoneIcon({
|
||||
className,
|
||||
color,
|
||||
...props
|
||||
}: IconProps) {
|
||||
const classNames = iconVariants({ className, color })
|
||||
return (
|
||||
<svg
|
||||
className={classNames}
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 21 20"
|
||||
width="21"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<mask
|
||||
height="20"
|
||||
id="mask0_58_5381"
|
||||
maskUnits="userSpaceOnUse"
|
||||
style={{ maskType: "alpha" }}
|
||||
width="21"
|
||||
x="0"
|
||||
y="0"
|
||||
>
|
||||
<rect x="0.449219" width="20" height="20" fill="#D9D9D9" />
|
||||
</mask>
|
||||
<g mask="url(#mask0_58_5381)">
|
||||
<path
|
||||
d="M6.20694 18.5831C5.83183 18.5831 5.51476 18.4536 5.25573 18.1946C4.9967 17.9356 4.86719 17.6185 4.86719 17.2434V2.75625C4.86719 2.38114 4.9967 2.06407 5.25573 1.80505C5.51476 1.54602 5.83183 1.4165 6.20694 1.4165H14.6941C15.0692 1.4165 15.3862 1.54602 15.6453 1.80505C15.9043 2.06407 16.0338 2.38114 16.0338 2.75625V17.2434C16.0338 17.6185 15.9043 17.9356 15.6453 18.1946C15.3862 18.4536 15.0692 18.5831 14.6941 18.5831H6.20694ZM5.9505 16.2915V17.2434C5.9505 17.3075 5.97721 17.3663 6.03063 17.4197C6.08406 17.4731 6.14283 17.4998 6.20694 17.4998H14.6941C14.7582 17.4998 14.8169 17.4731 14.8704 17.4197C14.9238 17.3663 14.9505 17.3075 14.9505 17.2434V16.2915H5.9505ZM5.9505 15.2082H14.9505V4.79146H5.9505V15.2082ZM5.9505 3.70817H14.9505V2.75625C14.9505 2.69214 14.9238 2.63337 14.8704 2.57994C14.8169 2.52653 14.7582 2.49982 14.6941 2.49982H6.20694C6.14283 2.49982 6.08406 2.52653 6.03063 2.57994C5.97721 2.63337 5.9505 2.69214 5.9505 2.75625V3.70817Z"
|
||||
fill="#1C1B1F"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
36
components/Icons/Globe.tsx
Normal file
36
components/Icons/Globe.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { iconVariants } from "./variants"
|
||||
|
||||
import type { IconProps } from "@/types/components/icon"
|
||||
|
||||
export default function GlobeIcon({ className, color, ...props }: IconProps) {
|
||||
const classNames = iconVariants({ className, color })
|
||||
return (
|
||||
<svg
|
||||
className={classNames}
|
||||
fill="none"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<mask
|
||||
height="24"
|
||||
id="mask0_4077_9694"
|
||||
maskUnits="userSpaceOnUse"
|
||||
style={{ maskType: "alpha" }}
|
||||
width="24"
|
||||
x="0"
|
||||
y="0"
|
||||
>
|
||||
<rect width="24" height="24" fill="#D9D9D9" />
|
||||
</mask>
|
||||
<g mask="url(#mask0_4077_9694)">
|
||||
<path
|
||||
d="M11.994 21.75C10.6563 21.75 9.39542 21.4945 8.21127 20.9835C7.02714 20.4726 5.99304 19.7751 5.10897 18.891C4.22492 18.007 3.52742 16.9729 3.01645 15.7887C2.50548 14.6046 2.25 13.3437 2.25 12.006C2.25 10.652 2.50548 9.38608 3.01645 8.20825C3.52742 7.0304 4.22492 5.99877 5.10897 5.11337C5.99304 4.22796 7.02714 3.52938 8.21127 3.01763C9.39542 2.50588 10.6563 2.25 11.994 2.25C13.348 2.25 14.6139 2.50594 15.7917 3.01783C16.9696 3.52969 18.0012 4.22843 18.8866 5.11405C19.772 5.99968 20.4706 7.03157 20.9824 8.2097C21.4941 9.38782 21.75 10.6512 21.75 12C21.75 13.3417 21.4941 14.6046 20.9824 15.7887C20.4706 16.9729 19.772 18.007 18.8866 18.891C18.0012 19.7751 16.9696 20.4726 15.7917 20.9835C14.6139 21.4945 13.348 21.75 11.994 21.75ZM12 19.9C12.4435 19.2868 12.8273 18.6481 13.1514 17.9839C13.4755 17.3196 13.7375 16.6167 13.9375 15.875H10.0625C10.2625 16.6167 10.5245 17.3196 10.8486 17.9839C11.1727 18.6481 11.5565 19.2868 12 19.9ZM9.55 19.475C9.23333 18.9 8.95625 18.3146 8.71875 17.7188C8.48125 17.1229 8.28673 16.5083 8.1352 15.875H5.1625C5.64583 16.7333 6.25833 17.4688 7 18.0813C7.74167 18.6938 8.59167 19.1583 9.55 19.475ZM14.45 19.475C15.4083 19.1583 16.2583 18.6938 17 18.0813C17.7417 17.4688 18.3542 16.7333 18.8375 15.875H15.8648C15.7133 16.5083 15.5188 17.1229 15.2812 17.7188C15.0437 18.3146 14.7667 18.9 14.45 19.475ZM4.3875 14H7.75C7.7 13.6583 7.6625 13.325 7.6375 13C7.6125 12.675 7.6 12.3417 7.6 12C7.6 11.6583 7.6125 11.325 7.6375 11C7.6625 10.675 7.7 10.3417 7.75 10H4.3875C4.29583 10.3417 4.22917 10.6737 4.1875 10.996C4.14583 11.3182 4.125 11.6529 4.125 12C4.125 12.3471 4.14583 12.6818 4.1875 13.0041C4.22917 13.3264 4.29583 13.6583 4.3875 14ZM9.6375 14H14.3625C14.4208 13.6583 14.4625 13.3264 14.4875 13.0041C14.5125 12.6818 14.525 12.3471 14.525 12C14.525 11.6529 14.5125 11.3182 14.4875 10.996C14.4625 10.6737 14.4208 10.3417 14.3625 10H9.6375C9.57917 10.3417 9.5375 10.6737 9.5125 10.996C9.4875 11.3182 9.475 11.6529 9.475 12C9.475 12.3471 9.4875 12.6818 9.5125 13.0041C9.5375 13.3264 9.57917 13.6583 9.6375 14ZM16.25 14H19.6125C19.7042 13.6583 19.7708 13.3264 19.8125 13.0041C19.8542 12.6818 19.875 12.3471 19.875 12C19.875 11.6529 19.8542 11.3182 19.8125 10.996C19.7708 10.6737 19.7042 10.3417 19.6125 10H16.25C16.3 10.3417 16.3375 10.675 16.3625 11C16.3875 11.325 16.4 11.6583 16.4 12C16.4 12.3417 16.3875 12.675 16.3625 13C16.3375 13.325 16.3 13.6583 16.25 14ZM15.8648 8.125H18.8375C18.3542 7.26667 17.7417 6.53125 17 5.91875C16.2583 5.30625 15.4083 4.84167 14.45 4.525C14.7667 5.1 15.0437 5.68542 15.2812 6.28125C15.5188 6.87708 15.7133 7.49167 15.8648 8.125ZM10.0625 8.125H13.9375C13.7375 7.38333 13.4755 6.68038 13.1514 6.01613C12.8273 5.35186 12.4435 4.71315 12 4.1C11.5565 4.71315 11.1727 5.35186 10.8486 6.01613C10.5245 6.68038 10.2625 7.38333 10.0625 8.125ZM5.1625 8.125H8.1352C8.28673 7.49167 8.48125 6.87708 8.71875 6.28125C8.95625 5.68542 9.23333 5.1 9.55 4.525C8.59167 4.84167 7.74167 5.30625 7 5.91875C6.25833 6.53125 5.64583 7.26667 5.1625 8.125Z"
|
||||
fill="#4D001B"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
40
components/Icons/Location.tsx
Normal file
40
components/Icons/Location.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import { iconVariants } from "./variants"
|
||||
|
||||
import type { IconProps } from "@/types/components/icon"
|
||||
|
||||
export default function LocationIcon({
|
||||
className,
|
||||
color,
|
||||
...props
|
||||
}: IconProps) {
|
||||
const classNames = iconVariants({ className, color })
|
||||
return (
|
||||
<svg
|
||||
className={classNames}
|
||||
fill="none"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<mask
|
||||
height="24"
|
||||
id="mask0_4077_9668"
|
||||
maskUnits="userSpaceOnUse"
|
||||
style={{ maskType: "alpha" }}
|
||||
width="24"
|
||||
x="0"
|
||||
y="0"
|
||||
>
|
||||
<rect width="24" height="24" fill="#D9D9D9" />
|
||||
</mask>
|
||||
<g mask="url(#mask0_4077_9668)">
|
||||
<path
|
||||
d="M12 19.2752C13.9917 17.4169 15.4688 15.7356 16.4313 14.2314C17.3938 12.7273 17.875 11.396 17.875 10.2377C17.875 8.44603 17.3077 6.98145 16.1732 5.84395C15.0386 4.70645 13.6469 4.1377 11.9982 4.1377C10.3494 4.1377 8.95833 4.70645 7.825 5.84395C6.69167 6.98145 6.125 8.44603 6.125 10.2377C6.125 11.396 6.60625 12.7273 7.56875 14.2314C8.53125 15.7356 10.0083 17.4169 12 19.2752ZM12 21.1002C11.775 21.1002 11.5533 21.0606 11.3349 20.9814C11.1166 20.9023 10.9216 20.7835 10.75 20.6252C9.88333 19.8335 9.05833 19.0064 8.275 18.1439C7.49167 17.2814 6.80208 16.4064 6.20625 15.5189C5.61042 14.6314 5.13542 13.7419 4.78125 12.8502C4.42708 11.9585 4.25 11.0877 4.25 10.2377C4.25 7.8063 5.03125 5.86928 6.59375 4.42665C8.15625 2.98401 9.95833 2.2627 12 2.2627C14.0417 2.2627 15.8438 2.98401 17.4062 4.42665C18.9688 5.86928 19.75 7.8063 19.75 10.2377C19.75 11.0877 19.5729 11.9585 19.2188 12.8502C18.8646 13.7419 18.3896 14.6314 17.7937 15.5189C17.1979 16.4064 16.5083 17.2814 15.725 18.1439C14.9417 19.0064 14.1167 19.8335 13.25 20.6252C13.0784 20.7835 12.8834 20.9023 12.6651 20.9814C12.4467 21.0606 12.225 21.1002 12 21.1002ZM12.0006 11.9377C12.5335 11.9377 12.9896 11.7479 13.3688 11.3684C13.7479 10.9889 13.9375 10.5326 13.9375 9.99965C13.9375 9.46668 13.7477 9.01061 13.3682 8.63145C12.9887 8.25228 12.5324 8.0627 11.9995 8.0627C11.4665 8.0627 11.0104 8.25246 10.6312 8.63199C10.2521 9.01153 10.0625 9.46778 10.0625 10.0007C10.0625 10.5337 10.2523 10.9898 10.6318 11.3689C11.0113 11.7481 11.4676 11.9377 12.0006 11.9377Z"
|
||||
fill="#4D001B"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
36
components/Icons/Lock.tsx
Normal file
36
components/Icons/Lock.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { iconVariants } from "./variants"
|
||||
|
||||
import type { IconProps } from "@/types/components/icon"
|
||||
|
||||
export default function LockIcon({ className, color, ...props }: IconProps) {
|
||||
const classNames = iconVariants({ className, color })
|
||||
return (
|
||||
<svg
|
||||
className={classNames}
|
||||
fill="none"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<mask
|
||||
height="24"
|
||||
id="mask0_4077_9699"
|
||||
maskUnits="userSpaceOnUse"
|
||||
style={{ maskType: "alpha" }}
|
||||
width="24"
|
||||
x="0"
|
||||
y="0"
|
||||
>
|
||||
<rect width="24" height="24" fill="#D9D9D9" />
|
||||
</mask>
|
||||
<g mask="url(#mask0_4077_9699)">
|
||||
<path
|
||||
d="M6.10156 21.75C5.58593 21.75 5.14452 21.5664 4.77734 21.1992C4.41015 20.832 4.22656 20.3906 4.22656 19.875V10.025C4.22656 9.50937 4.41015 9.06796 4.77734 8.70078C5.14452 8.33359 5.58593 8.15 6.10156 8.15H7.17656V6.20522C7.17656 4.86007 7.64531 3.71875 8.58281 2.78125C9.52031 1.84375 10.6599 1.375 12.0016 1.375C13.3432 1.375 14.4828 1.84375 15.4203 2.78125C16.3578 3.71875 16.8266 4.86007 16.8266 6.20522V8.15H17.9016C18.4172 8.15 18.8586 8.33359 19.2258 8.70078C19.593 9.06796 19.7766 9.50937 19.7766 10.025V19.875C19.7766 20.3906 19.593 20.832 19.2258 21.1992C18.8586 21.5664 18.4172 21.75 17.9016 21.75H6.10156ZM6.10156 19.875H17.9016V10.025H6.10156V19.875ZM12.0016 16.875C12.5309 16.875 12.9841 16.6865 13.3611 16.3095C13.7381 15.9326 13.9266 15.4794 13.9266 14.95C13.9266 14.4206 13.7381 13.9674 13.3611 13.5905C12.9841 13.2135 12.5309 13.025 12.0016 13.025C11.4722 13.025 11.019 13.2135 10.642 13.5905C10.2651 13.9674 10.0766 14.4206 10.0766 14.95C10.0766 15.4794 10.2651 15.9326 10.642 16.3095C11.019 16.6865 11.4722 16.875 12.0016 16.875ZM9.05156 8.15H14.9516V6.19615C14.9516 5.38205 14.665 4.6875 14.092 4.1125C13.519 3.5375 12.8231 3.25 12.0045 3.25C11.1859 3.25 10.4891 3.53681 9.91406 4.11042C9.33906 4.68402 9.05156 5.38055 9.05156 6.2V8.15Z"
|
||||
fill="#4D001B"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -8,27 +8,27 @@ export default function PhoneIcon({ className, color, ...props }: IconProps) {
|
||||
<svg
|
||||
className={classNames}
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 21 20"
|
||||
width="21"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<mask
|
||||
height="20"
|
||||
id="mask0_58_5381"
|
||||
height="24"
|
||||
id="mask0_4077_9677"
|
||||
maskUnits="userSpaceOnUse"
|
||||
style={{ maskType: "alpha" }}
|
||||
width="21"
|
||||
width="24"
|
||||
x="0"
|
||||
y="0"
|
||||
>
|
||||
<rect x="0.449219" width="20" height="20" fill="#D9D9D9" />
|
||||
<rect width="24" height="24" fill="#D9D9D9" />
|
||||
</mask>
|
||||
<g mask="url(#mask0_58_5381)">
|
||||
<g mask="url(#mask0_4077_9677)">
|
||||
<path
|
||||
d="M6.20694 18.5831C5.83183 18.5831 5.51476 18.4536 5.25573 18.1946C4.9967 17.9356 4.86719 17.6185 4.86719 17.2434V2.75625C4.86719 2.38114 4.9967 2.06407 5.25573 1.80505C5.51476 1.54602 5.83183 1.4165 6.20694 1.4165H14.6941C15.0692 1.4165 15.3862 1.54602 15.6453 1.80505C15.9043 2.06407 16.0338 2.38114 16.0338 2.75625V17.2434C16.0338 17.6185 15.9043 17.9356 15.6453 18.1946C15.3862 18.4536 15.0692 18.5831 14.6941 18.5831H6.20694ZM5.9505 16.2915V17.2434C5.9505 17.3075 5.97721 17.3663 6.03063 17.4197C6.08406 17.4731 6.14283 17.4998 6.20694 17.4998H14.6941C14.7582 17.4998 14.8169 17.4731 14.8704 17.4197C14.9238 17.3663 14.9505 17.3075 14.9505 17.2434V16.2915H5.9505ZM5.9505 15.2082H14.9505V4.79146H5.9505V15.2082ZM5.9505 3.70817H14.9505V2.75625C14.9505 2.69214 14.9238 2.63337 14.8704 2.57994C14.8169 2.52653 14.7582 2.49982 14.6941 2.49982H6.20694C6.14283 2.49982 6.08406 2.52653 6.03063 2.57994C5.97721 2.63337 5.9505 2.69214 5.9505 2.75625V3.70817Z"
|
||||
fill="#1C1B1F"
|
||||
d="M19.725 20.75C17.725 20.75 15.7375 20.3063 13.7625 19.4188C11.7875 18.5313 9.9875 17.2708 8.3625 15.6375C6.72917 14.0125 5.46875 12.2125 4.58125 10.2375C3.69375 8.2625 3.25 6.2734 3.25 4.2702C3.25 3.98173 3.34762 3.73958 3.54285 3.54375C3.7381 3.34792 3.98215 3.25 4.275 3.25H8.15C8.38333 3.25 8.58542 3.32292 8.75625 3.46875C8.92708 3.61458 9.03333 3.8 9.075 4.025L9.725 7.425C9.75833 7.65 9.74792 7.85208 9.69375 8.03125C9.63958 8.21042 9.55 8.36667 9.425 8.5L7.0625 10.9C7.40417 11.5167 7.79766 12.1082 8.24297 12.6747C8.68829 13.2412 9.17813 13.7871 9.7125 14.3125C10.2125 14.8125 10.7438 15.2833 11.3063 15.725C11.8688 16.1667 12.4667 16.575 13.1 16.95L15.475 14.6C15.6167 14.4583 15.7833 14.3583 15.975 14.3C16.1667 14.2417 16.3667 14.225 16.575 14.25L19.95 14.925C20.1833 14.9833 20.375 15.1013 20.525 15.2788C20.675 15.4564 20.75 15.6552 20.75 15.875V19.725C20.75 20.0179 20.6524 20.2619 20.4572 20.4572C20.2619 20.6524 20.0179 20.75 19.725 20.75ZM6.1625 9.125L7.8125 7.475L7.375 5.125H5.1625C5.22917 5.79167 5.34167 6.4625 5.5 7.1375C5.65833 7.8125 5.87917 8.475 6.1625 9.125ZM14.8625 17.825C15.5042 18.1083 16.1625 18.3333 16.8375 18.5C17.5125 18.6667 18.1917 18.775 18.875 18.825V16.625L16.575 16.1375L14.8625 17.825Z"
|
||||
fill="#4D001B"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
40
components/Icons/PlusCircle.tsx
Normal file
40
components/Icons/PlusCircle.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import { iconVariants } from "./variants"
|
||||
|
||||
import type { IconProps } from "@/types/components/icon"
|
||||
|
||||
export default function PlusCircleIcon({
|
||||
className,
|
||||
color,
|
||||
...props
|
||||
}: IconProps) {
|
||||
const classNames = iconVariants({ className, color })
|
||||
return (
|
||||
<svg
|
||||
className={classNames}
|
||||
fill="none"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<mask
|
||||
height="24"
|
||||
id="mask0_4077_9708"
|
||||
maskUnits="userSpaceOnUse"
|
||||
style={{ maskType: "alpha" }}
|
||||
width="24"
|
||||
x="0"
|
||||
y="0"
|
||||
>
|
||||
<rect width="24" height="24" fill="#D9D9D9" />
|
||||
</mask>
|
||||
<g mask="url(#mask0_4077_9708)">
|
||||
<path
|
||||
d="M11.075 12.95V15.9375C11.075 16.1958 11.1667 16.4167 11.35 16.6C11.5333 16.7833 11.7542 16.875 12.0125 16.875C12.2708 16.875 12.4917 16.7833 12.675 16.6C12.8583 16.4167 12.95 16.1958 12.95 15.9375V12.95H15.9375C16.1958 12.95 16.4167 12.8583 16.6 12.675C16.7833 12.4917 16.875 12.2708 16.875 12.0125C16.875 11.7542 16.7833 11.5333 16.6 11.35C16.4167 11.1667 16.1958 11.075 15.9375 11.075H12.95V8.0625C12.95 7.80417 12.8583 7.58333 12.675 7.4C12.4917 7.21667 12.2708 7.125 12.0125 7.125C11.7542 7.125 11.5333 7.21667 11.35 7.4C11.1667 7.58333 11.075 7.80417 11.075 8.0625V11.075H8.0625C7.80417 11.075 7.58333 11.1667 7.4 11.35C7.21667 11.5333 7.125 11.7542 7.125 12.0125C7.125 12.2708 7.21667 12.4917 7.4 12.675C7.58333 12.8583 7.80417 12.95 8.0625 12.95H11.075ZM12 21.75C10.6516 21.75 9.38434 21.4936 8.19838 20.9809C7.01239 20.4682 5.98075 19.7724 5.10345 18.8934C4.22615 18.0145 3.53125 16.9826 3.01875 15.7978C2.50625 14.613 2.25 13.3471 2.25 12C2.25 10.6516 2.50636 9.38434 3.01908 8.19838C3.53179 7.01239 4.22762 5.98075 5.10658 5.10345C5.98553 4.22615 7.01739 3.53125 8.20218 3.01875C9.38698 2.50625 10.6529 2.25 12 2.25C13.3484 2.25 14.6157 2.50636 15.8016 3.01908C16.9876 3.53179 18.0193 4.22762 18.8966 5.10658C19.7739 5.98553 20.4688 7.01739 20.9813 8.20217C21.4938 9.38697 21.75 10.6529 21.75 12C21.75 13.3484 21.4936 14.6157 20.9809 15.8016C20.4682 16.9876 19.7724 18.0193 18.8934 18.8966C18.0145 19.7739 16.9826 20.4688 15.7978 20.9813C14.613 21.4938 13.3471 21.75 12 21.75ZM12 19.875C14.1917 19.875 16.0521 19.1104 17.5813 17.5813C19.1104 16.0521 19.875 14.1917 19.875 12C19.875 9.80833 19.1104 7.94792 17.5813 6.41875C16.0521 4.88958 14.1917 4.125 12 4.125C9.80833 4.125 7.94792 4.88958 6.41875 6.41875C4.88958 7.94792 4.125 9.80833 4.125 12C4.125 14.1917 4.88958 16.0521 6.41875 17.5813C7.94792 19.1104 9.80833 19.875 12 19.875Z"
|
||||
fill="#CD0921"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -27,3 +27,8 @@
|
||||
.plosa * {
|
||||
fill: var(--Theme-Primary-Light-On-Surface-Accent);
|
||||
}
|
||||
|
||||
.red,
|
||||
.red * {
|
||||
fill: var(--Scandic-Brand-Scandic-Red);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
export { default as AccountCircleIcon } from "./AccountCircle"
|
||||
export { default as ArrowRightIcon } from "./ArrowRight"
|
||||
export { default as CalendarIcon } from "./Calendar"
|
||||
export { default as CellphoneIcon } from "./Cellphone"
|
||||
export { default as CheckIcon } from "./Check"
|
||||
export { default as CheckCircleIcon } from "./CheckCircle"
|
||||
export { default as ChevronDownIcon } from "./ChevronDown"
|
||||
export { default as ChevronRightIcon } from "./ChevronRight"
|
||||
export { default as EmailIcon } from "./Email"
|
||||
export { default as GlobeIcon } from "./Globe"
|
||||
export { default as HouseIcon } from "./House"
|
||||
export { default as LocationIcon } from "./Location"
|
||||
export { default as LockIcon } from "./Lock"
|
||||
export { default as PhoneIcon } from "./Phone"
|
||||
export { default as PlusCircleIcon } from "./PlusCircle"
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x5);
|
||||
padding: var(--Spacing-x4) var(--Spacing-x2) var(--Spacing-x5);
|
||||
}
|
||||
}
|
||||
@@ -56,11 +56,13 @@ export default function ClientPreviousStays({
|
||||
stay={stay}
|
||||
/>
|
||||
))}
|
||||
</Grids.Stackable>
|
||||
{hasNextPage ? (
|
||||
<ShowMoreButton disabled={isFetching} loadMoreData={loadMoreData} />
|
||||
) : null}
|
||||
</ListContainer>
|
||||
</Grids.Stackable >
|
||||
{
|
||||
hasNextPage ? (
|
||||
<ShowMoreButton disabled={isFetching} loadMoreData={loadMoreData} />
|
||||
) : null
|
||||
}
|
||||
</ListContainer >
|
||||
) : (
|
||||
<EmptyPreviousStaysBlock />
|
||||
)
|
||||
|
||||
@@ -36,4 +36,4 @@
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: var(--Spacing-x-half);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
.card {
|
||||
background-color: var(--Scandic-Brand-Warm-White);
|
||||
border-radius: var(--Corner-radius-Small);
|
||||
min-height: 156px;
|
||||
padding: var(--Spacing-x5);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { cva } from "class-variance-authority"
|
||||
|
||||
import styles from "./card.module.css"
|
||||
|
||||
import type { CardProps } from "@/types/components/myPages/myProfile/card/card"
|
||||
|
||||
const cardStyles = cva(styles.card)
|
||||
|
||||
export default function Card({
|
||||
className,
|
||||
tag = "section",
|
||||
...props
|
||||
}: CardProps) {
|
||||
const Cmp = tag
|
||||
return <Cmp className={cardStyles({ className })} {...props} />
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
.container {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import Card from "@/components/MyProfile/Card"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./com.module.css"
|
||||
|
||||
export default async function CommunicationPreferences() {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<Card className={styles.container}>
|
||||
<Title level="h4">
|
||||
{formatMessage({ id: "My communication preferences" })}
|
||||
</Title>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import Card from "@/components/MyProfile/Card"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./membershipCard.module.css"
|
||||
|
||||
export default async function MembershipCard() {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<Card className={styles.container}>
|
||||
<Title level="h4">{formatMessage({ id: "Membership cards" })}</Title>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
.container {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import Card from "@/components/MyProfile/Card"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./password.module.css"
|
||||
|
||||
export default async function Password() {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<Card className={styles.container}>
|
||||
<Title level="h4">{formatMessage({ id: "Password" })}</Title>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
.container {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import { cva } from "class-variance-authority"
|
||||
|
||||
import { AccountCircleIcon } from "@/components/Icons"
|
||||
import Card from "@/components/MyProfile/Card"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
|
||||
import styles from "./profile.module.css"
|
||||
|
||||
import type { ContainerProps } from "@/types/components/myPages/myProfile/container"
|
||||
|
||||
const profileStyles = cva(styles.profile)
|
||||
|
||||
export default function Container({
|
||||
children,
|
||||
className,
|
||||
user,
|
||||
...props
|
||||
}: ContainerProps) {
|
||||
return (
|
||||
<Card className={profileStyles({ className })} {...props}>
|
||||
<header className={styles.header}>
|
||||
<AccountCircleIcon />
|
||||
<Title as="h4" level="h2">
|
||||
{user.name}
|
||||
</Title>
|
||||
</header>
|
||||
{children}
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import Container from "../Container"
|
||||
import Form from "./Form"
|
||||
|
||||
export default async function EditProfile() {
|
||||
@@ -8,9 +7,5 @@ export default async function EditProfile() {
|
||||
if (!user) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<Container user={user}>
|
||||
<Form user={user} />
|
||||
</Container>
|
||||
)
|
||||
return <Form user={user} />
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
// import { dt } from "@/lib/dt"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import {
|
||||
CalendarIcon,
|
||||
EmailIcon,
|
||||
HouseIcon,
|
||||
PhoneIcon,
|
||||
} from "@/components/Icons"
|
||||
|
||||
// import { countries } from "@/components/TempDesignSystem/Form/Country/countries"
|
||||
// import { getIntl } from "@/i18n"
|
||||
import Container from "./Container"
|
||||
|
||||
import styles from "./profile.module.css"
|
||||
|
||||
export default async function Profile() {
|
||||
// const { formatMessage } = await getIntl()
|
||||
const user = await serverClient().user.get()
|
||||
if (!user) {
|
||||
return null
|
||||
}
|
||||
// const countryName = countries.find(
|
||||
// (country) => country.code === user.address.country
|
||||
// )
|
||||
// const dob = dt(user.dateOfBirth).format("DD/MM/YYYY")
|
||||
return (
|
||||
<Container user={user}>
|
||||
<section className={styles.info}>
|
||||
<CalendarIcon />
|
||||
<EmailIcon />
|
||||
<HouseIcon />
|
||||
<PhoneIcon />
|
||||
</section>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
.profile {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x4);
|
||||
grid-template-rows: auto 1fr;
|
||||
min-height: 460px;
|
||||
}
|
||||
|
||||
.header {
|
||||
align-items: center;
|
||||
display: grid;
|
||||
gap: var(--Spacing-x2);
|
||||
grid-template-columns: auto 1fr;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x2);
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import Card from "@/components/MyProfile/Card"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./wishes.module.css"
|
||||
|
||||
export default async function Wishes() {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<Card className={styles.container}>
|
||||
<Title level="h4">{formatMessage({ id: "My wishes" })}</Title>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
.container {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -14,8 +14,8 @@
|
||||
|
||||
.primary,
|
||||
a.primary {
|
||||
color: var(--font-color);
|
||||
background-color: var(--background-color);
|
||||
color: var(--font-color);
|
||||
}
|
||||
|
||||
.primary:hover,
|
||||
@@ -82,6 +82,7 @@ a.default {
|
||||
|
||||
.large {
|
||||
font-size: 16px;
|
||||
height: 50px;
|
||||
gap: var(--Spacing-x-half);
|
||||
padding: var(--Spacing-x2) var(--Spacing-x3);
|
||||
}
|
||||
@@ -108,6 +109,17 @@ a.default {
|
||||
--disabled-color: var(--Theme-Primary-Dark-Button-Primary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.primaryStrong {
|
||||
--background-color: var(--Theme-Primary-Strong-Button-Primary-Fill-Normal);
|
||||
--disabled-background-color: var(
|
||||
--Theme-Primary-Strong-Button-Primary-Fill-Disabled
|
||||
);
|
||||
--disabled-color: var(--Theme-Primary-Strong-Button-Primary-On-Fill-Disabled);
|
||||
--font-color: var(--Theme-Primary-Strong-Button-Primary-On-Fill-Normal);
|
||||
--hover-background: var(--Theme-Primary-Strong-Button-Primary-Fill-Hover);
|
||||
--hover-color: var(--Theme-Primary-Strong-Button-Primary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.secondaryLight {
|
||||
--font-color: var(--Theme-Secondary-Light-Button-Primary-On-Fill-Normal);
|
||||
--background-color: var(--Theme-Secondary-Light-Button-Primary-Fill-Normal);
|
||||
|
||||
@@ -14,8 +14,9 @@ export const buttonVariants = cva(styles.btn, {
|
||||
large: styles.large,
|
||||
},
|
||||
theme: {
|
||||
primaryLight: styles.primaryLight,
|
||||
primaryDark: styles.primaryDark,
|
||||
primaryLight: styles.primaryLight,
|
||||
primaryStrong: styles.primaryStrong,
|
||||
secondaryLight: styles.secondaryLight,
|
||||
secondaryDark: styles.secondaryDark,
|
||||
tertiaryLight: styles.tertiaryLight,
|
||||
|
||||
@@ -60,4 +60,4 @@ p.bodyText {
|
||||
display: flex;
|
||||
gap: var(--Spacing-x1);
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
55
components/TempDesignSystem/CardGrid/cardGrid.module.css
Normal file
55
components/TempDesignSystem/CardGrid/cardGrid.module.css
Normal file
@@ -0,0 +1,55 @@
|
||||
.gridContainer {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.carousel {
|
||||
display: grid;
|
||||
grid-auto-columns: 80dvw;
|
||||
grid-auto-flow: column;
|
||||
gap: var(--Spacing-x2);
|
||||
margin-left: calc(0 - var(--Spacing-x2));
|
||||
margin-right: calc(0 - var(--Spacing-x2));
|
||||
padding-left: var(--Spacing-x2);
|
||||
overflow-x: scroll;
|
||||
scroll-padding-left: var(--Spacing-x2);
|
||||
scroll-snap-type: x mandatory;
|
||||
scrollbar-width: none;
|
||||
/* Hide scrollbar IE and Edge */
|
||||
-ms-overflow-style: none;
|
||||
/* Hide Scrollbar Firefox */
|
||||
}
|
||||
|
||||
.carousel:last-child {
|
||||
margin-right: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.carousel > * {
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
|
||||
/* Hide Scrollbar Chrome, Safari and Opera */
|
||||
.gridContainer::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1367px) {
|
||||
.twoColumnGrid,
|
||||
.twoPlusOne {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.threeColumnGrid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
.twoPlusOne > *:last-child {
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
.carousel {
|
||||
grid-auto-flow: unset;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
@@ -16,3 +16,11 @@
|
||||
.peach {
|
||||
border-bottom-color: var(--Theme-Primary-Light-On-Surface-Divider);
|
||||
}
|
||||
|
||||
.opacity100 {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.opacity8 {
|
||||
opacity: 0.08;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,12 @@ import { dividerVariants } from "./variants"
|
||||
|
||||
import type { DividerProps } from "./divider"
|
||||
|
||||
export default function Divider({ className, color, variant }: DividerProps) {
|
||||
const classNames = dividerVariants({ className, color, variant })
|
||||
export default function Divider({
|
||||
className,
|
||||
color,
|
||||
opacity,
|
||||
variant,
|
||||
}: DividerProps) {
|
||||
const classNames = dividerVariants({ className, color, opacity, variant })
|
||||
return <div className={classNames} />
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ export const dividerVariants = cva(styles.divider, {
|
||||
burgundy: styles.burgundy,
|
||||
peach: styles.peach,
|
||||
},
|
||||
opacity: {
|
||||
100: styles.opacity100,
|
||||
8: styles.opacity8,
|
||||
},
|
||||
variant: {
|
||||
default: styles.default,
|
||||
dotted: styles.dotted,
|
||||
@@ -15,6 +19,7 @@ export const dividerVariants = cva(styles.divider, {
|
||||
},
|
||||
defaultVariants: {
|
||||
color: "burgundy",
|
||||
opacity: 100,
|
||||
variant: "default",
|
||||
},
|
||||
})
|
||||
|
||||
@@ -41,11 +41,10 @@
|
||||
border: var(--select-border);
|
||||
border-radius: var(--Corner-radius-Small);
|
||||
overflow: auto;
|
||||
padding: var(--Spacing-x2) var(--Spacing-x2) var(--Spacing-x2)
|
||||
var(--Spacing-x1);
|
||||
padding: var(--Spacing-x2) var(--Spacing-x2) var(--Spacing-x2) var(--Spacing-x1);
|
||||
width: var(--select-width);
|
||||
}
|
||||
|
||||
.listBoxItem {
|
||||
padding: 0 var(--Spacing-x1);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
.message {
|
||||
color: var(--Scandic-Red-60);
|
||||
margin: var(--Spacing-x-half) 0 0;
|
||||
}
|
||||
}
|
||||
@@ -5,4 +5,4 @@
|
||||
height: 40px;
|
||||
padding: var(--Spacing-x1) var(--Spacing-x2);
|
||||
width: min(280px, 100%);
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,12 @@ import "react-international-phone/style.css"
|
||||
|
||||
import { useCallback, useEffect, useRef } from "react"
|
||||
import { useController, useFormContext, useWatch } from "react-hook-form"
|
||||
import { defaultCountries, getCountry } from "react-international-phone"
|
||||
import { PhoneInput, type PhoneInputRefType } from "react-international-phone"
|
||||
import {
|
||||
defaultCountries,
|
||||
getCountry,
|
||||
PhoneInput,
|
||||
type PhoneInputRefType,
|
||||
} from "react-international-phone"
|
||||
|
||||
import ErrorMessage from "@/components/TempDesignSystem/Form/ErrorMessage"
|
||||
|
||||
|
||||
@@ -14,6 +14,12 @@
|
||||
line-height: var(--typography-Footnote-Bold-lineHeight);
|
||||
}
|
||||
|
||||
.icon {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.myPage {
|
||||
font-family: var(--typography-Body-Underlined-fontFamily);
|
||||
font-size: var(--typography-Body-Underlined-fontSize);
|
||||
|
||||
@@ -20,6 +20,7 @@ export const linkVariants = cva(styles.link, {
|
||||
variant: {
|
||||
breadcrumb: styles.breadcrumb,
|
||||
default: styles.default,
|
||||
icon: styles.icon,
|
||||
myPage: styles.myPage,
|
||||
shortcut: styles.shortcut,
|
||||
sidebar: styles.sidebar,
|
||||
|
||||
@@ -5,22 +5,18 @@
|
||||
}
|
||||
|
||||
.one {
|
||||
font-size: clamp(
|
||||
var(--typography-Script-1-Mobile-fontSize),
|
||||
1.3vw + 14px,
|
||||
var(--typography-Script-1-Desktop-fontSize)
|
||||
);
|
||||
font-size: clamp(var(--typography-Script-1-Mobile-fontSize),
|
||||
1.3vw + 14px,
|
||||
var(--typography-Script-1-Desktop-fontSize));
|
||||
font-weight: var(--typography-Script-1-fontWeight);
|
||||
letter-spacing: var(--typography-Script-1-letterSpacing);
|
||||
line-height: var(--typography-Script-1-lineHeight);
|
||||
}
|
||||
|
||||
.two {
|
||||
font-size: clamp(
|
||||
var(--typography-Script-2-Mobile-fontSize),
|
||||
0.6vw + 15px,
|
||||
var(--typography-Script-2-Desktop-fontSize)
|
||||
);
|
||||
font-size: clamp(var(--typography-Script-2-Mobile-fontSize),
|
||||
0.6vw + 15px,
|
||||
var(--typography-Script-2-Desktop-fontSize));
|
||||
font-weight: var(--typography-Script-2-fontWeight);
|
||||
letter-spacing: var(--typography-Script-2-letterSpacing);
|
||||
line-height: var(--typography-Script-2-lineHeight);
|
||||
@@ -48,4 +44,4 @@
|
||||
|
||||
.plosa {
|
||||
color: var(--Theme-Primary-Light-On-Surface-Accent);
|
||||
}
|
||||
}
|
||||
@@ -54,3 +54,7 @@
|
||||
.pale {
|
||||
color: var(--Scandic-Brand-Pale-Peach);
|
||||
}
|
||||
|
||||
.red {
|
||||
color: var(--Scandic-Brand-Scandic-Red);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import type { VariantProps } from "class-variance-authority"
|
||||
|
||||
export interface BodyProps
|
||||
extends Omit<React.HTMLAttributes<HTMLHeadingElement>, "color">,
|
||||
VariantProps<typeof bodyVariants> {
|
||||
VariantProps<typeof bodyVariants> {
|
||||
asChild?: boolean
|
||||
fontOnly?: boolean
|
||||
}
|
||||
|
||||
@@ -16,15 +16,15 @@ export default function Body({
|
||||
const Comp = asChild ? Slot : "p"
|
||||
const classNames = fontOnly
|
||||
? bodyFontOnlyVariants({
|
||||
className,
|
||||
textAlign,
|
||||
textTransform,
|
||||
})
|
||||
className,
|
||||
textAlign,
|
||||
textTransform,
|
||||
})
|
||||
: bodyVariants({
|
||||
className,
|
||||
color,
|
||||
textAlign,
|
||||
textTransform,
|
||||
})
|
||||
className,
|
||||
color,
|
||||
textAlign,
|
||||
textTransform,
|
||||
})
|
||||
return <Comp className={classNames} {...props} />
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ const config = {
|
||||
black: styles.black,
|
||||
burgundy: styles.burgundy,
|
||||
pale: styles.pale,
|
||||
red: styles.red,
|
||||
},
|
||||
textAlign: {
|
||||
center: styles.textAlignCenter,
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { VariantProps } from "class-variance-authority"
|
||||
|
||||
export interface CaptionProps
|
||||
extends Omit<React.HTMLAttributes<HTMLHeadingElement>, "color">,
|
||||
VariantProps<typeof captionVariants> {
|
||||
VariantProps<typeof captionVariants> {
|
||||
asChild?: boolean
|
||||
fontOnly?: boolean
|
||||
}
|
||||
|
||||
@@ -15,13 +15,13 @@ export default function Caption({
|
||||
const Comp = asChild ? Slot : "p"
|
||||
const classNames = fontOnly
|
||||
? fontOnlycaptionVariants({
|
||||
className,
|
||||
textTransform,
|
||||
})
|
||||
className,
|
||||
textTransform,
|
||||
})
|
||||
: captionVariants({
|
||||
className,
|
||||
color,
|
||||
textTransform,
|
||||
})
|
||||
className,
|
||||
color,
|
||||
textTransform,
|
||||
})
|
||||
return <Comp className={classNames} {...props} />
|
||||
}
|
||||
|
||||
@@ -44,4 +44,4 @@
|
||||
|
||||
.pale {
|
||||
color: var(--Scandic-Brand-Pale-Peach);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import type { VariantProps } from "class-variance-authority"
|
||||
|
||||
export interface FootnoteProps
|
||||
extends Omit<React.HTMLAttributes<HTMLParagraphElement>, "color">,
|
||||
VariantProps<typeof footnoteVariants> {
|
||||
VariantProps<typeof footnoteVariants> {
|
||||
asChild?: boolean
|
||||
fontOnly?: boolean
|
||||
}
|
||||
|
||||
@@ -16,15 +16,15 @@ export default function Footnote({
|
||||
const Comp = asChild ? Slot : "p"
|
||||
const classNames = fontOnly
|
||||
? footnoteFontOnlyVariants({
|
||||
className,
|
||||
textAlign,
|
||||
textTransform,
|
||||
})
|
||||
className,
|
||||
textAlign,
|
||||
textTransform,
|
||||
})
|
||||
: footnoteVariants({
|
||||
className,
|
||||
color,
|
||||
textAlign,
|
||||
textTransform,
|
||||
})
|
||||
className,
|
||||
color,
|
||||
textAlign,
|
||||
textTransform,
|
||||
})
|
||||
return <Comp className={classNames} {...props} />
|
||||
}
|
||||
|
||||
@@ -84,6 +84,10 @@
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.black {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.burgundy {
|
||||
color: var(--Scandic-Brand-Burgundy);
|
||||
}
|
||||
@@ -91,3 +95,7 @@
|
||||
.pale {
|
||||
color: var(--Scandic-Brand-Pale-Peach);
|
||||
}
|
||||
|
||||
.red {
|
||||
color: var(--Scandic-Brand-Scandic-Red);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ import styles from "./title.module.css"
|
||||
const config = {
|
||||
variants: {
|
||||
color: {
|
||||
black: styles.black,
|
||||
burgundy: styles.burgundy,
|
||||
pale: styles.pale,
|
||||
red: styles.red,
|
||||
},
|
||||
textAlign: {
|
||||
center: styles.center,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"Add new card": "Tilføj nyt kort",
|
||||
"Address": "Adresse",
|
||||
"Already a friend?": "Allerede en ven?",
|
||||
"Arrival date": "Ankomstdato",
|
||||
@@ -22,14 +23,17 @@
|
||||
"Day": "Dag",
|
||||
"Description": "Beskrivelse",
|
||||
"Edit": "Redigere",
|
||||
"Edit profile": "Rediger profil",
|
||||
"Email": "E-mail",
|
||||
"Empty": "Empty",
|
||||
"Explore all levels and benefits": "Udforsk alle niveauer og fordele",
|
||||
"Find booking": "Find booking",
|
||||
"Free soft drink voucher for the kids when staying": "Gratis sodavandskupon til børnene, når de bor",
|
||||
"Get inspired": "Blive inspireret",
|
||||
"Go back to overview": "Gå tilbage til oversigten",
|
||||
"How it works": "Hvordan det virker",
|
||||
"Join Scandic Friends": "Tilmeld dig Scandic Friends",
|
||||
"Language": "Sprog",
|
||||
"Level": "Niveau",
|
||||
"Level up to unlock": "Niveau op for at låse op",
|
||||
"Log in": "Log på",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"Add new card": "Neue Karte hinzufügen",
|
||||
"Address": "Adresse",
|
||||
"Already a friend?": "Schon ein Freund?",
|
||||
"Arrival date": "Ankunftsdatum",
|
||||
@@ -22,14 +23,17 @@
|
||||
"Day": "Tag",
|
||||
"Description": "Beschreibung",
|
||||
"Edit": "Bearbeiten",
|
||||
"Edit profile": "Profil bearbeiten",
|
||||
"Email": "Email",
|
||||
"Empty": "Empty",
|
||||
"Explore all levels and benefits": "Entdecken Sie alle Levels und Vorteile",
|
||||
"Find booking": "Buchung finden",
|
||||
"Free soft drink voucher for the kids when staying": "Gutschein für einen kostenlosen Softdrink für die Kinder bei Aufenthalt",
|
||||
"Get inspired": "Lass dich inspirieren",
|
||||
"Go back to overview": "Zurück zur Übersicht",
|
||||
"How it works": "Wie es funktioniert",
|
||||
"Join Scandic Friends": "Treten Sie Scandic Friends bei",
|
||||
"Language": "Sprache",
|
||||
"Level": "Ebene",
|
||||
"Level up to unlock": "Zum Freischalten aufsteigen",
|
||||
"Log in": "Anmeldung",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"Add new card": "Add new card",
|
||||
"Address": "Address",
|
||||
"Already a friend?": "Already a friend?",
|
||||
"Arrival date": "Arrival date",
|
||||
@@ -22,6 +23,7 @@
|
||||
"Day": "Day",
|
||||
"Description": "Description",
|
||||
"Edit": "Edit",
|
||||
"Edit profile": "Edit profile",
|
||||
"Email": "Email",
|
||||
"Empty": "Empty",
|
||||
"Explore all levels and benefits": "Explore all levels and benefits",
|
||||
@@ -31,6 +33,7 @@
|
||||
"Go back to overview": "Go back to overview",
|
||||
"How it works": "How it works",
|
||||
"Join Scandic Friends": "Join Scandic Friends",
|
||||
"Language": "Language",
|
||||
"Level": "Level",
|
||||
"Level up to unlock": "Level up to unlock",
|
||||
"Log in": "Log in",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"Add new card": "Lisää uusi kortti",
|
||||
"Address": "Osoite",
|
||||
"Already a friend?": "Oletko jo ystävä?",
|
||||
"Arrival date": "Saapumispäivä",
|
||||
@@ -22,14 +23,17 @@
|
||||
"Day": "Päivä",
|
||||
"Description": "Kuvaus",
|
||||
"Edit": "Muokata",
|
||||
"Edit profile": "Muokkaa profiilia",
|
||||
"Email": "Sähköposti",
|
||||
"Empty": "Empty",
|
||||
"Explore all levels and benefits": "Tutustu kaikkiin tasoihin ja etuihin",
|
||||
"Find booking": "Etsi varaus",
|
||||
"Free soft drink voucher for the kids when staying": "Ilmainen virvoitusjuomakuponki lapsille majoittuessaan",
|
||||
"Get inspired": "Inspiroidu",
|
||||
"Go back to overview": "Palaa yleiskatsaukseen",
|
||||
"How it works": "Kuinka se toimii",
|
||||
"Join Scandic Friends": "Liity Scandic Friends",
|
||||
"Language": "Kieli",
|
||||
"Level": "Taso",
|
||||
"Level up to unlock": "Nosta taso avataksesi lukituksen",
|
||||
"Log in": "Kirjaudu sisään",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"Add new card": "Legg til nytt kort",
|
||||
"Address": "Adresse",
|
||||
"Already a friend?": "Allerede en venn?",
|
||||
"Arrival date": "Ankomstdato",
|
||||
@@ -22,14 +23,17 @@
|
||||
"Day": "Dag",
|
||||
"Description": "Beskrivelse",
|
||||
"Edit": "Redigere",
|
||||
"Edit profile": "Rediger profil",
|
||||
"Email": "E-post",
|
||||
"Empty": "Empty",
|
||||
"Explore all levels and benefits": "Utforsk alle nivåer og fordeler",
|
||||
"Find booking": "Finn booking",
|
||||
"Free soft drink voucher for the kids when staying": "Gratis bruskupong for barna når de bor",
|
||||
"Get inspired": "Bli inspirert",
|
||||
"Go back to overview": "Gå tilbake til oversikten",
|
||||
"How it works": "Hvordan det fungerer",
|
||||
"Join Scandic Friends": "Bli med i Scandic Friends",
|
||||
"Language": "Språk",
|
||||
"Level": "Nivå",
|
||||
"Level up to unlock": "Nivå opp for å låse opp",
|
||||
"Log in": "Logg Inn",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"Add new card": "Lägg till nytt kort",
|
||||
"Address": "Adress",
|
||||
"Already a friend?": "Redan en vän?",
|
||||
"Arrival date": "Ankomstdatum",
|
||||
@@ -22,14 +23,17 @@
|
||||
"Day": "Dag",
|
||||
"Description": "Beskrivning",
|
||||
"Edit": "Redigera",
|
||||
"Edit profile": "Redigera profil",
|
||||
"Email": "E-post",
|
||||
"Empty": "Tom",
|
||||
"Explore all levels and benefits": "Utforska alla nivåer och fördelar",
|
||||
"Find booking": "Hitta bokning",
|
||||
"Free soft drink voucher for the kids when staying": "Gratis läskkupong för barnen när de bor",
|
||||
"Get inspired": "Bli inspirerad",
|
||||
"Go back to overview": "Gå tillbaka till översikten",
|
||||
"How it works": "Hur det fungerar",
|
||||
"Join Scandic Friends": "Gå med i Scandic Friends",
|
||||
"Language": "Språk",
|
||||
"Level": "Nivå",
|
||||
"Level up to unlock": "Nivå upp för att låsa upp",
|
||||
"Log in": "Logga in",
|
||||
|
||||
8
public/_static/icons/globe.svg
Normal file
8
public/_static/icons/globe.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_4077_9694" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
|
||||
<rect width="24" height="24" fill="#D9D9D9"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_4077_9694)">
|
||||
<path d="M11.994 21.75C10.6563 21.75 9.39542 21.4945 8.21127 20.9835C7.02714 20.4726 5.99304 19.7751 5.10897 18.891C4.22492 18.007 3.52742 16.9729 3.01645 15.7887C2.50548 14.6046 2.25 13.3437 2.25 12.006C2.25 10.652 2.50548 9.38608 3.01645 8.20825C3.52742 7.0304 4.22492 5.99877 5.10897 5.11337C5.99304 4.22796 7.02714 3.52938 8.21127 3.01763C9.39542 2.50588 10.6563 2.25 11.994 2.25C13.348 2.25 14.6139 2.50594 15.7917 3.01783C16.9696 3.52969 18.0012 4.22843 18.8866 5.11405C19.772 5.99968 20.4706 7.03157 20.9824 8.2097C21.4941 9.38782 21.75 10.6512 21.75 12C21.75 13.3417 21.4941 14.6046 20.9824 15.7887C20.4706 16.9729 19.772 18.007 18.8866 18.891C18.0012 19.7751 16.9696 20.4726 15.7917 20.9835C14.6139 21.4945 13.348 21.75 11.994 21.75ZM12 19.9C12.4435 19.2868 12.8273 18.6481 13.1514 17.9839C13.4755 17.3196 13.7375 16.6167 13.9375 15.875H10.0625C10.2625 16.6167 10.5245 17.3196 10.8486 17.9839C11.1727 18.6481 11.5565 19.2868 12 19.9ZM9.55 19.475C9.23333 18.9 8.95625 18.3146 8.71875 17.7188C8.48125 17.1229 8.28673 16.5083 8.1352 15.875H5.1625C5.64583 16.7333 6.25833 17.4688 7 18.0813C7.74167 18.6938 8.59167 19.1583 9.55 19.475ZM14.45 19.475C15.4083 19.1583 16.2583 18.6938 17 18.0813C17.7417 17.4688 18.3542 16.7333 18.8375 15.875H15.8648C15.7133 16.5083 15.5188 17.1229 15.2812 17.7188C15.0437 18.3146 14.7667 18.9 14.45 19.475ZM4.3875 14H7.75C7.7 13.6583 7.6625 13.325 7.6375 13C7.6125 12.675 7.6 12.3417 7.6 12C7.6 11.6583 7.6125 11.325 7.6375 11C7.6625 10.675 7.7 10.3417 7.75 10H4.3875C4.29583 10.3417 4.22917 10.6737 4.1875 10.996C4.14583 11.3182 4.125 11.6529 4.125 12C4.125 12.3471 4.14583 12.6818 4.1875 13.0041C4.22917 13.3264 4.29583 13.6583 4.3875 14ZM9.6375 14H14.3625C14.4208 13.6583 14.4625 13.3264 14.4875 13.0041C14.5125 12.6818 14.525 12.3471 14.525 12C14.525 11.6529 14.5125 11.3182 14.4875 10.996C14.4625 10.6737 14.4208 10.3417 14.3625 10H9.6375C9.57917 10.3417 9.5375 10.6737 9.5125 10.996C9.4875 11.3182 9.475 11.6529 9.475 12C9.475 12.3471 9.4875 12.6818 9.5125 13.0041C9.5375 13.3264 9.57917 13.6583 9.6375 14ZM16.25 14H19.6125C19.7042 13.6583 19.7708 13.3264 19.8125 13.0041C19.8542 12.6818 19.875 12.3471 19.875 12C19.875 11.6529 19.8542 11.3182 19.8125 10.996C19.7708 10.6737 19.7042 10.3417 19.6125 10H16.25C16.3 10.3417 16.3375 10.675 16.3625 11C16.3875 11.325 16.4 11.6583 16.4 12C16.4 12.3417 16.3875 12.675 16.3625 13C16.3375 13.325 16.3 13.6583 16.25 14ZM15.8648 8.125H18.8375C18.3542 7.26667 17.7417 6.53125 17 5.91875C16.2583 5.30625 15.4083 4.84167 14.45 4.525C14.7667 5.1 15.0437 5.68542 15.2812 6.28125C15.5188 6.87708 15.7133 7.49167 15.8648 8.125ZM10.0625 8.125H13.9375C13.7375 7.38333 13.4755 6.68038 13.1514 6.01613C12.8273 5.35186 12.4435 4.71315 12 4.1C11.5565 4.71315 11.1727 5.35186 10.8486 6.01613C10.5245 6.68038 10.2625 7.38333 10.0625 8.125ZM5.1625 8.125H8.1352C8.28673 7.49167 8.48125 6.87708 8.71875 6.28125C8.95625 5.68542 9.23333 5.1 9.55 4.525C8.59167 4.84167 7.74167 5.30625 7 5.91875C6.25833 6.53125 5.64583 7.26667 5.1625 8.125Z" fill="#4D001B"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
8
public/_static/icons/location.svg
Normal file
8
public/_static/icons/location.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_4077_9668" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
|
||||
<rect width="24" height="24" fill="#D9D9D9"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_4077_9668)">
|
||||
<path d="M12 19.2752C13.9917 17.4169 15.4688 15.7356 16.4313 14.2314C17.3938 12.7273 17.875 11.396 17.875 10.2377C17.875 8.44603 17.3077 6.98145 16.1732 5.84395C15.0386 4.70645 13.6469 4.1377 11.9982 4.1377C10.3494 4.1377 8.95833 4.70645 7.825 5.84395C6.69167 6.98145 6.125 8.44603 6.125 10.2377C6.125 11.396 6.60625 12.7273 7.56875 14.2314C8.53125 15.7356 10.0083 17.4169 12 19.2752ZM12 21.1002C11.775 21.1002 11.5533 21.0606 11.3349 20.9814C11.1166 20.9023 10.9216 20.7835 10.75 20.6252C9.88333 19.8335 9.05833 19.0064 8.275 18.1439C7.49167 17.2814 6.80208 16.4064 6.20625 15.5189C5.61042 14.6314 5.13542 13.7419 4.78125 12.8502C4.42708 11.9585 4.25 11.0877 4.25 10.2377C4.25 7.8063 5.03125 5.86928 6.59375 4.42665C8.15625 2.98401 9.95833 2.2627 12 2.2627C14.0417 2.2627 15.8438 2.98401 17.4062 4.42665C18.9688 5.86928 19.75 7.8063 19.75 10.2377C19.75 11.0877 19.5729 11.9585 19.2188 12.8502C18.8646 13.7419 18.3896 14.6314 17.7937 15.5189C17.1979 16.4064 16.5083 17.2814 15.725 18.1439C14.9417 19.0064 14.1167 19.8335 13.25 20.6252C13.0784 20.7835 12.8834 20.9023 12.6651 20.9814C12.4467 21.0606 12.225 21.1002 12 21.1002ZM12.0006 11.9377C12.5335 11.9377 12.9896 11.7479 13.3688 11.3684C13.7479 10.9889 13.9375 10.5326 13.9375 9.99965C13.9375 9.46668 13.7477 9.01061 13.3682 8.63145C12.9887 8.25228 12.5324 8.0627 11.9995 8.0627C11.4665 8.0627 11.0104 8.25246 10.6312 8.63199C10.2521 9.01153 10.0625 9.46778 10.0625 10.0007C10.0625 10.5337 10.2523 10.9898 10.6318 11.3689C11.0113 11.7481 11.4676 11.9377 12.0006 11.9377Z" fill="#4D001B"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -1,8 +1,8 @@
|
||||
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_58_5381" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="21" height="20">
|
||||
<rect x="0.449219" width="20" height="20" fill="#D9D9D9"/>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_4077_9677" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
|
||||
<rect width="24" height="24" fill="#D9D9D9"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_58_5381)">
|
||||
<path d="M6.20694 18.5831C5.83183 18.5831 5.51476 18.4536 5.25573 18.1946C4.9967 17.9356 4.86719 17.6185 4.86719 17.2434V2.75625C4.86719 2.38114 4.9967 2.06407 5.25573 1.80505C5.51476 1.54602 5.83183 1.4165 6.20694 1.4165H14.6941C15.0692 1.4165 15.3862 1.54602 15.6453 1.80505C15.9043 2.06407 16.0338 2.38114 16.0338 2.75625V17.2434C16.0338 17.6185 15.9043 17.9356 15.6453 18.1946C15.3862 18.4536 15.0692 18.5831 14.6941 18.5831H6.20694ZM5.9505 16.2915V17.2434C5.9505 17.3075 5.97721 17.3663 6.03063 17.4197C6.08406 17.4731 6.14283 17.4998 6.20694 17.4998H14.6941C14.7582 17.4998 14.8169 17.4731 14.8704 17.4197C14.9238 17.3663 14.9505 17.3075 14.9505 17.2434V16.2915H5.9505ZM5.9505 15.2082H14.9505V4.79146H5.9505V15.2082ZM5.9505 3.70817H14.9505V2.75625C14.9505 2.69214 14.9238 2.63337 14.8704 2.57994C14.8169 2.52653 14.7582 2.49982 14.6941 2.49982H6.20694C6.14283 2.49982 6.08406 2.52653 6.03063 2.57994C5.97721 2.63337 5.9505 2.69214 5.9505 2.75625V3.70817Z" fill="#1C1B1F"/>
|
||||
<g mask="url(#mask0_4077_9677)">
|
||||
<path d="M19.725 20.75C17.725 20.75 15.7375 20.3063 13.7625 19.4188C11.7875 18.5313 9.9875 17.2708 8.3625 15.6375C6.72917 14.0125 5.46875 12.2125 4.58125 10.2375C3.69375 8.2625 3.25 6.2734 3.25 4.2702C3.25 3.98173 3.34762 3.73958 3.54285 3.54375C3.7381 3.34792 3.98215 3.25 4.275 3.25H8.15C8.38333 3.25 8.58542 3.32292 8.75625 3.46875C8.92708 3.61458 9.03333 3.8 9.075 4.025L9.725 7.425C9.75833 7.65 9.74792 7.85208 9.69375 8.03125C9.63958 8.21042 9.55 8.36667 9.425 8.5L7.0625 10.9C7.40417 11.5167 7.79766 12.1082 8.24297 12.6747C8.68829 13.2412 9.17813 13.7871 9.7125 14.3125C10.2125 14.8125 10.7438 15.2833 11.3063 15.725C11.8688 16.1667 12.4667 16.575 13.1 16.95L15.475 14.6C15.6167 14.4583 15.7833 14.3583 15.975 14.3C16.1667 14.2417 16.3667 14.225 16.575 14.25L19.95 14.925C20.1833 14.9833 20.375 15.1013 20.525 15.2788C20.675 15.4564 20.75 15.6552 20.75 15.875V19.725C20.75 20.0179 20.6524 20.2619 20.4572 20.4572C20.2619 20.6524 20.0179 20.75 19.725 20.75ZM6.1625 9.125L7.8125 7.475L7.375 5.125H5.1625C5.22917 5.79167 5.34167 6.4625 5.5 7.1375C5.65833 7.8125 5.87917 8.475 6.1625 9.125ZM14.8625 17.825C15.5042 18.1083 16.1625 18.3333 16.8375 18.5C17.5125 18.6667 18.1917 18.775 18.875 18.825V16.625L16.575 16.1375L14.8625 17.825Z" fill="#4D001B"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -1,5 +1,11 @@
|
||||
import { z } from "zod"
|
||||
|
||||
export const getUserInputSchema = z
|
||||
.object({
|
||||
mask: z.boolean().default(true),
|
||||
})
|
||||
.default({})
|
||||
|
||||
export const staysInput = z
|
||||
.object({
|
||||
cursor: z.number().optional(),
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
import { parsePhoneNumber } from "libphonenumber-js"
|
||||
|
||||
import * as api from "@/lib/api"
|
||||
import { protectedProcedure, router } from "@/server/trpc"
|
||||
|
||||
import { friendTransactionsInput, staysInput } from "./input"
|
||||
import { countries } from "@/components/TempDesignSystem/Form/Country/countries"
|
||||
import * as maskValue from "@/utils/maskValue"
|
||||
|
||||
import {
|
||||
friendTransactionsInput,
|
||||
getUserInputSchema,
|
||||
staysInput,
|
||||
} from "./input"
|
||||
import {
|
||||
getCreditCardsSchema,
|
||||
getFriendTransactionsSchema,
|
||||
@@ -19,53 +28,95 @@ function fakingRequest<T>(payload: T): Promise<T> {
|
||||
}
|
||||
|
||||
export const userQueryRouter = router({
|
||||
get: protectedProcedure.query(async function ({ ctx }) {
|
||||
const apiResponse = await api.get(api.endpoints.v1.profile, {
|
||||
cache: "no-store",
|
||||
headers: {
|
||||
Authorization: `Bearer ${ctx.session.token.access_token}`,
|
||||
},
|
||||
})
|
||||
get: protectedProcedure
|
||||
.input(getUserInputSchema)
|
||||
.query(async function getUser({ ctx, input }) {
|
||||
const apiResponse = await api.get(api.endpoints.v1.profile, {
|
||||
cache: "no-store",
|
||||
headers: {
|
||||
Authorization: `Bearer ${ctx.session.token.access_token}`,
|
||||
},
|
||||
})
|
||||
|
||||
if (!apiResponse.ok) {
|
||||
// switch (apiResponse.status) {
|
||||
// case 400:
|
||||
// throw badRequestError(apiResponse)
|
||||
// case 401:
|
||||
// throw unauthorizedError(apiResponse)
|
||||
// case 403:
|
||||
// throw forbiddenError(apiResponse)
|
||||
// default:
|
||||
// throw internalServerError(apiResponse)
|
||||
// }
|
||||
console.info(`API Response Failed - Getting User`)
|
||||
console.info(`User: (${JSON.stringify(ctx.session.user)})`)
|
||||
console.error(apiResponse)
|
||||
return null
|
||||
}
|
||||
if (!apiResponse.ok) {
|
||||
// switch (apiResponse.status) {
|
||||
// case 400:
|
||||
// throw badRequestError()
|
||||
// case 401:
|
||||
// throw unauthorizedError()
|
||||
// case 403:
|
||||
// throw forbiddenError()
|
||||
// default:
|
||||
// throw internalServerError()
|
||||
// }
|
||||
console.info(`API Response Failed - Getting User`)
|
||||
console.info(`User: (${JSON.stringify(ctx.session.user)})`)
|
||||
console.error(apiResponse)
|
||||
return null
|
||||
}
|
||||
|
||||
const apiJson = await apiResponse.json()
|
||||
if (!apiJson.data?.attributes) {
|
||||
// throw notFound(apiJson)
|
||||
console.error(
|
||||
`User has no data - (user: ${JSON.stringify(ctx.session.user)})`
|
||||
const apiJson = await apiResponse.json()
|
||||
console.log({ apiJson })
|
||||
console.log({ attr: apiJson.data.attributes })
|
||||
if (!apiJson.data?.attributes) {
|
||||
// throw notFound(apiJson)
|
||||
console.error(
|
||||
`User has no data - (user: ${JSON.stringify(ctx.session.user)})`
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
const verifiedData = getUserSchema.safeParse(apiJson.data.attributes)
|
||||
if (!verifiedData.success) {
|
||||
console.info(
|
||||
`Failed to validate User - (User: ${JSON.stringify(ctx.session.user)})`
|
||||
)
|
||||
console.error(verifiedData.error)
|
||||
return null
|
||||
}
|
||||
|
||||
const country = countries.find(
|
||||
(c) => c.code === verifiedData.data.address.countryCode
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
const verifiedData = getUserSchema.safeParse(apiJson.data.attributes)
|
||||
if (!verifiedData.success) {
|
||||
console.info(`Failed to validate User - (name: ${ctx.session.user?.name}`)
|
||||
console.error(verifiedData.error)
|
||||
return null
|
||||
}
|
||||
const user = {
|
||||
...extendedUser,
|
||||
address: {
|
||||
city: verifiedData.data.address.city,
|
||||
country: country?.name ?? verifiedData.data.address.countryCode,
|
||||
streetAddress: verifiedData.data.address.streetAddress,
|
||||
zipCode: verifiedData.data.address.zipCode,
|
||||
},
|
||||
dateOfBirth: verifiedData.data.dateOfBirth,
|
||||
email: verifiedData.data.email,
|
||||
firstName: verifiedData.data.firstName,
|
||||
language: verifiedData.data.language,
|
||||
lastName: verifiedData.data.lastName,
|
||||
memberships: verifiedData.data.memberships,
|
||||
name: `${verifiedData.data.firstName} ${verifiedData.data.lastName}`,
|
||||
phoneNumber: verifiedData.data.phoneNumber,
|
||||
profileId: verifiedData.data.profileId,
|
||||
}
|
||||
|
||||
return {
|
||||
...extendedUser,
|
||||
...verifiedData.data,
|
||||
name: `${verifiedData.data.firstName} ${verifiedData.data.lastName}`,
|
||||
}
|
||||
}),
|
||||
if (input.mask) {
|
||||
if (user.address.city) {
|
||||
user.address.city = maskValue.text(user.address.city)
|
||||
}
|
||||
if (user.address.streetAddress) {
|
||||
user.address.streetAddress = maskValue.text(
|
||||
user.address.streetAddress
|
||||
)
|
||||
}
|
||||
|
||||
user.address.zipCode = maskValue.text(verifiedData.data.address.zipCode)
|
||||
user.email = maskValue.email(user.email)
|
||||
|
||||
const phonenumber = parsePhoneNumber(user.phoneNumber)
|
||||
user.phoneNumber = `+${phonenumber.countryCallingCode} ${maskValue.phone(user.phoneNumber)}`
|
||||
}
|
||||
|
||||
return user
|
||||
}),
|
||||
|
||||
benefits: router({
|
||||
current: protectedProcedure.query(async function (opts) {
|
||||
|
||||
@@ -4,12 +4,12 @@ import type { UserQueryRouter } from "../user"
|
||||
export type TransactionResponse = Awaited<
|
||||
ReturnType<UserQueryRouter["transaction"]["friendTransactions"]>
|
||||
>
|
||||
export type TransactionsObject = NonNullable<TransactionResponse>
|
||||
export type Transactions = NonNullable<TransactionResponse>["data"]
|
||||
export type Transaction = NonNullable<TransactionResponse>["data"][number]
|
||||
export type TransactionsNonNullResponseObject = NonNullable<TransactionResponse>
|
||||
export type Transactions = NonNullable<TransactionsNonNullResponseObject>["data"]
|
||||
export type Transaction = NonNullable<TransactionsNonNullResponseObject>["data"][number]
|
||||
|
||||
export type ClientEarnAndBurnProps = {
|
||||
initialData: TransactionsObject
|
||||
initialData: TransactionsNonNullResponseObject
|
||||
lang: Lang
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import type { CardProps } from "./card/card"
|
||||
import type { User } from "@/types/user"
|
||||
|
||||
export interface ContainerProps extends CardProps {
|
||||
user: User
|
||||
}
|
||||
@@ -1,10 +1,5 @@
|
||||
export type ProfileLayoutProps = {
|
||||
communication: React.ReactNode
|
||||
creditCards: React.ReactNode
|
||||
edit: React.ReactNode
|
||||
membershipCard: React.ReactNode
|
||||
password: React.ReactNode
|
||||
profile: React.ReactNode
|
||||
view: React.ReactNode
|
||||
wishes: React.ReactNode
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ export type PreviousStaysResponse = Awaited<
|
||||
>
|
||||
export type PreviousStaysNonNullResponseObject =
|
||||
NonNullable<PreviousStaysResponse>
|
||||
export type PreviousStays = NonNullable<PreviousStaysResponse>["data"]
|
||||
export type PreviousStay = NonNullable<PreviousStaysResponse>["data"][number]
|
||||
export type PreviousStays = NonNullable<PreviousStaysNonNullResponseObject>["data"]
|
||||
export type PreviousStay = NonNullable<PreviousStaysNonNullResponseObject>["data"][number]
|
||||
|
||||
export interface PreviousStaysClientProps {
|
||||
lang: Lang
|
||||
|
||||
@@ -6,8 +6,8 @@ export type UpcomingStaysResponse = Awaited<
|
||||
>
|
||||
export type UpcomingStaysNonNullResponseObject =
|
||||
NonNullable<UpcomingStaysResponse>
|
||||
export type UpcomingStays = NonNullable<UpcomingStaysResponse>["data"]
|
||||
export type UpcomingStay = NonNullable<UpcomingStaysResponse>["data"][number]
|
||||
export type UpcomingStays = NonNullable<UpcomingStaysNonNullResponseObject>["data"]
|
||||
export type UpcomingStay = NonNullable<UpcomingStaysNonNullResponseObject>["data"][number]
|
||||
|
||||
export interface UpcomingStaysClientProps {
|
||||
lang: Lang
|
||||
|
||||
15
utils/maskValue.ts
Normal file
15
utils/maskValue.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
const emailRegex =
|
||||
/(?<=.)[^@\n](?=[^@\n]*?@)|(?:(?<=@.+)|(?!^)\G(?=[^@\n]*$)).(?=.*\.)/gm
|
||||
export function email(str: string) {
|
||||
return str.replace(emailRegex, "*")
|
||||
}
|
||||
|
||||
const phoneRegex = /.(?!.{0,1}$)/gm
|
||||
export function phone(str: string) {
|
||||
return str.replace(phoneRegex, "*")
|
||||
}
|
||||
|
||||
const textRegex = /(?!^)./gm
|
||||
export function text(str: string) {
|
||||
return str.replace(textRegex, "*")
|
||||
}
|
||||
Reference in New Issue
Block a user