Merge pull request 'new-public-booking' (#14) from new-public-booking into development

Reviewed-on: https://gitea.2pidev.com/jselesan/playzer/pulls/14
This commit is contained in:
2026-05-28 13:03:13 +00:00
6 changed files with 2603 additions and 290 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,4 @@
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { useEffect, useState } from 'react';
type UserAvatarProps = { type UserAvatarProps = {
src?: string | null; src?: string | null;
@@ -22,25 +21,9 @@ export function UserAvatar({
size = 'default', size = 'default',
className, className,
}: UserAvatarProps) { }: UserAvatarProps) {
const [imageError, setImageError] = useState(false);
useEffect(() => {
setImageError(false);
}, [src]);
const canShowImage = Boolean(src) && !imageError;
return ( return (
<Avatar size={size} className={className}> <Avatar size={size} className={className}>
{canShowImage && ( <AvatarImage src={src ?? undefined} alt={alt} />
<AvatarImage
src={src ?? undefined}
alt={alt}
onError={() => {
setImageError(true);
}}
/>
)}
<AvatarFallback>{getInitials(fallbackText)}</AvatarFallback> <AvatarFallback>{getInitials(fallbackText)}</AvatarFallback>
</Avatar> </Avatar>
); );

View File

@@ -244,4 +244,46 @@ body,
border: 3px solid transparent; border: 3px solid transparent;
background-clip: padding-box; background-clip: padding-box;
} }
.public-booking-light {
background: #eaf2f4;
color: #0f172a;
}
.public-booking-light .public-booking-frame {
background: radial-gradient(circle at 18% 10%, rgba(16, 185, 129, 0.18), transparent 28%),
radial-gradient(circle at 82% 18%, rgba(59, 130, 246, 0.14), transparent 30%),
linear-gradient(180deg, #f8fbfc 0%, #edf5f7 52%, #e5eef2 100%);
}
.public-booking-light .public-booking-panel {
background: rgba(255, 255, 255, 0.78);
border-color: rgba(15, 23, 42, 0.13);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.72), 0 18px 48px rgba(15, 23, 42, 0.09);
}
.public-booking-light [class*="border-white"] {
border-color: rgba(15, 23, 42, 0.13);
}
.public-booking-light [class*="bg-white"] {
background-color: rgba(15, 23, 42, 0.045);
}
.public-booking-light [class*="text-white"] {
color: rgba(15, 23, 42, 0.72);
}
.public-booking-light .text-emerald-400,
.public-booking-light .text-cyan-300 {
color: #059669;
}
.public-booking-light .bg-emerald-500 {
background-color: #10b981;
}
.public-booking-light .text-red-300 {
color: #dc2626;
}
} }

View File

@@ -0,0 +1,61 @@
import * as React from 'react';
type PossibleRef<T> = React.Ref<T> | undefined;
/**
* Set a given ref to a given value
* This utility takes care of different types of refs: callback refs and RefObject(s)
*/
function setRef<T>(ref: PossibleRef<T>, value: T) {
if (typeof ref === 'function') {
return ref(value);
}
if (ref !== null && ref !== undefined) {
ref.current = value;
}
}
/**
* A utility to compose multiple refs together
* Accepts callback refs and RefObject(s)
*/
function composeRefs<T>(...refs: PossibleRef<T>[]): React.RefCallback<T> {
return (node) => {
let hasCleanup = false;
const cleanups = refs.map((ref) => {
const cleanup = setRef(ref, node);
if (!hasCleanup && typeof cleanup === 'function') {
hasCleanup = true;
}
return cleanup;
});
// React <19 will log an error to the console if a callback ref returns a
// value. We don't use ref cleanups internally so this will only happen if a
// user's ref callback returns a value, which we only expect if they are
// using the cleanup functionality added in React 19.
if (hasCleanup) {
return () => {
for (let i = 0; i < cleanups.length; i++) {
const cleanup = cleanups[i];
if (typeof cleanup === 'function') {
cleanup();
} else {
setRef(refs[i], null);
}
}
};
}
};
}
/**
* A custom hook that composes multiple refs
* Accepts callback refs and RefObject(s)
*/
function useComposedRefs<T>(...refs: PossibleRef<T>[]): React.RefCallback<T> {
return React.useCallback(composeRefs(...refs), refs);
}
export { composeRefs, useComposedRefs };

View File

@@ -3,7 +3,7 @@ import { NotFoundPage } from '@/features/not-found/not-found-page';
import { ServerErrorPage } from '@/features/server-error/server-error-page'; import { ServerErrorPage } from '@/features/server-error/server-error-page';
import type { ApiClient } from '@/lib/api-client'; import type { ApiClient } from '@/lib/api-client';
import type { AuthContextValue } from '@/lib/auth'; import type { AuthContextValue } from '@/lib/auth';
import { Outlet, createRootRouteWithContext } from '@tanstack/react-router'; import { Outlet, createRootRouteWithContext, useLocation } from '@tanstack/react-router';
type RouterContext = { type RouterContext = {
auth: AuthContextValue; auth: AuthContextValue;
@@ -17,6 +17,13 @@ export const Route = createRootRouteWithContext<RouterContext>()({
}); });
function RootRoute() { function RootRoute() {
const location = useLocation();
const isPublicBookingRoute = /^\/[^/]+\/booking(?:\/|$)/.test(location.pathname);
if (isPublicBookingRoute) {
return <Outlet />;
}
return ( return (
<Layout> <Layout>
<div className="flex flex-col"> <div className="flex flex-col">