Files
web/apps/scandic-web/components/MyPages/DigitalTeamMemberCard/Content.tsx
Bianca Widstam 5ac7e5deac Merged in fix/hotjar-suppress (pull request #3211)
Fix/hotjar suppress

* fix(hotjar): suppress personal info on my pages

* fix(hotjar): suppress more data


Approved-by: Linus Flood
2025-11-27 13:09:37 +00:00

185 lines
5.5 KiB
TypeScript

"use client"
import { useEffect, useRef, useState } from "react"
import { useIntl } from "react-intl"
import { debounce } from "@scandic-hotels/common/utils/debounce"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { getEmployeeInfo } from "@/utils/user"
import styles from "./digitalTeamMemberCard.module.css"
import type { User } from "@scandic-hotels/trpc/types/user"
interface DigitalTeamMemberCardCardProps {
user: User
}
export default function DigitalTeamMemberCardContent({
user,
}: DigitalTeamMemberCardCardProps) {
const intl = useIntl()
const cardRef = useRef<HTMLDivElement>(null)
const employeeInfo = getEmployeeInfo(user)
const notAvailableText = "N/A"
const [isHovering, setIsHovering] = useState(false)
const [coords, setCoords] = useState({ x: 0, y: 0 })
const shimmerRef = useRef<HTMLDivElement>(null)
const [rect, setRect] = useState<DOMRect>({
top: 0,
left: 0,
bottom: 0,
right: 0,
height: 0,
width: 0,
x: 0,
y: 0,
toJSON() {},
})
useEffect(() => {
const observer = new ResizeObserver(
debounce(() => {
const el = cardRef.current
if (!el) return
const rect = el.getBoundingClientRect()
setRect(rect)
})
)
observer.observe(document.body)
return () => {
observer.unobserve(document.body)
}
}, [])
function onInteractionMove(e: React.MouseEvent | React.TouchEvent) {
let x, y
if ("touches" in e) {
x = e.touches[0].clientX - rect.left
y = e.touches[0].clientY - rect.top
} else {
x = e.clientX - rect.left
y = e.clientY - rect.top
}
const centerX = rect.width / 2
const centerY = rect.height / 2
const rotateY = ((x - centerX) / centerX) * 8
const rotateX = ((centerY - y) / centerY) * 8
// Update shimmer position to be in the opposite corner
if (shimmerRef.current) {
// Calculate opposite position (invert percentage within bounds)
const oppositeX = 100 - (x / rect.width) * 100
const oppositeY = 100 - (y / rect.height) * 100
shimmerRef.current.style.background = `radial-gradient(
circle at ${oppositeX}% ${oppositeY}%,
rgba(233, 171, 163, 0.4) 0%,
rgba(255, 255, 255, 0) 50%
)`
}
setCoords({ x: rotateX, y: rotateY })
}
function onInteractionStart() {
setIsHovering(true)
}
function onInteractionEnd() {
setIsHovering(false)
setCoords({ x: 0, y: 0 })
}
return (
<div
className={styles.cardContainer}
ref={cardRef}
onTouchStart={onInteractionStart}
onTouchMove={onInteractionMove}
onTouchEnd={onInteractionEnd}
onMouseEnter={onInteractionStart}
onMouseMove={onInteractionMove}
onMouseLeave={onInteractionEnd}
>
<div
className={styles.card}
style={{
transform: `rotateX(${coords.x}deg) rotateY(${coords.y}deg)`,
}}
>
<div
className={styles.shimmer}
ref={shimmerRef}
style={{ opacity: isHovering ? 1 : 0 }}
/>
<div className={styles.content}>
<Typography variant="Tag/sm">
<div className={styles.top}>
<span>
{employeeInfo?.retired
? intl.formatMessage({
id: "myPages.seniorTeamMember",
defaultMessage: "Senior Team Member",
})
: intl.formatMessage({
id: "myPages.teamMember",
defaultMessage: "Team Member",
})}
</span>
<span>{employeeInfo?.country || notAvailableText}</span>
</div>
</Typography>
<div className={styles.middle}>
<div className={styles.employeeNumber}>
<Typography variant="Title/sm">
<div data-hj-suppress>
{employeeInfo?.employeeId || notAvailableText}
</div>
</Typography>
<svg
width="42"
height="42"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={styles.icon}
>
<path
d="M3.5 35V12.288C3.5 8.933 3.5 7 4.268 7c.912 0 1.569 1.156 3.17 3.978l11.374 20.044C20.413 33.844 21.041 35 21.982 35c.768 0 .768-1.933.768-5.288V7M28 22.75h10.5M29.016 8.016c1.355-1.355 7.113-1.355 8.468 0 1.355 1.355 1.355 7.113 0 8.468-1.355 1.355-7.114 1.355-8.468 0-1.355-1.355-1.355-7.113 0-8.468Z"
strokeWidth="2.625"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</div>
<Typography variant="Title/md">
<div data-hj-suppress>
{user.firstName} {user.lastName}
</div>
</Typography>
</div>
<Typography variant="Tag/sm">
<div className={styles.bottom}>
<span>{employeeInfo?.location || notAvailableText}</span>
<span>
{employeeInfo?.retired
? intl.formatMessage({
id: "myPages.retired",
defaultMessage: "Retired",
})
: intl.formatMessage({
id: "myPages.employee",
defaultMessage: "Employee",
})}
</span>
</div>
</Typography>
</div>
</div>
</div>
)
}