Skip to content

Commit

Permalink
Merge pull request #175 from sima-land/170-modifier-media-modal
Browse files Browse the repository at this point in the history
Шаг 5 #170 Внести доработки в компоненты на основе изменений в гайдах
  • Loading branch information
krutoo authored Jun 22, 2023
2 parents 0de319f + f9fc7c0 commit 2390022
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 16 deletions.
32 changes: 28 additions & 4 deletions src/desktop/components/gallery-modal/__test__/utils.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,41 @@ import { useImagesLoad, useSquareFit } from '../utils';

describe('useImagesLoad', () => {
const TestComponent = ({ srcList }: { srcList: string[] }) => {
const isLoaded = useImagesLoad(srcList);

return <div>{isLoaded ? 'ready' : 'loading'}</div>;
const status = useImagesLoad(srcList);
const isLoaded = status === 'done';
const isFailed = status === 'fail';

return (
<div>
{isLoaded && 'ready'}
{isFailed && 'fail'}
{!isLoaded && !isFailed && 'loading'}
</div>
);
};

it('should return boolean', () => {
it('should return status', () => {
const { container } = render(<TestComponent srcList={['a']} />);

expect(container.textContent).toBe('loading');
});

it('should handle error', () => {
const callbacks: Array<(...args: any[]) => void> = [];

jest.spyOn(Image.prototype, 'onerror', 'set').mockImplementation(callback => {
callbacks.push(callback);
});

const { container } = render(<TestComponent srcList={['a']} />);

act(() => {
callbacks.forEach(cb => cb({}));
});

expect(container.textContent).toBe('fail');
});

it('should return true after all images loaded', () => {
const callbacks: Array<(...args: any[]) => void> = [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import React from 'react';
import { mount } from 'enzyme';
import { AllRoundView } from '../all-round-view';
import { act } from 'react-dom/test-utils';
import { useImagesLoad } from '../../utils';

jest.mock('../../utils', () => {
const original = jest.requireActual('../../utils');

return {
...original,
__esModule: true,
useImagesLoad: jest.fn(() => true),
useImagesLoad: jest.fn(() => 'done'),
};
});

Expand Down Expand Up @@ -41,6 +42,16 @@ describe('AllRoundView', () => {
expect(wrapper).toMatchSnapshot();
});

it('should render stub for failed img set', () => {
(useImagesLoad as jest.Mock).mockReturnValue('fail');

const wrapper = mount(<AllRoundView photos={['broken-url']} />);

expect(wrapper.find(Selectors.image)).toHaveLength(0);

(useImagesLoad as jest.Mock).mockReturnValue('done');
});

it('should renders correctly default state', () => {
const wrapper = mount(<AllRoundView photos={testPhotos} />);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
width: 100%;
height: 100%;
}
.stub {
display: block;
width: 100%;
height: 100%;
}
}

.controls {
Expand Down
25 changes: 17 additions & 8 deletions src/desktop/components/gallery-modal/components/all-round-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import AllRoundSVG from '../icons/360.svg';
import PauseSVG from '../icons/pause.svg';
import TurnLeftSVG from '../icons/turn-left.svg';
import TurnRightSVG from '../icons/turn-right.svg';
import BrokenSVG from '../../../../common/icons/image-broken.svg';

export interface AllRoundViewProps {
photos: string[];
Expand Down Expand Up @@ -47,12 +48,13 @@ export const AllRoundView = ({

const [index, setIndex] = useState<number>(0);
const indexRef = useIdentityRef(index);

const photosReady = useImagesLoad(photos);
const imagesStatus = useImagesLoad(photos);
const ready = imagesStatus === 'done';
const failed = imagesStatus === 'fail';

// запуск/остановка вращения
useEffect(() => {
if (state !== 'default' && photosReady) {
if (state !== 'default' && ready) {
const timerId = window.setInterval(() => {
const increment = state === 'turn-left' ? -1 : 1;

Expand All @@ -61,15 +63,19 @@ export const AllRoundView = ({

return () => window.clearInterval(timerId);
}
}, [state, photosReady]);
}, [state, ready]);

// перетаскивание
useEffect(() => {
// переданное число всегда замениться на такое, которое будет в промежутке от 0 до количества фото
// eslint-disable-next-line require-jsdoc
const wrap = (value: number) => (photos.length + value) % photos.length;

const image = imageRef.current as HTMLImageElement;
const image = imageRef.current;

if (!image) {
return;
}

const offList = [
on<PointerEvent>(image, 'pointerdown', e => {
Expand Down Expand Up @@ -107,7 +113,7 @@ export const AllRoundView = ({
];

return () => offList.forEach(fn => fn());
}, [photos.length]);
}, [photos.length, failed]);

const HINT = (
<>
Expand All @@ -121,9 +127,12 @@ export const AllRoundView = ({

return (
<div className={cx('root')}>
<img data-testid='gallery-modal:360-current-photo' ref={imageRef} src={photos[index]} />
{failed && <BrokenSVG className={cx('stub')} />}
{!failed && (
<img data-testid='gallery-modal:360-current-photo' ref={imageRef} src={photos[index]} />
)}

{controls && (
{!failed && controls && (
<div className={cx('controls')}>
<button
className={cx('control', 'turn')}
Expand Down
23 changes: 20 additions & 3 deletions src/desktop/components/gallery-modal/utils.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
import React, { useEffect, useState } from 'react';
import on from '@sima-land/ui-nucleons/helpers/on';
import { useIsomorphicLayoutEffect } from '@sima-land/ui-nucleons/hooks';

type Status = 'load' | 'done' | 'fail';

/**
* Хук, вернет true когда все фото будут загружен.
* @param srcList Список адресов фото.
* @return Загружены ли все фото.
*/
export const useImagesLoad = (srcList: string[]): boolean => {
export function useImagesLoad(srcList: string[]): Status {
const [failed, setFailed] = useState(false);
const [loadedCount, setLoadedCount] = useState<number>(0);

useIsomorphicLayoutEffect(() => {
setFailed(false);
}, srcList);

useEffect(() => {
srcList.forEach(src => {
const image = new Image();

image.onload = () => setLoadedCount(c => c + 1);
image.onerror = () => setFailed(true);
image.src = src;
});

return () => setLoadedCount(0);
}, srcList);

return loadedCount === srcList.length;
};
if (loadedCount === srcList.length) {
return 'done';
}

if (failed) {
return 'fail';
}

return 'load';
}

/**
* Хук, вернет размер квадрата вписанного в область окна галереи фото по макетам.
Expand Down

0 comments on commit 2390022

Please sign in to comment.