aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--package-lock.json176
-rw-r--r--package.json8
-rw-r--r--packages/theme/src/themes/dark/index.ts2
-rw-r--r--packages/theme/src/themes/default/index.ts2
-rw-r--r--src/components/layout/AppLayout.js2
-rw-r--r--src/components/services/content/WebviewCrashHandler.js7
-rw-r--r--src/components/subscription/SubscriptionPopup.js3
-rw-r--r--src/components/ui/Modal/index.js26
-rw-r--r--src/components/ui/Modal/styles.js1
-rw-r--r--src/config.js7
-rw-r--r--src/features/basicAuth/Component.js1
-rw-r--r--src/features/basicAuth/index.js3
-rw-r--r--src/features/delayApp/index.js6
-rw-r--r--src/features/shareFranz/Component.js170
-rw-r--r--src/features/shareFranz/index.js52
-rw-r--r--src/i18n/locales/en-US.json9
-rw-r--r--src/lib/analytics.js4
-rw-r--r--src/stores/AppStore.js7
-rw-r--r--src/stores/FeaturesStore.js2
-rw-r--r--src/stores/RecipePreviewsStore.js3
-rw-r--r--src/stores/RequestStore.js3
-rw-r--r--src/stores/ServicesStore.js5
22 files changed, 394 insertions, 105 deletions
diff --git a/package-lock.json b/package-lock.json
index 05ad8f465..d7c209cc6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1948,15 +1948,6 @@
1948 "@meetfranz/theme": "^1.0.7", 1948 "@meetfranz/theme": "^1.0.7",
1949 "react-html-attributes": "^1.4.3", 1949 "react-html-attributes": "^1.4.3",
1950 "react-loader": "^2.4.5" 1950 "react-loader": "^2.4.5"
1951 },
1952 "dependencies": {
1953 "@meetfranz/theme": {
1954 "version": "1.0.9",
1955 "bundled": true,
1956 "requires": {
1957 "color": "^3.1.0"
1958 }
1959 }
1960 } 1951 }
1961 }, 1952 },
1962 "@meetfranz/theme": { 1953 "@meetfranz/theme": {
@@ -1972,15 +1963,6 @@
1972 "@mdi/react": "^1.1.0", 1963 "@mdi/react": "^1.1.0",
1973 "@meetfranz/theme": "^1.0.7", 1964 "@meetfranz/theme": "^1.0.7",
1974 "react-loader": "^2.4.5" 1965 "react-loader": "^2.4.5"
1975 },
1976 "dependencies": {
1977 "@meetfranz/theme": {
1978 "version": "1.0.9",
1979 "bundled": true,
1980 "requires": {
1981 "color": "^3.1.0"
1982 }
1983 }
1984 } 1966 }
1985 }, 1967 },
1986 "@mrmlnc/readdir-enhanced": { 1968 "@mrmlnc/readdir-enhanced": {
@@ -4388,6 +4370,14 @@
4388 "dev": true, 4370 "dev": true,
4389 "requires": { 4371 "requires": {
4390 "ms": "2.0.0" 4372 "ms": "2.0.0"
4373 },
4374 "dependencies": {
4375 "ms": {
4376 "version": "2.0.0",
4377 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
4378 "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
4379 "dev": true
4380 }
4391 } 4381 }
4392 }, 4382 },
4393 "negotiator": { 4383 "negotiator": {
@@ -5170,16 +5160,17 @@
5170 "version": "2.6.9", 5160 "version": "2.6.9",
5171 "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 5161 "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
5172 "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 5162 "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
5163 "dev": true,
5173 "requires": { 5164 "requires": {
5174 "ms": "2.0.0" 5165 "ms": "2.0.0"
5175 } 5166 },
5176 }, 5167 "dependencies": {
5177 "debug-electron": { 5168 "ms": {
5178 "version": "0.0.4", 5169 "version": "2.0.0",
5179 "resolved": "https://registry.npmjs.org/debug-electron/-/debug-electron-0.0.4.tgz", 5170 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
5180 "integrity": "sha1-mwNTSayBB7TkPaIA0jOcT9Wxaec=", 5171 "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
5181 "requires": { 5172 "dev": true
5182 "debug": "^2.4.1" 5173 }
5183 } 5174 }
5184 }, 5175 },
5185 "debuglog": { 5176 "debuglog": {
@@ -7419,6 +7410,14 @@
7419 "on-finished": "~2.3.0", 7410 "on-finished": "~2.3.0",
7420 "range-parser": "~1.2.0", 7411 "range-parser": "~1.2.0",
7421 "statuses": "~1.4.0" 7412 "statuses": "~1.4.0"
7413 },
7414 "dependencies": {
7415 "ms": {
7416 "version": "2.0.0",
7417 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
7418 "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
7419 "dev": true
7420 }
7422 } 7421 }
7423 }, 7422 },
7424 "serve-static": { 7423 "serve-static": {
@@ -7886,6 +7885,14 @@
7886 "dev": true, 7885 "dev": true,
7887 "requires": { 7886 "requires": {
7888 "ms": "2.0.0" 7887 "ms": "2.0.0"
7888 },
7889 "dependencies": {
7890 "ms": {
7891 "version": "2.0.0",
7892 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
7893 "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
7894 "dev": true
7895 }
7889 } 7896 }
7890 } 7897 }
7891 } 7898 }
@@ -8079,30 +8086,36 @@
8079 "dependencies": { 8086 "dependencies": {
8080 "abbrev": { 8087 "abbrev": {
8081 "version": "1.1.1", 8088 "version": "1.1.1",
8082 "bundled": true 8089 "resolved": false,
8090 "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
8083 }, 8091 },
8084 "ansi-regex": { 8092 "ansi-regex": {
8085 "version": "2.1.1", 8093 "version": "2.1.1",
8086 "bundled": true 8094 "resolved": false,
8095 "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
8087 }, 8096 },
8088 "aproba": { 8097 "aproba": {
8089 "version": "1.2.0", 8098 "version": "1.2.0",
8090 "bundled": true 8099 "resolved": false,
8100 "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
8091 }, 8101 },
8092 "are-we-there-yet": { 8102 "are-we-there-yet": {
8093 "version": "1.1.5", 8103 "version": "1.1.5",
8094 "bundled": true, 8104 "resolved": false,
8105 "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
8095 "requires": { 8106 "requires": {
8096 "delegates": "^1.0.0" 8107 "delegates": "^1.0.0"
8097 } 8108 }
8098 }, 8109 },
8099 "balanced-match": { 8110 "balanced-match": {
8100 "version": "1.0.0", 8111 "version": "1.0.0",
8101 "bundled": true 8112 "resolved": false,
8113 "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
8102 }, 8114 },
8103 "brace-expansion": { 8115 "brace-expansion": {
8104 "version": "1.1.11", 8116 "version": "1.1.11",
8105 "bundled": true, 8117 "resolved": false,
8118 "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
8106 "requires": { 8119 "requires": {
8107 "balanced-match": "^1.0.0", 8120 "balanced-match": "^1.0.0",
8108 "concat-map": "0.0.1" 8121 "concat-map": "0.0.1"
@@ -8110,57 +8123,66 @@
8110 }, 8123 },
8111 "chownr": { 8124 "chownr": {
8112 "version": "1.1.1", 8125 "version": "1.1.1",
8113 "bundled": true 8126 "resolved": false,
8127 "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
8114 }, 8128 },
8115 "code-point-at": { 8129 "code-point-at": {
8116 "version": "1.1.0", 8130 "version": "1.1.0",
8117 "bundled": true 8131 "resolved": false,
8132 "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
8118 }, 8133 },
8119 "concat-map": { 8134 "concat-map": {
8120 "version": "0.0.1", 8135 "version": "0.0.1",
8121 "bundled": true 8136 "resolved": false,
8137 "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
8122 }, 8138 },
8123 "console-control-strings": { 8139 "console-control-strings": {
8124 "version": "1.1.0", 8140 "version": "1.1.0",
8125 "bundled": true 8141 "resolved": false,
8142 "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
8126 }, 8143 },
8127 "core-util-is": { 8144 "core-util-is": {
8128 "version": "1.0.2", 8145 "version": "1.0.2",
8129 "bundled": true 8146 "resolved": false,
8147 "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
8130 }, 8148 },
8131 "debug": { 8149 "debug": {
8132 "version": "2.6.9", 8150 "version": "2.6.9",
8133 "bundled": true, 8151 "resolved": false,
8134 "requires": { 8152 "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="
8135 "ms": "2.0.0"
8136 }
8137 }, 8153 },
8138 "deep-extend": { 8154 "deep-extend": {
8139 "version": "0.6.0", 8155 "version": "0.6.0",
8140 "bundled": true 8156 "resolved": false,
8157 "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
8141 }, 8158 },
8142 "delegates": { 8159 "delegates": {
8143 "version": "1.0.0", 8160 "version": "1.0.0",
8144 "bundled": true 8161 "resolved": false,
8162 "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
8145 }, 8163 },
8146 "detect-libc": { 8164 "detect-libc": {
8147 "version": "1.0.3", 8165 "version": "1.0.3",
8148 "bundled": true 8166 "resolved": false,
8167 "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
8149 }, 8168 },
8150 "fs-minipass": { 8169 "fs-minipass": {
8151 "version": "1.2.5", 8170 "version": "1.2.5",
8152 "bundled": true, 8171 "resolved": false,
8172 "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
8153 "requires": { 8173 "requires": {
8154 "minipass": "^2.2.1" 8174 "minipass": "^2.2.1"
8155 } 8175 }
8156 }, 8176 },
8157 "fs.realpath": { 8177 "fs.realpath": {
8158 "version": "1.0.0", 8178 "version": "1.0.0",
8159 "bundled": true 8179 "resolved": false,
8180 "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
8160 }, 8181 },
8161 "gauge": { 8182 "gauge": {
8162 "version": "2.7.4", 8183 "version": "2.7.4",
8163 "bundled": true, 8184 "resolved": false,
8185 "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
8164 "requires": { 8186 "requires": {
8165 "aproba": "^1.0.3", 8187 "aproba": "^1.0.3",
8166 "console-control-strings": "^1.0.0", 8188 "console-control-strings": "^1.0.0",
@@ -8172,7 +8194,8 @@
8172 }, 8194 },
8173 "glob": { 8195 "glob": {
8174 "version": "7.1.3", 8196 "version": "7.1.3",
8175 "bundled": true, 8197 "resolved": false,
8198 "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
8176 "requires": { 8199 "requires": {
8177 "fs.realpath": "^1.0.0", 8200 "fs.realpath": "^1.0.0",
8178 "inflight": "^1.0.4", 8201 "inflight": "^1.0.4",
@@ -8184,25 +8207,29 @@
8184 }, 8207 },
8185 "has-unicode": { 8208 "has-unicode": {
8186 "version": "2.0.1", 8209 "version": "2.0.1",
8187 "bundled": true 8210 "resolved": false,
8211 "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
8188 }, 8212 },
8189 "iconv-lite": { 8213 "iconv-lite": {
8190 "version": "0.4.24", 8214 "version": "0.4.24",
8191 "bundled": true, 8215 "resolved": false,
8216 "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
8192 "requires": { 8217 "requires": {
8193 "safer-buffer": ">= 2.1.2 < 3" 8218 "safer-buffer": ">= 2.1.2 < 3"
8194 } 8219 }
8195 }, 8220 },
8196 "ignore-walk": { 8221 "ignore-walk": {
8197 "version": "3.0.1", 8222 "version": "3.0.1",
8198 "bundled": true, 8223 "resolved": false,
8224 "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
8199 "requires": { 8225 "requires": {
8200 "minimatch": "^3.0.4" 8226 "minimatch": "^3.0.4"
8201 } 8227 }
8202 }, 8228 },
8203 "inflight": { 8229 "inflight": {
8204 "version": "1.0.6", 8230 "version": "1.0.6",
8205 "bundled": true, 8231 "resolved": false,
8232 "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
8206 "requires": { 8233 "requires": {
8207 "once": "^1.3.0", 8234 "once": "^1.3.0",
8208 "wrappy": "1" 8235 "wrappy": "1"
@@ -8210,15 +8237,18 @@
8210 }, 8237 },
8211 "inherits": { 8238 "inherits": {
8212 "version": "2.0.3", 8239 "version": "2.0.3",
8213 "bundled": true 8240 "resolved": false,
8241 "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
8214 }, 8242 },
8215 "ini": { 8243 "ini": {
8216 "version": "1.3.5", 8244 "version": "1.3.5",
8217 "bundled": true 8245 "resolved": false,
8246 "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
8218 }, 8247 },
8219 "is-fullwidth-code-point": { 8248 "is-fullwidth-code-point": {
8220 "version": "1.0.0", 8249 "version": "1.0.0",
8221 "bundled": true, 8250 "resolved": false,
8251 "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
8222 "requires": { 8252 "requires": {
8223 "number-is-nan": "^1.0.0" 8253 "number-is-nan": "^1.0.0"
8224 } 8254 }
@@ -10314,6 +10344,14 @@
10314 "dev": true, 10344 "dev": true,
10315 "requires": { 10345 "requires": {
10316 "ms": "2.0.0" 10346 "ms": "2.0.0"
10347 },
10348 "dependencies": {
10349 "ms": {
10350 "version": "2.0.0",
10351 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
10352 "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
10353 "dev": true
10354 }
10317 } 10355 }
10318 } 10356 }
10319 } 10357 }
@@ -10563,7 +10601,8 @@
10563 "ini": { 10601 "ini": {
10564 "version": "1.3.5", 10602 "version": "1.3.5",
10565 "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", 10603 "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
10566 "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" 10604 "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
10605 "dev": true
10567 }, 10606 },
10568 "init-package-json": { 10607 "init-package-json": {
10569 "version": "1.10.3", 10608 "version": "1.10.3",
@@ -12301,7 +12340,8 @@
12301 "minimist": { 12340 "minimist": {
12302 "version": "1.2.0", 12341 "version": "1.2.0",
12303 "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 12342 "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
12304 "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" 12343 "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
12344 "dev": true
12305 }, 12345 },
12306 "minimist-options": { 12346 "minimist-options": {
12307 "version": "3.0.2", 12347 "version": "3.0.2",
@@ -12457,6 +12497,14 @@
12457 "dev": true, 12497 "dev": true,
12458 "requires": { 12498 "requires": {
12459 "ms": "2.0.0" 12499 "ms": "2.0.0"
12500 },
12501 "dependencies": {
12502 "ms": {
12503 "version": "2.0.0",
12504 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
12505 "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
12506 "dev": true
12507 }
12460 } 12508 }
12461 }, 12509 },
12462 "glob": { 12510 "glob": {
@@ -12521,9 +12569,9 @@
12521 } 12569 }
12522 }, 12570 },
12523 "ms": { 12571 "ms": {
12524 "version": "2.0.0", 12572 "version": "2.1.1",
12525 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 12573 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
12526 "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 12574 "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
12527 }, 12575 },
12528 "multicast-dns": { 12576 "multicast-dns": {
12529 "version": "6.2.3", 12577 "version": "6.2.3",
@@ -14622,14 +14670,6 @@
14622 "react-is": "^16.8.1" 14670 "react-is": "^16.8.1"
14623 } 14671 }
14624 }, 14672 },
14625 "prop-types-extended": {
14626 "version": "0.2.1",
14627 "resolved": "https://registry.npmjs.org/prop-types-extended/-/prop-types-extended-0.2.1.tgz",
14628 "integrity": "sha1-ziPz28SMzcds+hpMfj9+2aXdglk=",
14629 "requires": {
14630 "invariant": "^2.2.0"
14631 }
14632 },
14633 "proto-list": { 14673 "proto-list": {
14634 "version": "1.2.4", 14674 "version": "1.2.4",
14635 "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", 14675 "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
diff --git a/package.json b/package.json
index 912ee4662..b0ede2e7e 100644
--- a/package.json
+++ b/package.json
@@ -41,7 +41,6 @@
41 "auto-launch": "https://github.com/meetfranz/node-auto-launch.git", 41 "auto-launch": "https://github.com/meetfranz/node-auto-launch.git",
42 "classnames": "2.2.6", 42 "classnames": "2.2.6",
43 "cld3-asm": "1.0.1", 43 "cld3-asm": "1.0.1",
44 "debug-electron": "^0.0.4",
45 "du": "^0.1.0", 44 "du": "^0.1.0",
46 "electron-dl": "1.12.0", 45 "electron-dl": "1.12.0",
47 "electron-fetch": "1.3.0", 46 "electron-fetch": "1.3.0",
@@ -52,24 +51,21 @@
52 "electron-window-state": "5.0.3", 51 "electron-window-state": "5.0.3",
53 "fs-extra": "7.0.1", 52 "fs-extra": "7.0.1",
54 "hex-to-rgba": "1.0.2", 53 "hex-to-rgba": "1.0.2",
55 "ini": "^1.3.4",
56 "jsonwebtoken": "^7.4.1", 54 "jsonwebtoken": "^7.4.1",
57 "keymaster": "^1.6.2", 55 "keymaster": "^1.6.2",
58 "lodash": "^4.17.4", 56 "lodash": "^4.17.4",
59 "mdi": "^1.9.33", 57 "mdi": "^1.9.33",
60 "mime-types": "2.1.21", 58 "mime-types": "2.1.21",
61 "minimist": "^1.2.0",
62 "mkdirp": "^0.5.1",
63 "mobx": "5.7.0", 59 "mobx": "5.7.0",
64 "mobx-localstorage": "1.1.0", 60 "mobx-localstorage": "1.1.0",
65 "mobx-react": "5.4.2", 61 "mobx-react": "5.4.2",
66 "mobx-react-form": "1.35.1", 62 "mobx-react-form": "1.35.1",
67 "mobx-react-router": "3.1.2", 63 "mobx-react-router": "3.1.2",
68 "moment": "^2.17.1", 64 "moment": "^2.17.1",
65 "ms": "2.1.1",
69 "normalize-url": "^1.9.1", 66 "normalize-url": "^1.9.1",
70 "pretty-bytes": "^4.0.2", 67 "pretty-bytes": "^4.0.2",
71 "prop-types": "^15.5.10", 68 "prop-types": "^15.5.10",
72 "prop-types-extended": "^0.2.1",
73 "react": "16.6.3", 69 "react": "16.6.3",
74 "react-addons-css-transition-group": "15.6.2", 70 "react-addons-css-transition-group": "15.6.2",
75 "react-dom": "16.6.3", 71 "react-dom": "16.6.3",
@@ -157,7 +153,7 @@
157 } 153 }
158 }, 154 },
159 "browserslist": [ 155 "browserslist": [
160 "Chrome 66" 156 "Chrome 69"
161 ], 157 ],
162 "husky": { 158 "husky": {
163 "hooks": { 159 "hooks": {
diff --git a/packages/theme/src/themes/dark/index.ts b/packages/theme/src/themes/dark/index.ts
index 1757f5abd..3a56719b2 100644
--- a/packages/theme/src/themes/dark/index.ts
+++ b/packages/theme/src/themes/dark/index.ts
@@ -62,4 +62,4 @@ export const selectOptionItemHoverColor = selectColor;
62export const selectSearchColor = inputBackground; 62export const selectSearchColor = inputBackground;
63 63
64// Modal 64// Modal
65export const colorModalOverlayBackground = color(legacyStyles.darkThemeGray).alpha(0.8).rgb().string(); 65export const colorModalOverlayBackground = color(legacyStyles.darkThemeBlack).alpha(0.8).rgb().string();
diff --git a/packages/theme/src/themes/default/index.ts b/packages/theme/src/themes/default/index.ts
index 40521995b..8a71e61cf 100644
--- a/packages/theme/src/themes/default/index.ts
+++ b/packages/theme/src/themes/default/index.ts
@@ -139,4 +139,4 @@ export const badgeFontSize = uiFontSize - 2;
139export const badgeBorderRadius = 50; 139export const badgeBorderRadius = 50;
140 140
141// Modal 141// Modal
142export const colorModalOverlayBackground = color(legacyStyles.themeGrayLighter).alpha(0.8).rgb().string(); 142export const colorModalOverlayBackground = color('#000').alpha(0.5).rgb().string();
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js
index bce792e56..593149e72 100644
--- a/src/components/layout/AppLayout.js
+++ b/src/components/layout/AppLayout.js
@@ -7,6 +7,7 @@ import { TitleBar } from 'electron-react-titlebar';
7import InfoBar from '../ui/InfoBar'; 7import InfoBar from '../ui/InfoBar';
8import { Component as DelayApp } from '../../features/delayApp'; 8import { Component as DelayApp } from '../../features/delayApp';
9import { Component as BasicAuth } from '../../features/basicAuth'; 9import { Component as BasicAuth } from '../../features/basicAuth';
10import { Component as ShareFranz } from '../../features/shareFranz';
10import ErrorBoundary from '../util/ErrorBoundary'; 11import ErrorBoundary from '../util/ErrorBoundary';
11 12
12// import globalMessages from '../../i18n/globalMessages'; 13// import globalMessages from '../../i18n/globalMessages';
@@ -164,6 +165,7 @@ export default @observer class AppLayout extends Component {
164 )} 165 )}
165 {isDelayAppScreenVisible && (<DelayApp />)} 166 {isDelayAppScreenVisible && (<DelayApp />)}
166 <BasicAuth /> 167 <BasicAuth />
168 <ShareFranz />
167 {services} 169 {services}
168 </div> 170 </div>
169 </div> 171 </div>
diff --git a/src/components/services/content/WebviewCrashHandler.js b/src/components/services/content/WebviewCrashHandler.js
index 42bc3c877..7a69dba87 100644
--- a/src/components/services/content/WebviewCrashHandler.js
+++ b/src/components/services/content/WebviewCrashHandler.js
@@ -2,6 +2,7 @@ import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, intlShape } from 'react-intl';
5import ms from 'ms';
5 6
6import Button from '../../ui/Button'; 7import Button from '../../ui/Button';
7 8
@@ -35,12 +36,12 @@ export default @observer class WebviewCrashHandler extends Component {
35 }; 36 };
36 37
37 state = { 38 state = {
38 countdown: 10000, 39 countdown: ms('10s'),
39 } 40 }
40 41
41 countdownInterval = null; 42 countdownInterval = null;
42 43
43 countdownIntervalTimeout = 1000; 44 countdownIntervalTimeout = ms('1s');
44 45
45 46
46 componentDidMount() { 47 componentDidMount() {
@@ -75,7 +76,7 @@ export default @observer class WebviewCrashHandler extends Component {
75 <p className="footnote"> 76 <p className="footnote">
76 {intl.formatMessage(messages.autoReload, { 77 {intl.formatMessage(messages.autoReload, {
77 name, 78 name,
78 seconds: this.state.countdown / 1000, 79 seconds: this.state.countdown / ms('1s'),
79 })} 80 })}
80 </p> 81 </p>
81 </div> 82 </div>
diff --git a/src/components/subscription/SubscriptionPopup.js b/src/components/subscription/SubscriptionPopup.js
index b5d7c4b2d..0f6f0260f 100644
--- a/src/components/subscription/SubscriptionPopup.js
+++ b/src/components/subscription/SubscriptionPopup.js
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, intlShape } from 'react-intl';
5import Webview from 'react-electron-web-view'; 5import Webview from 'react-electron-web-view';
6import ms from 'ms';
6 7
7import Button from '../ui/Button'; 8import Button from '../ui/Button';
8 9
@@ -42,7 +43,7 @@ export default @observer class SubscriptionPopup extends Component {
42 43
43 setTimeout(() => { 44 setTimeout(() => {
44 this.props.closeWindow(); 45 this.props.closeWindow();
45 }, 4000); 46 }, ms('4s'));
46 } 47 }
47 48
48 render() { 49 render() {
diff --git a/src/components/ui/Modal/index.js b/src/components/ui/Modal/index.js
index d84e4c713..8e6ec5a0e 100644
--- a/src/components/ui/Modal/index.js
+++ b/src/components/ui/Modal/index.js
@@ -5,6 +5,9 @@ import classnames from 'classnames';
5import injectCSS from 'react-jss'; 5import injectCSS from 'react-jss';
6 6
7import styles from './styles'; 7import styles from './styles';
8import { Icon } from '../../../../packages/ui/lib';
9
10// ReactModal.setAppElement('#root');
8 11
9export default @injectCSS(styles) class Modal extends Component { 12export default @injectCSS(styles) class Modal extends Component {
10 static propTypes = { 13 static propTypes = {
@@ -14,11 +17,15 @@ export default @injectCSS(styles) class Modal extends Component {
14 isOpen: PropTypes.bool.isRequired, 17 isOpen: PropTypes.bool.isRequired,
15 portal: PropTypes.string, 18 portal: PropTypes.string,
16 close: PropTypes.func.isRequired, 19 close: PropTypes.func.isRequired,
20 shouldCloseOnOverlayClick: PropTypes.bool,
21 showClose: PropTypes.bool,
17 } 22 }
18 23
19 static defaultProps = { 24 static defaultProps = {
20 className: null, 25 className: null,
21 portal: 'modal-portal', 26 portal: 'modal-portal',
27 shouldCloseOnOverlayClick: false,
28 showClose: true,
22 } 29 }
23 30
24 render() { 31 render() {
@@ -29,6 +36,8 @@ export default @injectCSS(styles) class Modal extends Component {
29 isOpen, 36 isOpen,
30 portal, 37 portal,
31 close, 38 close,
39 shouldCloseOnOverlayClick,
40 showClose,
32 } = this.props; 41 } = this.props;
33 42
34 return ( 43 return (
@@ -42,14 +51,17 @@ export default @injectCSS(styles) class Modal extends Component {
42 overlayClassName={classes.overlay} 51 overlayClassName={classes.overlay}
43 portal={portal} 52 portal={portal}
44 onRequestClose={close} 53 onRequestClose={close}
54 shouldCloseOnOverlayClick={shouldCloseOnOverlayClick}
45 > 55 >
46 {/* <button 56 {showClose && close && (
47 type="button" 57 <button
48 className={classnames({ 58 type="button"
49 [`${classes.close}`]: true, 59 className={classes.close}
50 'mdi mdi-close': true, 60 onClick={close}
51 })} 61 >
52 /> */} 62 <Icon icon="mdiClose" size={1.5} />
63 </button>
64 )}
53 <div className={classes.content}> 65 <div className={classes.content}>
54 {children} 66 {children}
55 </div> 67 </div>
diff --git a/src/components/ui/Modal/styles.js b/src/components/ui/Modal/styles.js
index 56fecbf55..49b970c97 100644
--- a/src/components/ui/Modal/styles.js
+++ b/src/components/ui/Modal/styles.js
@@ -28,5 +28,6 @@ export default theme => ({
28 position: 'absolute', 28 position: 'absolute',
29 top: 0, 29 top: 0,
30 right: 0, 30 right: 0,
31 padding: 20,
31 }, 32 },
32}); 33});
diff --git a/src/config.js b/src/config.js
index b11952520..30a5a5cc0 100644
--- a/src/config.js
+++ b/src/config.js
@@ -1,13 +1,14 @@
1import electron from 'electron'; 1import electron from 'electron';
2import path from 'path'; 2import path from 'path';
3import isDevMode from 'electron-is-dev'; 3import isDevMode from 'electron-is-dev';
4import ms from 'ms';
4 5
5import { asarPath } from './helpers/asar-helpers'; 6import { asarPath } from './helpers/asar-helpers';
6 7
7const app = process.type === 'renderer' ? electron.remote.app : electron.app; 8const app = process.type === 'renderer' ? electron.remote.app : electron.app;
8const systemPreferences = process.type === 'renderer' ? electron.remote.systemPreferences : electron.systemPreferences; 9const systemPreferences = process.type === 'renderer' ? electron.remote.systemPreferences : electron.systemPreferences;
9 10
10export const CHECK_INTERVAL = 1000 * 3600; // How often should we perform checks 11export const CHECK_INTERVAL = ms('1h'); // How often should we perform checks
11export const LOCAL_API = 'http://localhost:3000'; 12export const LOCAL_API = 'http://localhost:3000';
12export const DEV_API = 'https://dev.franzinfra.com'; 13export const DEV_API = 'https://dev.franzinfra.com';
13export const LIVE_API = 'https://api.franzinfra.com'; 14export const LIVE_API = 'https://api.franzinfra.com';
@@ -35,8 +36,8 @@ export const DEFAULT_FEATURES_CONFIG = {
35 isSpellcheckerPremiumFeature: false, 36 isSpellcheckerPremiumFeature: false,
36 needToWaitToProceed: false, 37 needToWaitToProceed: false,
37 needToWaitToProceedConfig: { 38 needToWaitToProceedConfig: {
38 delayOffset: 3600000, 39 delayOffset: ms('1h'),
39 wait: 10000, 40 wait: ms('10s'),
40 }, 41 },
41 isServiceProxyEnabled: false, 42 isServiceProxyEnabled: false,
42 isServiceProxyPremiumFeature: true, 43 isServiceProxyPremiumFeature: true,
diff --git a/src/features/basicAuth/Component.js b/src/features/basicAuth/Component.js
index 13395fb40..a8252acb7 100644
--- a/src/features/basicAuth/Component.js
+++ b/src/features/basicAuth/Component.js
@@ -62,6 +62,7 @@ export default @injectSheet(styles) @observer class BasicAuthModal extends Compo
62 isOpen={isModalVisible} 62 isOpen={isModalVisible}
63 className={classes.modal} 63 className={classes.modal}
64 close={this.cancel.bind(this)} 64 close={this.cancel.bind(this)}
65 showClose={false}
65 > 66 >
66 <h1>Sign in</h1> 67 <h1>Sign in</h1>
67 <p> 68 <p>
diff --git a/src/features/basicAuth/index.js b/src/features/basicAuth/index.js
index 00ad65ce6..89607824b 100644
--- a/src/features/basicAuth/index.js
+++ b/src/features/basicAuth/index.js
@@ -6,7 +6,7 @@ import BasicAuthComponent from './Component';
6const debug = require('debug')('Franz:feature:basicAuth'); 6const debug = require('debug')('Franz:feature:basicAuth');
7 7
8const defaultState = { 8const defaultState = {
9 isModalVisible: false, 9 isModalVisible: true,
10 service: null, 10 service: null,
11 authInfo: null, 11 authInfo: null,
12}; 12};
@@ -15,7 +15,6 @@ export const state = observable(defaultState);
15 15
16export function resetState() { 16export function resetState() {
17 Object.assign(state, defaultState); 17 Object.assign(state, defaultState);
18 console.log('reset state', state);
19} 18}
20 19
21export default function initialize() { 20export default function initialize() {
diff --git a/src/features/delayApp/index.js b/src/features/delayApp/index.js
index 48aac34b6..abc8274cf 100644
--- a/src/features/delayApp/index.js
+++ b/src/features/delayApp/index.js
@@ -28,8 +28,12 @@ export default function init(stores) {
28 let shownAfterLaunch = false; 28 let shownAfterLaunch = false;
29 let timeLastDelay = moment(); 29 let timeLastDelay = moment();
30 30
31 window.franz.features.delayApp = {
32 state,
33 };
34
31 reaction( 35 reaction(
32 () => stores.features.features.needToWaitToProceed && !stores.user.data.isPremium, 36 () => stores.user.isLoggedIn && stores.features.features.needToWaitToProceed && !stores.user.data.isPremium,
33 (isEnabled) => { 37 (isEnabled) => {
34 if (isEnabled) { 38 if (isEnabled) {
35 debug('Enabling `delayApp` feature'); 39 debug('Enabling `delayApp` feature');
diff --git a/src/features/shareFranz/Component.js b/src/features/shareFranz/Component.js
new file mode 100644
index 000000000..d463664df
--- /dev/null
+++ b/src/features/shareFranz/Component.js
@@ -0,0 +1,170 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer, inject } from 'mobx-react';
4import injectSheet from 'react-jss';
5import { defineMessages, intlShape } from 'react-intl';
6import { Button } from '@meetfranz/forms';
7import { H1, Icon } from '@meetfranz/ui';
8
9import Modal from '../../components/ui/Modal';
10import { state } from '.';
11import { gaEvent } from '../../lib/analytics';
12import ServicesStore from '../../stores/ServicesStore';
13
14const messages = defineMessages({
15 headline: {
16 id: 'feature.shareFranz.headline',
17 defaultMessage: '!!!Franz is better together!',
18 },
19 text: {
20 id: 'feature.shareFranz.text',
21 defaultMessage: '!!!Tell your friends and colleagues how awesome Franz is and help us to spread the word.',
22 },
23 actions: {
24 email: {
25 id: 'feature.shareFranz.action.email',
26 defaultMessage: '!!!Share as email',
27 },
28 facebook: {
29 id: 'feature.shareFranz.action.facebook',
30 defaultMessage: '!!!Share on Facebook',
31 },
32 twitter: {
33 id: 'feature.shareFranz.action.twitter',
34 defaultMessage: '!!!Share on Twitter',
35 },
36 },
37 shareText: {
38 email: {
39 id: 'feature.shareFranz.shareText.email',
40 defaultMessage: '!!! I\'ve added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com',
41 },
42 twitter: {
43 id: 'feature.shareFranz.shareText.twitter',
44 defaultMessage: '!!! I\'ve added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com /cc @MeetFranz',
45 },
46 },
47});
48
49const styles = theme => ({
50 modal: {
51 width: '80%',
52 maxWidth: 600,
53 background: theme.styleTypes.primary.accent,
54 textAlign: 'center',
55 color: theme.styleTypes.primary.contrast,
56 },
57 heartContainer: {
58 display: 'flex',
59 justifyContent: 'center',
60 borderRadius: '100%',
61 background: theme.brandDanger,
62 padding: 20,
63 width: 100,
64 height: 100,
65 margin: [-70, 'auto', 30],
66 },
67 heart: {
68 fill: theme.styleTypes.primary.contrast,
69 },
70 headline: {
71 textAlign: 'center',
72 fontSize: 40,
73 marginBottom: 20,
74 },
75 actions: {
76 display: 'flex',
77 justifyContent: 'space-between',
78 marginTop: 30,
79 },
80 cta: {
81 background: theme.styleTypes.primary.contrast,
82 color: theme.styleTypes.primary.accent,
83
84 '& svg': {
85 fill: theme.styleTypes.primary.accent,
86 },
87 },
88});
89
90export default @injectSheet(styles) @inject('stores') @observer class ShareFranzModal extends Component {
91 static propTypes = {
92 classes: PropTypes.object.isRequired,
93 }
94
95 static contextTypes = {
96 intl: intlShape,
97 };
98
99 close() {
100 state.isModalVisible = false;
101 }
102
103 render() {
104 const { isModalVisible } = state;
105
106 const {
107 classes,
108 stores,
109 } = this.props;
110
111 const serviceCount = stores.services.all.length;
112
113 const { intl } = this.context;
114
115 return (
116 <Modal
117 isOpen={isModalVisible}
118 className={classes.modal}
119 shouldCloseOnOverlayClick
120 close={this.close.bind(this)}
121 >
122 <div className={classes.heartContainer}>
123 <Icon icon="mdiHeart" className={classes.heart} size={4} />
124 </div>
125 <H1 className={classes.headline}>
126 {intl.formatMessage(messages.headline)}
127 </H1>
128 <p>{intl.formatMessage(messages.text)}</p>
129 <div className={classes.actions}>
130 <Button
131 label={intl.formatMessage(messages.actions.email)}
132 className={classes.cta}
133 icon="mdiEmail"
134 href={`mailto:?subject=Meet the cool app Franz&body=${intl.formatMessage(messages.shareText.email, { count: serviceCount })}}`}
135 target="_blank"
136 onClick={() => {
137 gaEvent('Share Franz', 'share', 'Share via email');
138 }}
139 />
140 <Button
141 label={intl.formatMessage(messages.actions.facebook)}
142 className={classes.cta}
143 icon="mdiFacebookBox"
144 href="https://www.facebook.com/sharer/sharer.php?u=https://www.meetfranz.com?utm_source=facebook&utm_medium=referral&utm_campaign=share-button"
145 target="_blank"
146 onClick={() => {
147 gaEvent('Share Franz', 'share', 'Share via Facebook');
148 }}
149 />
150 <Button
151 label={intl.formatMessage(messages.actions.twitter)}
152 className={classes.cta}
153 icon="mdiTwitter"
154 href={`http://twitter.com/intent/tweet?status=${intl.formatMessage(messages.shareText.twitter, { count: serviceCount })}`}
155 target="_blank"
156 onClick={() => {
157 gaEvent('Share Franz', 'share', 'Share via Twitter');
158 }}
159 />
160 </div>
161 </Modal>
162 );
163 }
164}
165
166ShareFranzModal.wrappedComponent.propTypes = {
167 stores: PropTypes.shape({
168 services: PropTypes.instanceOf(ServicesStore).isRequired,
169 }).isRequired,
170};
diff --git a/src/features/shareFranz/index.js b/src/features/shareFranz/index.js
new file mode 100644
index 000000000..3a8ec95d3
--- /dev/null
+++ b/src/features/shareFranz/index.js
@@ -0,0 +1,52 @@
1import { observable, reaction } from 'mobx';
2import ms from 'ms';
3
4import { state as delayAppState } from '../delayApp';
5import { gaEvent, gaPage } from '../../lib/analytics';
6
7export { default as Component } from './Component';
8
9const debug = require('debug')('Franz:feature:shareFranz');
10
11const defaultState = {
12 isModalVisible: false,
13 lastShown: null,
14};
15
16export const state = observable(defaultState);
17
18export default function initialize(stores) {
19 debug('Initialize shareFranz feature');
20
21 window.franz.features.shareFranz = {
22 state,
23 };
24
25 function showModal() {
26 debug('Showing share window');
27
28 state.isModalVisible = true;
29
30 gaEvent('Share Franz', 'show');
31 gaPage('/share-modal');
32 }
33
34 reaction(
35 () => stores.user.isLoggedIn,
36 () => {
37 setTimeout(() => {
38 if (stores.settings.stats.appStarts % 30 === 0) {
39 if (delayAppState.isDelayAppScreenVisible) {
40 debug('Delaying share modal by 5 minutes');
41 setTimeout(() => showModal(), ms('5m'));
42 } else {
43 showModal();
44 }
45 }
46 }, ms('2s'));
47 },
48 {
49 fireImmediately: true,
50 },
51 );
52}
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index cd5c417e3..988ac46f2 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -286,5 +286,12 @@
286 "feature.delayApp.text": "Franz will continue in {seconds} seconds.", 286 "feature.delayApp.text": "Franz will continue in {seconds} seconds.",
287 "premiumFeature.button.upgradeAccount": "Upgrade account", 287 "premiumFeature.button.upgradeAccount": "Upgrade account",
288 "app.errorHandler.headline": "Something went wrong", 288 "app.errorHandler.headline": "Something went wrong",
289 "app.errorHandler.action": "Reload" 289 "app.errorHandler.action": "Reload",
290 "feature.shareFranz.headline": "Franz is better together!",
291 "feature.shareFranz.text": "Tell your friends and colleagues how awesome Franz is and help us to spread the word.",
292 "feature.shareFranz.action.email": "Send as email",
293 "feature.shareFranz.action.facebook": "Share on Facebook",
294 "feature.shareFranz.action.twitter": "Share on Twitter",
295 "feature.shareFranz.shareText.email": "I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com",
296 "feature.shareFranz.shareText.twitter": "I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com /cc @MeetFranz"
290} 297}
diff --git a/src/lib/analytics.js b/src/lib/analytics.js
index 7044e5bb7..0519192d1 100644
--- a/src/lib/analytics.js
+++ b/src/lib/analytics.js
@@ -37,7 +37,3 @@ export function gaEvent(category, action, label) {
37 37
38 debug('GA track event', category, action); 38 debug('GA track event', category, action);
39} 39}
40
41setTimeout(() => {
42 ga('send', 'Ping');
43}, 1000 * 60 * 10); // Ping GA every 10 Minutes
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js
index d90f32744..168aa7e48 100644
--- a/src/stores/AppStore.js
+++ b/src/stores/AppStore.js
@@ -7,6 +7,7 @@ import key from 'keymaster';
7import { getDoNotDisturb } from '@meetfranz/electron-notification-state'; 7import { getDoNotDisturb } from '@meetfranz/electron-notification-state';
8import AutoLaunch from 'auto-launch'; 8import AutoLaunch from 'auto-launch';
9import prettyBytes from 'pretty-bytes'; 9import prettyBytes from 'pretty-bytes';
10import ms from 'ms';
10 11
11import Store from './lib/Store'; 12import Store from './lib/Store';
12import Request from './lib/Request'; 13import Request from './lib/Request';
@@ -112,12 +113,12 @@ export default class AppStore extends Store {
112 // Check if system is muted 113 // Check if system is muted
113 // There are no events to subscribe so we need to poll everey 5s 114 // There are no events to subscribe so we need to poll everey 5s
114 this._systemDND(); 115 this._systemDND();
115 setInterval(() => this._systemDND(), 5000); 116 setInterval(() => this._systemDND(), ms('5s'));
116 117
117 // Check for updates once every 4 hours 118 // Check for updates once every 4 hours
118 setInterval(() => this._checkForUpdates(), CHECK_INTERVAL); 119 setInterval(() => this._checkForUpdates(), CHECK_INTERVAL);
119 // Check for an update in 30s (need a delay to prevent Squirrel Installer lock file issues) 120 // Check for an update in 30s (need a delay to prevent Squirrel Installer lock file issues)
120 setTimeout(() => this._checkForUpdates(), 30000); 121 setTimeout(() => this._checkForUpdates(), ms('30s'));
121 ipcRenderer.on('autoUpdate', (event, data) => { 122 ipcRenderer.on('autoUpdate', (event, data) => {
122 if (data.available) { 123 if (data.available) {
123 this.updateStatus = this.updateStatusTypes.AVAILABLE; 124 this.updateStatus = this.updateStatusTypes.AVAILABLE;
@@ -316,7 +317,7 @@ export default class AppStore extends Store {
316 } else { 317 } else {
317 const deltaTime = moment().diff(this.timeOfflineStart); 318 const deltaTime = moment().diff(this.timeOfflineStart);
318 319
319 if (deltaTime > 30 * 60 * 1000) { 320 if (deltaTime > ms('30m')) {
320 this.actions.service.reloadAll(); 321 this.actions.service.reloadAll();
321 } 322 }
322 } 323 }
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js
index 05a620f0b..b7130904b 100644
--- a/src/stores/FeaturesStore.js
+++ b/src/stores/FeaturesStore.js
@@ -8,6 +8,7 @@ import spellchecker from '../features/spellchecker';
8import serviceProxy from '../features/serviceProxy'; 8import serviceProxy from '../features/serviceProxy';
9import basicAuth from '../features/basicAuth'; 9import basicAuth from '../features/basicAuth';
10import workspaces from '../features/workspaces'; 10import workspaces from '../features/workspaces';
11import shareFranz from '../features/shareFranz';
11 12
12import { DEFAULT_FEATURES_CONFIG } from '../config'; 13import { DEFAULT_FEATURES_CONFIG } from '../config';
13 14
@@ -58,5 +59,6 @@ export default class FeaturesStore extends Store {
58 serviceProxy(this.stores, this.actions); 59 serviceProxy(this.stores, this.actions);
59 basicAuth(this.stores, this.actions); 60 basicAuth(this.stores, this.actions);
60 workspaces(this.stores, this.actions); 61 workspaces(this.stores, this.actions);
62 shareFranz(this.stores, this.actions);
61 } 63 }
62} 64}
diff --git a/src/stores/RecipePreviewsStore.js b/src/stores/RecipePreviewsStore.js
index 10b2928e3..382820d58 100644
--- a/src/stores/RecipePreviewsStore.js
+++ b/src/stores/RecipePreviewsStore.js
@@ -1,5 +1,6 @@
1import { action, computed, observable } from 'mobx'; 1import { action, computed, observable } from 'mobx';
2import { debounce } from 'lodash'; 2import { debounce } from 'lodash';
3import ms from 'ms';
3 4
4import Store from './lib/Store'; 5import Store from './lib/Store';
5import CachedRequest from './lib/CachedRequest'; 6import CachedRequest from './lib/CachedRequest';
@@ -48,5 +49,5 @@ export default class RecipePreviewsStore extends Store {
48 // Helper 49 // Helper
49 _analyticsSearch = debounce((needle) => { 50 _analyticsSearch = debounce((needle) => {
50 gaEvent('Recipe', 'search', needle); 51 gaEvent('Recipe', 'search', needle);
51 }, 3000); 52 }, ms('3s'));
52} 53}
diff --git a/src/stores/RequestStore.js b/src/stores/RequestStore.js
index 2629e0a38..9254e3223 100644
--- a/src/stores/RequestStore.js
+++ b/src/stores/RequestStore.js
@@ -1,4 +1,5 @@
1import { action, computed, observable } from 'mobx'; 1import { action, computed, observable } from 'mobx';
2import ms from 'ms';
2 3
3import Store from './lib/Store'; 4import Store from './lib/Store';
4 5
@@ -13,7 +14,7 @@ export default class RequestStore extends Store {
13 14
14 retries = 0; 15 retries = 0;
15 16
16 retryDelay = 2000; 17 retryDelay = ms('2s');
17 18
18 constructor(...args) { 19 constructor(...args) {
19 super(...args); 20 super(...args);
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js
index efd57a09d..c63bef196 100644
--- a/src/stores/ServicesStore.js
+++ b/src/stores/ServicesStore.js
@@ -5,6 +5,7 @@ import {
5 observable, 5 observable,
6} from 'mobx'; 6} from 'mobx';
7import { debounce, remove } from 'lodash'; 7import { debounce, remove } from 'lodash';
8import ms from 'ms';
8 9
9import Store from './lib/Store'; 10import Store from './lib/Store';
10import Request from './lib/Request'; 11import Request from './lib/Request';
@@ -679,7 +680,7 @@ export default class ServicesStore extends Store {
679 _initRecipePolling(serviceId) { 680 _initRecipePolling(serviceId) {
680 const service = this.one(serviceId); 681 const service = this.one(serviceId);
681 682
682 const delay = 2000; 683 const delay = ms('2s');
683 684
684 if (service) { 685 if (service) {
685 if (service.timer !== null) { 686 if (service.timer !== null) {
@@ -700,7 +701,7 @@ export default class ServicesStore extends Store {
700 701
701 _reorderAnalytics = debounce(() => { 702 _reorderAnalytics = debounce(() => {
702 gaEvent('Service', 'order'); 703 gaEvent('Service', 'order');
703 }, 5000); 704 }, ms('5s'));
704 705
705 _wrapIndex(index, delta, size) { 706 _wrapIndex(index, delta, size) {
706 return (((index + delta) % size) + size) % size; 707 return (((index + delta) % size) + size) % size;