Vulcan/packages/vulcan-core/lib/modules/components/Card.jsx

190 lines
5.3 KiB
React
Raw Normal View History

2017-07-25 18:39:26 +09:00
import { registerComponent, Components } from 'meteor/vulcan:lib';
2017-07-26 07:30:58 +09:00
import { intlShape, FormattedMessage } from 'meteor/vulcan:i18n';
2017-07-25 18:39:26 +09:00
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import moment from 'moment';
import { Link } from 'react-router';
2017-07-25 18:39:26 +09:00
const getLabel = (field, fieldName, collection, intl) => {
const schema = collection && collection.simpleSchema()._schema;
const fieldSchema = schema && schema[fieldName];
if (fieldSchema) {
return intl.formatMessage({id: `${collection._name}.${fieldName}`, defaultMessage: fieldSchema.label});
} else {
return fieldName;
}
2017-07-25 18:39:26 +09:00
}
const getTypeName = (field, fieldName, collection) => {
const schema = collection && collection.simpleSchema()._schema;
const fieldSchema = schema && schema[fieldName];
if (fieldSchema) {
const type = fieldSchema.type.singleType;
const typeName = typeof type === 'function' ? type.name : type;
return typeName;
} else {
return typeof field;
}
2017-07-25 18:39:26 +09:00
}
const parseImageUrl = value => {
const isImage = ['.png', '.jpg', '.gif'].indexOf(value.substr(-4)) !== -1 || ['.webp', '.jpeg' ].indexOf(value.substr(-5)) !== -1;
return isImage ?
2018-01-11 21:30:34 +09:00
<img style={{width: '100%', minWidth: 80, maxWidth: 200, display: 'block'}} src={value} alt={value}/> :
2018-02-24 18:58:14 +09:00
parseUrl(value);
}
const parseUrl = value => {
return value.slice(0,4) === 'http' ? <a href={value} target="_blank"><LimitedString string={value}/></a> : <LimitedString string={value}/>;
2017-07-25 18:39:26 +09:00
}
const LimitedString = ({ string }) =>
<div>
{string.indexOf(' ') === -1 && string.length > 30 ?
<span title={string}>{string.substr(0,30)}</span> :
2018-02-24 18:58:14 +09:00
<span>{(string)}</span>
2017-07-25 18:39:26 +09:00
}
</div>
export const getFieldValue = (value, typeName) => {
2017-09-30 11:47:41 +09:00
if (typeof value === 'undefined' || value === null) {
2017-07-25 18:39:26 +09:00
return ''
}
// JSX element
if (React.isValidElement(value)) {
return value;
}
2017-07-25 18:39:26 +09:00
if (Array.isArray(value)) {
typeName = 'Array';
}
if (typeof typeName === 'undefined') {
typeName = typeof value;
}
2017-07-25 18:39:26 +09:00
switch (typeName) {
case 'Boolean':
case 'boolean':
case 'Number':
case 'number':
case 'SimpleSchema.Integer':
return <code>{value.toString()}</code>;
2017-07-25 18:39:26 +09:00
case 'Array':
return <ol>{value.map((item, index) => <li key={index}>{getFieldValue(item, typeof item)}</li>)}</ol>
case 'Object':
case 'object':
return getObject(value);
2017-07-25 18:39:26 +09:00
case 'Date':
return moment(new Date(value)).format('dddd, MMMM Do YYYY, h:mm:ss');
case 'String':
case 'string':
2017-07-25 18:39:26 +09:00
return parseImageUrl(value);
default:
return value.toString();
}
2017-07-25 18:39:26 +09:00
}
const getObject = object => {
if (object.__typename === 'User') {
const user = object;
return (
<div className="dashboard-user" style={{ whiteSpace: 'nowrap' }}>
<Components.Avatar size="small" user={user} link />
<Link to={user.pageUrl}>{user.displayName}</Link>
</div>
)
} else {
return (
<table className="table table-bordered">
<tbody>
{_.without(Object.keys(object), '__typename').map(key =>
<tr key={key}>
<td><strong>{key}</strong></td>
<td>{getFieldValue(object[key], typeof object[key])}</td>
</tr>
)}
</tbody>
</table>
)
}
}
2017-07-25 18:39:26 +09:00
const CardItem = ({label, value, typeName}) =>
<tr>
<td className="datacard-label"><strong>{label}</strong></td>
<td className="datacard-value">{getFieldValue(value, typeName)}</td>
2017-07-25 18:39:26 +09:00
</tr>
2017-07-26 07:30:58 +09:00
const CardEdit = (props, context) =>
2017-07-25 18:39:26 +09:00
<tr>
<td colSpan="2">
<Components.ModalTrigger label={context.intl.formatMessage({id: 'cards.edit'})} component={<Components.Button variant="info"><FormattedMessage id="cards.edit" /></Components.Button>}>
2017-07-25 18:39:26 +09:00
<CardEditForm {...props} />
</Components.ModalTrigger>
</td>
</tr>
2017-07-26 07:30:58 +09:00
CardEdit.contextTypes = { intl: intlShape };
2017-07-25 18:39:26 +09:00
const CardEditForm = ({ collection, document, closeModal }) =>
<Components.SmartForm
collection={collection}
documentId={document._id}
showRemove={true}
successCallback={document => {
closeModal();
}}
/>
const Card = ({title, className, collection, document, currentUser, fields, showEdit = true}, {intl}) => {
2017-07-25 18:39:26 +09:00
const fieldNames = fields ? fields : _.without(_.keys(document), '__typename');
const canEdit = showEdit && currentUser && collection && collection.options.mutations.update.check(currentUser, document);
2017-07-25 18:39:26 +09:00
return (
<div className={classNames(className, 'datacard', collection && `datacard-${collection._name}`)}>
{title && <div className="datacard-title">{title}</div>}
2017-07-25 18:39:26 +09:00
<table className="table table-bordered" style={{maxWidth: '100%'}}>
<tbody>
{canEdit ? <CardEdit collection={collection} document={document} /> : null}
{fieldNames.map((fieldName, index) =>
<CardItem key={index} value={document[fieldName]} typeName={getTypeName(document[fieldName], fieldName, collection)} label={getLabel(document[fieldName], fieldName, collection, intl)}/>
2017-07-25 18:39:26 +09:00
)}
</tbody>
</table>
</div>
);
};
Card.displayName = "Card";
Card.propTypes = {
className: PropTypes.string,
collection: PropTypes.object,
document: PropTypes.object,
currentUser: PropTypes.object,
fields: PropTypes.array,
2018-01-27 12:46:45 +09:00
showEdit: PropTypes.bool
}
2017-07-25 18:39:26 +09:00
Card.contextTypes = {
intl: intlShape
}
2018-01-26 16:32:26 -07:00
registerComponent('Card', Card);