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

Fix dynamic zone reorder input file and date updates #5488

Merged
merged 6 commits into from
Mar 12, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/strapi-admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
"@babel/preset-env": "^7.4.3",
"@babel/preset-react": "^7.0.0",
"@babel/runtime": "^7.4.3",
"@buffetjs/core": "3.0.0",
"@buffetjs/custom": "3.0.0",
"@buffetjs/core": "3.0.1",
"@buffetjs/custom": "3.0.1",
"@buffetjs/hooks": "3.0.0",
"@buffetjs/icons": "3.0.0",
"@buffetjs/styles": "3.0.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react';

const IconUpload = () => {
return (
<svg
width="105"
height="84"
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
style={{ margin: 'auto' }}
>
<defs>
<rect id="a" y="1.354" width="77.333" height="62.292" rx="4" />
<rect id="b" y="1.354" width="77.333" height="62.292" rx="4" />
</defs>
<g fill="none" fillRule="evenodd" opacity=".05">
<g transform="rotate(-12 75.8 12.214)">
<use fill="#FAFAFB" xlinkHref="#a" />
<rect stroke="#979797" x=".5" y="1.854" width="76.333" height="61.292" rx="4" />
</g>
<path
d="M74.255 36.05l3.942 18.544-57.385 12.198-1.689-7.948L29.35 42.827l7.928 5.236 16.363-25.628L74.255 36.05zM71.974 6.078l-65.21 13.86a1.272 1.272 0 0 0-.833.589 1.311 1.311 0 0 0-.19 1.014l10.7 50.334c.076.358.27.641.584.849.314.207.648.273 1.001.198l65.21-13.86c.353-.076.63-.272.833-.589.203-.317.266-.655.19-1.014l-10.7-50.334a1.311 1.311 0 0 0-.584-.849 1.272 1.272 0 0 0-1.001-.198zm6.803-.061L89.475 56.35c.387 1.822.08 3.517-.921 5.085-1.001 1.568-2.399 2.543-4.192 2.924L19.152 78.22c-1.793.381-3.466.06-5.019-.966-1.552-1.026-2.522-2.45-2.91-4.27L.525 22.65c-.387-1.822-.08-3.517.921-5.085 1.001-1.568 2.399-2.543 4.192-2.924L70.848.78c1.793-.381 3.466-.06 5.019.966 1.552 1.026 2.522 2.45 2.91 4.27z"
fill="#333740"
fillRule="nonzero"
/>
<g>
<g transform="rotate(15 7.723 110.16)">
<use fill="#FAFAFB" xlinkHref="#b" />
<rect stroke="#979797" x=".5" y="1.854" width="76.333" height="61.292" rx="4" />
</g>
<path
d="M49.626 26.969c-.584 2.18-1.832 3.832-3.744 4.955-1.911 1.123-3.94 1.398-6.086.822-2.147-.575-3.767-1.827-4.86-3.755-1.094-1.929-1.35-3.983-.765-6.163.584-2.18 1.832-3.832 3.743-4.955 1.912-1.124 3.94-1.398 6.087-.823s3.767 1.827 4.86 3.756c1.094 1.928 1.349 3.983.765 6.163zm37.007 26.74L81.726 72.02 25.058 56.836l2.103-7.848 16.384-9.63 4.687 8.266 26.214-15.406 12.187 21.49zm11.574-27.742L33.812 8.712a1.272 1.272 0 0 0-1.01.146c-.324.19-.533.463-.628.817L18.855 59.38c-.095.354-.05.695.136 1.022.186.327.453.538.802.631l64.395 17.255c.349.093.685.045 1.01-.146.324-.19.533-.463.628-.817L99.145 27.62c.095-.354.05-.695-.136-1.022a1.272 1.272 0 0 0-.802-.631zm6.09 3.033l-13.32 49.705c-.481 1.799-1.524 3.17-3.128 4.112-1.605.943-3.292 1.177-5.063.703L18.39 66.265c-1.771-.474-3.115-1.52-4.033-3.14-.918-1.618-1.136-3.327-.654-5.125L27.022 8.295c.482-1.799 1.525-3.17 3.13-4.112 1.604-.943 3.291-1.177 5.062-.703L99.61 20.735c1.771.474 3.115 1.52 4.033 3.14.918 1.618 1.136 3.327.654 5.125z"
fill="#333740"
fillRule="nonzero"
/>
</g>
</g>
</svg>
);
};

export default IconUpload;
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import styled from 'styled-components';

const Wrapper = styled.div`
position: relative;
width: 100%;
height: 162px;
z-index: 1 !important;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
text-align: center;
vertical-align: middle;
background-color: #333740;
background-position: center;
background-repeat: no-repeat !important;
white-space: nowrap;

> img {
position: absolute;
top: 0;
left: 0;
right: 0;
margin: auto;
max-width: 100%;
max-height: 100%;
z-index: 3;
}

.fileIcon {
display: flex;
flex-direction: column;
height: 100%;
color: #fff;
justify-content: space-around;
font-size: 30px;
svg {
margin: auto;
}
}

.overlay {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
height: 162px;
z-index: 999;
background: #333740;
opacity: 0.9;
}
`;

export default Wrapper;
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
/**
*
*
* ImgPreview
*
*/

/* eslint-disable no-console */
import React from 'react';
import PropTypes from 'prop-types';
import { get, has, isArray, isEmpty, startsWith, size } from 'lodash';
import cn from 'classnames';
/* eslint-disable */

import ImgPreviewArrow from '../ImgPreviewArrow';
import ImgPreviewHint from '../ImgPreviewHint';
import IconUpload from './IconUpload';
import Wrapper from './Wrapper';

/* eslint-disable react/no-unused-state */
class ImgPreview extends React.Component {
state = {
imgURL: '',
isDraging: false,
isOver: false,
isOverArrow: false,
isImg: false,
isInitValue: false,
};

componentDidMount() {
// We don't need the generateImgURL function here since the compo will
// always have an init value here
const file = this.props.multiple
? get(this.props.files, ['0', 'name'], '')
: get(this.props.files, 'name');
this.setState({
imgURL: get(this.props.files, ['0', 'url'], '') || get(this.props.files, 'url', ''),
isImg: this.isPictureType(file),
});
}

UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.isUploading !== this.props.isUploading) {
const lastFile = this.props.multiple
? nextProps.files.slice(-1)[0]
: nextProps.files[0] || nextProps.files;
this.generateImgURL(lastFile);

if (this.props.multiple) {
this.updateFilePosition(nextProps.files.length - 1);
}
}
// Update the preview or slide pictures or init the component
if (
nextProps.didDeleteFile !== this.props.didDeleteFile ||
nextProps.position !== this.props.position ||
(size(nextProps.files) !== size(this.props.files) && !this.state.isInitValue)
) {
const file = nextProps.files[nextProps.position] || nextProps.files || '';
this.generateImgURL(file);

if (!this.state.isInitValue) {
this.setState({ isInitValue: true });
}
}

if (isEmpty(nextProps.files)) {
this.setState({ isImg: false, imgURL: null });
}

if (nextProps.files !== this.props.files) {
const file = nextProps.files[nextProps.position] || nextProps.files || '';
this.generateImgURL(file);

if (!this.state.isInitValue) {
this.setState({ isInitValue: true });
}
}
}

componentDidCatch(error, info) {
console.log('An error occured in ImgPreview', info);
}

getFileType = fileName => fileName.split('.').slice(-1)[0];

/**
* [generateImgURL description]
* @param {FileList} files
* @return {URL}
*/
generateImgURL = file => {
if (this.isPictureType(file.name) && !has(file, 'url')) {
const reader = new FileReader();
reader.onloadend = () => {
this.setState({
imgURL: reader.result,
isImg: true,
});
};

reader.readAsDataURL(file);
} else if (has(file, 'url')) {
const isImg = this.isPictureType(file.name);
const imgURL = file.url[0] === '/' ? `${strapi.backendURL}${file.url}` : file.url;

this.setState({ isImg, imgURL });
} else {
this.setState({ isImg: false, imgURL: file.name });
}
};

handleClick = type => {
const { files, position } = this.props;
let file; // eslint-disable-line no-unused-vars
let nextPosition;

switch (type) {
case 'right':
file = files[position + 1] || files[0];
nextPosition = files[position + 1] ? position + 1 : 0;
break;
case 'left':
file = files[position - 1] || files[files.length - 1];
nextPosition = files[position - 1] ? position - 1 : files.length - 1;
break;
default:
// Do nothing
}

// Update the parent position
this.updateFilePosition(nextPosition);
};

handleDragEnter = e => {
e.preventDefault();
e.stopPropagation();
this.setState({ isDraging: true });
};

handleDragLeave = e => {
e.preventDefault();
e.stopPropagation();
this.setState({ isDraging: false });
};

handleDragOver = e => {
e.preventDefault();
e.stopPropagation();
};

handleDrop = e => {
this.setState({ isDraging: false });
this.props.onDrop(e);
};

// TODO change logic to depend on the type
isPictureType = fileName => /\.(jpe?g|png|gif)$/i.test(fileName);

updateFilePosition = newPosition => {
this.props.updateFilePosition(newPosition);
};

renderContent = () => {
const fileType = this.getFileType(this.state.imgURL);

if (this.state.isImg) {
const imgURL = startsWith(this.state.imgURL, '/')
? `${strapi.backendURL}${this.state.imgURL}`
: this.state.imgURL;

return <img src={imgURL} alt="" />;
}

return (
<div className="fileIcon" onDrop={this.handleDrop}>
<i className={`far fa-file-${fileType}`} />
</div>
);
};

render() {
const { files, onBrowseClick } = this.props;
const { imgURL } = this.state;

const containerStyle = isEmpty(imgURL)
? {
display: 'flex',
zIndex: 9999,
}
: {};

return (
<Wrapper
onDragOver={this.handleDragOver}
onDragEnter={this.handleDragEnter}
style={containerStyle}
>
{isEmpty(imgURL) && <IconUpload />}
<div
className={cn(this.state.isDraging && 'overlay')}
onDragLeave={this.handleDragLeave}
onDragOver={this.handleDragOver}
onDrop={this.handleDrop}
/>
<ImgPreviewHint
displayHint={isEmpty(files)}
onClick={onBrowseClick}
onDrop={this.handleDrop}
showWhiteHint={this.state.isDraging || isEmpty(files)}
/>
{!isEmpty(imgURL) && this.renderContent()}
<ImgPreviewArrow
enable={isArray(files) && size(files) > 1}
onClick={this.handleClick}
onMouseEnter={() => this.setState({ isOverArrow: true })}
onMouseLeave={() => this.setState({ isOverArrow: false })}
show={isArray(files) && size(files) > 1}
type="right"
/>
<ImgPreviewArrow
enable={isArray(files) && size(files) > 1}
onClick={this.handleClick}
onMouseEnter={() => this.setState({ isOverArrow: true })}
onMouseLeave={() => this.setState({ isOverArrow: false })}
show={isArray(files) && size(files) > 1}
/>
</Wrapper>
);
}
}

ImgPreview.defaultProps = {
didDeleteFile: false,
files: [],
isUploading: false,
multiple: false,
onBrowseClick: () => {},
onDrop: () => {},
position: 0,
updateFilePosition: () => {},
};

ImgPreview.propTypes = {
didDeleteFile: PropTypes.bool,
files: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
isUploading: PropTypes.bool,
multiple: PropTypes.bool,
onBrowseClick: PropTypes.func,
onDrop: PropTypes.func,
position: PropTypes.number,
updateFilePosition: PropTypes.func,
};

export default ImgPreview;