aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar Stefan Malzner <stefan@adlk.io>2017-12-27 13:09:17 +0100
committerLibravatar Stefan Malzner <stefan@adlk.io>2017-12-27 13:09:17 +0100
commit150cfe764aeb9e93341ba2f231fd121fe85472af (patch)
treebc398a878ec736f666502af983160aa7829a7a3d /src
parentMerge branch 'develop' into feature/icon-upload (diff)
downloadferdium-app-150cfe764aeb9e93341ba2f231fd121fe85472af.tar.gz
ferdium-app-150cfe764aeb9e93341ba2f231fd121fe85472af.tar.zst
ferdium-app-150cfe764aeb9e93341ba2f231fd121fe85472af.zip
First working draft of icon upload
Diffstat (limited to 'src')
-rw-r--r--src/api/server/ServerApi.js42
-rw-r--r--src/components/settings/services/EditServiceForm.js7
-rw-r--r--src/components/ui/ImageUpload.js42
-rw-r--r--src/containers/settings/EditServiceScreen.js7
-rw-r--r--src/i18n/locales/en-US.json1
-rw-r--r--src/models/Service.js11
-rw-r--r--src/stores/ServicesStore.js14
7 files changed, 82 insertions, 42 deletions
diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js
index 8b3136d27..6b96f709e 100644
--- a/src/api/server/ServerApi.js
+++ b/src/api/server/ServerApi.js
@@ -167,27 +167,65 @@ export default class ServerApi {
167 throw request; 167 throw request;
168 } 168 }
169 const serviceData = await request.json(); 169 const serviceData = await request.json();
170
171 if (data.iconFile) {
172 const iconUrl = await this.uploadServiceIcon(serviceData.data.id, data.iconFile);
173
174 serviceData.data.iconUrl = iconUrl;
175 }
176
170 const service = Object.assign(serviceData, { data: await this._prepareServiceModel(serviceData.data) }); 177 const service = Object.assign(serviceData, { data: await this._prepareServiceModel(serviceData.data) });
171 178
172 console.debug('ServerApi::createService resolves', service); 179 console.debug('ServerApi::createService resolves', service);
173 return service; 180 return service;
174 } 181 }
175 182
176 async updateService(recipeId, data) { 183 async updateService(serviceId, rawData) {
177 const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/service/${recipeId}`, this._prepareAuthRequest({ 184 const data = rawData;
185
186 if (data.iconFile) {
187 await this.uploadServiceIcon(serviceId, data.iconFile);
188 }
189
190 const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/service/${serviceId}`, this._prepareAuthRequest({
178 method: 'PUT', 191 method: 'PUT',
179 body: JSON.stringify(data), 192 body: JSON.stringify(data),
180 })); 193 }));
194
181 if (!request.ok) { 195 if (!request.ok) {
182 throw request; 196 throw request;
183 } 197 }
198
184 const serviceData = await request.json(); 199 const serviceData = await request.json();
200
185 const service = Object.assign(serviceData, { data: await this._prepareServiceModel(serviceData.data) }); 201 const service = Object.assign(serviceData, { data: await this._prepareServiceModel(serviceData.data) });
186 202
187 console.debug('ServerApi::updateService resolves', service); 203 console.debug('ServerApi::updateService resolves', service);
188 return service; 204 return service;
189 } 205 }
190 206
207 async uploadServiceIcon(serviceId, icon) {
208 const formData = new FormData();
209 formData.append('icon', icon);
210
211 const requestData = this._prepareAuthRequest({
212 method: 'PUT',
213 body: formData,
214 });
215
216 delete requestData.headers['Content-Type'];
217
218 const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/service/${serviceId}`, requestData);
219
220 if (!request.ok) {
221 throw request;
222 }
223
224 const serviceData = await request.json();
225
226 return serviceData.data.iconUrl;
227 }
228
191 async reorderService(data) { 229 async reorderService(data) {
192 const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/service/reorder`, this._prepareAuthRequest({ 230 const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/service/reorder`, this._prepareAuthRequest({
193 method: 'PUT', 231 method: 'PUT',
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js
index ee69d53aa..4f2f98a01 100644
--- a/src/components/settings/services/EditServiceForm.js
+++ b/src/components/settings/services/EditServiceForm.js
@@ -127,6 +127,11 @@ export default class EditServiceForm extends Component {
127 const values = form.values(); 127 const values = form.values();
128 let isValid = true; 128 let isValid = true;
129 129
130 const files = form.$('customIcon').files;
131 if (files) {
132 values.iconFile = files[0];
133 }
134
130 if (recipe.validateUrl && values.customUrl) { 135 if (recipe.validateUrl && values.customUrl) {
131 this.setState({ isValidatingCustomUrl: true }); 136 this.setState({ isValidatingCustomUrl: true });
132 try { 137 try {
@@ -224,7 +229,7 @@ export default class EditServiceForm extends Component {
224 </div> 229 </div>
225 <div className="service-icon"> 230 <div className="service-icon">
226 {/* <Input field={form.$('name')} focus /> */} 231 {/* <Input field={form.$('name')} focus /> */}
227 <ImageUpload field={form.$('icon')} /> 232 <ImageUpload field={form.$('customIcon')} />
228 </div> 233 </div>
229 </div> 234 </div>
230 {(recipe.hasTeamId || recipe.hasCustomUrl) && ( 235 {(recipe.hasTeamId || recipe.hasCustomUrl) && (
diff --git a/src/components/ui/ImageUpload.js b/src/components/ui/ImageUpload.js
index d07c3649c..f25d966f4 100644
--- a/src/components/ui/ImageUpload.js
+++ b/src/components/ui/ImageUpload.js
@@ -12,82 +12,64 @@ export default class ImageUpload extends Component {
12 field: PropTypes.instanceOf(Field).isRequired, 12 field: PropTypes.instanceOf(Field).isRequired,
13 className: PropTypes.string, 13 className: PropTypes.string,
14 multiple: PropTypes.bool, 14 multiple: PropTypes.bool,
15 // disabled: PropTypes.bool,
16 // onClick: PropTypes.func,
17 // type: PropTypes.string,
18 // buttonType: PropTypes.string,
19 // loaded: PropTypes.bool,
20 // htmlForm: PropTypes.string,
21 }; 15 };
22 16
23 static defaultProps = { 17 static defaultProps = {
24 className: null, 18 className: null,
25 multiple: false, 19 multiple: false,
26 // disabled: false,
27 // onClick: () => {},
28 // type: 'button',
29 // buttonType: '',
30 // loaded: true,
31 // htmlForm: '',
32 }; 20 };
33 21
34 dropzoneRef = null;
35
36 state = { 22 state = {
37 path: null, 23 path: null,
38 } 24 }
39 25
40 onDrop(acceptedFiles) { 26 onDrop(acceptedFiles) {
41 // const req = request.post('/upload');
42 acceptedFiles.forEach((file) => { 27 acceptedFiles.forEach((file) => {
43 console.log(file);
44 this.setState({ 28 this.setState({
45 path: file.path, 29 path: file.path,
46 }); 30 });
47 // req.attach(file.name, file); 31 this.props.field.onDrop(file);
48 }); 32 });
49 // req.end(callback);
50 } 33 }
51 34
35 dropzoneRef = null;
36
52 render() { 37 render() {
53 const { 38 const {
54 field, 39 field,
55 className, 40 className,
56 multiple, 41 multiple,
57 // disabled,
58 // onClick,
59 // type,
60 // buttonType,
61 // loaded,
62 // htmlForm,
63 } = this.props; 42 } = this.props;
64 43
65 const cssClasses = classnames({ 44 const cssClasses = classnames({
66 'franz-form__button': true, 45 'franz-form__button': true,
67 // [`franz-form__button--${buttonType}`]: buttonType,
68 [`${className}`]: className, 46 [`${className}`]: className,
69 }); 47 });
70 48
71 return ( 49 return (
72 <div> 50 <div>
73 {field.label} 51 {field.label}
74 {this.state.path ? ( 52 {(field.value && field.value !== 'delete') || this.state.path ? (
75 <div 53 <div
76 className="image-upload" 54 className="image-upload"
77 > 55 >
78 <div 56 <div
79 className="image-upload__preview" 57 className="image-upload__preview"
80 style={({ 58 style={({
81 backgroundImage: `url(${this.state.path})`, 59 backgroundImage: `url(${field.value || this.state.path})`,
82 })} 60 })}
83 /> 61 />
84 <div className="image-upload__action"> 62 <div className="image-upload__action">
85 <button 63 <button
86 type="button" 64 type="button"
87 onClick={() => { 65 onClick={() => {
88 this.setState({ 66 if (field.value) {
89 path: null, 67 field.value = 'delete';
90 }); 68 } else {
69 this.setState({
70 path: null,
71 });
72 }
91 }} 73 }}
92 > 74 >
93 remove icon 75 remove icon
diff --git a/src/containers/settings/EditServiceScreen.js b/src/containers/settings/EditServiceScreen.js
index 8827896ef..8d3a268ad 100644
--- a/src/containers/settings/EditServiceScreen.js
+++ b/src/containers/settings/EditServiceScreen.js
@@ -106,10 +106,11 @@ export default class EditServiceScreen extends Component {
106 value: !service.isMuted, 106 value: !service.isMuted,
107 default: true, 107 default: true,
108 }, 108 },
109 icon: { 109 customIcon: {
110 label: intl.formatMessage(messages.icon), 110 label: intl.formatMessage(messages.icon),
111 value: service.icon, 111 value: service.hasCustomIcon ? service.icon : false,
112 default: true, 112 default: null,
113 type: 'file',
113 }, 114 },
114 }, 115 },
115 }; 116 };
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index 567537d75..bfb95da04 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -127,6 +127,7 @@
127 "settings.service.form.headlineNotifications": "Notifications", 127 "settings.service.form.headlineNotifications": "Notifications",
128 "settings.service.form.headlineBadges": "Unread message badges", 128 "settings.service.form.headlineBadges": "Unread message badges",
129 "settings.service.form.headlineGeneral": "General", 129 "settings.service.form.headlineGeneral": "General",
130 "settings.service.form.icon": "Icon",
130 "settings.service.error.headline": "Error", 131 "settings.service.error.headline": "Error",
131 "settings.service.error.goBack": "Back to services", 132 "settings.service.error.goBack": "Back to services",
132 "settings.service.error.message": "Could not load service recipe.", 133 "settings.service.error.message": "Could not load service recipe.",
diff --git a/src/models/Service.js b/src/models/Service.js
index 0b19440e7..652d2594c 100644
--- a/src/models/Service.js
+++ b/src/models/Service.js
@@ -24,7 +24,7 @@ export default class Service {
24 @observable isNotificationEnabled = true; 24 @observable isNotificationEnabled = true;
25 @observable isBadgeEnabled = true; 25 @observable isBadgeEnabled = true;
26 @observable isIndirectMessageBadgeEnabled = true; 26 @observable isIndirectMessageBadgeEnabled = true;
27 @observable customIconUrl = ''; 27 @observable iconUrl = '';
28 @observable hasCrashed = false; 28 @observable hasCrashed = false;
29 29
30 constructor(data, recipe) { 30 constructor(data, recipe) {
@@ -42,7 +42,8 @@ export default class Service {
42 this.name = data.name || this.name; 42 this.name = data.name || this.name;
43 this.team = data.team || this.team; 43 this.team = data.team || this.team;
44 this.customUrl = data.customUrl || this.customUrl; 44 this.customUrl = data.customUrl || this.customUrl;
45 this.customIconUrl = data.customIconUrl || this.customIconUrl; 45 // this.customIconUrl = data.customIconUrl || this.customIconUrl;
46 this.iconUrl = data.iconUrl || this.iconUrl;
46 47
47 this.order = data.order !== undefined 48 this.order = data.order !== undefined
48 ? data.order : this.order; 49 ? data.order : this.order;
@@ -97,15 +98,15 @@ export default class Service {
97 } 98 }
98 99
99 @computed get icon() { 100 @computed get icon() {
100 if (this.hasCustomIcon) { 101 if (this.iconUrl) {
101 return this.customIconUrl; 102 return this.iconUrl;
102 } 103 }
103 104
104 return path.join(this.recipe.path, 'icon.svg'); 105 return path.join(this.recipe.path, 'icon.svg');
105 } 106 }
106 107
107 @computed get hasCustomIcon() { 108 @computed get hasCustomIcon() {
108 return (this.customIconUrl !== ''); 109 return Boolean(this.iconUrl);
109 } 110 }
110 111
111 @computed get iconPNG() { 112 @computed get iconPNG() {
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js
index 66f37af26..4fb5c9767 100644
--- a/src/stores/ServicesStore.js
+++ b/src/stores/ServicesStore.js
@@ -172,9 +172,21 @@ export default class ServicesStore extends Store {
172 const data = this._cleanUpTeamIdAndCustomUrl(service.recipe.id, serviceData); 172 const data = this._cleanUpTeamIdAndCustomUrl(service.recipe.id, serviceData);
173 const request = this.updateServiceRequest.execute(serviceId, data); 173 const request = this.updateServiceRequest.execute(serviceId, data);
174 174
175 const newData = serviceData;
176 if (serviceData.iconFile) {
177 await request._promise;
178
179 newData.iconUrl = request.result.data.iconUrl;
180 }
181
175 this.allServicesRequest.patch((result) => { 182 this.allServicesRequest.patch((result) => {
176 if (!result) return; 183 if (!result) return;
177 Object.assign(result.find(c => c.id === serviceId), serviceData); 184
185 if (data.customIcon === 'delete') {
186 data.iconUrl = '';
187 }
188
189 Object.assign(result.find(c => c.id === serviceId), newData);
178 }); 190 });
179 191
180 await request._promise; 192 await request._promise;