harden media

This commit is contained in:
2025-12-31 15:39:28 +01:00
parent 92226800df
commit 8260bf7baf
413 changed files with 8361 additions and 1544 deletions

View File

@@ -5,13 +5,13 @@ import Image from 'next/image';
import Link from 'next/link';
import type { DriverViewModel } from '@/lib/view-models/DriverViewModel';
import DriverRating from '@/components/profile/DriverRatingPill';
import { useServices } from '@/lib/services/ServiceProvider';
import PlaceholderImage from '@/components/ui/PlaceholderImage';
export interface DriverSummaryPillProps {
driver: DriverViewModel;
rating: number | null;
rank: number | null;
avatarSrc?: string;
avatarSrc?: string | null;
onClick?: () => void;
href?: string;
}
@@ -19,21 +19,22 @@ export interface DriverSummaryPillProps {
export default function DriverSummaryPill(props: DriverSummaryPillProps) {
const { driver, rating, rank, avatarSrc, onClick, href } = props;
const { mediaService } = useServices();
const resolvedAvatar =
avatarSrc ?? mediaService.getDriverAvatar(driver.id);
const resolvedAvatar = avatarSrc;
const content = (
<>
<div className="w-8 h-8 rounded-full overflow-hidden bg-charcoal-outline flex items-center justify-center border border-charcoal-outline/80">
<Image
src={resolvedAvatar}
alt={driver.name}
width={32}
height={32}
className="w-full h-full object-cover"
/>
{resolvedAvatar ? (
<Image
src={resolvedAvatar}
alt={driver.name}
width={32}
height={32}
className="w-full h-full object-cover"
/>
) : (
<PlaceholderImage size={32} />
)}
</div>
<div className="flex flex-col leading-tight text-left">

View File

@@ -5,7 +5,7 @@ import type { DriverViewModel } from '@/lib/view-models/DriverViewModel';
import Button from '../ui/Button';
import DriverRatingPill from '@/components/profile/DriverRatingPill';
import CountryFlag from '@/components/ui/CountryFlag';
import { useServices } from '@/lib/services/ServiceProvider';
import PlaceholderImage from '@/components/ui/PlaceholderImage';
interface ProfileHeaderProps {
driver: DriverViewModel;
@@ -26,19 +26,21 @@ export default function ProfileHeader({
teamName,
teamTag,
}: ProfileHeaderProps) {
const { mediaService } = useServices();
return (
<div className="flex items-start justify-between">
<div className="flex items-start gap-4">
<div className="w-20 h-20 rounded-full bg-gradient-to-br from-primary-blue to-purple-600 overflow-hidden flex items-center justify-center">
<Image
src={mediaService.getDriverAvatar(driver.id)}
alt={driver.name}
width={80}
height={80}
className="w-full h-full object-cover"
/>
{driver.avatarUrl ? (
<Image
src={driver.avatarUrl}
alt={driver.name}
width={80}
height={80}
className="w-full h-full object-cover"
/>
) : (
<PlaceholderImage size={80} />
)}
</div>
<div>

View File

@@ -19,9 +19,8 @@ vi.mock('@/hooks/useEffectiveDriverId', () => {
};
});
// Mock services hook to inject stub driverService/mediaService
const mockFindById = vi.fn<[], Promise<DriverDTO | null>>();
const mockGetDriverAvatar = vi.fn<(driverId: string) => string>();
// Mock services hook to inject stub driverService
const mockFindById = vi.fn();
vi.mock('@/lib/services/ServiceProvider', () => {
return {
@@ -30,7 +29,7 @@ vi.mock('@/lib/services/ServiceProvider', () => {
findById: mockFindById,
},
mediaService: {
getDriverAvatar: mockGetDriverAvatar,
getDriverAvatar: vi.fn(),
},
}),
};
@@ -66,7 +65,6 @@ describe('UserPill', () => {
mockedAuthValue = { session: null };
mockedDriverId = null;
mockFindById.mockReset();
mockGetDriverAvatar.mockReset();
});
it('renders auth links when there is no session', () => {
@@ -94,19 +92,19 @@ describe('UserPill', () => {
expect(mockFindById).not.toHaveBeenCalled();
});
it('loads driver via driverService and uses mediaService avatar', async () => {
it('loads driver via driverService and uses driver avatarUrl', async () => {
const driver: DriverDTO = {
id: 'driver-1',
iracingId: 'ir-123',
name: 'Test Driver',
country: 'DE',
avatarUrl: '/api/media/avatar/driver-1',
};
mockedAuthValue = { session: { user: { id: 'user-1' } } };
mockedDriverId = driver.id;
mockFindById.mockResolvedValue(driver);
mockGetDriverAvatar.mockImplementation((driverId: string) => `/api/media/avatar/${driverId}`);
render(<UserPill />);
@@ -115,6 +113,5 @@ describe('UserPill', () => {
});
expect(mockFindById).toHaveBeenCalledWith('driver-1');
expect(mockGetDriverAvatar).toHaveBeenCalledWith('driver-1');
});
});

View File

@@ -106,7 +106,7 @@ export default function UserPill() {
const dto = await driverService.findById(primaryDriverId);
if (!cancelled) {
setDriver(dto ? new DriverViewModelClass(dto) : null);
setDriver(dto ? new DriverViewModelClass({ ...dto, avatarUrl: (dto as any).avatarUrl ?? null }) : null);
}
}
@@ -127,7 +127,7 @@ export default function UserPill() {
const rating: number | null = null;
const rank: number | null = null;
const avatarSrc = mediaService.getDriverAvatar(primaryDriverId);
const avatarSrc = driver.avatarUrl;
return {
driver,
@@ -135,7 +135,7 @@ export default function UserPill() {
rating,
rank,
};
}, [session, driver, primaryDriverId, mediaService]);
}, [session, driver, primaryDriverId]);
// Close menu when clicking outside
useEffect(() => {