Merged in feature/redis (pull request #1478)

Distributed cache

* cache deleteKey now uses an options object instead of a lonely argument variable fuzzy

* merge

* remove debug logs and cleanup

* cleanup

* add fault handling

* add fault handling

* add pid when logging redis client creation

* add identifier when logging redis client creation

* cleanup

* feat: add redis-api as it's own app

* feature: use http wrapper for redis

* feat: add the possibility to fallback to unstable_cache

* Add error handling if redis cache is unresponsive

* add logging for unstable_cache

* merge

* don't cache errors

* fix: metadatabase on branchdeploys

* Handle when /en/destinations throws
add ErrorBoundary

* Add sentry-logging when ErrorBoundary catches exception

* Fix error handling for distributed cache

* cleanup code

* Added Application Insights back

* Update generateApiKeys script and remove duplicate

* Merge branch 'feature/redis' of bitbucket.org:scandic-swap/web into feature/redis

* merge


Approved-by: Linus Flood
This commit is contained in:
Joakim Jäderberg
2025-03-14 07:54:21 +00:00
committed by Linus Flood
parent a8304e543e
commit fa63b20ed0
141 changed files with 4404 additions and 1941 deletions
@@ -24,7 +24,7 @@ export function SessionRefresher() {
const session = useSession()
const pathname = usePathname()
const searchParams = useSearchParams()
const timeoutId = useRef<NodeJS.Timeout>()
const timeoutId = useRef<Timer>()
// Simple inactivity control. Reset when the URL changes.
const stopPreRefreshAt = useMemo(
@@ -15,7 +15,10 @@
}
.partial {
grid-template-columns: minmax(auto, 150px) min-content minmax(auto, 150px) auto;
grid-template-columns: minmax(auto, 150px) min-content minmax(
auto,
150px
) auto;
}
.icon {
@@ -6,6 +6,7 @@ import { Map, type MapProps, useMap } from "@vis.gl/react-google-maps"
import { type PropsWithChildren, useEffect } from "react"
import { useIntl } from "react-intl"
import ErrorBoundary from "@/components/ErrorBoundary/ErrorBoundary"
import { CloseLargeIcon, MinusIcon, PlusIcon } from "@/components/Icons"
import Button from "@/components/TempDesignSystem/Button"
import { useHandleKeyUp } from "@/hooks/useHandleKeyUp"
@@ -84,7 +85,9 @@ export default function DynamicMap({
return (
<div className={styles.mapWrapper}>
<Map {...mapOptions}>{children}</Map>
<ErrorBoundary fallback={<h2>Unable to display map</h2>}>
<Map {...mapOptions}>{children}</Map>
</ErrorBoundary>
<div className={styles.ctaButtons}>
{onClose && (
<Button
@@ -69,8 +69,8 @@
@media screen and (min-width: 1367px) {
.pageContainer {
--hotel-page-scroll-margin-top: calc(
var(--hotel-page-navigation-height) + var(--booking-widget-desktop-height) +
var(--Spacing-x2)
var(--hotel-page-navigation-height) +
var(--booking-widget-desktop-height) + var(--Spacing-x2)
);
grid-template-areas:
"header mapContainer"
@@ -20,4 +20,4 @@
border-radius: 18px;
outline: 0 none;
padding: 5px 15px;
}
}
@@ -4,7 +4,9 @@ export default function OfflineBanner() {
return (
<div className={`${styles.banner} ${styles.hidden}`}>
You are offline, some content may be out of date.
<button className={styles.reloadBtn} type="button">Reload</button>
<button className={styles.reloadBtn} type="button">
Reload
</button>
</div>
)
}
@@ -12,17 +12,11 @@ export default function Breadcrumbs({
<ul className={styles.list}>
{parent ? (
<li className={styles.parent}>
<a href={parent.href}>
{parent.title}
</a>
<a href={parent.href}>{parent.title}</a>
</li>
) : null}
{breadcrumbs.map((breadcrumb) => (
<li
className={styles.li}
itemProp="breadcrumb"
key={breadcrumb.href}
>
<li className={styles.li} itemProp="breadcrumb" key={breadcrumb.href}>
<a className={styles.link} href={breadcrumb.href}>
{breadcrumb.title}
</a>
@@ -11,16 +11,12 @@ export default async function SubnavMobile({
<ul className="breadcrumb-list hidden-small hidden-medium hidden-large">
{parent ? (
<li className="breadcrumb-list__parent hidden-medium hidden-large">
<a href={parent.href}>
{parent.title}
</a>
<a href={parent.href}>{parent.title}</a>
</li>
) : null}
{breadcrumbs.map((breadcrumb) => (
<li className="breadcrumb-list__body" key={breadcrumb.href}>
<a href={breadcrumb.href}>
{breadcrumb.title}
</a>
<a href={breadcrumb.href}>{breadcrumb.title}</a>
</li>
))}
<li className="breadcrumb-list__body">
@@ -0,0 +1,40 @@
import * as Sentry from "@sentry/nextjs"
import React from "react"
type ErrorBoundaryProps = {
children: React.ReactNode
fallback?: React.ReactNode
}
type ErrorBoundaryState = { hasError: boolean; error?: Error }
class ErrorBoundary extends React.Component<
ErrorBoundaryProps,
ErrorBoundaryState
> {
constructor(props: ErrorBoundaryProps) {
super(props)
this.state = { hasError: false }
}
static getDerivedStateFromError(error: Error) {
return { hasError: true, error }
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error("ErrorBoundary caught an error:", error, errorInfo)
Sentry.captureException(error, { extra: { errorInfo } })
}
render() {
if (this.state.hasError) {
if (this.props.fallback) {
return this.props.fallback
}
return <h2>Something went wrong.</h2>
}
return this.props.children
}
}
export default ErrorBoundary
@@ -41,4 +41,4 @@
gap: var(--Spacing-x2);
justify-self: flex-end;
}
}
}
@@ -14,7 +14,8 @@
}
.link:nth-of-type(1) .promo {
background-image: linear-gradient(
background-image:
linear-gradient(
180deg,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 0.36) 37.88%,
@@ -24,7 +25,8 @@
}
.link:nth-of-type(2) .promo {
background-image: linear-gradient(
background-image:
linear-gradient(
180deg,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 0.36) 37.88%,
@@ -152,9 +152,9 @@ export default function Details({ user }: DetailsProps) {
{isPaymentNext
? intl.formatMessage({ id: "Proceed to payment method" })
: intl.formatMessage(
{ id: "Continue to room {nextRoomNumber}" },
{ nextRoomNumber: roomNr + 1 }
)}
{ id: "Continue to room {nextRoomNumber}" },
{ nextRoomNumber: roomNr + 1 }
)}
</Button>
</footer>
<MemberPriceModal
@@ -2,7 +2,8 @@
height: 100%;
width: 100%;
background-color: #fff;
background-image: linear-gradient(45deg, #000000 25%, transparent 25%),
background-image:
linear-gradient(45deg, #000000 25%, transparent 25%),
linear-gradient(-45deg, #000000 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #000000 75%),
linear-gradient(-45deg, transparent 75%, #000000 75%);
@@ -19,7 +19,8 @@
}
.link .promo {
background-image: linear-gradient(
background-image:
linear-gradient(
180deg,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 0.36) 37.88%,
@@ -107,7 +107,8 @@
height: 100%;
width: 100%;
background-color: #fff;
background-image: linear-gradient(45deg, #000000 25%, transparent 25%),
background-image:
linear-gradient(45deg, #000000 25%, transparent 25%),
linear-gradient(-45deg, #000000 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #000000 75%),
linear-gradient(-45deg, transparent 75%, #000000 75%);
@@ -18,13 +18,11 @@ import type { Rate } from "@/types/components/hotelReservation/selectRate/select
export default function SelectedRoomPanel() {
const intl = useIntl()
const { isUserLoggedIn, roomCategories } = useRatesStore(
(state) => ({
isUserLoggedIn: state.isUserLoggedIn,
rateDefinitions: state.roomsAvailability?.rateDefinitions,
roomCategories: state.roomCategories,
})
)
const { isUserLoggedIn, roomCategories } = useRatesStore((state) => ({
isUserLoggedIn: state.isUserLoggedIn,
rateDefinitions: state.roomsAvailability?.rateDefinitions,
roomCategories: state.roomCategories,
}))
const {
actions: { modifyRate },
isMainRoom,
@@ -40,7 +40,7 @@ export function useRoomsAvailability(
toDateString: string,
lang: Lang,
childArray?: Child[],
bookingCode?: string,
bookingCode?: string
) {
const returnValue =
trpc.hotel.availability.roomsCombinedAvailability.useQuery({
@@ -33,7 +33,8 @@
aspect-ratio: 16/9;
width: 100%;
background-color: #fff;
background-image: linear-gradient(45deg, #000000 25%, transparent 25%),
background-image:
linear-gradient(45deg, #000000 25%, transparent 25%),
linear-gradient(-45deg, #000000 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #000000 75%),
linear-gradient(-45deg, transparent 75%, #000000 75%);