Permalink
Browse files

feat(Service): Add custom service icon upload

  • Loading branch information...
adlk committed Jan 2, 2018
1 parent 150cfe7 commit 6b97e42537879be306cd2aaf95dd8aebf8655fcb
@@ -84,6 +84,14 @@ const messages = defineMessages({
id: 'settings.service.form.headlineGeneral',
defaultMessage: '!!!General',
},
iconDelete: {
id: 'settings.service.form.iconDelete',
defaultMessage: '!!!Delete',
},
iconUpload: {
id: 'settings.service.form.iconUpload',
defaultMessage: '!!!Drop your image, or click here',
},
});
@observer
@@ -223,14 +231,8 @@ export default class EditServiceForm extends Component {
</div>
<div className="settings__body">
<form onSubmit={e => this.submit(e)} id="form">
<div className="service-flex-grid">
<div className="service-name">
<Input field={form.$('name')} focus />
</div>
<div className="service-icon">
{/* <Input field={form.$('name')} focus /> */}
<ImageUpload field={form.$('customIcon')} />
</div>
<div className="service-name">
<Input field={form.$('name')} focus />
</div>
{(recipe.hasTeamId || recipe.hasCustomUrl) && (
<Tabs
@@ -275,32 +277,41 @@ export default class EditServiceForm extends Component {
)}
</Tabs>
)}
<div className="settings__options">
<div className="settings__settings-group">
<h3>{intl.formatMessage(messages.headlineNotifications)}</h3>
<Toggle field={form.$('isNotificationEnabled')} />
<Toggle field={form.$('isMuted')} />
<p className="settings__help">
{intl.formatMessage(messages.isMutedInfo)}
</p>
</div>
<div className="service-flex-grid">
<div className="settings__options">
<div className="settings__settings-group">
<h3>{intl.formatMessage(messages.headlineNotifications)}</h3>
<Toggle field={form.$('isNotificationEnabled')} />
<Toggle field={form.$('isMuted')} />
<p className="settings__help">
{intl.formatMessage(messages.isMutedInfo)}
</p>
</div>
<div className="settings__settings-group">
<h3>{intl.formatMessage(messages.headlineBadges)}</h3>
<Toggle field={form.$('isBadgeEnabled')} />
{recipe.hasIndirectMessages && form.$('isBadgeEnabled').value && (
<div>
<Toggle field={form.$('isIndirectMessageBadgeEnabled')} />
<p className="settings__help">
{intl.formatMessage(messages.indirectMessageInfo)}
</p>
</div>
)}
</div>
<div className="settings__settings-group">
<h3>{intl.formatMessage(messages.headlineBadges)}</h3>
<Toggle field={form.$('isBadgeEnabled')} />
{recipe.hasIndirectMessages && form.$('isBadgeEnabled').value && (
<div>
<Toggle field={form.$('isIndirectMessageBadgeEnabled')} />
<p className="settings__help">
{intl.formatMessage(messages.indirectMessageInfo)}
</p>
</div>
)}
</div>
<div className="settings__settings-group">
<h3>{intl.formatMessage(messages.headlineGeneral)}</h3>
<Toggle field={form.$('isEnabled')} />
<div className="settings__settings-group">
<h3>{intl.formatMessage(messages.headlineGeneral)}</h3>
<Toggle field={form.$('isEnabled')} />
</div>
</div>
<div className="service-icon">
<ImageUpload
field={form.$('customIcon')}
textDelete={intl.formatMessage(messages.iconDelete)}
textUpload={intl.formatMessage(messages.iconUpload)}
/>
</div>
</div>
{recipe.message && (
@@ -12,6 +12,8 @@ export default class ImageUpload extends Component {
field: PropTypes.instanceOf(Field).isRequired,
className: PropTypes.string,
multiple: PropTypes.bool,
textDelete: PropTypes.string.isRequired,
textUpload: PropTypes.string.isRequired,
};
static defaultProps = {
@@ -39,56 +41,63 @@ export default class ImageUpload extends Component {
field,
className,
multiple,
textDelete,
textUpload,
} = this.props;
const cssClasses = classnames({
'franz-form__button': true,
'image-upload__dropzone': true,
[`${className}`]: className,
});
return (
<div>
{field.label}
{(field.value && field.value !== 'delete') || this.state.path ? (
<div
className="image-upload"
>
<div
className="image-upload__preview"
style={({
backgroundImage: `url(${field.value || this.state.path})`,
})}
/>
<div className="image-upload__action">
<button
type="button"
onClick={() => {
if (field.value) {
field.value = 'delete';
} else {
this.setState({
path: null,
});
}
}}
>
remove icon
</button>
<div className="image-upload__action-background" />
<div className="image-upload-wrapper">
<label className="franz-form__label" htmlFor="iconUpload">{field.label}</label>
<div className="image-upload">
{(field.value && field.value !== 'delete') || this.state.path ? (
<div>
<div
className="image-upload__preview"
style={({
backgroundImage: `url("${field.value || this.state.path}")`,
})}
/>
<div className="image-upload__action">
<button
type="button"
onClick={() => {
if (field.value) {
field.set('delete');
} else {
this.setState({
path: null,
});
}
}}
>
<i className="mdi mdi-delete" />
<p>
{textDelete}
</p>
</button>
<div className="image-upload__action-background" />
</div>
</div>
</div>
) : (
<Dropzone
ref={(node) => { this.dropzoneRef = node; }}
onDrop={this.onDrop.bind(this)}
className={cssClasses}
multiple={multiple}
accept="image/jpeg, image/png"
>
<p>Try dropping some files here, or click to select files to upload.</p>
</Dropzone>
)}
) : (
<Dropzone
ref={(node) => { this.dropzoneRef = node; }}
onDrop={this.onDrop.bind(this)}
className={cssClasses}
multiple={multiple}
accept="image/jpeg, image/png"
>
<i className="mdi mdi-file-image" />
<p>
{textUpload}
</p>
</Dropzone>
)}
</div>
</div>
);
}
@@ -48,7 +48,7 @@ const messages = defineMessages({
},
icon: {
id: 'settings.service.form.icon',
defaultMessage: '!!!Icon',
defaultMessage: '!!!Custom icon',
},
});
@@ -108,7 +108,7 @@ export default class EditServiceScreen extends Component {
},
customIcon: {
label: intl.formatMessage(messages.icon),
value: service.hasCustomIcon ? service.icon : false,
value: service.hasCustomUploadedIcon ? service.icon : false,
default: null,
type: 'file',
},
@@ -127,7 +127,9 @@
"settings.service.form.headlineNotifications": "Notifications",
"settings.service.form.headlineBadges": "Unread message badges",
"settings.service.form.headlineGeneral": "General",
"settings.service.form.icon": "Icon",
"settings.service.form.icon": "Custom icon",
"settings.service.form.iconDelete": "Delete",
"settings.service.form.iconUpload": "Drop your image, or click here",
"settings.service.error.headline": "Error",
"settings.service.error.goBack": "Back to services",
"settings.service.error.message": "Could not load service recipe.",
@@ -25,6 +25,7 @@ export default class Service {
@observable isBadgeEnabled = true;
@observable isIndirectMessageBadgeEnabled = true;
@observable iconUrl = '';
@observable hasCustomUploadedIcon = false;
@observable hasCrashed = false;
constructor(data, recipe) {
@@ -62,6 +63,8 @@ export default class Service {
this.isMuted = data.isMuted !== undefined ? data.isMuted : this.isMuted;
this.hasCustomUploadedIcon = data.hasCustomIcon !== undefined ? data.hasCustomIcon : this.hasCustomUploadedIcon;
this.recipe = recipe;
autorun(() => {
@@ -177,13 +177,21 @@ export default class ServicesStore extends Store {
await request._promise;
newData.iconUrl = request.result.data.iconUrl;
newData.hasCustomUploadedIcon = true;
}
this.allServicesRequest.patch((result) => {
if (!result) return;
// patch custom icon deletion
if (data.customIcon === 'delete') {
data.iconUrl = '';
data.hasCustomUploadedIcon = false;
}
// patch custom icon url
if (data.customIconUrl) {
data.iconUrl = data.customIconUrl;
}
Object.assign(result.find(c => c.id === serviceId), newData);
@@ -328,7 +336,7 @@ export default class ServicesStore extends Store {
}
} else if (channel === 'avatar') {
const url = args[0];
if (service.customIconUrl !== url) {
if (service.iconUrl !== url && !service.hasCustomUploadedIcon) {
service.customIconUrl = url;
this.actions.service.updateService({
@@ -1,9 +1,12 @@
.image-upload {
position: absolute;
width: 100px;
height: 100px;
border-radius: $theme-border-radius;
width: 140px;
height: 140px;
border: 1px solid $theme-gray-lighter;
border-radius: $theme-border-radius-small;
background: $theme-gray-lightest;
overflow: hidden;
margin-top: 5px;
&__preview,
&__action {
@@ -19,14 +22,16 @@
background-size: 100%;
background-repeat: no-repeat;
background-position: center center;
margin: 5px;
border-radius: 3px;
}
&__action {
position: relative;
z-index: 10;
opacity: 0;
transition: opacity 0.5s;
display: flex;
justify-content: center;
&-background {
position: absolute;
@@ -41,6 +46,33 @@
button {
position: relative;
z-index: 100;
color: #FFF;
.mdi {
color: #FFF;
}
}
}
&__dropzone {
text-align: center;
border-radius: 5px;
padding: 10px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
&__dropzone,
button {
.mdi {
margin-bottom: 5px;
}
p {
font-size: 10px;
line-height: 10px;
}
}
@@ -49,4 +81,11 @@
opacity: 1;
}
}
}
.image-upload-wrapper {
.mdi {
font-size: 40px;
color: $theme-gray-light;
}
}
@@ -121,9 +121,15 @@
}
.service-icon {
width: 30%;
min-width: 100px;
width: 140px;
float: right;
margin-top: 30px;
margin-left: 40px;
label {
font-weight: bold;
letter-spacing: -0.1px;
}
}
}
@@ -167,6 +173,7 @@
&__options {
margin-top: 20px;
flex: 1;
}
&__settings-group {

0 comments on commit 6b97e42

Please sign in to comment.