@fleetbase/ember-core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +32 -0
  3. package/addon/adapters/application.js +155 -0
  4. package/addon/adapters/user.js +19 -0
  5. package/addon/authenticators/fleetbase.js +72 -0
  6. package/addon/decorators/fetch-from.js +55 -0
  7. package/addon/decorators/from-store.js +56 -0
  8. package/addon/decorators/is-equal.js +15 -0
  9. package/addon/exports/host-services.js +18 -0
  10. package/addon/exports/services.js +18 -0
  11. package/addon/initializers/local-storage-adapter.js +21 -0
  12. package/addon/serializers/application.js +87 -0
  13. package/addon/services/app-cache.js +59 -0
  14. package/addon/services/crud.js +226 -0
  15. package/addon/services/current-user.js +259 -0
  16. package/addon/services/fetch.js +648 -0
  17. package/addon/services/filters.js +183 -0
  18. package/addon/services/loader.js +136 -0
  19. package/addon/services/notifications.js +32 -0
  20. package/addon/services/session.js +221 -0
  21. package/addon/services/theme.js +200 -0
  22. package/addon/services/url-search-params.js +92 -0
  23. package/addon/transforms/array.js +29 -0
  24. package/addon/transforms/object.js +11 -0
  25. package/addon/transforms/raw.js +11 -0
  26. package/addon/utils/api-url.js +11 -0
  27. package/addon/utils/apply-column-filters.js +3 -0
  28. package/addon/utils/auto-serialize.js +100 -0
  29. package/addon/utils/calculate-percentage.js +3 -0
  30. package/addon/utils/close-sidebar.js +7 -0
  31. package/addon/utils/console-url.js +56 -0
  32. package/addon/utils/copy-to-clipboard.js +35 -0
  33. package/addon/utils/corslite.js +95 -0
  34. package/addon/utils/download.js +157 -0
  35. package/addon/utils/env.js +3 -0
  36. package/addon/utils/extract-coordinates.js +35 -0
  37. package/addon/utils/extract-latitude.js +28 -0
  38. package/addon/utils/extract-longitude.js +28 -0
  39. package/addon/utils/find-closest-waypoint.js +20 -0
  40. package/addon/utils/first.js +10 -0
  41. package/addon/utils/frontend-url.js +30 -0
  42. package/addon/utils/generate-slug.js +11 -0
  43. package/addon/utils/generate-uuid.js +3 -0
  44. package/addon/utils/get-length-units.js +44 -0
  45. package/addon/utils/get-meta-field-types.js +3 -0
  46. package/addon/utils/get-mime-type.js +25 -0
  47. package/addon/utils/get-model-name.js +45 -0
  48. package/addon/utils/get-permission-action.js +47 -0
  49. package/addon/utils/get-permission-resource.js +16 -0
  50. package/addon/utils/get-pod-methods.js +7 -0
  51. package/addon/utils/get-routing-host.js +44 -0
  52. package/addon/utils/get-service-name.js +21 -0
  53. package/addon/utils/get-user-options.js +21 -0
  54. package/addon/utils/get-weight-units.js +32 -0
  55. package/addon/utils/get-with-default.js +6 -0
  56. package/addon/utils/group-api-events.js +20 -0
  57. package/addon/utils/group-by.js +26 -0
  58. package/addon/utils/has-extension.js +11 -0
  59. package/addon/utils/has-json-structure.js +10 -0
  60. package/addon/utils/hason-structure.js +3 -0
  61. package/addon/utils/haversine.js +59 -0
  62. package/addon/utils/humanize.js +16 -0
  63. package/addon/utils/is-electron.js +18 -0
  64. package/addon/utils/is-email.js +5 -0
  65. package/addon/utils/is-function.js +3 -0
  66. package/addon/utils/is-image-file.js +3 -0
  67. package/addon/utils/is-iterable.js +7 -0
  68. package/addon/utils/is-json.js +9 -0
  69. package/addon/utils/is-latitude.js +3 -0
  70. package/addon/utils/is-letter.js +3 -0
  71. package/addon/utils/is-longitude.js +3 -0
  72. package/addon/utils/is-model.js +6 -0
  73. package/addon/utils/is-not-empty.js +5 -0
  74. package/addon/utils/is-not-model.js +5 -0
  75. package/addon/utils/is-numeric.js +3 -0
  76. package/addon/utils/is-object.js +3 -0
  77. package/addon/utils/is-proxy.js +5 -0
  78. package/addon/utils/is-relation-missing.js +21 -0
  79. package/addon/utils/is-valid-coordinates.js +38 -0
  80. package/addon/utils/is-video-file.js +3 -0
  81. package/addon/utils/is-waypoint-record.js +5 -0
  82. package/addon/utils/ison.js +3 -0
  83. package/addon/utils/isset.js +10 -0
  84. package/addon/utils/last.js +23 -0
  85. package/addon/utils/lazy-load-script.js +25 -0
  86. package/addon/utils/leaflet-icon.js +13 -0
  87. package/addon/utils/leaflet-points-from-coordinates.js +3 -0
  88. package/addon/utils/load-engines.js +37 -0
  89. package/addon/utils/load-extensions.js +8 -0
  90. package/addon/utils/macros/group-by.js +28 -0
  91. package/addon/utils/make-dataset.js +57 -0
  92. package/addon/utils/map-engines.js +30 -0
  93. package/addon/utils/mock-response.js +15 -0
  94. package/addon/utils/numbers-only.js +11 -0
  95. package/addon/utils/past-tense.js +40 -0
  96. package/addon/utils/path-to-route.js +10 -0
  97. package/addon/utils/polyline.js +161 -0
  98. package/addon/utils/range.js +19 -0
  99. package/addon/utils/refresh-route.js +3 -0
  100. package/addon/utils/replace-table-row.js +17 -0
  101. package/addon/utils/reverse-point.js +3 -0
  102. package/addon/utils/serialize/normalize-polymorphic-type-within-hash.js +27 -0
  103. package/addon/utils/serialize/normalize-polymorphic-type.js +13 -0
  104. package/addon/utils/serialize/normalize-relations-with-hash.js +32 -0
  105. package/addon/utils/set-column-filter-options.js +3 -0
  106. package/addon/utils/strip-html.js +3 -0
  107. package/addon/utils/to-leaflet-bounds.js +6 -0
  108. package/addon/utils/to-model.js +18 -0
  109. package/addon/utils/waypoint-label.js +3 -0
  110. package/addon/utils/with-default-value.js +5 -0
  111. package/addon/utils/words.js +5 -0
  112. package/app/adapters/user.js +1 -0
  113. package/app/authenticators/fleetbase.js +1 -0
  114. package/app/decorators/fetch-from.js +1 -0
  115. package/app/decorators/from-store.js +1 -0
  116. package/app/decorators/is-equal.js +1 -0
  117. package/app/exports/host-services.js +1 -0
  118. package/app/exports/services.js +1 -0
  119. package/app/initializers/local-storage-adapter.js +1 -0
  120. package/app/serializers/application.js +1 -0
  121. package/app/services/app-cache.js +1 -0
  122. package/app/services/crud.js +1 -0
  123. package/app/services/current-user.js +1 -0
  124. package/app/services/fetch.js +1 -0
  125. package/app/services/filters.js +1 -0
  126. package/app/services/loader.js +1 -0
  127. package/app/services/notifications.js +1 -0
  128. package/app/services/session.js +1 -0
  129. package/app/services/theme.js +1 -0
  130. package/app/services/url-search-params.js +1 -0
  131. package/app/storages/local-cache.js +12 -0
  132. package/app/storages/user-options.js +12 -0
  133. package/app/transforms/array.js +1 -0
  134. package/app/transforms/object.js +1 -0
  135. package/app/transforms/raw.js +1 -0
  136. package/app/utils/api-url.js +1 -0
  137. package/app/utils/apply-column-filters.js +1 -0
  138. package/app/utils/auto-serialize.js +1 -0
  139. package/app/utils/calculate-percentage.js +1 -0
  140. package/app/utils/close-sidebar.js +1 -0
  141. package/app/utils/console-url.js +1 -0
  142. package/app/utils/copy-to-clipboard.js +1 -0
  143. package/app/utils/corslite.js +1 -0
  144. package/app/utils/download.js +1 -0
  145. package/app/utils/env.js +1 -0
  146. package/app/utils/extract-coordinates.js +1 -0
  147. package/app/utils/extract-latitude.js +1 -0
  148. package/app/utils/extract-longitude.js +1 -0
  149. package/app/utils/find-closest-waypoint.js +1 -0
  150. package/app/utils/first.js +1 -0
  151. package/app/utils/frontend-url.js +1 -0
  152. package/app/utils/generate-slug.js +1 -0
  153. package/app/utils/generate-uuid.js +1 -0
  154. package/app/utils/get-length-units.js +1 -0
  155. package/app/utils/get-meta-field-types.js +1 -0
  156. package/app/utils/get-mime-type.js +1 -0
  157. package/app/utils/get-model-name.js +1 -0
  158. package/app/utils/get-permission-action.js +1 -0
  159. package/app/utils/get-permission-resource.js +1 -0
  160. package/app/utils/get-pod-methods.js +1 -0
  161. package/app/utils/get-routing-host.js +1 -0
  162. package/app/utils/get-service-name.js +1 -0
  163. package/app/utils/get-user-options.js +1 -0
  164. package/app/utils/get-weight-units.js +1 -0
  165. package/app/utils/get-with-default.js +1 -0
  166. package/app/utils/group-api-events.js +1 -0
  167. package/app/utils/group-by.js +1 -0
  168. package/app/utils/has-extension.js +1 -0
  169. package/app/utils/has-json-structure.js +1 -0
  170. package/app/utils/hason-structure.js +1 -0
  171. package/app/utils/haversine.js +1 -0
  172. package/app/utils/humanize.js +1 -0
  173. package/app/utils/is-electron.js +1 -0
  174. package/app/utils/is-email.js +1 -0
  175. package/app/utils/is-function.js +1 -0
  176. package/app/utils/is-image-file.js +1 -0
  177. package/app/utils/is-iterable.js +1 -0
  178. package/app/utils/is-latitude.js +1 -0
  179. package/app/utils/is-letter.js +1 -0
  180. package/app/utils/is-longitude.js +1 -0
  181. package/app/utils/is-model.js +1 -0
  182. package/app/utils/is-not-empty.js +1 -0
  183. package/app/utils/is-not-model.js +1 -0
  184. package/app/utils/is-numeric.js +1 -0
  185. package/app/utils/is-object.js +1 -0
  186. package/app/utils/is-proxy.js +1 -0
  187. package/app/utils/is-relation-missing.js +1 -0
  188. package/app/utils/is-valid-coordinates.js +1 -0
  189. package/app/utils/is-video-file.js +1 -0
  190. package/app/utils/is-waypoint-record.js +1 -0
  191. package/app/utils/ison.js +1 -0
  192. package/app/utils/isset.js +1 -0
  193. package/app/utils/last.js +1 -0
  194. package/app/utils/lazy-load-script.js +1 -0
  195. package/app/utils/leaflet-icon.js +1 -0
  196. package/app/utils/leaflet-points-from-coordinates.js +1 -0
  197. package/app/utils/load-engines.js +1 -0
  198. package/app/utils/load-extensions.js +1 -0
  199. package/app/utils/macros/group-by.js +1 -0
  200. package/app/utils/make-dataset.js +1 -0
  201. package/app/utils/map-engines.js +1 -0
  202. package/app/utils/mock-response.js +1 -0
  203. package/app/utils/numbers-only.js +1 -0
  204. package/app/utils/past-tense.js +1 -0
  205. package/app/utils/path-to-route.js +1 -0
  206. package/app/utils/polyline.js +1 -0
  207. package/app/utils/range.js +1 -0
  208. package/app/utils/refresh-route.js +1 -0
  209. package/app/utils/replace-table-row.js +1 -0
  210. package/app/utils/reverse-point.js +1 -0
  211. package/app/utils/serialize/normalize-polymorphic-type-within-hash.js +1 -0
  212. package/app/utils/serialize/normalize-polymorphic-type.js +1 -0
  213. package/app/utils/serialize/normalize-relations-with-hash.js +1 -0
  214. package/app/utils/set-column-filter-options.js +1 -0
  215. package/app/utils/strip-html.js +1 -0
  216. package/app/utils/to-leaflet-bounds.js +1 -0
  217. package/app/utils/to-model.js +1 -0
  218. package/app/utils/waypoint-label.js +1 -0
  219. package/app/utils/with-default-value.js +1 -0
  220. package/app/utils/words.js +1 -0
  221. package/config/environment.js +5 -0
  222. package/index.js +26 -0
  223. package/package.json +117 -0
  224. package/pnpm-lock.yaml +12750 -0
@@ -0,0 +1,226 @@
1
+ import Service from '@ember/service';
2
+ import { inject as service } from '@ember/service';
3
+ import { action } from '@ember/object';
4
+ import { isArray } from '@ember/array';
5
+ import { dasherize } from '@ember/string';
6
+ import { pluralize } from 'ember-inflector';
7
+ import { format as formatDate } from 'date-fns';
8
+ import getModelName from '../utils/get-model-name';
9
+ import humanize from '../utils/humanize';
10
+ import first from '../utils/first';
11
+
12
+ export default class CrudService extends Service {
13
+ /**
14
+ * Inject the `fetch` service
15
+ *
16
+ * @var {Service}
17
+ */
18
+ @service fetch;
19
+
20
+ /**
21
+ * Inject the `modalsManager` service
22
+ *
23
+ * @var {Service}
24
+ */
25
+ @service modalsManager;
26
+
27
+ /**
28
+ * Inject the `notifications` service
29
+ *
30
+ * @var {Service}
31
+ */
32
+ @service notifications;
33
+
34
+ /**
35
+ * Inject the `store` service
36
+ *
37
+ * @var {Service}
38
+ */
39
+ @service store;
40
+
41
+ /**
42
+ * Generic deletion modal with options
43
+ *
44
+ * @param {Model} model
45
+ * @param {Object} options
46
+ * @void
47
+ */
48
+ @action delete(model, options = {}) {
49
+ const modelName = getModelName(model, options?.modelName, { humanize: true, capitalizeWords: true });
50
+
51
+ this.modalsManager.confirm({
52
+ title: `Are you sure to delete this ${modelName}?`,
53
+ args: ['model'],
54
+ model,
55
+ confirm: (modal) => {
56
+ if (typeof options.onConfirm === 'function') {
57
+ options.onConfirm(model);
58
+ }
59
+
60
+ modal.startLoading();
61
+
62
+ return model
63
+ .destroyRecord()
64
+ .then((model) => {
65
+ this.notifications.success(options.successNotification || `${model.name ? modelName + " '" + model.name + "'" : "'" + modelName + "'"} has been deleted.`);
66
+ if (typeof options.onSuccess === 'function') {
67
+ options.onSuccess(model);
68
+ }
69
+ })
70
+ .catch((error) => {
71
+ this.notifications.serverError(error);
72
+
73
+ if (typeof options.onError === 'function') {
74
+ options.onError(error, model);
75
+ }
76
+ })
77
+ .finally(() => {
78
+ if (typeof options.callback === 'function') {
79
+ options.callback(model);
80
+ }
81
+ });
82
+ },
83
+ ...options,
84
+ });
85
+ }
86
+
87
+ /**
88
+ * Generic deletion modal with options
89
+ *
90
+ * @param {Array} selected an array of selected models for deletion
91
+ * @param {Object} options
92
+ * @void
93
+ */
94
+ @action bulkDelete(selected, options = {}) {
95
+ if (!isArray(selected) || selected.length === 0) {
96
+ return;
97
+ }
98
+
99
+ const firstModel = first(selected);
100
+ const modelName = getModelName(firstModel, options?.modelName, { humanize: true, capitalizeWords: true });
101
+
102
+ // make sure all are the same type
103
+ selected = selected.filter((m) => getModelName(m) === getModelName(firstModel));
104
+
105
+ return this.bulkAction('delete', selected, {
106
+ acceptButtonScheme: 'danger',
107
+ acceptButtonIcon: 'trash',
108
+ actionPath: `${dasherize(pluralize(modelName))}/bulk-delete`,
109
+ actionMethod: `DELETE`,
110
+ modelName,
111
+ ...options,
112
+ });
113
+ }
114
+
115
+ /**
116
+ * Generic bulk action on multiple models modal with options
117
+ *
118
+ * @param {Array} selected an array of selected models for deletion
119
+ * @param {Object} options
120
+ * @void
121
+ */
122
+ @action bulkAction(verb, selected, options = {}) {
123
+ if (!isArray(selected) || selected.length === 0) {
124
+ return;
125
+ }
126
+
127
+ const firstModel = first(selected);
128
+ const modelName = getModelName(firstModel, options?.modelName, { humanize: true, capitalizeWords: true });
129
+ const count = selected.length;
130
+ const actionMethod = (typeof options.actionMethod === 'string' ? options.actionMethod : `POST`).toLowerCase();
131
+
132
+ this.modalsManager.show('modals/bulk-action-model', {
133
+ title: `Bulk ${verb} ${pluralize(modelName)}`,
134
+ acceptButtonText: humanize(verb),
135
+ args: ['selected'],
136
+ modelNamePath: 'name',
137
+ verb,
138
+ selected,
139
+ count,
140
+ modelName,
141
+ remove: (model) => {
142
+ selected.removeObject(model);
143
+ this.modalsManager.setOption('selected', selected);
144
+ },
145
+ confirm: (modal) => {
146
+ const selected = modal.getOption('selected');
147
+
148
+ if (typeof options.onConfirm === 'function') {
149
+ options.onConfirm(selected);
150
+ }
151
+
152
+ modal.startLoading();
153
+
154
+ return this.fetch[actionMethod](options.actionPath, {
155
+ ids: selected.map((model) => model.id),
156
+ })
157
+ .then((response) => {
158
+ this.notifications.success(response.message ?? options.successNotification ?? `${count} ${pluralize(modelName, count)} were updated successfully.`);
159
+
160
+ if (typeof options.onSuccess === 'function') {
161
+ options.onSuccess(selected);
162
+ }
163
+ })
164
+ .catch((error) => {
165
+ this.notifications.serverError(error);
166
+
167
+ if (typeof options.onError === 'function') {
168
+ options.onError(error, selected);
169
+ }
170
+ })
171
+ .finally(() => {
172
+ if (typeof options.callback === 'function') {
173
+ options.callback(selected);
174
+ }
175
+ });
176
+ },
177
+ ...options,
178
+ });
179
+ }
180
+
181
+ /**
182
+ * Toggles dialog to export resource data
183
+ *
184
+ * @void
185
+ */
186
+ @action export(modelName, options = {}) {
187
+ // always lowercase modelname
188
+ modelName = modelName.toLowerCase();
189
+
190
+ // set the model uri endpoint
191
+ const modelEndpoint = dasherize(pluralize(modelName));
192
+
193
+ this.modalsManager.show('modals/export-form', {
194
+ title: `Export ${pluralize(modelName)}`,
195
+ acceptButtonText: 'Download',
196
+ formatOptions: ['csv', 'xlsx', 'xls', 'html', 'pdf'],
197
+ setFormat: ({ target }) => {
198
+ this.modalsManager.setOption('format', target.value || null);
199
+ },
200
+ confirm: (modal, done) => {
201
+ const format = modal.getOption('format') || 'xlsx';
202
+ modal.startLoading();
203
+ return this.fetch
204
+ .download(
205
+ `${modelEndpoint}/export`,
206
+ {
207
+ format,
208
+ },
209
+ {
210
+ fileName: `${modelEndpoint}-${formatDate(new Date(), 'yyyy-MM-dd-HH:mm')}.${format}`,
211
+ }
212
+ )
213
+ .then(() => {
214
+ setTimeout(() => {
215
+ return done();
216
+ }, 600);
217
+ })
218
+ .catch((error) => {
219
+ modal.stopLoading();
220
+ this.notifications.serverError(error, 'Unable to download API credentials export.');
221
+ });
222
+ },
223
+ ...options,
224
+ });
225
+ }
226
+ }
@@ -0,0 +1,259 @@
1
+ import Service from '@ember/service';
2
+ import Evented from '@ember/object/evented';
3
+ import { inject as service } from '@ember/service';
4
+ import { dasherize } from '@ember/string';
5
+ import { computed, get, action } from '@ember/object';
6
+ import { isBlank } from '@ember/utils';
7
+ import { alias } from '@ember/object/computed';
8
+ import { storageFor } from 'ember-local-storage';
9
+
10
+ export default class CurrentUserService extends Service.extend(Evented) {
11
+ /**
12
+ * Inject the `session` service
13
+ *
14
+ * @var {Service}
15
+ */
16
+ @service session;
17
+
18
+ /**
19
+ * Inject the `store` service
20
+ *
21
+ * @var {Service}
22
+ */
23
+ @service store;
24
+
25
+ /**
26
+ * Inject the `fetch` service
27
+ *
28
+ * @var {Service}
29
+ */
30
+ @service fetch;
31
+
32
+ /**
33
+ * Inject the `theme` service
34
+ *
35
+ * @var {Service}
36
+ */
37
+ @service theme;
38
+
39
+ /**
40
+ * Inject the `notifications` service
41
+ *
42
+ * @var {Service}
43
+ */
44
+ @service notifications;
45
+
46
+ /**
47
+ * User options in localStorage
48
+ *
49
+ * @var StorageObject
50
+ */
51
+ @storageFor('user-options') options;
52
+
53
+ /**
54
+ * Alias for current user id
55
+ *
56
+ * @var {String}
57
+ */
58
+ @alias('user.id') id;
59
+
60
+ /**
61
+ * Alias for current user name
62
+ *
63
+ * @var {String}
64
+ */
65
+ @alias('user.name') name;
66
+
67
+ /**
68
+ * Alias for current user phone
69
+ *
70
+ * @var {String}
71
+ */
72
+ @alias('user.phone') phone;
73
+
74
+ /**
75
+ * Alias for current user phone
76
+ *
77
+ * @var {String}
78
+ */
79
+ @alias('user.email') email;
80
+
81
+ /**
82
+ * Alias for current user's company id
83
+ *
84
+ * @var {String}
85
+ */
86
+ @alias('user.company_uuid') companyId;
87
+
88
+ /**
89
+ * Loads the current authenticated user
90
+ *
91
+ * @void
92
+ */
93
+ async load() {
94
+ if (this.session.isAuthenticated) {
95
+ let user = await this.store.findRecord('user', 'me');
96
+ this.set('user', user);
97
+ this.trigger('user.loaded', user);
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Resolves a user model.
103
+ *
104
+ * @return {Promise}
105
+ */
106
+ @action promiseUser(options = {}) {
107
+ const NoUserAuthenticatedError = new Error('Failed to authenticate user.');
108
+
109
+ return new Promise((resolve, reject) => {
110
+ if (this.session.isAuthenticated) {
111
+ return this.store
112
+ .queryRecord('user', { me: true })
113
+ .then((user) => {
114
+ // set the `current user`
115
+ this.set('user', user);
116
+ this.trigger('user.loaded', user);
117
+
118
+ // set environment from user option
119
+ this.theme.setEnvironment();
120
+
121
+ // @TODO Create an event dispatch for when an authenticated user is resolved from the server
122
+ if (typeof options?.onUserResolved === 'function') {
123
+ options.onUserResolved(user);
124
+ }
125
+
126
+ resolve(user);
127
+ })
128
+ .catch((error) => {
129
+ reject(NoUserAuthenticatedError);
130
+ });
131
+ } else {
132
+ reject(NoUserAuthenticatedError);
133
+ }
134
+ });
135
+ }
136
+
137
+ /**
138
+ * Loads and resolved all current users installed order configurations.
139
+ *
140
+ * @return {Promise}
141
+ */
142
+ @action getInstalledOrderConfigs(params = {}) {
143
+ return new Promise((resolve, reject) => {
144
+ this.fetch
145
+ .get('fleet-ops/order-configs/get-installed', params)
146
+ .then((configs) => {
147
+ const serialized = [];
148
+
149
+ for (let i = 0; i < configs.length; i++) {
150
+ const config = configs.objectAt(i);
151
+ const normalizedConfig = this.store.normalize('order-config', config);
152
+ const serializedConfig = this.store.push(normalizedConfig);
153
+
154
+ serialized.pushObject(serializedConfig);
155
+ }
156
+
157
+ resolve(serialized);
158
+ })
159
+ .catch(reject);
160
+ });
161
+ }
162
+
163
+ /**
164
+ * The prefix for this user options
165
+ *
166
+ * @var {String}
167
+ */
168
+ @computed('id') get optionsPrefix() {
169
+ return `${this.id}:`;
170
+ }
171
+
172
+ get latitude() {
173
+ return this.whois('latitude');
174
+ }
175
+
176
+ get longitude() {
177
+ return this.whois('longitude');
178
+ }
179
+
180
+ get currency() {
181
+ return this.whois('currency.code');
182
+ }
183
+
184
+ get city() {
185
+ return this.whois('city');
186
+ }
187
+
188
+ get country() {
189
+ return this.whois('country_code');
190
+ }
191
+
192
+ @action whois(key) {
193
+ return this.getWhoisProperty(key);
194
+ }
195
+
196
+ /**
197
+ * Sets a user's option in local storage
198
+ *
199
+ * @param {String} key
200
+ * @param {Mixed} value
201
+ * @return {CurrentUserService}
202
+ */
203
+ @action setOption(key, value) {
204
+ key = `${this.optionsPrefix}${dasherize(key)}`;
205
+
206
+ this.options.set(key, value);
207
+
208
+ return this;
209
+ }
210
+
211
+ /**
212
+ * Retrieves a user option from local storage
213
+ *
214
+ * @param {String} key
215
+ * @return {Mixed}
216
+ */
217
+ @action getOption(key, defaultValue = null) {
218
+ key = `${this.optionsPrefix}${dasherize(key)}`;
219
+
220
+ const value = this.options.get(key);
221
+ return value !== undefined ? value : defaultValue;
222
+ }
223
+
224
+ /**
225
+ * Retrieves a user option from local storage
226
+ *
227
+ * @param {String} key
228
+ * @return {Mixed}
229
+ */
230
+ @action getWhoisProperty(prop) {
231
+ const whois = this.getOption('whois');
232
+
233
+ if (!whois || typeof whois !== 'object') {
234
+ return null;
235
+ }
236
+
237
+ return get(whois, prop);
238
+ }
239
+
240
+ /**
241
+ * Checks if an option exists in users local storage
242
+ *
243
+ * @param {String} key
244
+ * @return {Boolean}
245
+ */
246
+ @action hasOption(key) {
247
+ return this.getOption(key) !== undefined;
248
+ }
249
+
250
+ /**
251
+ * Checks if an option exists in users local storage
252
+ *
253
+ * @param {String} key
254
+ * @return {Boolean}
255
+ */
256
+ @action filledOption(key) {
257
+ return !isBlank(this.getOption(key));
258
+ }
259
+ }