Skip to content

Commit b919c27

Browse files
committed
feat: display pdf files
1 parent 0d9ad78 commit b919c27

File tree

3 files changed

+192
-1
lines changed

3 files changed

+192
-1
lines changed

src/components/phase/PhaseItem.js

+28-1
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,46 @@ import {
99
APPLICATION,
1010
IFRAME,
1111
DEFAULT_PROTOCOL,
12+
PDF,
1213
} from '../../config/constants';
1314
import PhaseText from './PhaseText';
1415
import PhaseImage from './PhaseImage';
1516
import PhaseVideo from './PhaseVideo';
1617
import PhaseApp from './PhaseApp';
18+
import PhasePdf from './PhasePdf';
1719

1820
// prop types gets confused when dealing with helper renderers
1921
// eslint-disable-next-line react/prop-types
20-
const renderResource = ({ id, mimeType, content, asset, url, name }) => {
22+
const renderResource = ({
23+
id,
24+
mimeType,
25+
content,
26+
asset,
27+
url,
28+
name,
29+
spaceId,
30+
phaseId,
31+
appInstance,
32+
}) => {
2133
if (mimeType === TEXT) {
2234
return <PhaseText key={id} id={id} content={content} />;
2335
}
2436

37+
if (mimeType === PDF) {
38+
return (
39+
<PhasePdf
40+
key={id}
41+
id={id}
42+
url={url}
43+
asset={asset}
44+
name={name}
45+
spaceId={spaceId}
46+
phaseId={phaseId}
47+
appInstance={appInstance}
48+
/>
49+
);
50+
}
51+
2552
if (IMAGE.test(mimeType)) {
2653
return <PhaseImage key={id} id={id} url={url} asset={asset} name={name} />;
2754
}

src/components/phase/PhasePdf.js

+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
import { connect } from 'react-redux';
4+
import { Resizable } from 're-resizable';
5+
import SwapVerticalCircleIcon from '@material-ui/icons/SwapVerticalCircle';
6+
import PlayCircleFilledIcon from '@material-ui/icons/PlayCircleFilled';
7+
import './PhaseApp.css';
8+
import { getHeight, setHeight } from '../../actions/layout';
9+
import {
10+
DEFAULT_APP_HEIGHT,
11+
MAX_APP_HEIGHT,
12+
MIN_APP_HEIGHT,
13+
} from '../../config/layout';
14+
import { buildPhaseAppName } from '../../config/selectors';
15+
16+
const style = {
17+
marginTop: '2rem',
18+
marginBottom: '2rem',
19+
};
20+
21+
const iconStyle = { background: 'white', borderRadius: '12px' };
22+
23+
class PhasePdf extends Component {
24+
static propTypes = {
25+
url: PropTypes.string,
26+
asset: PropTypes.string,
27+
name: PropTypes.string,
28+
folder: PropTypes.string.isRequired,
29+
id: PropTypes.string.isRequired,
30+
};
31+
32+
static defaultProps = {
33+
url: null,
34+
asset: null,
35+
name: 'Pdf',
36+
};
37+
38+
state = {
39+
height: DEFAULT_APP_HEIGHT,
40+
};
41+
42+
constructor(props) {
43+
super(props);
44+
const { id } = props;
45+
this.state.height = getHeight(id) || DEFAULT_APP_HEIGHT;
46+
}
47+
48+
componentDidMount() {
49+
window.addEventListener('message', this.handleReceiveMessage);
50+
}
51+
52+
componentWillUnmount() {
53+
window.removeEventListener('message', this.handleReceiveMessage);
54+
}
55+
56+
renderHandleIcon = () => {
57+
const { height } = this.state;
58+
if (height >= MAX_APP_HEIGHT) {
59+
return (
60+
<PlayCircleFilledIcon
61+
color="primary"
62+
style={{
63+
...iconStyle,
64+
transform: 'rotate(-90deg)',
65+
}}
66+
/>
67+
);
68+
}
69+
if (height <= MIN_APP_HEIGHT) {
70+
return (
71+
<PlayCircleFilledIcon
72+
color="primary"
73+
style={{
74+
...iconStyle,
75+
transform: 'rotate(90deg)',
76+
}}
77+
/>
78+
);
79+
}
80+
return <SwapVerticalCircleIcon color="primary" style={iconStyle} />;
81+
};
82+
83+
render() {
84+
const { url, asset, name, id, folder } = this.props;
85+
86+
// replace 'download' by 'raw' to display the resource
87+
// when the space is not saved
88+
let uri = url.replace('download', 'raw');
89+
if (asset) {
90+
// assets with absolute paths are usually for testing
91+
if (asset.startsWith('/')) {
92+
uri = `file://${asset}`;
93+
} else {
94+
uri = `file://${folder}/${asset}`;
95+
}
96+
}
97+
98+
// get style
99+
const { height } = this.state;
100+
return (
101+
<Resizable
102+
style={style}
103+
defaultSize={{
104+
height,
105+
width: 'auto',
106+
}}
107+
minHeight={MIN_APP_HEIGHT}
108+
maxHeight={MAX_APP_HEIGHT}
109+
enable={{
110+
top: false,
111+
right: false,
112+
bottom: true,
113+
left: false,
114+
topRight: false,
115+
bottomRight: false,
116+
bottomLeft: false,
117+
topLeft: false,
118+
}}
119+
onResizeStop={(e, direction, ref, d) => {
120+
const { height: oldHeight } = this.state;
121+
const newHeight = oldHeight + d.height;
122+
this.setState({
123+
height: newHeight,
124+
});
125+
setHeight(id, newHeight);
126+
}}
127+
handleComponent={{
128+
bottom: (
129+
<div
130+
style={{
131+
width: '100%',
132+
textAlign: 'center',
133+
marginTop: '-8px',
134+
}}
135+
>
136+
{this.renderHandleIcon()}
137+
</div>
138+
),
139+
}}
140+
>
141+
<div style={{ height: '100%', overflowY: 'hidden' }}>
142+
<iframe
143+
title={name}
144+
className="Pdf"
145+
name={buildPhaseAppName(id)}
146+
src={uri}
147+
ref={(c) => {
148+
this.iframe = c;
149+
}}
150+
/>
151+
</div>
152+
</Resizable>
153+
);
154+
}
155+
}
156+
157+
const mapStateToProps = ({ authentication }) => ({
158+
folder: authentication.getIn(['current', 'folder']),
159+
});
160+
161+
const ConnectedComponent = connect(mapStateToProps)(PhasePdf);
162+
163+
export default ConnectedComponent;

src/config/constants.js

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export const PRODUCT_NAME = 'Graasp';
22

33
// phase item types
44
export const TEXT = 'text/html';
5+
export const PDF = 'application/pdf';
56
export const VIDEO = new RegExp('video/*');
67
export const IMAGE = new RegExp('image/*');
78
export const RESOURCE = 'Resource';

0 commit comments

Comments
 (0)