Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/tmpz 775 build button for aduio naration #3996

Merged
merged 59 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
5d09508
feat/TMPZ-777-audio-player-mobile
dbuljanNewsUk Nov 15, 2024
fd71256
feat/TMPZ-777-audio-player-working-player
dbuljanNewsUk Nov 16, 2024
8033ea5
feat/TMPZ-777-audio-player-working-player
dbuljanNewsUk Nov 16, 2024
e85ad64
feat/TMPZ-777-audio-player
dbuljanNewsUk Nov 19, 2024
2535894
feat/TMPZ-777-audio-player-lin-sht
dbuljanNewsUk Nov 19, 2024
4968d1a
feat(TMPZ-775): created audio playe button
josipVuko Nov 20, 2024
4c5515a
Merge branch 'feat/TMPZ-777-audio-player' into feat/TMPZ-775-build_bu…
josipVuko Nov 20, 2024
e85f570
feat/TMPZ-777-audio-player-update-icons-from-master
dbuljanNewsUk Nov 20, 2024
39c7817
Merge branch 'master' into feat/TMPZ-777-audio-player
dbuljanNewsUk Nov 21, 2024
786dea4
feat/TMPZ-777-audio-player-icons
dbuljanNewsUk Nov 21, 2024
caf54b0
feat/TMPZ-777-audio-player-icons
dbuljanNewsUk Nov 21, 2024
4e21301
feat/TMPZ-777-audio-player-tests
dbuljanNewsUk Nov 21, 2024
6133478
feat(TMPZ-775): added imperative handle for audio player
josipVuko Nov 21, 2024
77bc1ea
feat/TMPZ-777-audio-player-tests
dbuljanNewsUk Nov 21, 2024
2d102c8
feat/TMPZ-777-audio-player-tests
dbuljanNewsUk Nov 21, 2024
22db637
feat(TMPZ-775): minor adjustments
josipVuko Nov 21, 2024
c6b3614
feat/TMPZ-777-audio-player-tests
dbuljanNewsUk Nov 21, 2024
bf060fa
feat/TMPZ-777-audio-player-tests
dbuljanNewsUk Nov 21, 2024
fd19129
feat/TMPZ-777-audio-player-tests
dbuljanNewsUk Nov 21, 2024
7d3de68
feat/TMPZ-777-audio-player-tests
dbuljanNewsUk Nov 21, 2024
36be192
feat/TMPZ-777-audio-player-no-test-cus-of-bad-and-outdated-env
dbuljanNewsUk Nov 21, 2024
45f85c9
feat/TMPZ-777-audio-player-no-test-cus-of-bad-and-outdated-env
dbuljanNewsUk Nov 21, 2024
523ad1a
feat/TMPZ-777-audio-player-no-test-audio
dbuljanNewsUk Nov 21, 2024
fffa567
feat/TMPZ-777-audio-player-no-test-audio
dbuljanNewsUk Nov 21, 2024
ef3b742
feat/TMPZ-777-audio-player-no-test-audio
dbuljanNewsUk Nov 21, 2024
3948a82
feat/TMPZ-777-audio-player-no-test-audio
dbuljanNewsUk Nov 21, 2024
85a38ff
feat/TMPZ-777-audio-player-no-test-audio
dbuljanNewsUk Nov 21, 2024
6234925
feat/TMPZ-777-audio-player-no-test-audio
dbuljanNewsUk Nov 21, 2024
a7680e6
feat/TMPZ-777-audio-player-no-test-audio
dbuljanNewsUk Nov 21, 2024
4ce9226
feat/TMPZ-777-audio-player-no-test-audio
dbuljanNewsUk Nov 22, 2024
6397c98
feat(TMPZ-775): updated new icons
josipVuko Nov 22, 2024
98114a7
feat/TMPZ-777-audio-player-components-fix
dbuljanNewsUk Nov 22, 2024
5258af2
feat/TMPZ-777-audio-player-components-fix-remove-old-player
dbuljanNewsUk Nov 22, 2024
a22d716
Merge branch 'master' into feat/TMPZ-777-audio-player
dbuljanNewsUk Nov 22, 2024
8badd22
feat/TMPZ-777-audio-player-with-tests
dbuljanNewsUk Nov 22, 2024
57b1fbc
feat/TMPZ-777-audio-player-with-tests
dbuljanNewsUk Nov 22, 2024
6ede200
feat/TMPZ-777-audio-player-with-tests
dbuljanNewsUk Nov 22, 2024
d7a37b6
feat/TMPZ-777-audio-player-with-tests
dbuljanNewsUk Nov 22, 2024
3b1597a
feat/TMPZ-777-audio-player-analyitcs-test
dbuljanNewsUk Nov 25, 2024
5318ceb
temporary reduction in thresholds code is in transition
adamosborne-tnl Nov 25, 2024
59c415e
feat/TMPZ-777-audio-player-using-ts-styles
dbuljanNewsUk Nov 25, 2024
da44476
feat/TMPZ-777-audio-player-new-tests
dbuljanNewsUk Nov 25, 2024
0d55227
feat/TMPZ-777-audio-player-new-tests
dbuljanNewsUk Nov 25, 2024
8f0b60d
feat/TMPZ-777-audio-player-new-tests
dbuljanNewsUk Nov 25, 2024
9f02d41
feat/TMPZ-777-audio-player-new-tests
dbuljanNewsUk Nov 25, 2024
2c2dca1
feat(TMPZ-775): connected with new audio-player
josipVuko Nov 26, 2024
3a8e54a
feat/TMPZ-775-build_button_for_aduio_naration-resolve-audio-branch-re…
dbuljanNewsUk Nov 26, 2024
4d0ebfa
feat/TMPZ-775-build_button_for_aduio_naration-resolve-audio-branch-re…
dbuljanNewsUk Nov 26, 2024
aa15049
feat/TMPZ-775-build_button_for_aduio_naration-resolve-audio-branch-re…
dbuljanNewsUk Nov 26, 2024
ce086e2
feat/TMPZ-775-build_button_for_aduio_naration-writing-helping-with-test
dbuljanNewsUk Nov 26, 2024
09333b8
feat/TMPZ-775-build_button_for_aduio_naration-writing-helping-with-test
dbuljanNewsUk Nov 26, 2024
e3cc592
feat(TMPZ-775): adjusted styles, adjusted tests
josipVuko Dec 2, 2024
db293e0
feat/TMPZ-775-build_button_for_aduio_naration-test-fix
dbuljanNewsUk Dec 2, 2024
c73a9f4
feat/TMPZ-775-build_button_for_aduio_naration-test-fix
dbuljanNewsUk Dec 2, 2024
826c981
Merge branch 'master' into feat/TMPZ-775-build_button_for_aduio_naration
josipVuko Dec 3, 2024
12ef98c
feat(TMPZ-775): removed unused prop from test
josipVuko Dec 3, 2024
8ce8aa9
feat(TMPZ-775): adjusted tests
josipVuko Dec 3, 2024
10cad31
feat/TMPZ-775-build_button_for_aduio_naration
dbuljanNewsUk Dec 3, 2024
086586f
feat(TMPZ-775): manualy adjusted snap
josipVuko Dec 3, 2024
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
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"devDependencies": ["**/storybook/**"],
"optionalDependencies": false
}
]
],
"@typescript-eslint/prefer-nullish-coalescing": "off"
},
"settings": {
"import/resolver": {
Expand Down
6 changes: 3 additions & 3 deletions packages/ts-components/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ const buildConfig = dir => {
],
coverageThreshold: {
global: {
statements: 95.9,
statements: 95.5,
branches: 83,
lines: 96,
functions: 96
lines: 95.5,
functions: 94.49
}
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import { ArticleAudio } from './ArticleAudio';

storiesOf('Typescript Component/Article Audio', module).add(
'Article Audio',
() => {
return (
<div style={{ padding: '10px' }}>
<ArticleAudio audioSrc="https://www.kozco.com/tech/LRMonoPhase4.mp3" />
</div>
);
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React, { FC, useState, useRef } from 'react';
import { AudioButton } from './styles';
import { AudioPlayer } from '../audio-player-components/AudioPlayer';
import {
PlayIcon,
PauseIcon,
} from '@times-components/icons';
export interface ArticleAudioProps {
audioSrc: string;
}

export const ArticleAudio: FC<ArticleAudioProps> = ({ audioSrc }) => {
const [audioState, setAudioState] = useState<
'not-started' | 'playing' | 'paused'
>('not-started');
const [isAudioPlayerVisible, setisAudioPlayerVisible] = useState<boolean>(
false
);
const [duration, setDuration] = useState<string | null>(null);

const audioRef = useRef<HTMLAudioElement | null>(null);

const handleLoadedMetadata = () => {
if (audioRef.current) {
const totalSeconds = Math.floor(audioRef.current.duration);
const minutes = Math.floor(totalSeconds / 60) + 1;
setDuration(`${minutes}`);
}
};

const handlePlayPause = () => {
setisAudioPlayerVisible(true);

if (audioState === 'playing') {
setAudioState('paused');
} else {
setAudioState('playing');
}
};

return (
<div>
<audio
ref={audioRef}
src={audioSrc}
onLoadedMetadata={handleLoadedMetadata}
preload="metadata"
/>
<AudioButton
onClick={handlePlayPause}
style={{
backgroundColor: audioState !== 'not-started' ? '#1D1D1B' : 'unset',
color: audioState === 'not-started' ? '#333' : '#fff'
}}
>
{audioState === 'playing' ? (
<>
<PauseIcon width={16} height={16} fill="#fff"/> Playing
</>
) : audioState === 'paused' ? (
<>
<PlayIcon width={16} height={16} fill="#fff" /> Paused
</>
) : (
<>
<PlayIcon width={16} height={16} /> Listen
</>
)}
<span
style={{
color: audioState === 'not-started' ? '#696969' : '#fff'
}}
>
{' '}
{duration} min
</span>
</AudioButton>
{isAudioPlayerVisible && (
<AudioPlayer
src={audioSrc}
isPlayingProp={audioState === 'playing'}
onPlay={() => setAudioState('playing')}
onPause={() => setAudioState('paused')}
onEnded={() => setAudioState('not-started')}
/>
)}
</div>
);
};

export default ArticleAudio;
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import React from 'react';
import { render, fireEvent, act } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { ArticleAudio } from '../ArticleAudio';

jest.mock('../styles', () => ({
AudioButton: ({ children, onClick, style }: any) => (
<button data-testid="audio-button" onClick={onClick} style={style}>
{children}
</button>
)
}));

jest.mock('@times-components/icons', () => ({
__esModule: true,
PlayIcon: ({ color }: any) => (
<svg data-testid="play-icon" style={{ color: color || '#333' }} />
),
PauseIcon: ({ color }: any) => (
<svg data-testid="pause-icon" style={{ color: color || '#333' }} />
)
}));

jest.mock('../../audio-player-components/AudioPlayer', () => ({
AudioPlayer: ({
onPlay,
onPause,
onEnded
}: any) => (
<div data-testid="audio-player">
<button onClick={onPlay}>Play</button>
<button onClick={onPause}>Pause</button>
<button onClick={onEnded}>Ended</button>
</div>
)
}));

describe('ArticleAudio', () => {
beforeEach(() => {
// Mock the duration of the audio element
Object.defineProperty(HTMLMediaElement.prototype, 'duration', {
get(): number {
return 120; // 2 minutes
}
});
});

afterEach(() => {
jest.clearAllMocks();
});

test('renders audio button with correct initial state', () => {
const { getByTestId, getByText, container } = render(
<ArticleAudio audioSrc="https://www.kozco.com/tech/LRMonoPhase4.mp3" />
);

// Trigger the 'loadedmetadata' event to set the duration
const audio = container.querySelector('audio') as HTMLAudioElement;
act(() => {
fireEvent.loadedMetadata(audio);
});

const audioButton = getByTestId('audio-button');
expect(audioButton).toBeInTheDocument();

expect(audioButton.style.backgroundColor).toBe('');
expect(audioButton).toHaveStyle('color: #333');

// The initial state should display 'Listen' and the duration
expect(getByText('Listen')).toBeInTheDocument();
expect(getByText('3 min')).toBeInTheDocument();

// Since audioState is 'not-started', duration color should be '#696969'
const durationSpan = getByText('3 min');
expect(durationSpan).toHaveStyle('color: #696969');
});

test('handles play and pause', () => {
const { getByTestId, getByText, container } = render(
<ArticleAudio audioSrc="https://www.kozco.com/tech/LRMonoPhase4.mp3" />
);

// Trigger the 'loadedmetadata' event to set the duration
const audio = container.querySelector('audio') as HTMLAudioElement;
act(() => {
fireEvent.loadedMetadata(audio);
});

const audioButton = getByTestId('audio-button');

// Simulate clicking the play button
fireEvent.click(audioButton);

// Now, audioState should be 'playing'
expect(audioButton).toHaveStyle('background-color: #1D1D1B');
expect(audioButton).toHaveStyle('color: #fff');
expect(getByText('Playing')).toBeInTheDocument();

// Since audioState is 'playing', duration color should be '#fff'
const durationSpan = getByText('3 min');
expect(durationSpan).toHaveStyle('color: #fff');

// Simulate clicking the pause button
fireEvent.click(audioButton);

expect(getByText('Paused')).toBeInTheDocument();
expect(audioButton).toHaveStyle('background-color: #1D1D1B');
expect(audioButton).toHaveStyle('color: #fff');

// Simulate clicking the play button again
fireEvent.click(audioButton);

expect(getByText('Playing')).toBeInTheDocument();
});

test('shows AudioPlayer when audio is played', () => {
const { getByTestId, queryByTestId, container } = render(
<ArticleAudio audioSrc="https://www.kozco.com/tech/LRMonoPhase4.mp3" />
);

// Trigger the 'loadedmetadata' event to set the duration
const audio = container.querySelector('audio') as HTMLAudioElement;
act(() => {
fireEvent.loadedMetadata(audio);
});

expect(queryByTestId('audio-player')).not.toBeInTheDocument();

const audioButton = getByTestId('audio-button');
fireEvent.click(audioButton);

expect(getByTestId('audio-player')).toBeInTheDocument();
});

test('updates audioState based on AudioPlayer callbacks', () => {
const { getByTestId, getByText, container } = render(
<ArticleAudio audioSrc="https://www.kozco.com/tech/LRMonoPhase4.mp3" />
);

// Trigger the 'loadedmetadata' event to set the duration
const audio = container.querySelector('audio') as HTMLAudioElement;
act(() => {
fireEvent.loadedMetadata(audio);
});

const audioButton = getByTestId('audio-button');
fireEvent.click(audioButton); // Start playing

expect(getByText('Playing')).toBeInTheDocument();

const pauseButton = getByText('Pause');
fireEvent.click(pauseButton);

expect(getByText('Paused')).toBeInTheDocument();

const playButton = getByText('Play');
fireEvent.click(playButton);

expect(getByText('Playing')).toBeInTheDocument();

const endedButton = getByText('Ended');
fireEvent.click(endedButton);

expect(getByText('Listen')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from 'react';
import { render } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import 'jest-styled-components';
import { AudioButton } from '../styles';

describe('AudioButton', () => {
test('renders correctly with default styles', () => {
const { getByTestId } = render(
<AudioButton data-testid="audio-button">Test Button</AudioButton>
);

const button = getByTestId('audio-button');

expect(button).toHaveStyleRule('background-color', 'unset');
expect(button).toHaveStyleRule('border-radius', '0');
expect(button).toHaveStyleRule('padding', '7px 11px');
expect(button).toHaveStyleRule('border', '1px solid #333333');
expect(button).toHaveStyleRule('display', 'flex');
expect(button).toHaveStyleRule('align-items', 'center');
expect(button).toHaveStyleRule('color', '#333333');
expect(button).toHaveStyleRule('font-family', 'Roboto');
expect(button).toHaveStyleRule('font-weight', '500');
expect(button).toHaveStyleRule('font-size', '14px');
expect(button).toHaveStyleRule('line-height', '18px');
});

test('renders svg child with correct styles', () => {
const { getByTestId } = render(
<AudioButton data-testid="audio-button">
<svg data-testid="icon" />
</AudioButton>
);

const button = getByTestId('audio-button');

expect(button).toHaveStyleRule('margin-right', '8px', {
modifier: 'svg'
});
});

test('renders span child with correct styles', () => {
const { getByTestId } = render(
<AudioButton data-testid="audio-button">
<span data-testid="span">Test Span</span>
</AudioButton>
);

const button = getByTestId('audio-button');

expect(button).toHaveStyleRule('margin-left', '4px', {
modifier: 'span'
});
expect(button).toHaveStyleRule('font-size', '12px', {
modifier: 'span'
});
expect(button).toHaveStyleRule('color', '#696969', {
modifier: 'span'
});
});
});
26 changes: 26 additions & 0 deletions packages/ts-components/src/components/article-audio/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import styled from 'styled-components';
import { colours } from '@times-components/ts-styleguide';

export const AudioButton = styled.button`
background-color: unset;
border-radius: 0;
padding: 7px 11px;
border: 1px solid ${colours.functional.primary};
display: flex;
align-items: center;
color: ${colours.functional.primary};
font-family: Roboto;
font-weight: 500;
font-size: 14px;
line-height: 18px;

svg {
margin-right: 8px;
}

span {
margin-left: 4px;
font-size: 12px;
color:${colours.functional.secondary};
}
`;
Loading