Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { PublicProfile } from '../../../../lib/user';
import { ProfileUserWorkspacePhotos } from './ProfileUserWorkspacePhotos';
import { useUserWorkspacePhotos } from '../../hooks/useUserWorkspacePhotos';
import { useGear } from '../../hooks/useGear';
import { LazyModal } from '../../../../components/modals/common/types';

jest.mock('../../hooks/useUserWorkspacePhotos', () => ({
...jest.requireActual('../../hooks/useUserWorkspacePhotos'),
Expand All @@ -22,6 +23,11 @@ jest.mock('../../../../hooks/usePrompt', () => ({
usePrompt: () => ({ showPrompt: jest.fn() }),
}));

const mockOpenModal = jest.fn();
jest.mock('../../../../hooks/useLazyModal', () => ({
useLazyModal: () => ({ openModal: mockOpenModal }),
}));

const mockUseUserWorkspacePhotos =
useUserWorkspacePhotos as jest.MockedFunction<typeof useUserWorkspacePhotos>;
const mockUseGear = useGear as jest.MockedFunction<typeof useGear>;
Expand All @@ -39,11 +45,6 @@ const baseUser: PublicProfile = {

const photo = { id: 'p1', image: 'https://daily.dev/desk.png', position: 0 };

const renderAndOpenLightbox = () => {
render(<ProfileUserWorkspacePhotos user={baseUser} />);
fireEvent.click(screen.getByRole('button', { name: 'View workspace photo' }));
};

beforeEach(() => {
jest.clearAllMocks();
mockUseUserWorkspacePhotos.mockReturnValue({
Expand All @@ -63,27 +64,28 @@ beforeEach(() => {
});

describe('ProfileUserWorkspacePhotos lightbox', () => {
it('opens a dialog with a blurred backdrop when a photo is clicked', () => {
renderAndOpenLightbox();

expect(
screen.getByRole('dialog', { name: 'Workspace photo lightbox' }),
).toBeInTheDocument();
const backdrop = screen.getByRole('button', { name: 'Close lightbox' });
expect(backdrop.className).toMatch(/backdrop-blur/);
});

it('closes the lightbox when the backdrop is clicked', () => {
renderAndOpenLightbox();

fireEvent.click(screen.getByRole('button', { name: 'Close lightbox' }));
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});
it('opens the shared image lightbox with the photo when clicked', () => {
render(<ProfileUserWorkspacePhotos user={baseUser} />);

it('closes the lightbox when the close button is clicked', () => {
renderAndOpenLightbox();
fireEvent.click(
screen.getByRole('button', { name: 'View workspace photo' }),
);

fireEvent.click(screen.getByRole('button', { name: 'Close' }));
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
expect(mockOpenModal).toHaveBeenCalledTimes(1);
expect(mockOpenModal).toHaveBeenCalledWith(
expect.objectContaining({
type: LazyModal.ImageView,
props: expect.objectContaining({
src: photo.image,
alt: 'Workspace',
originRect: expect.objectContaining({
top: expect.any(Number),
left: expect.any(Number),
width: expect.any(Number),
height: expect.any(Number),
}),
}),
}),
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
sortableKeyboardCoordinates,
rectSortingStrategy,
} from '@dnd-kit/sortable';
import { useEventListener } from '../../../../hooks/useEventListener';
import type { PublicProfile } from '../../../../lib/user';
import {
useUserWorkspacePhotos,
Expand All @@ -33,7 +32,9 @@ import {
ButtonVariant,
} from '../../../../components/buttons/Button';
import { CameraIcon, SettingsIcon } from '../../../../components/icons';
import CloseButton from '../../../../components/CloseButton';
import { useLazyModal } from '../../../../hooks/useLazyModal';
import { LazyModal } from '../../../../components/modals/common/types';
import { getImageOriginRect } from '../../../../components/modals/ImageModal';
import { SortableWorkspacePhotoItem } from './WorkspacePhotoItem';
import { WorkspacePhotoUploadModal } from './WorkspacePhotoUploadModal';
import { GearModal } from '../gear/GearModal';
Expand Down Expand Up @@ -63,10 +64,10 @@ export function ProfileUserWorkspacePhotos({
const { displayToast } = useToastNotification();
const { showPrompt } = usePrompt();
const { logEvent } = useLogContext();
const { openModal } = useLazyModal();

const [isPhotoModalOpen, setIsPhotoModalOpen] = useState(false);
const [isGearModalOpen, setIsGearModalOpen] = useState(false);
const [selectedPhoto, setSelectedPhoto] = useState<string | null>(null);

const sensors = useSensors(
useSensor(PointerSensor, {
Expand Down Expand Up @@ -197,20 +198,19 @@ export function ProfileUserWorkspacePhotos({
setIsGearModalOpen(false);
}, []);

const handlePhotoClick = useCallback((photo: { image: string }) => {
setSelectedPhoto(photo.image);
}, []);

const handleCloseLightbox = useCallback(() => {
setSelectedPhoto(null);
}, []);

// Close lightbox on ESC key
useEventListener(globalThis as unknown as Window, 'keydown', (event) => {
if (event.key === 'Escape' && selectedPhoto) {
handleCloseLightbox();
}
});
const handlePhotoClick = useCallback(
(photo: { image: string }, event: React.MouseEvent<HTMLButtonElement>) => {
openModal({
type: LazyModal.ImageView,
props: {
src: photo.image,
alt: 'Workspace',
originRect: getImageOriginRect(event.currentTarget),
},
});
},
[openModal],
);

const hasPhotos = photos.length > 0;
const hasGear = gearItems.length > 0;
Expand Down Expand Up @@ -355,33 +355,6 @@ export function ProfileUserWorkspacePhotos({
onSubmit={handleAddGear}
/>
)}

{selectedPhoto && (
<div
className="fixed inset-0 z-modal flex items-center justify-center p-4"
role="dialog"
aria-modal="true"
aria-label="Workspace photo lightbox"
>
<button
type="button"
className="absolute inset-0 bg-overlay-primary-pepper backdrop-blur-md"
onClick={handleCloseLightbox}
aria-label="Close lightbox"
/>
<img
src={selectedPhoto}
alt="Workspace"
className="relative max-h-full max-w-full rounded-16 object-contain"
/>
<CloseButton
size={ButtonSize.Small}
variant={ButtonVariant.Primary}
className="absolute right-4 top-4 z-1"
onClick={handleCloseLightbox}
/>
</div>
)}
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ interface WorkspacePhotoItemProps {
photo: UserWorkspacePhoto;
isOwner: boolean;
onDelete?: (photo: UserWorkspacePhoto) => void;
onClick?: (photo: UserWorkspacePhoto) => void;
onClick?: (
photo: UserWorkspacePhoto,
event: React.MouseEvent<HTMLButtonElement>,
) => void;
}

export function WorkspacePhotoItem({
Expand All @@ -35,7 +38,7 @@ export function WorkspacePhotoItem({
<button
type="button"
className="size-full"
onClick={onClick ? () => onClick(photo) : undefined}
onClick={onClick ? (event) => onClick(photo, event) : undefined}
aria-label="View workspace photo"
>
<img
Expand Down
Loading