diff --git a/blackboxtest/yarn.lock b/blackboxtest/yarn.lock index d422ab193e1aabb7dbc091510c90d0f308f6dd09..a7bdf3abd7309fa2c8b71ea58576b44d169391e5 100644 --- a/blackboxtest/yarn.lock +++ b/blackboxtest/yarn.lock @@ -19,8 +19,10 @@ ajv@^5.1.0: json-schema-traverse "^0.3.0" asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + dependencies: + safer-buffer "~2.1.0" assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" @@ -51,8 +53,8 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" dependencies: tweetnacl "^0.14.3" @@ -189,10 +191,11 @@ diff@1.4.0: resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" dependencies: jsbn "~0.1.0" + safer-buffer "^2.1.0" ejs@2.5.7: version "2.5.7" @@ -230,8 +233,8 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" extend@3, extend@~3.0.0, extend@~3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" extract-zip@^1.6.5: version "1.6.6" @@ -912,6 +915,10 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" +safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + semver@~5.0.1: version "5.0.3" resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" @@ -950,17 +957,17 @@ source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" sshpk@^1.7.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" ecc-jsbn "~0.1.1" + getpass "^0.1.1" jsbn "~0.1.0" + safer-buffer "^2.0.2" tweetnacl "~0.14.0" "statuses@>= 1.3.1 < 2": @@ -978,8 +985,8 @@ string_decoder@~1.0.3: safe-buffer "~5.1.0" stringstream@~0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + version "0.0.6" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" supports-color@3.1.2: version "3.1.2" diff --git a/config/custom-environment-variables.json b/config/custom-environment-variables.json index 459b7c9408e8179c136a4abbf41b49c5fec09bbc..92faf7449895e6d77aacaf290054bd353c11ccd2 100644 --- a/config/custom-environment-variables.json +++ b/config/custom-environment-variables.json @@ -25,22 +25,8 @@ "secret_key": "SDC_RECAPTCHA_SECRET_KEY", "site_key": "SDC_RECAPTCHA_SITE_KEY" }, - "sendgrid": { - "from": "SDC_SENDGRID_FROM", - "key": "SDC_SENDGRID_API_KEY", - "templates": { - } - }, "server_session_secret": "SDC_SESSION_SECRETKEY", "site_domain": "SDC_SITE_DOMAIN", - "telesign": { - "customer_id": "SDC_TELESIGN_CUSTOMER_ID", - "rest_api_key": "SDC_TELESIGN_API_KEY" - }, - "twilio": { - "account_sid": "SDC_TWILIO_ACCOUNT_SID", - "auth_token": "SDC_TWILIO_AUTH_TOKEN" - }, "upload_image": "SDC_UPLOAD_IMAGE_URL", "session_cookie_key": "SDC_SESSION_COOKIE_KEY", "steemd_connection_client": "SDC_CLIENT_STEEMD_URL", diff --git a/config/default.json b/config/default.json index d8c985314939d08b2b8758c470abca4a43201ff1..91cfa4d426d8e51e93143340c81549f9b389d569 100644 --- a/config/default.json +++ b/config/default.json @@ -30,24 +30,10 @@ "secret_key": false, "site_key": false }, - "sendgrid": { - "from": "noreply@example.com", - "key": "SG.xxx_yyyy", - "templates": { - } - }, "server_session_secret": "exiKdyF+IwRIXJDmtGIl4vWUz4i3eVSISpfZoeYc0s4=", "session_cookie_key": "stm-dev", "session_key": "steemses", "site_domain": "steemitdev.com", - "telesign": { - "customer_id": false, - "rest_api_key": false - }, - "twilio": { - "account_sid": false, - "auth_token": false - }, "upload_image": false, "steemd_connection_client": "https://api.steemit.com", "steemd_connection_server": "https://api.steemit.com", diff --git a/grep b/grep new file mode 100755 index 0000000000000000000000000000000000000000..210372f1239fec35d287c627c1e43ccc26702f5f --- /dev/null +++ b/grep @@ -0,0 +1,2 @@ +grep -rin $1 --color=always --exclude-dir=node_modules --exclude-dir=dist --exclude-dir=tmp * +find src | grep -i $1 diff --git a/package.json b/package.json index 5e06223b51956f3702d81aac408d4eda2cca2fc8..d345ca28ab813f6d0c1ba97494d1db9f46495479 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,6 @@ "file-loader": "0.11.2", "foundation-sites": "git+https://github.com/steemit/foundation-sites.git#e8e32c715bbc4c822b80b555345f61337269ca78", "git-rev-sync": "1.9.1", - "highcharts": "4.2.7", "humanize-number": "0.0.2", "imports-loader": "0.7.1", "intl": "1.2.5", @@ -103,7 +102,6 @@ "react-dom": "15.6.2", "react-dropzone": "3.13.4", "react-headroom": "^2.2.7", - "react-highcharts": "8.4.2", "react-intl": "2.4.0", "react-medium-editor": "1.8.1", "react-notification": "5.0.7", @@ -126,7 +124,6 @@ "sass-loader": "6.0.6", "secure-random": "1.1.1", "selection-position": "^1.0.0", - "sendgrid": "4.10.0", "slate": "^0.16.9", "slate-drop-or-paste-images": "^0.4.1", "slate-insert-block-on-enter": "0.0.1", @@ -139,9 +136,8 @@ "svg-inline-loader": "0.8.0", "svg-inline-react": "1.0.3", "svgo-loader": "1.2.1", - "twilio": "3.17.0", "uncontrollable": "3.3.1", - "underscore.string": "3.3.4", + "underscore.string": "3.3.5", "url-loader": "0.6.2", "web-push": "3.2.3", "webpack": "3.7.1", diff --git a/src/app/Main.js b/src/app/Main.js index ceeba5b8b60c69fa1d455fcaa481bc1857879bd5..a54f62ba659f5c4972782ab94e9e23cbe7bd6d04 100644 --- a/src/app/Main.js +++ b/src/app/Main.js @@ -25,7 +25,7 @@ try { ConsoleExports.init(window); } } catch (e) { - console.error(e); + console.error('console_export', e); } function runApp(initial_state) { @@ -122,7 +122,7 @@ function runApp(initial_state) { try { clientRender(initial_state); } catch (error) { - console.error(error); + console.error('render_error', error); serverApiRecordEvent('client_error', error); } } diff --git a/src/app/RootRoute.js b/src/app/RootRoute.js index b1fedb797d02852cda80c8c1d9070dd6171421cb..06898f97316aace7f07f3ee12c79d43e011bdd65 100644 --- a/src/app/RootRoute.js +++ b/src/app/RootRoute.js @@ -61,18 +61,6 @@ export default { //require.ensure([], (require) => { cb(null, [require('app/components/pages/Tos')]); //}); - } else if (route.page === 'ChangePassword') { - //require.ensure([], (require) => { - cb(null, [require('app/components/pages/ChangePasswordPage')]); - //}); - } else if (route.page === 'RecoverAccountStep1') { - //require.ensure([], (require) => { - cb(null, [require('app/components/pages/RecoverAccountStep1')]); - //}); - } else if (route.page === 'Witnesses') { - //require.ensure([], (require) => { - cb(null, [require('app/components/pages/Witnesses')]); - //}); } else if (route.page === 'SubmitPost') { if (process.env.BROWSER) { // require.ensure([], (require) => { @@ -87,10 +75,6 @@ export default { //require.ensure([], (require) => { cb(null, [require('app/components/pages/UserProfile')]); //}); - } else if (route.page === 'Market') { - require.ensure([], require => { - cb(null, [require('app/components/pages/Market')]); - }); } else if (route.page === 'Post') { //require.ensure([], (require) => { cb(null, [require('app/components/pages/PostPage')]); diff --git a/src/app/assets/images/welcome-hero.png b/src/app/assets/images/welcome-hero.png index c85fca9d972a742986da7dfa231b10dc22559705..bf83636736cf023c62e372f97e3a09ecc4e28a7f 100644 Binary files a/src/app/assets/images/welcome-hero.png and b/src/app/assets/images/welcome-hero.png differ diff --git a/src/app/assets/stylesheets/_themes.scss b/src/app/assets/stylesheets/_themes.scss index fedd89e96f5087cb4a1df9eb84495bdc933c5ea7..16b3af3c8064994b0ac31e1d14154f81c9b0f4c4 100755 --- a/src/app/assets/stylesheets/_themes.scss +++ b/src/app/assets/stylesheets/_themes.scss @@ -20,6 +20,9 @@ $themes: ( borderAccent: 1px solid $color-blue, borderDotted: 1px dotted $color-border-light, borderTransparent: transparent, + roundedCorners: 5px, + roundedCornersTop: 5px 5px 0 0, + roundedCornersBottom: 0px 0px 5px 5px, iconColorSecondary: #cacaca, textColorPrimary: $color-text-dark, textColorSecondary: $color-text-gray, @@ -55,8 +58,11 @@ $themes: ( borderLight: 1px solid $color-border-light-lightest, borderDark: 1px solid $color-text-gray, borderAccent: 1px solid $color-teal, - borderDotted: 1px dotted $color-border-light, + borderDotted: 1px dotted $color-border-less-light, borderTransparent: transparent, + roundedCorners: 5px, + roundedCornersTop: 5px 5px 0 0, + roundedCornersBottom: 0px 0px 5px 5px, iconColorSecondary: #cacaca, textColorPrimary: $color-text-dark, textColorSecondary: $color-text-gray, @@ -82,19 +88,22 @@ $themes: ( backgroundColor: $color-background-dark, backgroundColorEmphasis: $color-background-super-dark, backgroundColorOpaque: $color-blue-dark, - moduleBackgroundColor: $color-background-dark, + moduleBackgroundColor: $color-background-less-dark, backgroundTransparent: transparent, menuBackgroundColor: $color-blue-dark, moduleMediumBackgroundColor: $color-background-dark, - navBackgroundColor: $color-background-dark, + navBackgroundColor: $color-background-less-dark, highlightBackgroundColor: $color-blue-black-darkest, tableRowEvenBackgroundColor: #212C33, - border: 1px solid $color-border-dark, + border: 1px solid $color-border-dark-lightest, borderLight: 1px solid $color-border-dark-lightest, borderDark: 1px solid $color-text-gray-light, borderAccent: 1px solid $color-teal, borderDotted: 1px dotted $color-border-dark, borderTransparent: transparent, + roundedCorners: 5px, + roundedCornersTop: 5px 5px 0 0, + roundedCornersBottom: 0px 0px 5px 5px, iconColorSecondary: $color-text-gray-light, textColorPrimary: $color-text-white, textColorSecondary: $color-text-gray-light, @@ -137,24 +146,24 @@ $themes: ( } - .theme-original { - background-color: $white; - color: $color-text-dark; - @include MQ(M) { - background-color: $color-background-off-white; - } - } - .theme-light { - background-color: $white; - color: $color-text-dark; - @include MQ(M) { - background-color: $color-background-off-white; - } +.theme-original { + background-color: $white; + color: $color-text-dark; + @include MQ(M) { + background-color: $color-background-off-white; } - .theme-dark { - background-color: $color-background-dark; - color: $color-text-white; +} +.theme-light { + background-color: $color-background-off-white; + color: $color-text-dark; + @include MQ(M) { + background-color: $color-background-off-white; } +} +.theme-dark { + background-color: $color-background-dark; + color: $color-text-white; +} // Utility classes to be used with @extend @@ -164,46 +173,46 @@ $themes: ( transition: 0.2s all ease-in-out; &--primary { @include themify($themes) { - color: themed('textColorPrimary'); + color: themed('textColorPrimary'); } &:visited, &:active { @include themify($themes) { - color: themed('textColorPrimary'); + color: themed('textColorPrimary'); } } &:hover, &:focus { @include themify($themes) { - color: themed('textColorAccent'); + color: themed('textColorAccent'); } } } &--secondary { @include themify($themes) { - color: themed('textColorSecondary'); + color: themed('textColorSecondary'); } &:visited, &:active { @include themify($themes) { - color: themed('textColorSecondary'); + color: themed('textColorSecondary'); } } &:hover, &:focus { @include themify($themes) { - color: themed('textColorAccent'); + color: themed('textColorAccent'); } } } &--accent { @include themify($themes) { - color: themed('textColorAccent'); + color: themed('textColorAccent'); } &:visited, &:active { @include themify($themes) { - color: themed('textColorAccent'); + color: themed('textColorAccent'); } } &:hover, &:focus { @include themify($themes) { - color: themed('textColorAccentHover'); + color: themed('textColorAccentHover'); } } } @@ -262,11 +271,11 @@ $themes: ( opacity: 0.25; cursor: not-allowed; box-shadow: 0px 0px 0px 0 rgba(0,0,0,0); - @include themify($themes) { - background-color: themed('buttonBackground'); - box-shadow: 0px 0px 0px 0 rgba(0,0,0,0); - color: themed('buttonText'); - } + @include themify($themes) { + background-color: themed('buttonBackground'); + box-shadow: 0px 0px 0px 0 rgba(0,0,0,0); + color: themed('buttonText'); + } &:hover { @include themify($themes) { background-color: themed('buttonBackground'); diff --git a/src/app/assets/stylesheets/_variables.scss b/src/app/assets/stylesheets/_variables.scss index 307c471bc50162bf77e811b31ade5d5d7ba679e1..c582eea029b746ab2cdb427e73fda72069b259ee 100755 --- a/src/app/assets/stylesheets/_variables.scss +++ b/src/app/assets/stylesheets/_variables.scss @@ -18,8 +18,10 @@ $color-orange: #F76900; $color-transparent: transparent; $color-background-almost-white:#fefefe; -$color-background-off-white: #fcfcfc; +$color-background-off-white: #f4f4f4; +$color-background-off-white-light: #fafafa; $color-background-dark: #1C252B; +$color-background-less-dark: #283336; $color-background-super-dark: #10151b; $color-text-dark: #333; @@ -31,6 +33,7 @@ $color-text-teal: #1FBF8F; $color-text-red: $color-red; $color-border-light: #eee; +$color-border-less-light: #e5e5e5; $color-border-light-lightest: #f6f6f6; $color-border-dark: #232F38; $color-border-dark-lightest: #2B3A45; diff --git a/src/app/assets/stylesheets/foundation-overrides.scss b/src/app/assets/stylesheets/foundation-overrides.scss index 5172347c3c3dd789c35a890d9f635c53d7ac407d..cd6fc067b2a00d394f178168a3ce7278ce72319c 100644 --- a/src/app/assets/stylesheets/foundation-overrides.scss +++ b/src/app/assets/stylesheets/foundation-overrides.scss @@ -115,13 +115,18 @@ tbody tr:nth-child(even) { .reveal { box-shadow: 2px 2px 2px 0 rgba(0,0,0,0.1), 7px 7px 0 0 $color-teal; - border-radius: 0; + border-radius: 0 30px; border: transparent; transition: 0.2s all ease-in-out; @include themify($themes) { background-color: themed('modalBackgroundColor'); color: themed('modalTextColorPrimary'); } + label { + @include themify($themes) { + color: themed('modalTextColorPrimary'); + } + } .button { @extend .e-btn; @extend .e-btn--black; diff --git a/src/app/components/App.scss b/src/app/components/App.scss index ff2d08303ad5547a9ec20bd8fd92071f0fa96441..b1f39b8a513cc46653e48ac35916384c67127782 100644 --- a/src/app/components/App.scss +++ b/src/app/components/App.scss @@ -10,19 +10,6 @@ .welcomeWrapper { padding-bottom: 1rem; } -.welcomeBanner { - margin-top: -1rem; - padding: 4em 0 0em; - background-color: $color-blue-black; - color: $color-white; - @include MQ(M) { - padding: 3em 0 3em; - min-height: 440px; - } - @include MQ(L) { - min-height: 552px; - } -} .RightMenu { background-color: #555; @@ -66,28 +53,32 @@ } .welcomeBanner { + margin-top: -1rem; + padding: 0; + background-color: $color-blue-black; + color: $color-white; position: relative; box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.05); + h2 { font-weight: bold; margin-bottom: 16px; @include font-size(28px); line-height: 1; font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif; - max-width: 240px; @include opacity(0); @include MQ(M) { - @include font-size(34px); + @include font-size(34px); max-width: 280px; } } + h4 { color: $color-white; font-weight: normal; margin-bottom: 1rem; width: 85%; - max-width: 310px; - /*margin: 0 auto; */ + max-width: 360px; font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 1.3 !important; @include font-size(16px); @@ -96,16 +87,12 @@ @include font-size(17px); } } - .buttonWrapper { - padding:15px; - } + .row { - @include MQ(M) { - align-items: center; - } + align-items: center; } - .button { + .button { min-width: 120px; white-space: nowrap; text-decoration: none; @@ -133,6 +120,7 @@ min-width: 132px; } } + .button--primary { @include opacity(0); } @@ -143,47 +131,43 @@ top: 0.5rem; } } - .button.hollow { - background: none; - box-shadow: none; - color: $color-teal; - border: 1px solid $color-teal; - } + .button.ghost { background: transparent; color: $color-white; border: 1px solid #30414A; - box-shadow: 0px 0px 0px 0 #30414A, 2px 2px 0 0 #30414A; + box-shadow: 0px 0px 0px 0 #30414A, 2px 2px 0 0 #30414A; @include opacity(0); &:hover, &:focus { - box-shadow: 0px 0px 0px 0 #30414A, 4px 4px 0 0 $color-teal; - } + box-shadow: 0px 0px 0px 0 #30414A, 4px 4px 0 0 $color-teal; + } } - .heroImage { - max-height: 360px; - @include opacity(0); - animation: fade-in-up 0.6s ease-out both; - @media screen and (prefers-reduced-motion) { - animation: none; - @include opacity(1); - } + .heroImage { + max-height: 360px; + @include opacity(0); + animation: fade-in-up 0.6s ease-out both; + @media screen and (prefers-reduced-motion) { + animation: none; + @include opacity(1); } + } - .welcomeImage { - padding: 0em 4em 1em 3em; - @include MQ(M) { - padding: 3em; - } + .welcomeImage { + padding: 1em 0; + @include MQ(L) { + padding: 2em 0; } + } - .welcomePitch { - padding: 20px; - @include MQ(M) { - padding-left: 40px; - } + .welcomePitch { + padding: 20px; + @include MQ(M) { + padding: 0; } + } } + .downvoted { opacity: 0.5; //-webkit-filter: grayscale(1); // image diff --git a/src/app/components/all.scss b/src/app/components/all.scss index 1d5958c7f80d986a4d69af69261505cfb142115b..fd225773d12e324989d635000fdc348eb10ebad1 100644 --- a/src/app/components/all.scss +++ b/src/app/components/all.scss @@ -18,7 +18,6 @@ @import "./elements/SlateEditor"; @import "./elements/DropdownMenu"; @import "./elements/VerticalMenu"; -@import "./elements/HorizontalMenu"; @import "./elements/VotesAndComments"; @import "./elements/TagList"; @import "./elements/Reputation"; @@ -35,19 +34,18 @@ @import "./elements/SteemLogo/styles"; @import "./elements/SteemMarket"; @import "./elements/SanitizedLink/styles"; -@import "./elements/HelpTip/styles"; @import "./elements/Dropdown"; @import "./elements/Notices"; @import "./elements/GoogleAd"; @import "./elements/GptAd"; @import "./elements/PostCategoryBanner"; +@import "./elements/FlagButton"; // modules @import "./modules/Header/styles"; @import "./modules/LoginForm"; @import "./modules/SidePanel/styles"; @import "./modules/Settings"; -@import "./modules/BottomPanel"; @import "./modules/UserWallet"; @import "./modules/ConfirmTransactionForm"; diff --git a/src/app/components/cards/Comment.jsx b/src/app/components/cards/Comment.jsx index b7c12c385836bbaa6d12b94cfef47699e289f950..ddfe9fe57fc1d73b682a86f79915c3be50db9320 100644 --- a/src/app/components/cards/Comment.jsx +++ b/src/app/components/cards/Comment.jsx @@ -4,6 +4,7 @@ import { Map } from 'immutable'; import Author from 'app/components/elements/Author'; import ReplyEditor from 'app/components/elements/ReplyEditor'; import MuteButton from 'app/components/elements/MuteButton'; +import FlagButton from 'app/components/elements/FlagButton'; import MarkdownViewer from 'app/components/cards/MarkdownViewer'; import shouldComponentUpdate from 'app/utils/shouldComponentUpdate'; import Voting from 'app/components/elements/Voting'; @@ -220,6 +221,8 @@ class CommentImpl extends React.Component { const canDelete = username && username === author && allowDelete(post); const canReply = username && allowReply && comment.depth < 255; const canMute = username && Role.atLeast(viewer_role, 'mod'); + const canFlag = + username && community && Role.atLeast(viewer_role, 'guest'); let body = null; let controls = null; @@ -332,6 +335,9 @@ class CommentImpl extends React.Component { </div> <div className="Comment__header"> <div className="Comment__header_collapse"> + {canFlag && ( + <FlagButton post={post} isComment={true} /> + )} <a onClick={this.toggleCollapsed}> {this.state.collapsed ? '[+]' : '[-]'} </a> diff --git a/src/app/components/cards/Comment.scss b/src/app/components/cards/Comment.scss index 661036428bb2624b82ee424ccfc3d65df2bf6240..a176a6160e9a5f4140d3c09d11796c275700d022 100644 --- a/src/app/components/cards/Comment.scss +++ b/src/app/components/cards/Comment.scss @@ -1,7 +1,7 @@ .Comment { position: relative; clear: both; - margin-bottom: 2.4rem; + margin-bottom: 1.2rem; .Markdown { p { margin: 0.1rem 0 0.6rem 0; @@ -23,7 +23,7 @@ } .Userpic { - margin-left: 5px; + margin-left: 7px; } } @@ -85,10 +85,10 @@ .Comment__header { @include themify($themes) { margin-left: 62px; - border-radius: 3px 3px 0 0; + border-radius: themed('roundedCornersTop'); border: themed('border'); - background: themed('backgroundColorOpaque'); - padding: 1px 5px; + background: themed('moduleBackgroundColor'); + padding: 3px 5px; } } @@ -116,12 +116,12 @@ .Comment .Comment__block .Comment__body { @include themify($themes) { margin-left: 62px; - max-width: 50rem; border: themed('border'); - padding: 2px 7px; + padding: 0 5px; border-top: none; border-bottom: none; font-size: 90%; + background: themed('moduleBackgroundColor'); } } @@ -129,8 +129,9 @@ @include themify($themes) { margin-left: 62px; border: themed('border'); - border-radius: 3px 0; - padding: 3px 8px; + border-radius: themed('roundedCornersBottom'); + padding: 3px 10px 5px 10px; + background: themed('moduleBackgroundColor'); } @include themify($themes) { diff --git a/src/app/components/cards/MarkdownViewer.scss b/src/app/components/cards/MarkdownViewer.scss index f1bfaa0a8efb67090616412704c2f37e9945b047..1d95f4db94353e9198deeda5788308f8cd4dec00 100644 --- a/src/app/components/cards/MarkdownViewer.scss +++ b/src/app/components/cards/MarkdownViewer.scss @@ -11,5 +11,5 @@ } img.normal-size { - width: 640px; + max-width: 640px; } diff --git a/src/app/components/cards/NotificationsList.jsx b/src/app/components/cards/NotificationsList.jsx index 7ab866993f58e38b473a97bdbc96b13c0540c729..57967a65e1c63ee6ccfd3f3e8ccbb2f18969c0c7 100644 --- a/src/app/components/cards/NotificationsList.jsx +++ b/src/app/components/cards/NotificationsList.jsx @@ -58,38 +58,36 @@ class NotificationsList extends React.Component { } = this.props; const renderItem = item => ( - <div> - <div - style={{ - padding: '0.5em 1em', - background: 'rgba(225,255,225,' + item.score + '%)', - }} - > - <span style={{ float: 'right', color: '#999' }}> - {item.type}{' '} - </span> + <div + key={item.id} + style={{ + padding: '0.5em 1em', + background: 'rgba(225,255,225,' + item.score + '%)', + }} + > + <span style={{ opacity: '0.5' }}> + {item.type} + {' / '} + </span> + <strong> <a href={`/${item.url}`}>{item.msg}</a> - <br /> - <small> - <TimeAgoWrapper date={item.date + 'Z'} /> - </small> - </div> + </strong> + <br /> + <small> + <TimeAgoWrapper date={item.date + 'Z'} /> + </small> </div> ); return ( - <div id="posts_list" className="PostsList"> + <div className=""> {isOwnAccount && <ClaimBox accountName={accountName} />} {notifications && ( - <ul className="PostsList__summaries hfeed" itemScope> + <div style={{ lineHeight: '1rem' }}> {notifications .get('notifications') - .map(item => ( - <li key={item.get('id')}> - {renderItem(item.toJS())} - </li> - ))} - </ul> + .map(item => renderItem(item.toJS()))} + </div> )} {loading && ( <center> @@ -103,8 +101,9 @@ class NotificationsList extends React.Component { notifications && !notifications.get('isLastPage', false) && ( <center> + <br /> <a href="#" onClick={this.onClickLoadMore}> - Load more... + <strong>Load more...</strong> </a> </center> )} diff --git a/src/app/components/cards/PostFull.jsx b/src/app/components/cards/PostFull.jsx index 5573e420289194df9f3fd313e044d668f3a1dcd2..2bb4829ef39fd548407d4f66325a26c4be8a087d 100644 --- a/src/app/components/cards/PostFull.jsx +++ b/src/app/components/cards/PostFull.jsx @@ -13,12 +13,14 @@ import MarkdownViewer from 'app/components/cards/MarkdownViewer'; import ReplyEditor from 'app/components/elements/ReplyEditor'; import { immutableAccessor } from 'app/utils/Accessors'; import { extractBodySummary } from 'app/utils/ExtractContent'; +import Tag from 'app/components/elements/Tag'; import TagList from 'app/components/elements/TagList'; import Author from 'app/components/elements/Author'; import { parsePayoutAmount } from 'app/utils/ParsersAndFormatters'; import DMCAList from 'app/utils/DMCAList'; import ShareMenu from 'app/components/elements/ShareMenu'; import MuteButton from 'app/components/elements/MuteButton'; +import FlagButton from 'app/components/elements/FlagButton'; import { serverApiRecordEvent } from 'app/utils/ServerApiClient'; import Userpic from 'app/components/elements/Userpic'; import { APP_DOMAIN, APP_NAME } from 'app/client_config'; @@ -46,7 +48,7 @@ function TimeAuthorCategoryLarge({ post }) { <Userpic account={post.get('author')} /> <div className="right-side"> <Author post={post} showAffiliation /> - {tt('g.in')} <TagList post={post} single /> + {tt('g.in')} <Tag post={post} /> {' • '} <TimeAgoWrapper date={post.get('created')} />{' '} <ContentEditedWrapper @@ -297,30 +299,22 @@ class PostFull extends React.Component { const share_menu = [ { - link: '#', onClick: this.fbShare, - value: 'Facebook', title: tt('postfull_jsx.share_on_facebook'), icon: 'facebook', }, { - link: '#', onClick: this.twitterShare, - value: 'Twitter', title: tt('postfull_jsx.share_on_twitter'), icon: 'twitter', }, { - link: '#', onClick: this.redditShare, - value: 'Reddit', title: tt('postfull_jsx.share_on_reddit'), icon: 'reddit', }, { - link: '#', onClick: this.linkedInShare, - value: 'LinkedIn', title: tt('postfull_jsx.share_on_linkedin'), icon: 'linkedin', }, @@ -401,11 +395,13 @@ class PostFull extends React.Component { } const allowReply = Role.canComment(community, viewer_role); - const canReblog = !post.get('is_paidout') && !isReply; + const canReblog = !isReply; const canPromote = false && !post.get('is_paidout') && !isReply; const canPin = post.get('depth') == 0 && Role.atLeast(viewer_role, 'mod'); const canMute = username && Role.atLeast(viewer_role, 'mod'); + const canFlag = + username && community && Role.atLeast(viewer_role, 'guest'); const canReply = username && allowReply && post.get('depth') < 255; const canEdit = username === author && !showEdit; const canDelete = username === author && allowDelete(post); @@ -436,6 +432,7 @@ class PostFull extends React.Component { itemScope itemType="http://schema.org/Blog" > + {canFlag && <FlagButton post={post} />} {showEdit ? ( renderedEditor ) : ( @@ -459,7 +456,7 @@ class PostFull extends React.Component { {tt('g.promote')} </button> )} - {!isReply && <TagList post={post} horizontal />} + {!isReply && <TagList post={post} />} <div className="PostFull__footer row"> <div className="columns medium-12 large-6"> <TimeAuthorCategory post={post} /> diff --git a/src/app/components/cards/PostFull.scss b/src/app/components/cards/PostFull.scss index f123f58758143960be5baa187ed10ffed7cf1000..4ed503b0b14e7f68b4cfdbd164d2910244f3273e 100644 --- a/src/app/components/cards/PostFull.scss +++ b/src/app/components/cards/PostFull.scss @@ -1,21 +1,23 @@ .Post { @include themify($themes) { - background-color: themed('moduleBackgroundColor'); + background-color: themed('transparent'); } } .PostFull { - padding-bottom: 1rem; - padding-top: 2rem; + padding: 2rem 1rem 1rem 1rem; margin: 0 auto; max-width: 54rem; + position: relative; @include themify($themes) { - border-bottom: themed('border'); + border-radius: themed('roundedCorners'); + border: themed('border'); + background-color: themed('moduleBackgroundColor'); } .button.hollow { @include themify($themes) { - border: themed('borderAccent'); - color: themed('textColorAccent'); + border: themed('borderAccent'); + color: themed('textColorAccent'); } } @@ -28,8 +30,8 @@ font-weight: 400; border-right: none!important; @include themify($themes) { - border-right: themed('border'); - color: themed('textColorSecondary'); + border-right: themed('border'); + color: themed('textColorSecondary'); } padding-right: .6rem; @@ -43,8 +45,8 @@ margin: 1rem 0 1rem 0; line-height: 1.2; @include themify($themes) { - color: themed('textColorSecondary'); - } + color: themed('textColorSecondary'); + } strong, a { @include themify($themes) { color: themed('textColorSecondary'); @@ -96,7 +98,7 @@ top: 5px; svg { @include themify($themes) { - fill: themed('textColorSecondary'); + fill: themed('textColorSecondary'); } } } @@ -104,7 +106,7 @@ } .PostFull__body { - padding: 1rem 0 2rem 0; + padding: 1rem 0 1rem 0; clear: left; a { @extend .link; @@ -118,7 +120,7 @@ font-size: 94%; svg { @include themify($themes) { - fill: themed('textColorSecondary'); + fill: themed('textColorSecondary'); } } .RightShare__Menu { @@ -126,11 +128,6 @@ text-align: right; } } - .VerticalMenu > li > a { - @include themify($themes) { - fill: themed('textColorSecondary'); - } - } span { white-space: normal; } @@ -139,7 +136,7 @@ padding-right: .4rem; margin-right: .4rem; @include themify($themes) { - border-right: themed('border'); + border-right: themed('border'); } } } @@ -154,8 +151,8 @@ font-size: 94%; font-weight: 600; @include themify($themes) { - border-right: themed('border'); - fill: themed('textColorSecondary'); + border-right: themed('border'); + fill: themed('textColorSecondary'); } } @@ -163,7 +160,7 @@ padding-right: .4rem; margin-right: .4rem; @include themify($themes) { - border-right: themed('border'); + border-right: themed('border'); } a {margin: 0 0.15rem;} } @@ -210,11 +207,11 @@ input.share-box { } .chain-right { - -webkit-transform: rotate(120deg); - -moz-transform: rotate(120deg); - -ms-transform: rotate(120deg); - -o-transform: rotate(120deg); - transform: rotate(120deg); + -webkit-transform: rotate(120deg); + -moz-transform: rotate(120deg); + -ms-transform: rotate(120deg); + -o-transform: rotate(120deg); + transform: rotate(120deg); } /* Small only */ diff --git a/src/app/components/cards/PostSummary.jsx b/src/app/components/cards/PostSummary.jsx index e91b2f36dff6b672e9fc6e023d1548c0f018190a..0d361e6ed6e21641cde8340ca2dab4214f6db1fe 100644 --- a/src/app/components/cards/PostSummary.jsx +++ b/src/app/components/cards/PostSummary.jsx @@ -12,7 +12,7 @@ import { extractBodySummary, extractImageLink } from 'app/utils/ExtractContent'; import VotesAndComments from 'app/components/elements/VotesAndComments'; import { List, Map } from 'immutable'; import Author from 'app/components/elements/Author'; -import TagList from 'app/components/elements/TagList'; +import Tag from 'app/components/elements/Tag'; import UserNames from 'app/components/elements/UserNames'; import tt from 'counterpart'; import ImageUserBlockList from 'app/utils/ImageUserBlockList'; @@ -57,7 +57,6 @@ class PostSummary extends React.Component { render() { const { ignore, hideCategory } = this.props; const { post, content, featured, promoted, onClose } = this.props; - const { account } = this.props; if (!content) return null; let reblogged_by; @@ -80,6 +79,7 @@ class PostSummary extends React.Component { } // 'account' is the current blog being viewed, if applicable. + const { account } = this.props; if (account && account != content.get('author')) { reblogged_by = ( <div className="articles__resteem"> @@ -96,7 +96,7 @@ class PostSummary extends React.Component { const gray = content.getIn(['stats', 'gray']); const isNsfw = hasNsfwTag(content); const isReply = content.get('depth') > 0; - const showReblog = !content.get('is_paidout') && !isReply; + const showReblog = !isReply; const full_power = content.get('percent_steem_dollars') === 0; const author = content.get('author'); @@ -148,7 +148,7 @@ class PostSummary extends React.Component { {hideCategory || ( <span className="articles__tag-link"> {tt('g.in')} - <TagList post={content} single /> + <Tag post={content} /> • </span> )} @@ -315,7 +315,11 @@ class PostSummary extends React.Component { <div className="articles__content-block articles__content-block--text"> {content_title} {content_body} - {this.props.blogmode ? null : summary_footer} + {this.props.blogmode ? null : ( + <div className="articles__footer"> + {summary_footer} + </div> + )} </div> {this.props.blogmode ? summary_footer : null} </div> diff --git a/src/app/components/cards/PostSummary.scss b/src/app/components/cards/PostSummary.scss index 9abd03b394d2e66d9af70fc9c68d0b6736c063a8..022dc38870f45b8abfbf6dd79df8ce0195d6beab 100644 --- a/src/app/components/cards/PostSummary.scss +++ b/src/app/components/cards/PostSummary.scss @@ -2,6 +2,25 @@ ul.PostsList__summaries { margin-left: 0; } +ul.PostsList__summaries > li { + padding: 0.1em 0.5em 0 0.5em; + margin-bottom: 0.8em; + + @include themify($themes) { + border-radius: themed('roundedCorners'); + border: themed('border'); + background-color: themed('moduleBackgroundColor'); + } + + &:hover { + @include MQ(L) { + @include themify($themes) { + box-shadow: 2px 2px 3px 0 themed('contentBorderAccent'); + } + } + } +} + .PostSummary { // padding: 0 0 0.5rem; margin: 0 0 1.25vw; @@ -23,14 +42,14 @@ ul.PostsList__summaries { } .nsfw-flag { - color: $color-red; - border: 1px solid $color-red; - font-size: 75%; - border-radius: 3px; - font-weight: normal; - font-family: Arial; - margin: 0 0.1rem; - padding: 2px 5px; + color: $color-red; + border: 1px solid $color-red; + font-size: 75%; + border-radius: 3px; + font-weight: normal; + font-family: Arial; + margin: 0 0.1rem; + padding: 2px 5px; } } @@ -92,10 +111,11 @@ ul.PostsList__summaries { .PostSummary__body { width: auto; - padding: 0.3rem 0.1rem 0.15rem; + padding: 0 0 0.15rem; + font-size: 0.9rem; font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif; @include themify($themes) { - color: themed('textColorPrimary'); + color: themed('textColorPrimary'); } overflow: hidden; line-height: 1.4; @@ -104,8 +124,8 @@ ul.PostsList__summaries { a { display: inline; @include themify($themes) { - color: themed('textColorPrimary'); - } + color: themed('textColorPrimary'); + } } } @@ -139,8 +159,8 @@ ul.PostsList__summaries { } padding-left: 1rem; @include themify($themes) { - border-left: themed('borderLight'); - } + border-left: themed('borderLight'); + } .Reblog__button { margin-right: 1rem; @@ -198,7 +218,7 @@ ul.PostsList__summaries { text-overflow: initial; padding-bottom: 0.3rem; a { - display: block; + display: block; } } .PostSummary.with-image .PostSummary__reblogged_by, @@ -212,26 +232,28 @@ ul.PostsList__summaries { margin-left: 0; border-left: 1px solid $color-border-light; .Reblog__button { - margin-right: 1rem; - padding-right: 1rem; - border-right: none; + margin-right: 1rem; + padding-right: 1rem; + border-right: none; } } } .articles__summary { - .nsfw-flag { - color: $color-red; - border: 1px solid $color-red; - font-size: 75%; - border-radius: 3px; - font-weight: normal; - font-family: Arial; - margin: 0 0.1rem; - padding: 2px 5px; - margin-right: 5px; + .nsfw-flag { + color: $color-red; + border: 1px solid $color-red; + font-size: 75%; + border-radius: 3px; + font-weight: normal; + font-family: Arial; + margin: 0 0.1rem; + padding: 2px 5px; + margin-right: 5px; } -} - - + .articles__resteem { + padding-top: 0; + margin-top: 0; + } +} diff --git a/src/app/components/cards/PostsList.jsx b/src/app/components/cards/PostsList.jsx index 8883175f5eb0bd9573fa15b647958aff0cd6478e..7d61b67ed15bc33dc02ffa24e292142959e8bf45 100644 --- a/src/app/components/cards/PostsList.jsx +++ b/src/app/components/cards/PostsList.jsx @@ -44,7 +44,6 @@ class PostsList extends React.Component { }; this.scrollListener = this.scrollListener.bind(this); this.onBackButton = this.onBackButton.bind(this); - this.closeOnOutsideClick = this.closeOnOutsideClick.bind(this); this.shouldComponentUpdate = shouldComponentUpdate(this, 'PostsList'); } @@ -56,7 +55,6 @@ class PostsList extends React.Component { this.detachScrollListener(); window.removeEventListener('popstate', this.onBackButton); window.removeEventListener('keydown', this.onBackButton); - document.getElementsByTagName('body')[0].className = ''; } onBackButton(e) { @@ -65,19 +63,6 @@ class PostsList extends React.Component { window.removeEventListener('keydown', this.onBackButton); } - closeOnOutsideClick(e) { - const inside_post = findParent(e.target, 'PostsList__post_container'); - if (!inside_post) { - const inside_top_bar = findParent( - e.target, - 'PostsList__post_top_bar' - ); - if (!inside_top_bar) { - this.closePostModal(); - } - } - } - fetchIfNeeded() { this.scrollListener(); } diff --git a/src/app/components/cards/PostsList.scss b/src/app/components/cards/PostsList.scss index e09697a93edd381bc95bea6a62e64787710cf3ab..e5941fc7c840bb053472702ac644fb154f600495 100644 --- a/src/app/components/cards/PostsList.scss +++ b/src/app/components/cards/PostsList.scss @@ -1,81 +1,9 @@ -.PostsList__post_top_bar { - position: relative; - width: 100%; - height: 3rem; - margin: 0 auto; - overflow: hidden; - @include themify($themes) { - background-color: themed('navBackgroundColor'); - } - @media screen and (min-width: 60rem) { - @include themify($themes) { - background-color: themed('backgroundTransparent'); - } - } - - a { - span.Icon path { - @include themify($themes) { - fill: themed('textColorAccent'); - } - } - } - - > .close-button { - visibility: hidden; - top: 1rem; - right: 0; - } -} - -.PostsList__post_container { - position: relative; - @include themify($themes) { - background-color: themed('moduleBackgroundColor'); - } - margin: 1rem auto; - padding: 2rem 0.9rem 0; - transform: translateZ(0); -} - -@media screen and (min-width: 60rem) { - .PostsList__post_top_bar { - width: 56rem; - background-color: transparent; - - > .close-button { - visibility: visible; - } - - > .back-button-menu { - visibility: hidden; - } - } - - .PostsList__post_container { - width: 56rem; - margin-bottom: 3em; - @include themify($themes) { - box-shadow: 5px 5px 0 0 themed('contentBorderAccent'); - } - } -} -@media screen and (min-width: 67rem) { - .PostsList__post_container { - width: 62rem; - } - - .PostsList__post_top_bar { - width: 62rem; - } -} - .PostsList__summaries { .articles__summary { position: relative; } - .FeaturedTag { + .FeaturedTag, .PromotedTag { font-weight: 400; display: inline; padding: 0.1rem 0.2rem; @@ -88,18 +16,9 @@ color: themed('buttonText'); } } - .PromotedTag { - font-weight: 400; - display: inline; - padding: 0.1rem 0.2rem; - margin: 0 1rem 0 0.5rem; - border-radius: 0.3rem; - font-size: 0.75rem; - vertical-align: 15%; @include themify($themes) { background-color: themed('iconColorSecondary'); - color: themed('buttonText'); } } diff --git a/src/app/components/elements/ChangePassword.jsx b/src/app/components/elements/ChangePassword.jsx deleted file mode 100644 index 359bad604eff467ed31c69130657ae27787688bb..0000000000000000000000000000000000000000 --- a/src/app/components/elements/ChangePassword.jsx +++ /dev/null @@ -1,16 +0,0 @@ -/* eslint react/prop-types: 0 */ -import React from 'react'; -import tt from 'counterpart'; -import { Link } from 'react-router'; - -class ChangePassword extends React.Component { - render() { - return ( - <div> - <Link to={`${$STM_Config.wallet_url}`}>Visit Wallet</Link> - </div> - ); - } -} - -export default ChangePassword; diff --git a/src/app/components/elements/ClaimBox.jsx b/src/app/components/elements/ClaimBox.jsx index 9893cd22b9b080963bfa7158408b6c5c4aa35d73..a6553b13523903dd57535ffe504b71c3fc876b63 100644 --- a/src/app/components/elements/ClaimBox.jsx +++ b/src/app/components/elements/ClaimBox.jsx @@ -83,36 +83,31 @@ class ClaimBox extends React.Component { render() { const { account } = this.props; + const { rewards_str } = this.state; if (!account) return null; if (this.state.empty) return null; - return ( - <div className="row" style={{ margin: '0 0 1.5em' }}> - <div className="columns small-12"> - {this.state.claimed ? ( - <div className="UserWallet__claimbox"> - <span className="UserWallet__claimbox-text"> - Claim successful. - </span> - </div> - ) : ( - <div className="UserWallet__claimbox"> - <span className="UserWallet__claimbox-text"> - Your current rewards: {this.state.rewards_str} - </span> - <button - disabled={this.state.claimInProgress} - className="button" - onClick={e => { - e.preventDefault(); - this.handleClaimRewards(account); - }} - > - {tt('userwallet_jsx.redeem_rewards')} - </button> - </div> - )} + if (this.state.claimed) { + return ( + <div className="UserWallet__claimbox"> + <strong>Claim successful.</strong> </div> + ); + } + + return ( + <div className="UserWallet__claimbox"> + <strong>Unclaimed rewards: {rewards_str}</strong> + <button + disabled={this.state.claimInProgress} + className="button" + onClick={e => { + e.preventDefault(); + this.handleClaimRewards(account); + }} + > + Redeem + </button> </div> ); } diff --git a/src/app/components/elements/CommunityPane.jsx b/src/app/components/elements/CommunityPane.jsx index 078c5a67ba203cd0a00d4277f0a7ae10e28e3f3e..a5f6d8e4ca901bbc013a3f37af618298b4a70a3e 100644 --- a/src/app/components/elements/CommunityPane.jsx +++ b/src/app/components/elements/CommunityPane.jsx @@ -8,6 +8,16 @@ import SettingsEditButton from 'app/components/elements/SettingsEditButton'; import SubscribeButton from 'app/components/elements/SubscribeButton'; import Icon from 'app/components/elements/Icon'; +const nl2br = text => + text.split('\n').map((item, key) => ( + <span key={key}> + {item} + <br /> + </span> + )); +const nl2li = text => + text.split('\n').map((item, key) => <li key={key}>{item}</li>); + class CommunityPane extends Component { static propTypes = { community: PropTypes.object.isRequired, @@ -82,7 +92,7 @@ class CommunityPane extends Component { <div className="column small-4"> {community.get('num_pending')} <br /> - <small>pending posts</small> + <small>active posts</small> </div> </div> @@ -136,7 +146,15 @@ class CommunityPane extends Component { <div> <strong>Description</strong> <br /> - {community.get('description', 'empty')} + {nl2br(community.get('description', 'empty'))} + <br /> + </div> + )} + {community.get('flag_text') && ( + <div> + <strong>Rules</strong> + <br /> + <ol>{nl2li(community.get('flag_text'))}</ol> <br /> </div> )} diff --git a/src/app/components/elements/CommunityPaneMobile.jsx b/src/app/components/elements/CommunityPaneMobile.jsx index 971b54c581e2e2e3eb033be6cdce0da538acd483..e1604be2079be2ff636108042e1fe41a4296ecd6 100644 --- a/src/app/components/elements/CommunityPaneMobile.jsx +++ b/src/app/components/elements/CommunityPaneMobile.jsx @@ -83,7 +83,7 @@ class CommunityPaneMobile extends Component { > {community.get('num_pending')} <br /> - <small>pending posts</small> + <small>active posts</small> </div> <div className="column large-4 medium-6 small-12"> diff --git a/src/app/components/elements/CountryCode.jsx b/src/app/components/elements/CountryCode.jsx deleted file mode 100644 index b15a72ca0ca644d6129d6be86814bee9e3fb5277..0000000000000000000000000000000000000000 --- a/src/app/components/elements/CountryCode.jsx +++ /dev/null @@ -1,276 +0,0 @@ -import React from 'react'; - -export default props => { - return ( - <select {...props}> - {/* Top countries (duplicated from below) */} - <option value="1">United States +(1)</option> - <option value="44">United Kingdom +(44)</option> - <option value="1">Canada +(1)</option> - <option value="34">Spain +(34)</option> - - {/* TeleSign supported country codes */} - <option value="" /> - <option value="93">Afghanistan +(93)</option> - <option value="355">Albania +(355)</option> - <option value="213">Algeria +(213)</option> - <option value="1">American Samoa +(1)</option> - <option value="376">Andorra +(376)</option> - <option value="244">Angola +(244)</option> - <option value="1">Anguilla +(1)</option> - <option value="1">Antigua and Barbuda +(1)</option> - <option value="54">Argentina +(54)</option> - <option value="374">Armenia +(374)</option> - <option value="297">Aruba +(297)</option> - <option value="247">Ascension +(247)</option> - <option value="61">Australia +(61)</option> - <option value="672">Australian External Territories +(672)</option> - <option value="43">Austria +(43)</option> - <option value="994">Azerbaijan +(994)</option> - <option value="1">Bahamas +(1)</option> - <option value="973">Bahrain +(973)</option> - <option value="880">Bangladesh +(880)</option> - <option value="1">Barbados +(1)</option> - <option value="375">Belarus +(375)</option> - <option value="32">Belgium +(32)</option> - <option value="501">Belize +(501)</option> - <option value="229">Benin +(229)</option> - <option value="1">Bermuda +(1)</option> - <option value="975">Bhutan +(975)</option> - <option value="591">Bolivia +(591)</option> - <option value="599"> - Bonaire, Sabo & St. Eustacius +(599) - </option> - <option value="387">Bosnia and Herzegovina +(387)</option> - <option value="267">Botswana +(267)</option> - <option value="55">Brazil +(55)</option> - <option value="1">British Virgin Islands +(1)</option> - <option value="673">Brunei Darussalam +(673)</option> - <option value="359">Bulgaria +(359)</option> - <option value="226">Burkina Faso +(226)</option> - <option value="257">Burundi +(257)</option> - <option value="855">Cambodia +(855)</option> - <option value="237">Cameroon +(237)</option> - <option value="1">Canada +(1)</option> - <option value="238">Cape Verde +(238)</option> - <option value="1">Cayman Islands +(1)</option> - <option value="236">Central African Republic +(236)</option> - <option value="235">Chad +(235)</option> - <option value="56">Chile +(56)</option> - <option value="86">China +(86)</option> - <option value="57">Colombia +(57)</option> - <option value="269">Comoros +(269)</option> - <option value="242">Congo +(242)</option> - <option value="682">Cook Islands +(682)</option> - <option value="506">Costa Rica +(506)</option> - <option value="225">Cote d'Ivoire +(225)</option> - <option value="385">Croatia +(385)</option> - <option value="53">Cuba +(53)</option> - <option value="599">Curacao +(599)</option> - <option value="357">Cyprus +(357)</option> - <option value="420">Czech Republic +(420)</option> - <option value="243">Democratic Republic of the Congo +(243)</option> - <option value="45">Denmark +(45)</option> - <option value="246">Diego Garcia +(246)</option> - <option value="253">Djibouti +(253)</option> - <option value="1">Dominica +(1)</option> - <option value="1">Dominican Republic +(1)</option> - <option value="670">East Timor +(670)</option> - <option value="593">Ecuador +(593)</option> - <option value="20">Egypt +(20)</option> - <option value="503">El Salvador +(503)</option> - <option value="240">Equatorial Guinea +(240)</option> - <option value="291">Eritrea +(291)</option> - <option value="372">Estonia +(372)</option> - <option value="251">Ethiopia +(251)</option> - <option value="388"> - European Telephony Numbering Space +(388) - </option> - <option value="500">Falkland Islands +(500)</option> - <option value="298">Faroe Islands +(298)</option> - <option value="679">Fiji +(679)</option> - <option value="358">Finland +(358)</option> - <option value="33">France +(33)</option> - <option value="262">French Dept/Terr in Indian Ocean +(262)</option> - <option value="594">French Guiana +(594)</option> - <option value="689">French Polynesia +(689)</option> - <option value="241">Gabon +(241)</option> - <option value="220">Gambia +(220)</option> - <option value="995">Georgia +(995)</option> - <option value="49">Germany +(49)</option> - <option value="233">Ghana +(233)</option> - <option value="350">Gibraltar +(350)</option> - <option value="881">Global Mobile Satellite System +(881)</option> - <option value="30">Greece +(30)</option> - <option value="299">Greenland +(299)</option> - <option value="1">Grenada +(1)</option> - <option value="590">Guadeloupe +(590)</option> - <option value="1">Guam +(1)</option> - <option value="502">Guatemala +(502)</option> - <option value="224">Guinea +(224)</option> - <option value="245">Guinea-Bissau +(245)</option> - <option value="592">Guyana +(592)</option> - <option value="509">Haiti +(509)</option> - <option value="504">Honduras +(504)</option> - <option value="852">Hong Kong +(852)</option> - <option value="36">Hungary +(36)</option> - <option value="354">Iceland +(354)</option> - <option value="91">India +(91)</option> - <option value="62">Indonesia +(62)</option> - <option value="870">Inmarsat SNAC +(870)</option> - <option value="882">International Networks +(882)</option> - <option value="883">International VoIP +(883)</option> - <option value="98">Iran +(98)</option> - <option value="964">Iraq +(964)</option> - <option value="353">Ireland +(353)</option> - <option value="972">Israel +(972)</option> - <option value="39">Italy +(39)</option> - <option value="1">Jamaica +(1)</option> - <option value="81">Japan +(81)</option> - <option value="962">Jordan +(962)</option> - <option value="7">Kazakhstan +(7)</option> - <option value="254">Kenya +(254)</option> - <option value="686">Kiribati +(686)</option> - <option value="965">Kuwait +(965)</option> - <option value="996">Kyrgyzstan +(996)</option> - <option value="856">Lao +(856)</option> - <option value="371">Latvia +(371)</option> - <option value="961">Lebanon +(961)</option> - <option value="266">Lesotho +(266)</option> - <option value="231">Liberia +(231)</option> - <option value="218">Libya +(218)</option> - <option value="423">Liechtenstein +(423)</option> - <option value="370">Lithuania +(370)</option> - <option value="352">Luxembourg +(352)</option> - <option value="853">Macao +(853)</option> - <option value="389">Macedonia +(389)</option> - <option value="261">Madagascar +(261)</option> - <option value="265">Malawi +(265)</option> - <option value="60">Malaysia +(60)</option> - <option value="960">Maldives +(960)</option> - <option value="223">Mali +(223)</option> - <option value="356">Malta +(356)</option> - <option value="692">Marshall Islands +(692)</option> - <option value="596">Martinique +(596)</option> - <option value="222">Mauritania +(222)</option> - <option value="230">Mauritius +(230)</option> - <option value="52">Mexico +(52)</option> - <option value="691">Micronesia +(691)</option> - <option value="373">Moldova +(373)</option> - <option value="377">Monaco +(377)</option> - <option value="976">Mongolia +(976)</option> - <option value="382">Montenegro +(382)</option> - <option value="1">Montserrat +(1)</option> - <option value="212">Morocco +(212)</option> - <option value="258">Mozambique +(258)</option> - <option value="95">Myanmar +(95)</option> - <option value="264">Namibia +(264)</option> - <option value="674">Nauru +(674)</option> - <option value="977">Nepal +(977)</option> - <option value="31">Netherlands +(31)</option> - <option value="687">New Caledonia +(687)</option> - <option value="64">New Zealand +(64)</option> - <option value="505">Nicaragua +(505)</option> - <option value="227">Niger +(227)</option> - <option value="234">Nigeria +(234)</option> - <option value="683">Niue +(683)</option> - <option value="850">North Korea +(850)</option> - <option value="1">Northern Mariana Islands +(1)</option> - <option value="47">Norway +(47)</option> - <option value="968">Oman +(968)</option> - <option value="92">Pakistan +(92)</option> - <option value="680">Palau +(680)</option> - <option value="970">Palestine +(970)</option> - <option value="507">Panama +(507)</option> - <option value="675">Papua New Guinea +(675)</option> - <option value="595">Paraguay +(595)</option> - <option value="51">Peru +(51)</option> - <option value="63">Philippines +(63)</option> - <option value="48">Poland +(48)</option> - <option value="351">Portugal +(351)</option> - <option value="1">Puerto Rico +(1)</option> - <option value="974">Qatar +(974)</option> - <option value="262">Reunion +(262)</option> - <option value="40">Romania +(40)</option> - <option value="7">Russia +(7)</option> - <option value="250">Rwanda +(250)</option> - <option value="290">Saint Helena +(290)</option> - <option value="1">Saint Kitts and Nevis +(1)</option> - <option value="1">Saint Lucia +(1)</option> - <option value="508">Saint Pierre and Miquelon +(508)</option> - <option value="1">Saint Vincent and the Grenadines +(1)</option> - <option value="685">Samoa +(685)</option> - <option value="378">San Marino +(378)</option> - <option value="239">Sao Tome and Principe +(239)</option> - <option value="966">Saudi Arabia +(966)</option> - <option value="221">Senegal +(221)</option> - <option value="381">Serbia +(381)</option> - <option value="248">Seychelles +(248)</option> - <option value="232">Sierra Leone +(232)</option> - <option value="65">Singapore +(65)</option> - <option value="1">Sint Maarten +(1)</option> - <option value="421">Slovakia +(421)</option> - <option value="386">Slovenia +(386)</option> - <option value="677">Solomon Islands +(677)</option> - <option value="252">Somalia +(252)</option> - <option value="27">South Africa +(27)</option> - <option value="82">South Korea +(82)</option> - <option value="211">South Sudan +(211)</option> - <option value="34">Spain +(34)</option> - <option value="94">Sri Lanka +(94)</option> - <option value="249">Sudan +(249)</option> - <option value="597">Suriname +(597)</option> - <option value="268">Swaziland +(268)</option> - <option value="46">Sweden +(46)</option> - <option value="41">Switzerland +(41)</option> - <option value="963">Syria +(963)</option> - <option value="886">Taiwan +(886)</option> - <option value="992">Tajikistan +(992)</option> - <option value="255">Tanzania +(255)</option> - <option value="66">Thailand +(66)</option> - <option value="228">Togo +(228)</option> - <option value="690">Tokelau +(690)</option> - <option value="676">Tonga +(676)</option> - <option value="1">Trinidad and Tobago +(1)</option> - <option value="216">Tunisia +(216)</option> - <option value="90">Turkey +(90)</option> - <option value="993">Turkmenistan +(993)</option> - <option value="1">Turks and Caicos Islands +(1)</option> - <option value="688">Tuvalu +(688)</option> - <option value="1">U.S. Virgin Islands +(1)</option> - <option value="256">Uganda +(256)</option> - <option value="380">Ukraine +(380)</option> - <option value="971">United Arab Emirates +(971)</option> - <option value="44">United Kingdom +(44)</option> - <option value="1">United States +(1)</option> - <option value="991"> - Univ Int'l Telecom. Correspondence Svc. +(991) - </option> - <option value="888"> - Univ Telecom. For Disaster Relief +(888) - </option> - <option value="800"> - Universal International Freephone Number +(800) - </option> - <option value="979"> - Universal Int'l Premium Rate Service +(979) - </option> - <option value="808"> - Universal Int'l Shared Cost Service +(808) - </option> - <option value="878"> - Universal Personal Telecommunications +(878) - </option> - <option value="598">Uruguay +(598)</option> - <option value="998">Uzbekistan +(998)</option> - <option value="678">Vanuatu +(678)</option> - <option value="379">Vatican City State +(379)</option> - <option value="58">Venezuela +(58)</option> - <option value="84">Vietnam +(84)</option> - <option value="681">Wallis and Futuna +(681)</option> - <option value="967">Yemen +(967)</option> - <option value="260">Zambia +(260)</option> - <option value="263">Zimbabwe +(263)</option> - </select> - ); -}; diff --git a/src/app/components/elements/DropdownMenu.jsx b/src/app/components/elements/DropdownMenu.jsx index 231358640bb9d446e4fbf2c1db66d94c3e2a857a..b564a3c1c4fcfde8a5222fd0b69a7877dd1f08aa 100644 --- a/src/app/components/elements/DropdownMenu.jsx +++ b/src/app/components/elements/DropdownMenu.jsx @@ -103,7 +103,6 @@ export default class DropdownMenu extends React.Component { title={title} items={items} hideValue={selected} - className="VerticalMenu" /> ); const cls = diff --git a/src/app/components/elements/FlagButton.jsx b/src/app/components/elements/FlagButton.jsx new file mode 100644 index 0000000000000000000000000000000000000000..5ac81fddea049988331cbace5600750237147ead --- /dev/null +++ b/src/app/components/elements/FlagButton.jsx @@ -0,0 +1,134 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; + +import * as globalActions from 'app/redux/GlobalReducer'; +import * as transactionActions from 'app/redux/TransactionReducer'; + +import Icon from 'app/components/elements/Icon'; +import Reveal from 'app/components/elements/Reveal'; +import CloseButton from 'app/components/elements/CloseButton'; +import FlagCommunityPost from '../modules/FlagCommunityPost'; + +class FlagButton extends React.Component { + constructor(props) { + super(props); + this.state = { showDialog: false }; + } + + showDialog = () => { + this.setState({ showDialog: true }); + }; + + hideDialog = () => { + this.setState({ showDialog: false }); + }; + + onSubmit = notes => { + const { account, community, username, permlink, flagPost } = this.props; + if (!notes || !community || !username) return false; // Fail Fast + flagPost(username, community, account, notes, permlink); + }; + + render() { + return ( + <span + className={` flag__button ${ + this.props.isComment + ? 'flag__button--comment' + : 'flag__button--post' + } `} + > + <a onClick={() => this.showDialog()}> + <Icon name="flag1" /> + <Icon name="flag2" /> + </a> + {this.state.showDialog && ( + <Reveal onHide={() => null} show> + <CloseButton onClick={() => this.hideDialog()} /> + <FlagCommunityPost + onSubmit={notes => { + this.hideDialog(); + this.onSubmit(notes); + }} + flagText={this.props.flagText} + isComment={this.props.isComment} + /> + </Reveal> + )} + </span> + ); + } +} + +FlagButton.propTypes = { + account: PropTypes.string.isRequired, + permlink: PropTypes.string.isRequired, + username: PropTypes.string.isRequired, + community: PropTypes.string.isRequired, //TODO: Define shape + flagText: PropTypes.string.isRequired, + isComment: PropTypes.bool, +}; + +FlagButton.defaultProps = { + isComment: false, +}; + +export default connect( + (state, ownProps) => { + const { post } = ownProps; + const account = post.get('author'); + const permlink = post.get('permlink'); + const community = post.get('category'); + const flagText = state.global.getIn([ + 'community', + community, + 'flag_text', + ]); + return { + account, + permlink, + community, + username: state.user.getIn(['current', 'username']), + flagText, + }; + }, + dispatch => ({ + stateSet: (key, value) => { + dispatch(globalActions.set({ key, value })); + }, + flagPost: ( + username, + community, + account, + notes, + permlink, + successCallback, + errorCallback + ) => { + const action = 'flagPost'; + const payload = [ + action, + { + community, + account, + permlink, + notes, + }, + ]; + + return dispatch( + transactionActions.broadcastOperation({ + type: 'custom_json', + operation: { + id: 'community', + required_posting_auths: [username], + json: JSON.stringify(payload), + }, + successCallback, + errorCallback, + }) + ); + }, + }) +)(FlagButton); diff --git a/src/app/components/elements/FlagButton.scss b/src/app/components/elements/FlagButton.scss new file mode 100644 index 0000000000000000000000000000000000000000..1f5002ad29d7434d87e27f71bca5bc9a04e13e61 --- /dev/null +++ b/src/app/components/elements/FlagButton.scss @@ -0,0 +1,25 @@ + .flag__button { + cursor: pointer; + .flag2 { + display: none !important; + visibility: hidden; + } + &:hover { + .flag1 { + display: none !important; + visibility: hidden; + } + .flag2 { + visibility: visible; + display: inline-block !important; + } + svg { + fill: red; + } + } + } + + .flag__button--post { + position: absolute; + right: 1em; + } diff --git a/src/app/components/elements/FoundationDropdown.jsx b/src/app/components/elements/FoundationDropdown.jsx deleted file mode 100644 index 6b5b5e26456429af42eefb8e07dafb8a366b1265..0000000000000000000000000000000000000000 --- a/src/app/components/elements/FoundationDropdown.jsx +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { findParent } from 'app/utils/DomUtils'; -import { Dropdown } from 'react-foundation-components/lib/global/dropdown'; - -export default class FoundationDropdown extends React.Component { - static propTypes = { - show: PropTypes.bool.isRequired, - className: PropTypes.string, - children: PropTypes.any, - onHide: PropTypes.func, - }; - - constructor(props) { - super(props); - this.state = { show: props.show }; - this.closeOnOutsideClick = this.closeOnOutsideClick.bind(this); - } - - componentDidUpdate(prevProps, prevState) { - const show = this.state.show; - if (show !== prevState.show) { - if (show) - document.body.addEventListener( - 'mousedown', - this.closeOnOutsideClick - ); - else - document.body.removeEventListener( - 'mousedown', - this.closeOnOutsideClick - ); - } - } - - componentWillReceiveProps(newProps) { - if ( - newProps.show !== this.props.show && - newProps.show !== this.state.show - ) { - this.setState({ show: newProps.show }); - } - } - - componentWillUnmount() { - document.body.removeEventListener( - 'mousedown', - this.closeOnOutsideClick - ); - } - - closeOnOutsideClick(e) { - const inside_dropdown = findParent(e.target, 'FoundationDropdown'); - // console.log('-- closeOnOutsideClick -->', e.target, inside_dropdown); - if (!inside_dropdown) { - this.setState({ show: false }); - if (this.props.onHide) this.props.onHide(); - } - } - - render() { - if (!this.state.show) return null; - const { className } = this.props; - return ( - <Dropdown className={`FoundationDropdown ${className}`}> - {this.props.children} - </Dropdown> - ); - } -} diff --git a/src/app/components/elements/HelpTip/HelpTip.story.jsx b/src/app/components/elements/HelpTip/HelpTip.story.jsx deleted file mode 100644 index 0b229978c81d11a5fcca35494d89d8072c06c65b..0000000000000000000000000000000000000000 --- a/src/app/components/elements/HelpTip/HelpTip.story.jsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import HelpTip from './index'; -import IconButton from '../IconButton'; -import { Center } from 'decorators'; - -storiesOf('Elements', module) - .addDecorator(Center) - .add('HelpTip', () => ( - <HelpTip content="Hello World"> - <IconButton /> - </HelpTip> - )); diff --git a/src/app/components/elements/HelpTip/index.jsx b/src/app/components/elements/HelpTip/index.jsx deleted file mode 100644 index 6f3d0872ac19eef1c53fb83d5bc18eef1226e309..0000000000000000000000000000000000000000 --- a/src/app/components/elements/HelpTip/index.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import PropTypes from 'prop-types'; - -export default class HelpTip extends React.Component { - static propTypes = { - children: PropTypes.any.isRequired, - content: PropTypes.oneOfType([PropTypes.string, PropTypes.array]) - .isRequired, - }; - - constructor(props) { - super(props); - this.state = { - visible: false, - }; - } - - show = () => this.setVisibility(true); - hide = () => this.setVisibility(false); - - setVisibility = visible => { - this.setState({ - visible, - }); - }; - - handleTouch = () => { - this.show(); - this.assignOutsideTouchHandler(); - }; - - assignOutsideTouchHandler = () => { - const handler = e => { - let currentNode = e.target; - const componentNode = ReactDOM.findDOMNode(this.refs.instance); - while (currentNode.parentNode) { - if (currentNode === componentNode) return; - currentNode = currentNode.parentNode; - } - if (currentNode !== document) return; - this.hide(); - document.removeEventListener('touchstart', handler); - }; - document.addEventListener('touchstart', handler); - }; - - render() { - const { props, state, show, hide, handleTouch } = this; - return ( - <div - onMouseEnter={show} - onMouseLeave={hide} - onTouchStart={handleTouch} - ref="helptip" - className="helptip" - > - <span className="helptip__target">{props.children}</span> - {state.visible && ( - <div ref="helptip" className="helptip__box"> - <div - ref="helptip-content" - className="helptip__box-content" - > - {props.content} - </div> - </div> - )} - </div> - ); - } -} diff --git a/src/app/components/elements/HelpTip/styles.scss b/src/app/components/elements/HelpTip/styles.scss deleted file mode 100644 index 0225512b6ab2f47419cd88dc1920afa483676e05..0000000000000000000000000000000000000000 --- a/src/app/components/elements/HelpTip/styles.scss +++ /dev/null @@ -1,71 +0,0 @@ - .helptip { - position: relative; - display: inline-flex; - z-index: 98; - cursor: pointer; - width: auto; - vertical-align: middle; - margin-left: 0.625em; - svg.icon-button__svg.icon-button__svg--small { - width: 24px; - height: 24px; - } - }; - - .helptip:before { - position:absolute; - content:''; - top:-10px; - right:-10px; - left:-10px; - bottom:-10px; - z-index:40; - } - - .helptip__box { - position: absolute; - padding: 1em; - @include themify($themes) { - background: themed('moduleBackgroundColor'); - } - border: 1px solid; - @include themify($themes) { - border-color: themed('colorAccentReverse'); - } - bottom: 150%; - right: 0; - width: auto; - @include MQ(M) { - min-width: 150px; - } - @include MQ(L) { - min-width: 200px; - } - } - - .helptip__box:after, .helptip__box:before { - top: 100%; - left: calc(100% - 20px); - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - } - - .helptip__box:after { - @include themify($themes) { - border-top-color: themed('moduleBackgroundColor'); - } - border-width: 10px; - margin-left: -5px; - } - - .helptip__box:before { - @include themify($themes) { - border-top-color: themed('colorAccentReverse'); - } - border-width: 11px; - margin-left: -6px; - } \ No newline at end of file diff --git a/src/app/components/elements/HorizontalMenu.jsx b/src/app/components/elements/HorizontalMenu.jsx deleted file mode 100644 index 7beadaa1bc45a520a525816fc388600c94f057e3..0000000000000000000000000000000000000000 --- a/src/app/components/elements/HorizontalMenu.jsx +++ /dev/null @@ -1,52 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { Link } from 'react-router'; -import Icon from 'app/components/elements/Icon'; -import tt from 'counterpart'; - -export default class HorizontalMenu extends React.Component { - static propTypes = { - items: PropTypes.arrayOf(PropTypes.object).isRequired, - title: PropTypes.string, - className: PropTypes.string, - hideValue: PropTypes.string, - includeSearch: PropTypes.bool, - }; - - render() { - const { - items, - title, - className, - hideValue, - includeSearch, - } = this.props; - return ( - <ul - className={ - 'HorizontalMenu menu' + (className ? ' ' + className : '') - } - > - {title && <li className="title">{title}</li>} - {items.map(i => { - if (i.value === hideValue) return null; - return ( - <li key={i.value} className={i.active ? 'active' : ''}> - {i.link ? ( - <Link to={i.link} onClick={i.onClick}> - {i.icon && <Icon name={i.icon} />} - {i.label ? i.label : i.value} - </Link> - ) : ( - <span> - {i.icon && <Icon name={i.icon} />} - {i.label ? i.label : i.value} - </span> - )} - </li> - ); - })} - </ul> - ); - } -} diff --git a/src/app/components/elements/HorizontalMenu.scss b/src/app/components/elements/HorizontalMenu.scss deleted file mode 100644 index 9e297e801fb0690512bbc73e20b6b7138d26d8d1..0000000000000000000000000000000000000000 --- a/src/app/components/elements/HorizontalMenu.scss +++ /dev/null @@ -1,48 +0,0 @@ -.HorizontalMenu { - display: none; - .active > a { - background: none; - font-weight: bold; - @include themify($themes) { - color: themed('textColorAccent'); - } - } - li > a:hover { - // color: $black; - } - > li:first-child > a { - padding-left: 0; - } - > li:last-child > a { - padding-right: 0; - } - .input-group-button { - z-index: 1; - transform: scaleX(-1); - padding-left: 10px; - } -} - - -@media screen and (min-width: 52.5em) { - ul.HorizontalMenu.menu { - display: flex; - li > a { - padding-right: 0.5em; - line-height: 1.5rem; - display: flex; - text-transform: lowercase; - padding-left: 0.5em; - padding-right: 0.5em; - } - .active { - font-weight: bold; - } - } -} - -@media print, screen and (min-width: 52.5em) { - .menu-hide-for-large { - display: none !important; - } -} \ No newline at end of file diff --git a/src/app/components/elements/MuteButton.jsx b/src/app/components/elements/MuteButton.jsx index e621015669ddf0dee3cfca579df063bbb5679224..dc3debc3f15fb069bc251bc9e57b8d48636d20cc 100644 --- a/src/app/components/elements/MuteButton.jsx +++ b/src/app/components/elements/MuteButton.jsx @@ -50,7 +50,7 @@ class MuteButton extends React.Component { </a> {this.state.showDialog && ( <Reveal onHide={() => null} show> - <CloseButton onClick={() => this.hideDialot()} /> + <CloseButton onClick={() => this.hideDialog()} /> <MutePost isMuted={isMuted} onSubmit={notes => { diff --git a/src/app/components/elements/MuteList.jsx b/src/app/components/elements/MuteList.jsx new file mode 100644 index 0000000000000000000000000000000000000000..2ce906cc76b9253d0a61493e8269305209d75f72 --- /dev/null +++ b/src/app/components/elements/MuteList.jsx @@ -0,0 +1,71 @@ +import { connect } from 'react-redux'; +import React from 'react'; +import { Link } from 'react-router'; +import * as transactionActions from 'app/redux/TransactionReducer'; + +class MuteList extends React.Component { + constructor(props) { + super(); + this.state = {}; + this.unmute = this.unmute.bind(this); + } + + unmute(e, target) { + e.preventDefault(); + + if (this.state.busy) return; + this.setState({ busy: target }); + const done = () => { + this.setState({ busy: null }); + }; + + const { account } = this.props; + this.props.updateFollow(account, target, null, done); + } + + render() { + const { users } = this.props; + const { busy } = this.state; + const { unmute } = this; + + const items = users.map(user => ( + <li key={user}> + <Link to={'/@' + user}> + <strong>@{user}</strong> + </Link> + + {busy == user ? ( + <span>saving....</span> + ) : ( + <a href="#" onClick={e => unmute(e, user)}> + [unmute] + </a> + )} + </li> + )); + + return <ol>{items}</ol>; + } +} + +module.exports = connect( + (state, props) => ({}), + dispatch => ({ + updateFollow: (follower, following, type, done) => { + const what = type ? [type] : []; + const json = ['follow', { follower, following, what }]; + dispatch( + transactionActions.broadcastOperation({ + type: 'custom_json', + operation: { + id: 'follow', + required_posting_auths: [follower], + json: JSON.stringify(json), + }, + successCallback: done, + errorCallback: done, + }) + ); + }, + }) +)(MuteList); diff --git a/src/app/components/elements/ReplyEditor.jsx b/src/app/components/elements/ReplyEditor.jsx index 778aeb69dca1f595266b6098eecc676a4f016654..2137096a9b47e65fc8fa2b595bb44a010317dd69 100644 --- a/src/app/components/elements/ReplyEditor.jsx +++ b/src/app/components/elements/ReplyEditor.jsx @@ -420,14 +420,16 @@ class ReplyEditor extends React.Component { const errorCallback = estr => { this.setState({ postError: estr, loading: false }); }; + const isEdit = type === 'edit'; const successCallbackWrapper = (...args) => { - resetForm(); + if (!isEdit) { + resetForm(); + } this.setState({ loading: false }); this.props.setPayoutType(formId, defaultPayoutType); this.props.setBeneficiaries(formId, []); if (successCallback) successCallback(args); }; - const isEdit = type === 'edit'; const isHtml = rte || isHtmlTest(body.value); const replyParams = { author, @@ -889,7 +891,9 @@ export default formId => } const jsonMetadata = ownProps.jsonMetadata - ? ownProps.jsonMetadata.toJS() + ? ownProps.jsonMetadata instanceof Map + ? ownProps.jsonMetadata.toJS() + : ownProps.jsonMetadata : {}; let tags = category; diff --git a/src/app/components/elements/ReplyEditor.scss b/src/app/components/elements/ReplyEditor.scss index a32e45db4c960b11c4155cd8fa8cbb71f1da00ee..35111b7cf474ca3b60b2a444cd8b38fcb8349cb3 100644 --- a/src/app/components/elements/ReplyEditor.scss +++ b/src/app/components/elements/ReplyEditor.scss @@ -1,7 +1,5 @@ .ReplyEditor { max-width: 54rem; - margin-bottom: 0.5rem; - padding-bottom: 2em; .vframe { display: block; .public-DraftEditor-content { diff --git a/src/app/components/elements/ShareMenu.jsx b/src/app/components/elements/ShareMenu.jsx index b0d25dac02887f24b16f19a8826222f7efc7687b..ab6f99e0e5a958c7310f85487605d4f481d11218 100644 --- a/src/app/components/elements/ShareMenu.jsx +++ b/src/app/components/elements/ShareMenu.jsx @@ -6,38 +6,20 @@ import Icon from 'app/components/elements/Icon'; export default class ShareMenu extends React.Component { static propTypes = { menu: PropTypes.arrayOf(PropTypes.object).isRequired, - title: PropTypes.string, }; render() { - const title = this.props.title; - const items = this.props.menu; + const { menu } = this.props; return ( - <span className={'shareMenu'}> - <ul className={'shareItems'}> - {title && <li className="title">{title}</li>} - {items.map(i => { - return ( - <li key={i.value}> - {i.link ? ( - <Link - to={i.link} - onClick={i.onClick} - title={i.title} - > - {i.icon && <Icon name={i.icon} />} - {} - {i.addon} - </Link> - ) : ( - <span> - {i.icon && <Icon name={i.icon} />} - {i.label ? i.label : i.value} - </span> - )} - </li> - ); - })} + <span className="shareMenu"> + <ul> + {menu.map(i => ( + <li key={i.title}> + <Link to="#" onClick={i.onClick} title={i.title}> + <Icon name={i.icon} /> + </Link> + </li> + ))} </ul> </span> ); diff --git a/src/app/components/elements/ShareMenu.scss b/src/app/components/elements/ShareMenu.scss index 9327fb69cb1b44f423b6afc32abc37d043f03d0e..2f4fe5973ffacc9a32b37a15bb34cfd378a817f0 100644 --- a/src/app/components/elements/ShareMenu.scss +++ b/src/app/components/elements/ShareMenu.scss @@ -2,32 +2,19 @@ display: inline-block; vertical-align: middle; height: 2em; -} -.shareItems { - list-style: none; - display: inline; - margin-left: 0.01em; - li { - float: left; - padding-left: 4px; - } - li > a { - transition: 0.2s all ease-in-out; - } - li > a:hover { - color: #ffffff; - svg { + > ul { + list-style: none; + display: inline; + margin: 0; + li { + float: left; + padding: 2px; + } + li > a:hover svg { @include themify($themes) { fill: themed('colorAccent'); - } + } } } - li > a:link { - text-decoration: none; - } -} - -.RightShare__Menu { - padding-right: 0.6rem!important; } diff --git a/src/app/components/elements/SidebarLinks.jsx b/src/app/components/elements/SidebarLinks.jsx index e99cc436bbe334eb82260acf3d3e6e4cdd99aed4..b95418a6aa0a1fef983e67e36614789dd2b55a93 100644 --- a/src/app/components/elements/SidebarLinks.jsx +++ b/src/app/components/elements/SidebarLinks.jsx @@ -2,7 +2,7 @@ import React from 'react'; import tt from 'counterpart'; import { Link } from 'react-router'; -const SidebarLinks = ({ username, subscriptions }) => ( +const SidebarLinks = ({ username, topics }) => ( <div className="c-sidebar__module"> {/* <div className="c-sidebar__header"> @@ -28,15 +28,15 @@ const SidebarLinks = ({ username, subscriptions }) => ( </a> </li> */} - {subscriptions && ( + {topics && ( <li className="c-sidebar__list-item"> <div style={{ color: '#aaa', paddingTop: '0em' }}> - My subscriptions + Trending Communities </div> </li> )} - {subscriptions && - subscriptions.map(item => ( + {topics && + topics.toJS().map(item => ( <li key={item[0]} className="c-sidebar__list-item"> <Link className="c-sidebar__link" diff --git a/src/app/components/elements/SidebarNewUsers.jsx b/src/app/components/elements/SidebarNewUsers.jsx index fd6ee5a155a11bdb8d2f3e024a8e68e31a65e35c..d434b44bc486f14d9b8bf365d4b5dcecc2d55992 100644 --- a/src/app/components/elements/SidebarNewUsers.jsx +++ b/src/app/components/elements/SidebarNewUsers.jsx @@ -14,24 +14,19 @@ const SidebarNewUsers = () => ( Quick start guide </a> </li> - <li className="c-sidebar__list-item"> - <a className="c-sidebar__link" href="https://steem.io"> - The blockchain - </a> - </li> <li className="c-sidebar__list-item"> <a className="c-sidebar__link" href="/faq.html"> FAQs </a> </li> <li className="c-sidebar__list-item"> - <a className="c-sidebar__link" href={SIGNUP_URL}> - Sign up + <a className="c-sidebar__link" href="/@steemitblog"> + {tt('g.read_offical_blog')} </a> </li> <li className="c-sidebar__list-item"> - <a className="c-sidebar__link" href="/@steemitblog"> - {tt('g.read_offical_blog')} + <a className="c-sidebar__link" href="https://steem.io"> + Steem.io </a> </li> </ul> diff --git a/src/app/components/elements/SidebarStats.jsx b/src/app/components/elements/SidebarStats.jsx deleted file mode 100644 index 4a86111d5ab85180c3951251968b720b61f3a25c..0000000000000000000000000000000000000000 --- a/src/app/components/elements/SidebarStats.jsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; - -const SidebarStats = ({ steemPower, followers, reputation }) => ( - <div className="c-sidebar__module"> - <div className="c-sidebar__header"> - <h3 className="c-sidebar__h3">Stats</h3> - </div> - <div className="c-sidebar__content"> - <ul className="c-sidebar__list"> - <li className="c-sidebar__list-item"> - <span className="c-sidebar__label">Steem Power</span> - <span className="c-sidebar__score">{steemPower}</span> - </li> - <li className="c-sidebar__list-item"> - <span className="c-sidebar__label">Followers</span> - <span className="c-sidebar__score">{followers}</span> - </li> - <li className="c-sidebar__list-item"> - <span className="c-sidebar__label">Reputation</span> - <span className="c-sidebar__score">{reputation}</span> - </li> - </ul> - </div> - </div> -); - -export default SidebarStats; diff --git a/src/app/components/elements/SubscribeButton.jsx b/src/app/components/elements/SubscribeButton.jsx index 17ba726b33b7c17f861693e200f8ade7c09db29f..3f31353e38e7e381b968516e0cfffdf084a5ae38 100644 --- a/src/app/components/elements/SubscribeButton.jsx +++ b/src/app/components/elements/SubscribeButton.jsx @@ -45,11 +45,13 @@ class SubscribeButton extends React.Component { onClick={this.onClick} className={'community--subscribe button primary' + hollowed} style={{ - minWidth: '6em', + minWidth: '7em', display: this.props.display || 'inline-block', }} > - <span>{loading ? loader : subscribed ? 'Joined' : 'Join'}</span> + <span> + {loading ? loader : subscribed ? 'Joined' : 'Subscribe'} + </span> </a> ); } diff --git a/src/app/components/elements/Tag.jsx b/src/app/components/elements/Tag.jsx new file mode 100644 index 0000000000000000000000000000000000000000..430683f56e45437ff35ce137da5afd979208acc6 --- /dev/null +++ b/src/app/components/elements/Tag.jsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { Link } from 'react-router'; + +const Tag = ({ post }) => { + const tag = post.get('category'); + const name = post.get('community_title', '#' + tag); + return ( + <Link to={`/trending/${tag}`} key={tag}> + {name} + </Link> + ); +}; + +export default Tag; diff --git a/src/app/components/elements/TagList.jsx b/src/app/components/elements/TagList.jsx index 3230ff96cf698b8ca32c81f4a7f023d13bae027d..d77bbf26a64c57949f50ad80097cb9fd4c66fa11 100644 --- a/src/app/components/elements/TagList.jsx +++ b/src/app/components/elements/TagList.jsx @@ -1,23 +1,18 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { Link } from 'react-router'; import { normalizeTags } from 'app/utils/StateFunctions'; -import DropdownMenu from 'app/components/elements/DropdownMenu'; class TagList extends Component { render() { - const { post, single } = this.props; + const { post } = this.props; const category = post.get('category'); const link = tag => { - const primary = tag === category && post.get('community_title'); - const name = primary || '#' + tag; - return <Link to={`/trending/${tag}`} key={tag}>{` ${name} `}</Link>; + if (tag == category) return null; + return <Link to={`/trending/${tag}`} key={tag}>{` #${tag} `}</Link>; }; - if (single) return link(category); - return ( <div className="TagList__horizontal"> {normalizeTags(post.get('json_metadata'), category).map(link)} @@ -30,6 +25,5 @@ export default connect( // mapStateToProps (state, ownProps) => ({ post: ownProps.post, - single: ownProps.single, }) )(TagList); diff --git a/src/app/components/elements/TagList.scss b/src/app/components/elements/TagList.scss index 52ac45defb2d096e09c0f27c49cb81c42dc1418e..2006c40f6ed7e971dddd3083728b09544de42a1c 100644 --- a/src/app/components/elements/TagList.scss +++ b/src/app/components/elements/TagList.scss @@ -1,32 +1,24 @@ -.TagList { - ul.VerticalMenu { - a { - padding: 0 0.4rem; - line-height: 1.5; - color: inherit; - } - } -} - .TagList__horizontal { - margin-bottom: 0.5rem; + max-width: 40rem; + margin: 0 auto 0.5rem; a { + font-size: 95%; display: inline-block; margin: 0.1rem 0.4rem 0.1rem 0; - padding: 0.2rem 0.5rem; + padding: 0.1rem 0.3rem; border-radius: 0.3rem; transition: 0.2s all ease-in-out; @include themify($themes) { background: themed('backgroundColorOpaque'); color: themed('textColorPrimary'); border: themed('border'); - } + } &:hover { @include themify($themes) { background: themed('backgroundColor'); color: themed('textColorPrimary'); border: themed('borderDark'); - } + } } } } diff --git a/src/app/components/elements/UserTitle.jsx b/src/app/components/elements/UserTitle.jsx index b5547c341d120ac723112184421fec3228be6d1c..26a4f529b3f126d3cf69d6f1af8bb9845f4f3f5c 100644 --- a/src/app/components/elements/UserTitle.jsx +++ b/src/app/components/elements/UserTitle.jsx @@ -42,10 +42,10 @@ class UserTitle extends React.Component { render() { const { title, role, viewer_role, hideEdit } = this.props; const isMod = Role.atLeast(viewer_role, 'mod'); - const showRole = role && (isMod || role != 'guest'); + const showRole = role && role != 'guest'; const showTitle = title != '' || (isMod && !hideEdit); - if (!showRole || !showTitle) return null; + if (!showRole && !showTitle) return null; let editor; if (isMod && !hideEdit) { diff --git a/src/app/components/elements/VerticalMenu.jsx b/src/app/components/elements/VerticalMenu.jsx index ed59e5f6d9798764ad99583511e216b40ac83061..83778103ae110cb2d3d0c1f8170481f0f9024766 100644 --- a/src/app/components/elements/VerticalMenu.jsx +++ b/src/app/components/elements/VerticalMenu.jsx @@ -7,7 +7,6 @@ export default class VerticalMenu extends React.Component { static propTypes = { items: PropTypes.arrayOf(PropTypes.object).isRequired, title: PropTypes.string, - className: PropTypes.string, hideValue: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), }; @@ -20,14 +19,9 @@ export default class VerticalMenu extends React.Component { }; render() { - const { items, title, className, hideValue } = this.props; + const { items, title, hideValue } = this.props; return ( - <ul - className={ - 'VerticalMenu menu vertical' + - (className ? ' ' + className : '') - } - > + <ul className="VerticalMenu menu vertical"> {title && <li className="title">{title}</li>} {items.map(i => { if (i.value === hideValue) return null; @@ -38,13 +32,11 @@ export default class VerticalMenu extends React.Component { <a href={i.link} target="_blank"> {i.icon && <Icon name={i.icon} />} {i.label ? i.label : i.value} - {i.addon} </a> ) : ( <Link to={i.link} onClick={i.onClick}> {i.icon && <Icon name={i.icon} />} {i.label ? i.label : i.value} - {i.addon} </Link> ) ) : ( diff --git a/src/app/components/elements/Voting.jsx b/src/app/components/elements/Voting.jsx index e846f791c0dc2e18735c295d0a1e14b4ab2e03c0..807a3afc4663e0b1a51119340e8a00e8737ddc62 100644 --- a/src/app/components/elements/Voting.jsx +++ b/src/app/components/elements/Voting.jsx @@ -604,7 +604,7 @@ export default connect( ); if (!post) { - console.log('props', ownProps); + console.error('post_not_found', ownProps); throw 'post not found'; } diff --git a/src/app/components/elements/WelcomePanel.jsx b/src/app/components/elements/WelcomePanel.jsx index 99e5d33be717c05f71278537ddfddd3763aa016b..2ed812e5c2d791963039ee93d519f5d643b86c89 100644 --- a/src/app/components/elements/WelcomePanel.jsx +++ b/src/app/components/elements/WelcomePanel.jsx @@ -11,45 +11,42 @@ export default class WelcomePanel extends React.Component { } render() { + const signup = ( + <a className="button ghost fade-in--5" href={SIGNUP_URL}> + {tt('navigation.sign_up')} + </a> + ); + + const learn = ( + <Link href="/faq.html" className="button ghost fade-in--7"> + {tt('navigation.learn_more')} + </Link> + ); + return ( <div className="welcomeWrapper"> <div className="welcomeBanner"> <CloseButton onClick={this.setShowBannerFalse} /> <div className="row"> - <div className="text-center welcomeImage small-12 show-for-small-only"> - <img - className="heroImage" - src={require('app/assets/images/welcome-hero.png')} - /> - </div> - </div> - <div className="row"> - <div className="large-1 show-for-large" /> + <div className="large-2 medium-1 show-for-medium" /> <div className="small-12 medium-6 large-5 welcomePitch"> <h2 className="fade-in--1"> - {tt('navigation.intro_tagline')} + Communities Without Borders + {/*tt('navigation.intro_tagline')*/} </h2> <h4 className="fade-in--3"> - {tt('navigation.intro_paragraph')} + { + 'A social network owned and operated by its users, ' + } + {'powered by '} + <a href="https://steem.io">Steem</a>. + {/*tt('navigation.intro_paragraph')*/} </h4> - <div className="row buttonWrapper"> - <a - className="button button--primary fade-in--5" - href={SIGNUP_URL} - > - {' '} - <b>{tt('navigation.sign_up')}</b>{' '} - </a> - - <Link - href="/faq.html" - className="button ghost fade-in--7" - > - <b>{tt('navigation.learn_more')}</b> - </Link> + <div> + {signup} {learn} </div> </div> - <div className="text-center welcomeImage medium-6 large-5 show-for-medium"> + <div className="text-center welcomeImage medium-4 large-3 show-for-medium"> <img className="heroImage" src={require('app/assets/images/welcome-hero.png')} diff --git a/src/app/components/modules/BottomPanel.jsx b/src/app/components/modules/BottomPanel.jsx deleted file mode 100644 index 62f7451a05a78e58ef4b3f9fae06c445301f58c5..0000000000000000000000000000000000000000 --- a/src/app/components/modules/BottomPanel.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; -import CloseButton from 'app/components/elements/CloseButton'; -import PropTypes from 'prop-types'; - -export default class BottomPanel extends React.Component { - static propTypes = { - children: PropTypes.object, - visible: PropTypes.bool, - hide: PropTypes.func.isRequired, - }; - - componentWillReceiveProps(nextProps) { - if (nextProps.visible) { - document.addEventListener('click', this.props.hide); - } else { - document.removeEventListener('click', this.props.hide); - } - } - - componentWillUnmount() { - document.removeEventListener('click', this.props.hide); - } - - render() { - const { children, visible, hide } = this.props; - return ( - <div className="BottomPanel"> - <div className={visible ? 'visible ' : ''}> - <CloseButton onClick={hide} /> - {children} - </div> - </div> - ); - } -} diff --git a/src/app/components/modules/BottomPanel.scss b/src/app/components/modules/BottomPanel.scss deleted file mode 100644 index e68c958b5ac5cf820955d971ba6ab4ae98ade53c..0000000000000000000000000000000000000000 --- a/src/app/components/modules/BottomPanel.scss +++ /dev/null @@ -1,41 +0,0 @@ -$btm-panel-width: 400px; -$btm-panel-height: 90px; - -.BottomPanel { - > div { - background-color: rgba(220, 220, 220, .9); - color: #fff; - padding: 2rem 1rem 0.5rem 1rem; - border-top-left-radius: $global-radius; - border-top-right-radius: $global-radius; - .close-button { - color: #000; - } - - position: fixed; - z-index: 1000; - width: $btm-panel-width; - height: $btm-panel-height; - box-sizing: border-box; - transition: visibility 250ms, transform ease 250ms; - left: 50%; - margin-left: -$btm-panel-width/2; - bottom: -$btm-panel-height; - visibility: hidden; - - &.visible { - transform: translate3d(0, -$btm-panel-height, 0); - visibility: visible; - } - } -} - -/* Small only */ -@media screen and (max-width: 39.9375em) { - .BottomPanel > div { - width: 100%; - left: 0; - margin-left: 0; - border-radius: 0; - } -} diff --git a/src/app/components/modules/CommunitySettings.jsx b/src/app/components/modules/CommunitySettings.jsx index f873cc4ce62ccc5e7ac39d17d4702b8879c7f2fd..a96d9a909d77497200ebbd61b74e0dfe07ccca8d 100644 --- a/src/app/components/modules/CommunitySettings.jsx +++ b/src/app/components/modules/CommunitySettings.jsx @@ -100,7 +100,7 @@ class CommunitySettings extends Component { /> </label> <label style={{ margin: '0 0 0.5rem' }}> - Flag Text<br /> + Rules (one per line)<br /> <textarea style={{ whiteSpace: 'normal' }} type="text" diff --git a/src/app/components/modules/ConnectedFlag/README.md b/src/app/components/modules/ConnectedFlag/README.md deleted file mode 100644 index b74a67d0669805e919f2ade6b999ed27d3bcf58a..0000000000000000000000000000000000000000 --- a/src/app/components/modules/ConnectedFlag/README.md +++ /dev/null @@ -1,30 +0,0 @@ -This HOC can be used to conditionally render a component based on a flag being present in the redux store. -If the flag is not present or if it is false a fallback component is rendered. - -If you provide both children and a FlagComponent the children will be rendered. - -Example Usage: - -``` -// Conditionally render wrapped Children -<ConnectedFlag - flag="yup" - Fallback={LoadingIndicator} -> - <h1> Hello World </h1> -</ConnectedFlag> - -// Explicitly Render a component. -<ConnectedFlag - flag="yup" - FlagComponent={<Icon name="user" />} - Fallback={<LoadingIndicator/>} -/> - -// If flag is false or not present, render a fallback -<ConnectedFlag - flag="NOPE" - FlagComponent={<Icon name="user" />} - Fallback={<LoadingIndicator/>} -/> -``` diff --git a/src/app/components/modules/ConnectedFlag/index.jsx b/src/app/components/modules/ConnectedFlag/index.jsx deleted file mode 100644 index 53b31ddfe6f1dcc5926e6c942882ed38be766dec..0000000000000000000000000000000000000000 --- a/src/app/components/modules/ConnectedFlag/index.jsx +++ /dev/null @@ -1,15 +0,0 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { selectors as appSelectors } from 'app/redux/AppReducer'; -import Flag from 'app/components/modules/Flag'; - -const mapStateToProps = (state, ownProps) => { - return { - flagged: appSelectors.getFeatureFlag(state.app, ownProps.flag), - ...ownProps, - }; -}; - -const ConnectedFlag = connect(mapStateToProps)(Flag); - -export default ConnectedFlag; diff --git a/src/app/components/modules/Flag/Flag.test.jsx b/src/app/components/modules/Flag/Flag.test.jsx deleted file mode 100644 index ed8514e6487318603b9f8756f6a4e8fb5b4d8ae1..0000000000000000000000000000000000000000 --- a/src/app/components/modules/Flag/Flag.test.jsx +++ /dev/null @@ -1,71 +0,0 @@ -/*global describe, it, before, beforeEach, after, afterEach */ -import React from 'react'; -import { configure, shallow } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-15'; -import LoadingIndicator from 'app/components/elements/LoadingIndicator'; -import Icon from 'app/components/elements/Icon'; - -import Flag from 'app/components/modules/Flag'; - -configure({ adapter: new Adapter() }); - -describe('Flag', () => { - let component = <LoadingIndicator />; - let fallback = <Icon name="user" />; - let child = <div> HELLO WORLD </div>; - - it('should render the children when the flag prop is true', () => { - const wrapper = shallow( - <Flag - flagged={true} - FlagComponent={component} - Fallback={fallback} - children={child} - /> - ); - expect(wrapper.text()).toEqual(' HELLO WORLD '); - }); - it('should render the FlagComponent when the flag prop is true and there are no children', () => { - const wrapper = shallow( - <Flag - flagged={true} - FlagComponent={component} - Fallback={fallback} - /> - ); - expect(wrapper.text()).toEqual('<LoadingIndicator />'); - }); - - it('should render null when the flag condition fails and no fallback is provided', () => { - const wrapper = shallow( - <Flag flagged={false} FlagComponent={component} /> - ); - expect(wrapper.html()).toBe(null); - }); - - it('should render the fallback component if the flag condition is false', () => { - const wrapper = shallow( - <Flag - flagged={false} - FlagComponent={component} - Fallback={fallback} - /> - ); - expect(wrapper.html()).not.toBe(null); - expect(wrapper.text()).toEqual('<Icon />'); - }); - - it('should render children but not FlagComponent if both are provided', () => { - const wrapper = shallow( - <Flag - flagged={true} - FlagComponent={component} - Fallback={fallback} - children={child} - /> - ); - // There isn't a good way to check for proptypes errors - // see https://stackoverflow.com/questions/26124914/how-to-test-react-proptypes-through-jest - expect(wrapper.text()).toEqual(' HELLO WORLD '); - }); -}); diff --git a/src/app/components/modules/Flag/index.jsx b/src/app/components/modules/Flag/index.jsx deleted file mode 100644 index 2cf51eeb273ccf6e7113887a45fdd1a89fb657a4..0000000000000000000000000000000000000000 --- a/src/app/components/modules/Flag/index.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; - -const Flag = ({ flagged, FlagComponent, Fallback = null, children }) => { - if (flagged && children) return { ...children }; - else return flagged ? FlagComponent : Fallback; -}; - -Flag.propTypes = { - flagged: PropTypes.bool.isRequired, - FlagComponent: (props, propName, componentName) => { - // First ensure it is a React element - PropTypes.checkPropTypes( - { FlagComponent: PropTypes.element }, - props, - 'FlagComponent', - 'Flag' - ); - // Also issue a warning if children are also supplied - if (props[propName] && props.children) { - return new Error( - 'Supplied both a FlagComponent and children to Flag; rendering children!' - ); - } - }, - Fallback: PropTypes.element, -}; - -export default Flag; diff --git a/src/app/components/modules/FlagCommunityPost.jsx b/src/app/components/modules/FlagCommunityPost.jsx new file mode 100644 index 0000000000000000000000000000000000000000..a15643ec48947654caac5093e89e149ffa352e82 --- /dev/null +++ b/src/app/components/modules/FlagCommunityPost.jsx @@ -0,0 +1,91 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; + +import tt from 'counterpart'; +const nl2li = text => + text.split('\n').map((item, key) => <li key={key}>{item}</li>); + +class FlagCommunityPost extends Component { + constructor(props) { + super(props); + this.state = { notes: '', disableSubmit: true }; + } + + componentWillUpdate = (nextProps, nextState) => { + if (nextState.notes != this.state.notes) { + this.setState({ disableSubmit: nextState.notes == '' }); + } + }; + + onInput = e => { + this.setState({ notes: `${e.target.value || ''}`.trim() }); + }; + + onSubmit = () => { + if (this.state.notes) this.props.onSubmit(this.state.notes); + }; + + render() { + const { disableSubmit } = this.state; + const { flagText, isComment } = this.props; + return ( + <span> + <div> + <h4> + {tt('g.flag_this_post', { + type: isComment ? 'comment' : 'post', + })} + </h4> + <p> + {tt('g.flag_this_post_description', { + type: isComment ? 'comment' : 'post', + })} + </p> + {flagText && + flagText.length > 0 && ( + <span> + <strong>Community Rules</strong> + <ol>{nl2li(flagText)}</ol> + </span> + )} + </div> + <hr /> + <div className="input-group"> + <span className="input-group-label">Notes</span> + <input + className="input-group-field" + type="text" + maxLength={120} + onKeyUp={e => { + if (e.key === 'Enter') { + this.onSubmit(); + } + this.onInput(e); + }} + /> + <button + className="button slim hollow secondary" + type="submit" + disabled={disableSubmit} + onClick={() => this.onSubmit()} + > + {tt('g.flag')} + </button> + </div> + </span> + ); + } +} + +FlagCommunityPost.propTypes = { + onSubmit: PropTypes.func.isRequired, + flagText: PropTypes.string.isRequired, + isComment: PropTypes.bool, +}; + +FlagCommunityPost.defaultProps = { + isComment: false, +}; + +export default connect()(FlagCommunityPost); diff --git a/src/app/components/modules/Header/index.jsx b/src/app/components/modules/Header/index.jsx index 34c81c519538be1b177aac942e60748033c996d0..7ac3d87a54dafaf796c000273b0ca65d75116d15 100644 --- a/src/app/components/modules/Header/index.jsx +++ b/src/app/components/modules/Header/index.jsx @@ -172,8 +172,6 @@ class Header extends React.Component { page_title = tt('navigation.terms_of_service'); } else if (route.page == 'CommunityRoles') { page_title = 'Community Roles'; - } else if (route.page == 'RecoverAccountStep1') { - page_title = tt('header_jsx.stolen_account_recovery'); } else if (route.page === 'UserProfile') { const user_name = route.params[0].slice(1); const user_title = display_name @@ -296,12 +294,14 @@ class Header extends React.Component { </div> <div className="large-4 medium-3 columns show-for-medium large-centered Header__sort"> + {/* <SortOrder sortOrder={order} topic={category === 'feed' ? '' : category} horizontal pathname={pathname} /> + */} </div> <div className="small-6 medium-6 large-4 columns Header__buttons"> @@ -345,13 +345,10 @@ class Header extends React.Component { items={user_menu} title={username} el="span" - selected={tt('g.rewards')} position="left" > <li className={'Header__userpic '}> - <span title={username}> - <Userpic account={username} /> - </span> + <Userpic account={username} /> </li> </DropdownMenu> )} diff --git a/src/app/components/modules/MutePost.jsx b/src/app/components/modules/MutePost.jsx index b956cfec0834bb5e8821adc34f71654449a28bce..64a6d17755ccf069727bb8750750d007572c62cb 100644 --- a/src/app/components/modules/MutePost.jsx +++ b/src/app/components/modules/MutePost.jsx @@ -12,12 +12,12 @@ class MutePost extends Component { componentWillUpdate = (nextProps, nextState) => { if (nextState.notes != this.state.notes) { - this.setState({ disableSubmit: false }); + this.setState({ disableSubmit: nextState.notes == '' }); } }; onInput = e => { - this.setState({ notes: `${e.target.value || ''}` }); + this.setState({ notes: `${e.target.value || ''}`.trim() }); }; onSubmit = () => { diff --git a/src/app/components/modules/Settings.jsx b/src/app/components/modules/Settings.jsx index f41c578ba60de00ecdbed9e45e5084180e4c3ce3..be5b9a69403d845bb70dc86d33df86dececa01b1 100644 --- a/src/app/components/modules/Settings.jsx +++ b/src/app/components/modules/Settings.jsx @@ -3,7 +3,7 @@ import { connect } from 'react-redux'; import tt from 'counterpart'; import * as userActions from 'app/redux/UserReducer'; import * as appActions from 'app/redux/AppReducer'; -import UserList from 'app/components/elements/UserList'; +import MuteList from 'app/components/elements/MuteList'; class Settings extends React.Component { constructor(props) { @@ -48,7 +48,7 @@ class Settings extends React.Component { const { walletUrl, ignores, - account, + accountname, isOwnAccount, user_preferences, } = this.props; @@ -64,7 +64,7 @@ class Settings extends React.Component { href={ walletUrl + '/@' + - account.name + + accountname + '/settings' } > @@ -174,9 +174,9 @@ class Settings extends React.Component { <div className="row"> <div className="small-12 medium-6 large-6 columns"> <br /> - <br /> - <UserList - title={tt('settings_jsx.muted_users')} + <h4>Muted Users</h4> + <MuteList + account={accountname} users={ignores} /> </div> @@ -206,7 +206,6 @@ export default connect( accountname, isOwnAccount, ignores, - account: state.global.getIn(['accounts', accountname]).toJS(), user_preferences: state.app.get('user_preferences').toJS(), walletUrl: state.app.get('walletUrl'), ...ownProps, diff --git a/src/app/components/modules/SidebarModule.jsx b/src/app/components/modules/SidebarModule.jsx deleted file mode 100644 index ce92681b8a99181d75aaf9e33f93af348959a879..0000000000000000000000000000000000000000 --- a/src/app/components/modules/SidebarModule.jsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; - -export class SidebarModule extends React.Component { - render() { - return ( - <div className="c-sidebar__module"> - <div className="c-sidebar__header"> - <h3 className="c-sidebar__h3">Links React Component</h3> - </div> - <div className="c-sidebar__content"> - <ul className="c-sidebar__list"> - <li className="c-sidebar__list-item"> - <a className="c-sidebar__link" href="#"> - Test - </a> - </li> - </ul> - </div> - </div> - ); - } -} diff --git a/src/app/components/modules/UserRole.jsx b/src/app/components/modules/UserRole.jsx index 93ce8cfab4b3503efbdb8eb381b1546ddb3fbea1..fe2e87bb85e4125b81215a735b6f2a3ff32c84f1 100644 --- a/src/app/components/modules/UserRole.jsx +++ b/src/app/components/modules/UserRole.jsx @@ -122,6 +122,21 @@ class UserRole extends Component { </button> </div> <div>{message.length > 0 && message}</div> + <div> + <h5>Role Permissions</h5> + <p> + <strong>Owner</strong> - assign admins<br /> + <strong>Admin</strong> - edit settings, assign mods<br + /> + <strong>Moderator</strong> - mute, pin, set user titles<br + /> + <strong>Member</strong> - listed on leadership team<br + /> + <strong>Guest</strong> - default; can post and comment<br + /> + <strong>Muted</strong> - new posts automatically muted + </p> + </div> </span> ); } diff --git a/src/app/components/modules/UserWallet.jsx b/src/app/components/modules/UserWallet.jsx deleted file mode 100644 index 003c9b0b521399e5d2ea6a190d043526cc284757..0000000000000000000000000000000000000000 --- a/src/app/components/modules/UserWallet.jsx +++ /dev/null @@ -1,33 +0,0 @@ -/* eslint react/prop-types: 0 */ -import React from 'react'; -import { connect } from 'react-redux'; -import { Link } from 'react-router'; -import tt from 'counterpart'; - -class UserWallet extends React.Component { - render() { - const { account, walletUrl } = this.props; - if (!account) return null; - - return ( - <div className="UserWallet"> - <div className="wallet-link row zebra"> - <p> - <a href={walletUrl}>Go to wallet</a> - </p> - </div> - </div> - ); - } -} - -export default connect( - // mapStateToProps - (state, ownProps) => { - const walletUrl = state.app.get('walletUrl'); - return { - walletUrl, - ...ownProps, - }; - } -)(UserWallet); diff --git a/src/app/components/modules/UserWallet.scss b/src/app/components/modules/UserWallet.scss index 301641dfb7184ba0516345c0260d6a87f18b7701..4179e705f5a3390a06417432eebfa895ea0c4469 100644 --- a/src/app/components/modules/UserWallet.scss +++ b/src/app/components/modules/UserWallet.scss @@ -1,28 +1,7 @@ -.UserWallet { - padding-top: 2rem; - - .wallet-link { - margin-top: 1rem; - padding-left: 1rem; - } -} - -.UserWallet__balance { - padding-bottom: 1rem; - padding-top: 1rem; - - &.UserWallet__balance.zebra { - @include themify($themes) { - background-color: themed('tableRowEvenBackgroundColor'); - color: themed('textColorPrimary'); - } - } -} - .UserWallet__claimbox { - margin: 1.5rem 0 0.5rem; - padding: 1rem 1rem 1.1rem 1rem; - border-radius: 5px; + margin: 1rem 0; + padding: 0.5rem 1rem; + border-radius: 8px; display: flex; align-items: center; justify-content: space-between; @@ -34,25 +13,9 @@ color: themed('textColorPrimary'); } - &-text { - font-weight: bold; - } .button { @extend .e-btn; @include font-size(14px); margin: 0; } - // spacing for mobile collapse - @media only screen and (max-width: 680px) { - .button { - margin: 8px 0 0 0; - } - } -} - -// protect for foundation bug for collapsed state drop-downs -@media only screen and (max-width: 40em) { - .Wallet_dropdown { - left: 10px!important; - } } diff --git a/src/app/components/pages/ChangePasswordPage.jsx b/src/app/components/pages/ChangePasswordPage.jsx deleted file mode 100644 index 07edd74f741f6a6be12772823358089ccf2be57b..0000000000000000000000000000000000000000 --- a/src/app/components/pages/ChangePasswordPage.jsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import ChangePassword from 'app/components/elements/ChangePassword'; -import tt from 'counterpart'; - -class ChangePasswordPage extends React.Component { - render() { - return ( - <div className="row"> - <div className="column"> - <ChangePassword /> - </div> - </div> - ); - } -} - -module.exports = { - path: 'change_password', - component: ChangePasswordPage, -}; diff --git a/src/app/components/pages/CommunitiesIndex.jsx b/src/app/components/pages/CommunitiesIndex.jsx index 3162647370c3a19ecbe8660fc909e1b734a8dc46..a26d49a31cec397027e2c01d5ba8cea2fb75a9b8 100644 --- a/src/app/components/pages/CommunitiesIndex.jsx +++ b/src/app/components/pages/CommunitiesIndex.jsx @@ -6,6 +6,7 @@ import { Map, List } from 'immutable'; import { actions as fetchDataSagaActions } from 'app/redux/FetchDataSaga'; import SubscribeButton from 'app/components/elements/SubscribeButton'; import { Link } from 'react-router'; +import PostsIndexLayout from 'app/components/pages/PostsIndexLayout'; export default class CommunitiesIndex extends React.Component { componentWillMount = () => { @@ -42,17 +43,24 @@ export default class CommunitiesIndex extends React.Component { {role(comm)} <br /> {comm.about} + <small> + {comm.subscribers} subscribers • {comm.num_pending}{' '} + posts + </small> </th> <td width="40"> <SubscribeButton community={comm.name} /> - <small>{comm.subscribers} subscribers</small> </td> </tr> ); return ( - <div className="CommunitiesIndex row"> - <div className="column"> + <PostsIndexLayout + category={null} + enableAds={false} + blogmode={false} + > + <div className="CommunitiesIndex c-sidebar__module"> {username && ( <div style={{ float: 'right' }}> <a href={`${walletUrl}/@${username}/communities`}> @@ -69,7 +77,7 @@ export default class CommunitiesIndex extends React.Component { <tbody>{ordered.map(comm => row(comm.toJS()))}</tbody> </table> </div> - </div> + </PostsIndexLayout> ); } } diff --git a/src/app/components/pages/CommunitiesIndex.scss b/src/app/components/pages/CommunitiesIndex.scss index 81aae97c9bcad84bd178f6a6dffd588127efb99d..dcd99f91f74609ee77e313213ec0bb5d5cca1cf8 100644 --- a/src/app/components/pages/CommunitiesIndex.scss +++ b/src/app/components/pages/CommunitiesIndex.scss @@ -1,10 +1,11 @@ .CommunitiesIndex { max-width: 800px; - margin: 0 auto; table {margin-top: 1em;} + table tbody {background: transparent;} + table tbody tr {background: transparent !important;} table th {text-align: left; font-weight: normal} table th a {font-weight: 400; font-size: 1.3em;} - table td {vertical-align: top; color: #666; text-align: center;} + table td {vertical-align: middle; color: #666; text-align: center;} table small {color: #999; display: block;} table .button {margin: 0} } diff --git a/src/app/components/pages/CommunityRoles.jsx b/src/app/components/pages/CommunityRoles.jsx index 418c7cef927a37734ef3b704e1bbd51fe5b9f063..ee473c40ac4bfbef39c4d770d7c46544e3f2fce2 100644 --- a/src/app/components/pages/CommunityRoles.jsx +++ b/src/app/components/pages/CommunityRoles.jsx @@ -7,6 +7,7 @@ import Reveal from 'app/components/elements/Reveal'; import CloseButton from 'app/components/elements/CloseButton'; import UserRole from 'app/components/modules/UserRole'; import { Link } from 'react-router'; +import PostsIndexLayout from 'app/components/pages/PostsIndexLayout'; class CommunityRoles extends React.Component { constructor(props) { @@ -78,11 +79,6 @@ class CommunityRoles extends React.Component { roles, communityMetadata, } = this.props; - const spinner = ( - <center> - <LoadingIndicator type="circle" /> - </center> - ); const canEdit = { owner: ['admin', 'mod', 'member', 'guest', 'muted'], @@ -197,39 +193,57 @@ class CommunityRoles extends React.Component { const commName = (communityMetadata && communityMetadata.title) || null; - return ( - <div className="CommunityRoles"> - <div className="row"> - <div className="column large-3 medium-2 small-0" /> - <div className="column large-6 medium-8 small-12"> - <h3> - <Link to={`/trending/${community}`}> - {commName || community} - </Link> - </h3> + let body; + if (loading) { + body = ( + <center> + <LoadingIndicator type="circle" /> + </center> + ); + } else { + body = ( + <div> + <h1 className="articles__h1"> + <Link to={`/trending/${community}`}> + {commName || community} + </Link> + </h1> + <br /> + <div className="c-sidebar__module"> + <h4>User Roles</h4> {updating && <div>Updating User...</div>} - {loading && spinner} {this.state.updateRoleModal && editUserModal} {this.state.addUserToCommunityModal && addUserModal} - {!loading && ( - <div> - <h5>Community Roles</h5> - {table} - <button - onClick={() => { - this.toggleAddUserToCommunityModal( - true - ); - }} - className="button slim hollow secondary" - > - Add User - </button> - </div> - )} + <div> + {table} + <button + onClick={() => { + this.toggleAddUserToCommunityModal(true); + }} + className="button slim hollow secondary" + > + Add User + </button> + </div> + </div> + </div> + ); + } + + return ( + <PostsIndexLayout + category={community} + enableAds={false} + blogmode={false} + > + <div className="CommunityRoles"> + <div className="row"> + <div className="column large-9 medium-12 small-12"> + {body} + </div> </div> </div> - </div> + </PostsIndexLayout> ); } } diff --git a/src/app/components/pages/CommunityRoles.scss b/src/app/components/pages/CommunityRoles.scss index 040d752f077a480ab1d3959526bc7e9e7299b194..407bc1bcfb6e1ba932527c43bb5361ae1009ece8 100644 --- a/src/app/components/pages/CommunityRoles.scss +++ b/src/app/components/pages/CommunityRoles.scss @@ -1,3 +1,8 @@ +.CommunityRoles { + table tbody {background: transparent;} + table tbody tr {background: transparent !important;} +} + .community-user--role { cursor: pointer; } diff --git a/src/app/components/pages/Market.jsx b/src/app/components/pages/Market.jsx deleted file mode 100644 index a4168d4845d3a3a86e7569f9a6123437d09f569c..0000000000000000000000000000000000000000 --- a/src/app/components/pages/Market.jsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import { Link } from 'react-router'; -import tt from 'counterpart'; - -class Market extends React.Component { - render() { - return ( - <div className="row"> - <div className="column"> - {tt('g.external_link_message')} - {': '} - <Link to={`${$STM_Config.wallet_url}/market`}> - {tt('navigation.currency_market')} - </Link> - </div> - </div> - ); - } -} -module.exports = { - path: 'market', - component: Market, -}; diff --git a/src/app/components/pages/Post.jsx b/src/app/components/pages/Post.jsx index 0bbe8358521c8e0f91a1ac9d3356acc83dc67ef2..87532965256d48706121cd5825c0948eb0bd5ff6 100644 --- a/src/app/components/pages/Post.jsx +++ b/src/app/components/pages/Post.jsx @@ -206,29 +206,30 @@ class Post extends React.Component { <div className="row"> <div className="column">{postBody}</div> </div> - {!isLoggedIn() && ( - <div className="row"> - <div className="column"> - <div className="Post__promo"> - {tt( - 'g.next_7_strings_single_block.authors_get_paid_when_people_like_you_upvote_their_post' - )}. - <br /> - {tt( - 'g.next_7_strings_single_block.if_you_enjoyed_what_you_read_earn_amount' - )} - <br /> - <button - type="button" - className="button e-btn" - onClick={showSignUp} - > - {tt('loginform_jsx.sign_up_get_steem')} - </button> + {false && + !isLoggedIn() && ( + <div className="row"> + <div className="column"> + <div className="Post__promo"> + {tt( + 'g.next_7_strings_single_block.authors_get_paid_when_people_like_you_upvote_their_post' + )}. + <br /> + {tt( + 'g.next_7_strings_single_block.if_you_enjoyed_what_you_read_earn_amount' + )} + <br /> + <button + type="button" + className="button e-btn" + onClick={showSignUp} + > + {tt('loginform_jsx.sign_up_get_steem')} + </button> + </div> </div> </div> - </div> - )} + )} {this.props.gptEnabled && commentCount >= 5 ? ( <div className="Post_footer__ad"> <GptAd diff --git a/src/app/components/pages/Post.scss b/src/app/components/pages/Post.scss index abb2406855d8359bc5f6e770b2378266b017e287..7ccb2617ab4af552a4e9cad1c5bef8985acb3734 100644 --- a/src/app/components/pages/Post.scss +++ b/src/app/components/pages/Post.scss @@ -32,7 +32,7 @@ } .Post_comments__content { - max-width: 50rem; + max-width: 54rem; margin: 0 auto 3.5rem; font-size: 92%; } diff --git a/src/app/components/pages/PostsIndex.jsx b/src/app/components/pages/PostsIndex.jsx index 6ae9ef82f407192f7d1137fcf784ea05382bdfbd..5b7d62a0c021a12e6062ab9e68d142ce978bfb13 100644 --- a/src/app/components/pages/PostsIndex.jsx +++ b/src/app/components/pages/PostsIndex.jsx @@ -10,18 +10,12 @@ import shouldComponentUpdate from 'app/utils/shouldComponentUpdate'; import PostsList from 'app/components/cards/PostsList'; import { isFetchingOrRecentlyUpdated } from 'app/utils/StateFunctions'; import Callout from 'app/components/elements/Callout'; -import SidebarLinks from 'app/components/elements/SidebarLinks'; -import SidebarNewUsers from 'app/components/elements/SidebarNewUsers'; -import Notices from 'app/components/elements/Notices'; -import SteemMarket from 'app/components/elements/SteemMarket'; import { GptUtils } from 'app/utils/GptUtils'; -import GptAd from 'app/components/elements/GptAd'; import ArticleLayoutSelector from 'app/components/modules/ArticleLayoutSelector'; import Topics from './Topics'; import SortOrder from 'app/components/elements/SortOrder'; import { ifHive } from 'app/utils/Community'; -import CommunityPane from 'app/components/elements/CommunityPane'; -import CommunityPaneMobile from 'app/components/elements/CommunityPaneMobile'; +import PostsIndexLayout from 'app/components/pages/PostsIndexLayout'; const emptyFeedText = (isMyAccount, account_name) => { return isMyAccount ? ( @@ -82,6 +76,7 @@ class PostsIndex extends React.Component { loadMore(last_post) { if (!last_post) return; + if (last_post == this.props.pending) return; // if last post is 'pending', its an invalid start token const { category, order, status } = this.props; if (isFetchingOrRecentlyUpdated(status, order, category || '')) return; const [author, permlink] = last_post.split('/'); @@ -98,7 +93,7 @@ class PostsIndex extends React.Component { const { topics, subscriptions, - allowAdsOnContent, + enableAds, community, category, account_name, // TODO: for feed @@ -141,158 +136,84 @@ class PostsIndex extends React.Component { page_title = '#' + category; } - const layoutClass = this.props.blogmode - ? ' layout-block' - : ' layout-list'; return ( - <div - className={ - 'PostsIndex row' + - (fetching ? ' fetching' : '') + - layoutClass - } + <PostsIndexLayout + category={category} + enableAds={enableAds} + blogmode={this.props.blogmode} > - <article className="articles"> - {community && ( - <span className="hide-for-mq-large articles__header-select"> - <CommunityPaneMobile - community={community} - username={this.props.username} - /> - </span> - )} - <div className="articles__header row"> - <div className="small-8 medium-7 large-8 column"> - <h1 className="articles__h1 show-for-mq-large articles__h1--no-wrap"> - {page_title} - </h1> - <div className="show-for-mq-large"> - {community && ( + <div className="articles__header row"> + <div className="small-8 medium-7 large-8 column"> + <h1 className="articles__h1 show-for-mq-large articles__h1--no-wrap"> + {page_title} + </h1> + <div className="show-for-mq-large"> + {community && ( + <div + style={{ + fontSize: '80%', + color: 'gray', + }} + > + Community + </div> + )} + {!community && + category && + order !== 'feed' && + category !== 'my' && ( <div style={{ fontSize: '80%', color: 'gray', }} > - Community + Unmoderated tag </div> )} - {!community && - category && - order !== 'feed' && - category !== 'my' && ( - <div - style={{ - fontSize: '80%', - color: 'gray', - }} - > - Unmoderated tag - </div> - )} - </div> - <span className="hide-for-mq-large articles__header-select"> - <Topics - username={this.props.username} - order={order} - current={category} - topics={topics} - compact - /> - </span> </div> - {order != 'feed' && ( - <div className="small-4 medium-4 large-3 column hide-for-largeX articles__header-select"> - <SortOrder - sortOrder={order} - topic={category} - horizontal={false} - /> - </div> - )} - <div className="medium-1 show-for-mq-medium column"> - <ArticleLayoutSelector /> - </div> - </div> - <hr className="articles__hr" /> - {!fetching && !posts.size ? ( - <Callout>{emptyText}</Callout> - ) : ( - <PostsList - ref="list" - posts={posts} - loading={fetching} - anyPosts - order={order} - category={category} - hideCategory={!!community} - loadMore={this.loadMore} - showFeatured - showPromoted - allowAdsOnContent={allowAdsOnContent} - /> - )} - </article> - - <aside className="c-sidebar c-sidebar--right"> - {community && ( - <CommunityPane - community={community} - username={this.props.username} - /> - )} - {this.props.isBrowser && - !community && - !this.props.username && <SidebarNewUsers />} - {this.props.isBrowser && - !community && - this.props.username && ( - <SidebarLinks + <span className="hide-for-mq-large articles__header-select"> + <Topics username={this.props.username} - subscriptions={subscriptions} + current={category} + topics={subscriptions || topics} + compact /> - )} - {false && !community && <Notices />} - {!category && <SteemMarket />} - {allowAdsOnContent && ( - <div className="sidebar-ad"> - <GptAd - type="Freestar" - id="bsa-zone_1566495004689-0_123456" + </span> + </div> + {order != 'feed' && ( + <div className="small-4 medium-4 large-3 column articles__header-select"> + <SortOrder + sortOrder={order} + topic={category} + horizontal={false} /> </div> )} - </aside> + <div className="medium-1 show-for-mq-medium column"> + <ArticleLayoutSelector /> + </div> + </div> + <hr className="articles__hr" /> - <aside className="c-sidebar c-sidebar--left"> - <Topics + {!fetching && !posts.size ? ( + <Callout>{emptyText}</Callout> + ) : ( + <PostsList + ref="list" + posts={posts} + loading={fetching} + anyPosts order={order} - current={category} - compact={false} - username={this.props.username} - topics={topics} + category={category} + hideCategory={!!community} + loadMore={this.loadMore} + showFeatured + showPromoted + allowAdsOnContent={enableAds} /> - {allowAdsOnContent && ( - <div> - <div className="sidebar-ad"> - <GptAd - type="Freestar" - slotName="bsa-zone_1566494461953-7_123456" - /> - </div> - <div - className="sidebar-ad" - style={{ marginTop: 20 }} - > - <GptAd - type="Freestar" - slotName="bsa-zone_1566494856923-9_123456" - /> - </div> - </div> - )} - </aside> - </div> + )} + </PostsIndexLayout> ); } } @@ -318,26 +239,33 @@ module.exports = { const hive = ifHive(category); const community = state.global.getIn(['community', hive], null); - const allowAdsOnContent = + const enableAds = ownProps.gptEnabled && !GptUtils.HasBannedTags( [category], state.app.getIn(['googleAds', 'gptBannedTags']) ); - const subscriptions = state.global.get('subscriptions'); + const key = ['discussion_idx', category || '', order]; + let posts = state.global.getIn(key, List()); + + // if 'pending' post is found, prepend it to posts list + // (see GlobalReducer RECEIVE_CONTENT) + const pkey = ['discussion_idx', category || '', '_' + order]; + const pending = state.global.getIn(pkey, null); + if (pending && !posts.includes(pending)) { + posts = posts.unshift(pending); + } return { - subscriptions: subscriptions ? subscriptions.toJS() : null, + subscriptions: state.global.get('subscriptions'), status: state.global.get('status'), loading: state.app.get('loading'), account_name, category, order, - posts: state.global.getIn( - ['discussion_idx', category || '', order], - List() - ), + posts, + pending, community, username: state.user.getIn(['current', 'username']) || @@ -345,7 +273,7 @@ module.exports = { blogmode: state.app.getIn(['user_preferences', 'blogmode']), topics: state.global.getIn(['topics'], List()), isBrowser: process.env.BROWSER, - allowAdsOnContent, + enableAds, }; }, dispatch => ({ diff --git a/src/app/components/pages/PostsIndex.scss b/src/app/components/pages/PostsIndex.scss index d5143d315e3deeae44ecf439a4906d6a50d9e245..187a51439d670303ce45387e866c6a4943051828 100644 --- a/src/app/components/pages/PostsIndex.scss +++ b/src/app/components/pages/PostsIndex.scss @@ -12,9 +12,9 @@ } .PostsIndex { - .articles__h1--no-wrap { - white-space: nowrap; - } + .articles__h1--no-wrap { + white-space: nowrap; + } } .PostsIndex__topics { @@ -33,10 +33,6 @@ } } -.PostsIndex.fetching .PostsIndex__topics_compact { - visibility: hidden; -} - /* Small only */ @media screen and (max-width: 39.9375em) { .PostsIndex__left { @@ -102,10 +98,11 @@ flex: 0 0 320px; font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif; &__module { - padding: 1.5em 2em; + padding: 1.5em 2em; @include themify($themes) { - background-color: themed('moduleBackgroundColor'); - border: themed('border'); + border-radius: themed('roundedCorners'); + background-color: themed('moduleBackgroundColor'); + border: themed('border'); } margin-bottom: 1em; box-shadow: 0px 5px 10px 0 rgba(0,0,0,0); @@ -199,42 +196,32 @@ } .articles { - font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif; - padding: 4px 1em 1em 1em; - transition: all 0.2s ease-out; - border: transparent; - min-width: 300px; - width: 100%; - margin: auto; - background-color: transparent; + font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif; + padding: 0.25em 1em; + transition: all 0.2s ease-out; + border: transparent; + min-width: 300px; + width: 100%; + margin: 0 auto; + background-color: transparent; + box-shadow: none; + h2 { + font-family: sans-serif; + } @include MQ(M) { - margin: 0 1em; - padding: 0.5em 0em; + padding: 0.25em 1em; min-width: 500px; max-width: 664px; order: 2; } - h2 { - font-family: sans-serif; - } @include MQ(L) { min-width: 550px; max-width: 664px; - padding: 1.5em 4em; @include themify($themes) { - border: themed('border'); - box-shadow: 5px 5px 0 0 themed('contentBorderAccent'); - background-color: themed('moduleBackgroundColor'); - } - } - - &:hover { - @include MQ(L) { - @include themify($themes) { - box-shadow: 6px 6px 0 0 themed('contentBorderAccent'); - } + border: themed('borderTransparent'); + background-color: themed('transparent'); } } @@ -242,10 +229,10 @@ margin-bottom: 20px; margin-top: 0px; @include themify($themes) { - border-bottom: themed('border'); - } + border-bottom: themed('border'); + } @include MQ(M) { - display: none; + display: none; } } @@ -257,8 +244,8 @@ float: right; } @include MQ(FM) { - display: flex; - justify-content: flex-end; + display: flex; + justify-content: flex-end; } } &__icon--layout { @@ -267,27 +254,26 @@ position: relative; } &__summary { - margin: 0em 0 1em; - transition: 0.2s all ease-in-out; - border: transparent; - padding-bottom: 10px; + margin: 0; + transition: 0.2s all ease-in-out; + border: transparent; + padding-bottom: 0; + @include themify($themes) { + background-color: themed('moduleBackgroundColor'); + } + @include MQ(M) { + margin: 0 0 40px; + box-shadow: 0px 5px 10px 0 rgba(0,0,0,0.0); + padding-bottom: 0; @include themify($themes) { - background-color: themed('moduleBackgroundColor'); - border-bottom: themed('border'); - } - @include MQ(M) { - margin: 0 0 40px; - box-shadow: 0px 5px 10px 0 rgba(0,0,0,0.0); - padding-bottom: 0; - @include themify($themes) { - border: themed('border'); - } + border: themed('border'); } - &:hover { - @include MQ(M) { - box-shadow: 0px 5px 10px 0 rgba(0,0,0,0.03); - } + } + &:hover { + @include MQ(M) { + box-shadow: 0px 5px 10px 0 rgba(0,0,0,0.03); } + } } &__resteem-icon { position: relative; @@ -302,18 +288,18 @@ @include MQ(M) { padding: 10px 16px 5px; @include themify($themes) { - border-bottom: themed('border'); - } + border-bottom: themed('border'); } + } &--footer { @include themify($themes) { - border-top: themed('border'); - border-bottom: themed('border'); - } + border-top: themed('border'); + border-bottom: themed('border'); + } @include MQ(M) { @include themify($themes) { - border-bottom: transparent; - } + border-bottom: transparent; + } } } } @@ -326,8 +312,8 @@ @include MQ(M) { padding: 16px; @include themify($themes) { - border-top: themed('border'); - } + border-top: themed('border'); + } } a { @extend .link; @@ -344,13 +330,14 @@ justify-content: space-between; flex-wrap: wrap; line-height: 1; + min-height: 50px; @include MQ(M) { padding-top: 0; } &-select { - select { - max-width: 300px; - } + select { + max-width: 300px; + } } } &__header-col { @@ -365,21 +352,20 @@ } &__resteem { padding-bottom: 0px; - margin-top: 24px; + margin-top: 6px; @include MQ(M) { - margin-top: 8px; padding-bottom: 5px; @include themify($themes) { - border-bottom: themed('border'); - } + border-bottom: themed('border'); } + } } &__resteem-text { @include font-size(13px); margin-bottom: 0px; @include themify($themes) { - color: themed('textColorSecondary'); + color: themed('textColorSecondary'); } @include MQ(M) { margin-bottom: 2px; @@ -412,19 +398,19 @@ // @extend .h2; margin: 0; @include font-size(16px); - overflow : hidden; - text-overflow: ellipsis; - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; + overflow : hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; a { - font-weight: bold; - @include themify($themes) { + font-weight: bold; + @include themify($themes) { color: themed('textColorPrimary'); - } - &:visited { + } + &:visited { @include themify($themes) { - color: themed('textColorSecondary'); + color: themed('textColorSecondary'); } } } @@ -448,7 +434,7 @@ top: -4px; margin-top: 12px; @include themify($themes) { - color: themed('textColorSecondary'); + color: themed('textColorSecondary'); } @media only screen and (min-width: 370px) { margin-top: 0; @@ -471,8 +457,8 @@ &__link { text-decoration: none; @include themify($themes) { - color: themed('textColorPrimary'); - } + color: themed('textColorPrimary'); + } } // &__profile-img { // display: none; @@ -486,16 +472,16 @@ } &__tags { @include themify($themes) { - color: themed('textColorSecondary'); - } + color: themed('textColorSecondary'); + } @include font-size(14px); margin-bottom: 18px; } &__tag-link { - @include font-size(14px); + @include font-size(14px); @include themify($themes) { - color: themed('textColorSecondary'); - } + color: themed('textColorSecondary'); + } a { @extend .link; @extend .link--secondary; @@ -515,16 +501,16 @@ .icon-flag-svg { @include themify($themes) { - fill: themed('textColorSecondary'); - } + fill: themed('textColorSecondary'); + } transition: 0.2s all ease-in-out; } &:hover { cursor: pointer; .icon-flag-svg { @include themify($themes) { - fill: themed('textColorError'); - } + fill: themed('textColorError'); + } } } } @@ -567,8 +553,8 @@ .user__username { transition: 0.2s all ease-in-out; @include themify($themes) { - color: themed('textColorAccent'); - } + color: themed('textColorAccent'); + } } } } @@ -625,12 +611,12 @@ .icon-svg { transition: 0.2s all 0.05s ease-in-out; @include themify($themes) { - fill: themed('textColorSecondary'); - } + fill: themed('textColorSecondary'); + } &--accent { @include themify($themes) { - fill: themed('textColorAccent'); - } + fill: themed('textColorAccent'); + } } &--layout-line1, &--layout-line2, &--layout-line3 { height: 2px; @@ -650,21 +636,21 @@ .articles__layout-selector { - display: inline-block; - .icon-svg { - &--accent { - @include themify($themes) { - fill: themed('textColorSecondary'); - } - } + display: inline-block; + .icon-svg { + &--accent { + @include themify($themes) { + fill: themed('textColorSecondary'); + } } + } } .articles__layout-selector:hover .icon-svg { &--accent { @include themify($themes) { - fill: themed('textColorPrimary'); - } + fill: themed('textColorPrimary'); + } } } @@ -706,15 +692,14 @@ a#changeLayout:focus { } } .articles { - padding: 1.5em 1.5em; max-width: none; max-width: 1056px; @include MQ(XL) { min-width: 850px; } @include themify($themes) { - background-color: themed('moduleBackgroundColor'); - border: themed('border'); + background-color: transparent; + border: themed('borderTransparent'); } &__hr { @include MQ(M) { @@ -728,19 +713,16 @@ a#changeLayout:focus { border: transparent; box-shadow: none; padding-bottom: 0px; - margin: 0 0 1.4em; - @include themify($themes) { - border-bottom: themed('borderLight'); - } + margin: 0; @include MQ(M) { - padding-bottom: 6px; + padding-bottom: 0; } } &__h2 { - @include font-size(16px); + @include font-size(15px); @include MQ(M) { - -webkit-line-clamp: 2; + -webkit-line-clamp: 1; } @include MQ(XL) { -webkit-line-clamp: 1; @@ -761,7 +743,7 @@ a#changeLayout:focus { transform:translateY(-50%) } &__summary-header { - padding: 2px 0 5px; + padding: 2px 0 0; border: transparent; } &__summary-footer { @@ -784,6 +766,12 @@ a#changeLayout:focus { display: flex; align-items: top; } + &__footer { + @include themify($themes) { + border-top: themed('borderLight'); + margin-top: 0.25em; + } + } &__content-block { margin-bottom: 0; &--img { @@ -810,6 +798,10 @@ a#changeLayout:focus { padding-right: 0; } } + .articles__hr { + margin-bottom: 0.3em; + display: none; + } } // ,user layout-list .user { @@ -824,20 +816,6 @@ a#changeLayout:focus { } } - -.layout-list { - @include MQ(L) { - .articles { - padding: 1.5em 3em; - } - } - @include MQ(XL) { - .articles { - padding: 1.5em 4em; - } - } -} - .layout-list .user > .user__col > .user__link > .Userpic { width: 24px !important; height: 24px !important; @@ -851,73 +829,15 @@ a#changeLayout:focus { } } -.layout-compressed { - @extend .layout-list; - - @include MQ(M) { - .Userpic { - display: none; - } - .articles { - &__summary { - margin: 0 0 10px; - padding-bottom: 0; - @include themify($themes) { - border-bottom: themed('borderTransparent'); - } - } - &__summary-header { - padding: 2px 0; - } - &__summary-footer { - padding: 0; - } - &__h2 { - @include font-size(14px); - padding-bottom: 2px; - } - .PostSummary__body { - padding: 0; - @include font-size(14px); - } - &__content-block { - &--img { - margin-right: 12px; - } - } - &__feature-img-container { - width: 90px; - height: 56px; - } - &__hr { - margin-bottom: 12px; - } - } - .c-sidebar { - &__content { - @include font-size(14px); - } - } - .user { - &__name { - a { - font-weight: normal; - } - } - } - } -} - - .icon-svg { transition: 0.2s all ease-in-out; @include themify($themes) { - fill: themed('textColorSecondary'); - } + fill: themed('textColorSecondary'); + } &--accent { @include themify($themes) { - fill: themed('textColorAccent'); - } + fill: themed('textColorAccent'); + } } &--layout-line1, &--layout-line2, &--layout-line3 { height: 2px; @@ -941,12 +861,12 @@ a#changeLayout:focus { .articles__resteem .username { - @extend .link; - @extend .link--secondary; - text-decoration: none; + @extend .link; + @extend .link--secondary; + text-decoration: none; } .articles__resteem-icon path { - fill: #cacaca; + fill: #cacaca; } diff --git a/src/app/components/pages/PostsIndexLayout.jsx b/src/app/components/pages/PostsIndexLayout.jsx new file mode 100644 index 0000000000000000000000000000000000000000..e2bb46a2586f862757626a279ffcb966816b5f6c --- /dev/null +++ b/src/app/components/pages/PostsIndexLayout.jsx @@ -0,0 +1,139 @@ +/* eslint react/prop-types: 0 */ +import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { Link } from 'react-router'; +import tt from 'counterpart'; +import { List, Map } from 'immutable'; +import { actions as fetchDataSagaActions } from 'app/redux/FetchDataSaga'; +import SidebarLinks from 'app/components/elements/SidebarLinks'; +import SidebarNewUsers from 'app/components/elements/SidebarNewUsers'; +import Notices from 'app/components/elements/Notices'; +import SteemMarket from 'app/components/elements/SteemMarket'; +import GptAd from 'app/components/elements/GptAd'; +import Topics from './Topics'; +import { ifHive } from 'app/utils/Community'; +import CommunityPane from 'app/components/elements/CommunityPane'; +import CommunityPaneMobile from 'app/components/elements/CommunityPaneMobile'; + +class PostsIndexLayout extends React.Component { + static propTypes = { + username: PropTypes.string, + blogmode: PropTypes.bool, + topics: PropTypes.object, + }; + + componentWillMount() { + const { subscriptions, getSubscriptions, username } = this.props; + if (!subscriptions && username) getSubscriptions(username); + } + + render() { + const { + topics, + subscriptions, + enableAds, + community, + username, + blogmode, + isBrowser, + children, + } = this.props; + + return ( + <div + className={ + 'PostsIndex row ' + + (blogmode ? 'layout-block' : 'layout-list') + } + > + <article className="articles"> + {community && ( + <span className="hide-for-mq-large articles__header-select"> + <CommunityPaneMobile + community={community} + username={username} + /> + </span> + )} + {children} + </article> + + <aside className="c-sidebar c-sidebar--right"> + {community && ( + <CommunityPane + community={community} + username={username} + /> + )} + {isBrowser && + !community && + !username && <SidebarNewUsers />} + {isBrowser && + !community && + username && ( + <SidebarLinks username={username} topics={topics} /> + )} + {false && !community && <Notices />} + {!community && <SteemMarket />} + {enableAds && ( + <div className="sidebar-ad"> + <GptAd + type="Freestar" + id="bsa-zone_1566495004689-0_123456" + /> + </div> + )} + </aside> + + <aside className="c-sidebar c-sidebar--left"> + <Topics + compact={false} + username={username} + subscriptions={subscriptions} + topics={topics} + /> + {enableAds && ( + <div> + <div className="sidebar-ad"> + <GptAd + type="Freestar" + slotName="bsa-zone_1566494461953-7_123456" + /> + </div> + <div + className="sidebar-ad" + style={{ marginTop: 20 }} + > + <GptAd + type="Freestar" + slotName="bsa-zone_1566494856923-9_123456" + /> + </div> + </div> + )} + </aside> + </div> + ); + } +} + +export default connect( + (state, props) => { + return { + blogmode: props.blogmode, + enableAds: props.enableAds, + community: state.global.getIn(['community', props.category], null), + subscriptions: state.global.get('subscriptions', null), + topics: state.global.getIn(['topics'], List()), + isBrowser: process.env.BROWSER, + username: + state.user.getIn(['current', 'username']) || + state.offchain.get('account'), + }; + }, + dispatch => ({ + getSubscriptions: account => + dispatch(fetchDataSagaActions.getSubscriptions(account)), + }) +)(PostsIndexLayout); diff --git a/src/app/components/pages/RecoverAccountStep1.jsx b/src/app/components/pages/RecoverAccountStep1.jsx deleted file mode 100644 index a71f47bff205e016d908f25148314222038069b6..0000000000000000000000000000000000000000 --- a/src/app/components/pages/RecoverAccountStep1.jsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; -import tt from 'counterpart'; -import { APP_DOMAIN, APP_NAME } from 'app/client_config'; -import { Link } from 'react-router'; - -class RecoverAccountStep1 extends React.Component { - render() { - return ( - <div className="RestoreAccount"> - <div className="row"> - <div className="column large-4"> - <h2>{tt('navigation.stolen_account_recovery')}</h2> - <p> - {tt( - 'recoveraccountstep1_jsx.recover_account_intro', - { APP_URL: APP_DOMAIN, APP_NAME } - )} - </p> - - <p> - {tt('g.external_link_message')} - {': '} - <Link - to={`${ - $STM_Config.wallet_url - }/recover_account_step_1`} - > - {tt('navigation.stolen_account_recovery')} - </Link> - </p> - </div> - </div> - </div> - ); - } -} - -module.exports = { - path: 'recover_account_step_1', - component: RecoverAccountStep1, -}; diff --git a/src/app/components/pages/SubmitPost.jsx b/src/app/components/pages/SubmitPost.jsx index 3593888e0e727bca271afe2fdc3a4f318fdef45c..246b7762b55d399412bfcb9a65490e0ab222d51e 100644 --- a/src/app/components/pages/SubmitPost.jsx +++ b/src/app/components/pages/SubmitPost.jsx @@ -11,7 +11,7 @@ function _redirect_url(operations) { const { category } = operations[0][0][1]; return '/created/' + category; } catch (e) { - console.error(e); + console.error('redirect_url', e); } return '/created'; } diff --git a/src/app/components/pages/TagsIndex.jsx b/src/app/components/pages/TagsIndex.jsx index 24b4b27cf8526f8574ad5ce51dbd0b25e8d7b014..8c8e8d0018e2f627084a2a07d48c7c8f73ee1d30 100644 --- a/src/app/components/pages/TagsIndex.jsx +++ b/src/app/components/pages/TagsIndex.jsx @@ -54,7 +54,6 @@ export default class TagsIndex extends React.Component { render() { const { tagsAll } = this.props; - //console.log('-- TagsIndex.render -->', tagsAll.toJS()); const { order } = this.state; let tags = tagsAll; diff --git a/src/app/components/pages/Topics.jsx b/src/app/components/pages/Topics.jsx index 66822f145d2cc0b1e694850c3da7502f8ec15ce4..61a44bdbad1d268424a01f4dd3a67bcf4dca33dc 100644 --- a/src/app/components/pages/Topics.jsx +++ b/src/app/components/pages/Topics.jsx @@ -9,6 +9,7 @@ import NativeSelect from 'app/components/elements/NativeSelect'; class Topics extends Component { static propTypes = { topics: PropTypes.object.isRequired, + subscriptions: PropTypes.object, current: PropTypes.string, compact: PropTypes.bool.isRequired, }; @@ -18,7 +19,14 @@ class Topics extends Component { }; render() { - const { current, compact, username, topics, communities } = this.props; + const { + current, + compact, + username, + topics, + subscriptions, + communities, + } = this.props; if (compact) { const opt = (tag, label = null) => { @@ -29,6 +37,11 @@ class Topics extends Component { }; if (tag === 'my') return { value: `/trending/my`, label: 'My subscriptions' }; + if (tag == 'explore') + return { + value: `/communities`, + label: 'Explore Communities...', + }; if (tag) return { value: `/trending/${tag}`, @@ -46,12 +59,16 @@ class Topics extends Component { } options = options.concat( - topics.toJS().map(cat => opt(cat[0], cat[1])) + (subscriptions || topics).toJS().map(cat => opt(cat[0], cat[1])) ); + options.push(opt('explore')); + const currOpt = opt(current); if (!options.find(opt => opt.value == currOpt.value)) { - options.push(opt(current)); + options.push( + opt(current, communities.getIn([current, 'title'])) + ); } return ( @@ -78,19 +95,22 @@ class Topics extends Component { ); const moreLabel = <span>{tt('g.show_more_topics')}…</span>; + const title = subscriptions + ? 'My Subscriptions' + : 'Trending Communities'; const commsHead = ( - <div style={{ color: '#aaa', paddingTop: '1em' }}>Communities</div> + <div style={{ color: '#aaa', paddingTop: '0em' }}>{title}</div> ); const list = ( <ul className="c-sidebar__list"> - <li>{link('/trending', tt('g.all_tags'))}</li> + {/*<li>{link('/trending', tt('g.all_tags'))}</li>*/} {username && ( <li>{link(`/@${username}/feed`, 'My friends')}</li> )} {username && <li>{link(`/trending/my`, 'My communities')}</li>} <li>{commsHead}</li> - {topics + {(subscriptions || topics) .toJS() .map(cat => ( <li key={cat[0]}> diff --git a/src/app/components/pages/UserProfile.jsx b/src/app/components/pages/UserProfile.jsx index b1fc2d5e31ae32358ef90bd98edde55d91eae6e9..ffa82cfa6327fde325dab17a4cad87a27998b55c 100644 --- a/src/app/components/pages/UserProfile.jsx +++ b/src/app/components/pages/UserProfile.jsx @@ -255,7 +255,7 @@ export default class UserProfile extends React.Component { } else { tab_content = ( <PostsList - account={accountname} // 'blog' only + account={section == 'blog' ? accountname : null} // 'blog' only posts={posts} loading={fetching} loadMore={this.loadMore} diff --git a/src/app/components/pages/UserProfile.scss b/src/app/components/pages/UserProfile.scss index 4085417db8e9326ca50def17e6082225e61f71d5..798f08ecbfa2c8518c4be98d2533cb3da4bff614 100644 --- a/src/app/components/pages/UserProfile.scss +++ b/src/app/components/pages/UserProfile.scss @@ -65,7 +65,7 @@ color: $white; } > div.column { - background: $color-blue-black; + background: $color-background-less-dark; background-size: cover; background-repeat: no-repeat; background-position: 50% 50%; @@ -137,12 +137,6 @@ } } -.UserWallet__balance { - > div:nth-child(2) { - text-align: right; - } -} - @media screen and (max-width: 39.9375em) { div.UserProfile__top-nav .menu li>a { @@ -175,18 +169,6 @@ color: $black; } } - - .UserWallet__balance { - > div:last-of-type { - text-align: left; - } - } - - .UserReward__row { - > div:last-of-type { - padding-left: 20px; - } - } } // Temporary fix to prevent alternate User Profile pages outside the blog from taking the narrow layout. diff --git a/src/app/components/pages/Witnesses.jsx b/src/app/components/pages/Witnesses.jsx deleted file mode 100644 index 6e6656221e005a6ddc708d061fd41b1115903e5b..0000000000000000000000000000000000000000 --- a/src/app/components/pages/Witnesses.jsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import { Link } from 'react-router'; -import tt from 'counterpart'; - -class Witnesses extends React.Component { - render() { - return ( - <div className="row"> - <div className="column"> - {tt('g.external_link_message')} - {': '} - <Link to={`${$STM_Config.wallet_url}/~witnesses`}> - {tt('navigation.vote_for_witnesses')} - </Link> - </div> - </div> - ); - } -} - -module.exports = { - path: '/~witnesses(/:witness)', - component: Witnesses, -}; diff --git a/src/app/help/en/faq.md b/src/app/help/en/faq.md index 183c0a381a8838b4da39727c95b56009fdf6774b..f38afa368a16efd5b55b0b4367504be8b7fe9d82 100644 --- a/src/app/help/en/faq.md +++ b/src/app/help/en/faq.md @@ -566,7 +566,7 @@ All tags must be lowercase letters. Spaces aren't allowed, but hyphenated words <a href="#Table_of_Contents_Posting">^</a> ## <span id="How_many_tags_can_I_use">How many tags can I use?</span> -You can use up to 5 tags per post. +You can use up to 8 tags per post. <a href="#Table_of_Contents_Posting">^</a> ## <span id="Why_is_the_Post_button_grayed_out">Why is the "Post" button grayed out?</span> diff --git a/src/app/locales/en.json b/src/app/locales/en.json index 5e99963900872efadc69314cce4196b2eee29569..1dc9309e2197e9aa90744b8dbd0c825ff664fa11 100644 --- a/src/app/locales/en.json +++ b/src/app/locales/en.json @@ -45,6 +45,10 @@ "affiliation_steemit": "Steemit Team", "affiliation_sm": "Steem Monsters Team", "feed": "Feed", + "flag": "Flag", + "flag_this_post": "Flag this %(type)s", + "flag_this_post_description": + "Please provide a note regarding your decision to flag this %(type)s, it will be reviewed by community moderators.", "follow": "Follow", "for": " for ", "from": " from ", @@ -118,12 +122,12 @@ "sell": "Sell", "settings": "Settings", "share_this_post": "Share this post", - "mute_this_post": "Mute this post", + "mute_this_post": "Mute post/comment", "mute_this_post_description": - "Please provide a note regarding your decision to mute this post.", - "unmute_this_post": "Unmute this post", + "Please provide a note regarding your decision to mute this content.", + "unmute_this_post": "Unmute this post/comment", "unmute_this_post_description": - "Please provide a note regarding your decision to unmute this post.", + "Please provide a note regarding your decision to unmute this content.", "show": "Show", "sign_in": "Sign in", "sign_up": "Sign up", @@ -351,12 +355,11 @@ }, "category_selector_jsx": { "tag_your_story": - "Tag (up to 5 tags), the first tag is your main category.", + "Tag (up to 8 tags), the first tag is your main category.", "select_a_tag": "Select a tag", "maximum_tag_length_is_24_characters": "Maximum tag length is 24 characters", - "use_limited_amount_of_categories": - "Please use only %(amount)s categories", + "use_limited_amount_of_categories": "Please use only %(amount)s tags", "use_only_lowercase_letters": "Use only lowercase letters", "use_one_dash": "Use only one dash", "use_spaces_to_separate_tags": "Use spaces to separate tags", @@ -432,7 +435,7 @@ "post_jsx": { "now_showing_comments_with_low_ratings": "Now showing comments with low ratings", - "sort_order": "Sort Order", + "sort_order": "Sort", "comments_were_hidden_due_to_low_ratings": "Comments were hidden due to low ratings", "comment_sort_order": { diff --git a/src/app/redux/FollowSaga.js b/src/app/redux/FollowSaga.js index a2e482d7f40e89f7fb932f97796041c509aa5753..f19ea58e5298da16067b2118bea6c8834a06e3be 100644 --- a/src/app/redux/FollowSaga.js +++ b/src/app/redux/FollowSaga.js @@ -15,8 +15,7 @@ export function* loadFollows(method, account, type, force = false) { state.global.getIn(['follow', method, account, type + '_loading']) ) ) { - // console.log('Already loading', method, account, type) - return; + return; //already loading } if (!force) { @@ -24,8 +23,7 @@ export function* loadFollows(method, account, type, force = false) { state.global.hasIn(['follow', method, account, type + '_result']) ); if (hasResult) { - // console.log('Already loaded', method, account, type) - return; + return; //already loaded } } @@ -42,7 +40,6 @@ export function* loadFollows(method, account, type, force = false) { function* loadFollowsLoop(method, account, type, start = '', limit = 1000) { const res = fromJS(yield api[method](account, start, type, limit)); - // console.log('res.toJS()', res.toJS()) let cnt = 0; let lastAccountName = null; diff --git a/src/app/redux/GlobalReducer.js b/src/app/redux/GlobalReducer.js index 98751c7da7271a78db17f6d6bb9f8a04a57879e7..beae6818872ddf025dfc4e62fd19b3d4d73fe8cb 100644 --- a/src/app/redux/GlobalReducer.js +++ b/src/app/redux/GlobalReducer.js @@ -145,12 +145,23 @@ export default function reducer(state = defaultState, action = {}) { } case RECEIVE_CONTENT: { - let content = fromJS(payload.content); - console.log('received content...', payload.content); + const content = fromJS(payload.content); const key = content.get('author') + '/' + content.get('permlink'); - return state.updateIn(['content', key], Map(), c => + console.log('received content...', payload.content); + + // merge content object into map + let new_state = state.updateIn(['content', key], Map(), c => c.mergeDeep(content) ); + + // set creation-pending key (optimistic UI update) + if (content.get('depth') == 0) { + const category = content.get('category'); + const dkey = ['discussion_idx', category, '_created']; + new_state = new_state.setIn(dkey, key); + } + + return new_state; } case LINK_REPLY: { diff --git a/src/app/redux/TransactionReducer.js b/src/app/redux/TransactionReducer.js index 24d33846a5b01e9df05d679c04f323f72fd923ec..528d642222ab26508e06db7a276397b96e8319d7 100644 --- a/src/app/redux/TransactionReducer.js +++ b/src/app/redux/TransactionReducer.js @@ -92,6 +92,11 @@ export default function reducer(state = defaultState, action) { } else if (/missing required posting authority/.test(key)) { // missing required posting authority:Missing Posting Authority test-safari msg = last_part(key, ':'); + } else if ( + /Cannot delete a comment with net positive votes/.test(key) + ) { + // Assert Exception:comment.net_rshares <= 0: Cannot delete a comment with net positive votes. + msg = last_part(key, ':'); } else { msg = 'Transaction broadcast error: ' + last_part(key, ':'); console.error('unhandled error:', key, 'msg:', error.message); @@ -107,7 +112,7 @@ export default function reducer(state = defaultState, action) { } if (!errorCallback) - throw new Error(`PANIC: no error callback for '${errorKey}'`); + throw new Error(`PANIC: no error callback for '${key}'`); errorCallback(msg); return state; diff --git a/src/app/redux/UserSaga.js b/src/app/redux/UserSaga.js index 9a2344775873a7b26d05a6e8e05bcb5483dc52ec..14f59bef01e01982ee265f45661cf952f41615d3 100644 --- a/src/app/redux/UserSaga.js +++ b/src/app/redux/UserSaga.js @@ -569,7 +569,7 @@ function* saveLogin_localStorage() { throw 'Login will not be saved, posting key is the same as owner key'; }); } catch (e) { - console.error(e); + console.error('login_auth_err', e); return; } @@ -747,7 +747,15 @@ function* uploadImage({ xhr.open('POST', postUrl); xhr.onload = function() { console.log(xhr.status, xhr.responseText); - const res = JSON.parse(xhr.responseText); + + let res = {}; + try { + res = JSON.parse(xhr.responseText); + } catch (error) { + console.error('upload_resp', error, xhr.responseText); + res = { error: 'invalid server response' }; + } + const { error } = res; if (error) { progress({ error: 'Error: ' + error }); @@ -757,7 +765,7 @@ function* uploadImage({ progress({ url }); }; xhr.onerror = function(error) { - console.error(filename, error); + console.error('xhr', filename, error); progress({ error: 'Unable to contact the server.' }); }; xhr.upload.onprogress = function(event) { diff --git a/src/app/utils/BrowserTests.js b/src/app/utils/BrowserTests.js index a41f22c8bef505d2e4f483446867e6963620a1d6..7b19840cbbf6487d71e857fcc4faa12c73ca3676 100644 --- a/src/app/utils/BrowserTests.js +++ b/src/app/utils/BrowserTests.js @@ -14,7 +14,7 @@ export default function runTests() { try { fn(); } catch (error) { - console.error(error); + console.error('test', name, error); pass = false; rpt += error.stack + '\n\n'; serverApiRecordEvent('client_error', error); diff --git a/src/app/utils/ConsoleExports.js b/src/app/utils/ConsoleExports.js index 25fbf58648d26b7ca1882662a429314c4e36018a..9dd374e306304a687f8678727afcf6d82cf3ffda 100644 --- a/src/app/utils/ConsoleExports.js +++ b/src/app/utils/ConsoleExports.js @@ -46,7 +46,7 @@ module.exports = { window[atty] = result; }) .catch(error => { - console.error(error); + console.error('resolve_err', error); reject(error); window[atty] = error; }); diff --git a/src/server/api/general.js b/src/server/api/general.js index 5722ab3702bfcbd16209d7a82a0f18e1044a8c84..c015045b4f82aa4abb88ce1311ea5bd22c0163d9 100644 --- a/src/server/api/general.js +++ b/src/server/api/general.js @@ -15,6 +15,20 @@ const mixpanel = config.get('mixpanel') : null; const _stringval = v => (typeof v === 'string' ? v : JSON.stringify(v)); + +const _parse = params => { + if (typeof params === 'string') { + try { + return JSON.parse(params); + } catch (error) { + console.error('json_parse', error, params); + return {}; + } + } else { + return params; + } +}; + function logRequest(path, ctx, extra) { let d = { ip: getRemoteIp(ctx.req) }; if (ctx.session) { @@ -48,8 +62,7 @@ export default function useGeneralApi(app) { router.post('/login_account', koaBody, function*() { // if (rateLimitReq(this, this.req)) return; const params = this.request.body; - const { csrf, account, signatures } = - typeof params === 'string' ? JSON.parse(params) : params; + const { csrf, account, signatures } = _parse(params); if (!checkCSRF(this, csrf)) return; logRequest('login_account', this, { account }); @@ -154,8 +167,7 @@ export default function useGeneralApi(app) { router.post('/logout_account', koaBody, function*() { // if (rateLimitReq(this, this.req)) return; - logout maybe immediately followed with login_attempt event const params = this.request.body; - const { csrf } = - typeof params === 'string' ? JSON.parse(params) : params; + const { csrf } = _parse(params); if (!checkCSRF(this, csrf)) return; logRequest('logout_account', this); try { @@ -204,8 +216,7 @@ export default function useGeneralApi(app) { router.post('/setUserPreferences', koaBody, function*() { const params = this.request.body; - const { csrf, payload } = - typeof params === 'string' ? JSON.parse(params) : params; + const { csrf, payload } = _parse(params); if (!checkCSRF(this, csrf)) return; console.log( '-- /setUserPreferences -->', @@ -236,8 +247,7 @@ export default function useGeneralApi(app) { router.post('/isTosAccepted', koaBody, function*() { const params = this.request.body; - const { csrf } = - typeof params === 'string' ? JSON.parse(params) : params; + const { csrf } = _parse(params); if (!checkCSRF(this, csrf)) return; this.body = '{}'; @@ -271,8 +281,7 @@ export default function useGeneralApi(app) { router.post('/acceptTos', koaBody, function*() { const params = this.request.body; - const { csrf } = - typeof params === 'string' ? JSON.parse(params) : params; + const { csrf } = _parse(params); if (!checkCSRF(this, csrf)) return; if (!this.session.a) { diff --git a/src/server/app_render.jsx b/src/server/app_render.jsx index 32ee9c0ce13638f5be852fdb1d7b2a445fcd7c12..329207288b93e3fb9df8196227196d133f182ed4 100644 --- a/src/server/app_render.jsx +++ b/src/server/app_render.jsx @@ -130,7 +130,7 @@ async function appRender(ctx, locales = false, resolvedAssets = false) { '<!DOCTYPE html>' + renderToString(<ServerHTML {...props} />); } catch (err) { // Render 500 error page from server - console.log('AppRender error', err); + console.error('AppRender error', pathname, err); const { error, redirect } = err; if (error) throw error; diff --git a/src/server/sendEmail.js b/src/server/sendEmail.js deleted file mode 100644 index 9e8295bd306b5bc3f120e1972eae3df63cf40fbf..0000000000000000000000000000000000000000 --- a/src/server/sendEmail.js +++ /dev/null @@ -1,47 +0,0 @@ -import sendgrid from 'sendgrid'; -import config from 'config'; - -const sg = sendgrid(config.get('sendgrid.key')); - -export default function sendEmail(template, to, params, from = null) { - if (process.env.NODE_ENV !== 'production') { - console.log( - `mail: to <${to}>, from <${from}>, template ${ - template - } (not sent due to not production env)` - ); - return; - } - const tmpl_id = config.get('sendgrid.templates')[template]; - if (!tmpl_id) throw new Error(`can't find template ${template}`); - - const request = sg.emptyRequest({ - method: 'POST', - path: '/v3/mail/send', - body: { - template_id: tmpl_id, - personalizations: [ - { - to: [{ email: to }], - substitutions: params, - }, - ], - from: { email: from || config.get('sendgrid.from') }, - }, - }); - - sg - .API(request) - .then(response => { - console.log( - `sent '${template}' email to '${to}'`, - response.statusCode - ); - }) - .catch(error => { - console.error( - `failed to send '${template}' email to '${to}'`, - error - ); - }); -} diff --git a/src/server/utils/SpecialPosts.js b/src/server/utils/SpecialPosts.js index e66212f76f37ae870213f97cf727ae703c935648..0caf48eacf084756486c81e33010187bcc00b426 100644 --- a/src/server/utils/SpecialPosts.js +++ b/src/server/utils/SpecialPosts.js @@ -27,7 +27,8 @@ function loadSpecialPosts() { }); resp.on('end', () => { const json = JSON.parse(data); - console.info('Received special posts payload', json); + console.info('Received special posts payload'); + //console.info('Received special posts payload', json); if (json === Object(json)) { resolve(json); } @@ -55,7 +56,7 @@ export async function specialPosts() { console.info('Loading special posts'); const postData = await loadSpecialPosts(); - console.info('Loading special posts', postData); + //console.info('Loaded special posts', postData); let loadedPostData = { featured_posts: [], promoted_posts: [], diff --git a/src/server/utils/teleSign.js b/src/server/utils/teleSign.js deleted file mode 100644 index 110851d9447cf37ca093c87a9419a0b4f9e6ebaf..0000000000000000000000000000000000000000 --- a/src/server/utils/teleSign.js +++ /dev/null @@ -1,191 +0,0 @@ -import fetch from 'node-fetch'; -import config from 'config'; -import crypto from 'crypto'; -import secureRandom from 'secure-random'; - -const customer_id = config.get('telesign.customer_id'); - -let api_key = ''; - -if (config.get('telesign.rest_api_key')) { - api_key = new Buffer(config.get('telesign.rest_api_key'), 'base64'); -} - -const use_case_code = 'BACS'; // Use Case: avoid bulk attack and spammers - -// Testing, always blocked: 1-310-555-0100 - -/** @return {object} - {reference_id} or {error} */ -export default function* verify({ - mobile, - confirmation_code, - ip, - ignore_score, -}) { - try { - const result = yield getScore(mobile); - const { recommendation, score } = result.risk; - let phone = mobile; - // if (!ignore_score && recommendation !== 'allow') { - if (!ignore_score && (!score || score > 600)) { - console.log( - `TeleSign did not allow phone ${mobile} ip ${ - ip - }. TeleSign responded: ${recommendation}` - ); - return { - error: - 'Unable to verify your phone number. Please try a different phone number.', - score, - }; - } - if ( - result.numbering && - result.numbering.cleansing && - result.numbering.cleansing.sms - ) { - const sms = result.numbering.cleansing.sms; - phone = sms.country_code + sms.phone_number; - } - const { reference_id } = yield verifySms({ - mobile, - confirmation_code, - ip, - }); - return { reference_id, score, phone }; - } catch (error) { - console.log('-- verify score error -->', error); - return { error: 'Unable to verify phone, please try again later.' }; - } -} - -function getScore(mobile) { - const fields = urlencode({ - ucid: use_case_code, - }); - const resource = '/v1/phoneid/score/' + mobile.match(/\d+/g).join(''); - const method = 'GET'; - return fetch(`https://rest-ww.telesign.com${resource}?${fields}`, { - method, - headers: authHeaders({ resource, method }), - }) - .then(r => r.json()) - .catch(error => { - console.error( - `ERROR: Phone ${mobile} score exception`, - JSON.stringify(error, null, 0) - ); - return Promise.reject(error); - }) - .then(response => { - const { status } = response; - if (status.code === 300) { - // Transaction successfully completed - console.log( - `Phone ${mobile} score`, - JSON.stringify(response, null, 0) - ); - return Promise.resolve(response); - } - console.error( - `ERROR: Phone ${mobile} score`, - JSON.stringify(response, null, 0) - ); - return Promise.reject(response); - }); -} - -function verifySms({ mobile, confirmation_code, ip }) { - // https://developer.telesign.com/v2.0/docs/rest_api-verify-sms - const f = { - phone_number: mobile, - language: 'en-US', - ucid: use_case_code, - verify_code: confirmation_code, - template: '$$CODE$$ is your Steemit confirmation code', - }; - if (ip) f.originating_ip = ip; - const fields = urlencode(f); - // console.log('fields', fields) // logspam - - const resource = '/v1/verify/sms'; - const method = 'POST'; - return fetch('https://rest.telesign.com' + resource, { - method, - body: fields, - headers: authHeaders({ resource, method, fields }), - }) - .then(r => r.json()) - .catch(error => { - console.error( - `ERROR: SMS failed to ${mobile} code ${ - confirmation_code - } req ip ${ip} exception`, - JSON.stringify(error, null, 0) - ); - return Promise.reject(error); - }) - .then(response => { - const { status } = response; - if (status.code === 290) { - // Message in progress - console.log( - `Sent SMS to ${mobile} code ${confirmation_code}`, - JSON.stringify(response, null, 0) - ); - return Promise.resolve(response); - } - console.error( - `ERROR: SMS failed to ${mobile} code ${confirmation_code}:`, - JSON.stringify(response, null, 0) - ); - return Promise.reject(response); - }); -} - -/** - @arg {string} resource `/v1/verify/AEBC93B5898342F790E4E19FED41A7DA` - @arg {string} method [GET|POST|PUT] - @arg {string} fields url query string -*/ -function authHeaders({ resource, fields, method = 'GET' }) { - const auth_method = 'HMAC-SHA256'; - const currDate = new Date().toUTCString(); - const nonce = parseInt( - secureRandom.randomBuffer(8).toString('hex'), - 16 - ).toString(36); - - let content_type = ''; - if (/POST|PUT/.test(method)) - content_type = 'application/x-www-form-urlencoded'; - - let strToSign = `${method}\n${content_type}\n\nx-ts-auth-method:${ - auth_method - }\nx-ts-date:${currDate}\nx-ts-nonce:${nonce}`; - - if (fields) { - strToSign += '\n' + fields; - } - strToSign += '\n' + resource; - - // console.log('strToSign', strToSign) // logspam - const sig = crypto - .createHmac('sha256', api_key) - .update(strToSign, 'utf8') - .digest('base64'); - - const headers = { - Authorization: `TSA ${customer_id}:${sig}`, - 'Content-Type': content_type, - 'x-ts-date': currDate, - 'x-ts-auth-method': auth_method, - 'x-ts-nonce': nonce, - }; - return headers; -} - -const urlencode = json => - Object.keys(json) - .map(key => encodeURI(key) + '=' + encodeURI(json[key])) - .join('&'); diff --git a/src/server/utils/twilio.js b/src/server/utils/twilio.js deleted file mode 100644 index b8653965712ffaf7132c2e523797889559fd8684..0000000000000000000000000000000000000000 --- a/src/server/utils/twilio.js +++ /dev/null @@ -1,104 +0,0 @@ -import twilio from 'twilio'; -import config from 'config'; - -const accountSid = config.get('twilio.account_sid'); -const authToken = config.get('twilio.auth_token'); -let client; - -function checkEligibility(phone) { - // US, Canada +1 - // France +33 - // Spain +34 - // Italy +39 - // UK +44 - // Sweden +46 - // Germany +49 - // Mexico +52 - // Australia +61 - // Phillipines +63 - // Singapore +65 - // Turkey +90 - // Hong Kong +852 - // Israel +972 - - for (const prefix of [ - '1', - '33', - '34', - '39', - '44', - '46', - '49', - '52', - '61', - '63', - '65', - '90', - '852', - '972', - ]) { - if (phone.startsWith(prefix)) return true; - } - return false; -} - -export default function verify(phone) { - if (!client) client = new twilio.LookupsClient(accountSid, authToken); - return new Promise(resolve => { - if (!checkEligibility(phone)) { - resolve('na'); - return; - } - client.phoneNumbers(phone).get( - { - type: 'carrier', - addOns: 'whitepages_pro_phone_rep', - }, - (error, result) => { - if (error) { - if (error.code === 20404) { - console.log('Twilio phone not found ', phone); - resolve('block'); - } else { - console.error( - 'Twilio error', - JSON.stringify(error, null, 2) - ); - resolve('error'); - } - } else { - if ( - result.addOns && - result.addOns.results && - result.addOns.results.whitepages_pro_phone_rep && - result.addOns.results.whitepages_pro_phone_rep.result && - result.addOns.results.whitepages_pro_phone_rep.result - .results && - result.addOns.results.whitepages_pro_phone_rep.result - .results[0] && - result.addOns.results.whitepages_pro_phone_rep.result - .results[0].reputation && - result.addOns.results.whitepages_pro_phone_rep.result - .results[0].reputation.level - ) { - const reputation_level = - result.addOns.results.whitepages_pro_phone_rep - .result.results[0].reputation.level; - console.log( - 'Twilio reputation level ', - phone, - reputation_level - ); - resolve(reputation_level < 3 ? 'pass' : 'block'); - } else { - console.error( - 'Twilio result does not contain reputation level:', - JSON.stringify(result, null, 2) - ); - resolve('error'); - } - } - } - ); - }); -} diff --git a/src/shared/HtmlReady.js b/src/shared/HtmlReady.js index ac350f2738d4d16aabd9b8878d47dc55308aade3..9d791a1a7381587a2b789e41fcf728fdb7b5d5c3 100644 --- a/src/shared/HtmlReady.js +++ b/src/shared/HtmlReady.js @@ -113,7 +113,7 @@ export default function(html, { mutate = true, hideImages = false } = {}) { }; } catch (error) { // xmldom error is bad - console.log( + console.error( 'rendering error', JSON.stringify({ error: error.message, html }) ); @@ -143,7 +143,9 @@ function link(state, child) { state.links.add(url); if (state.mutate) { // If this link is not relative, http, https, steem or esteem -- add https. - if (!/^((#)|(\/(?!\/))|(((steem|esteem|https?):)?\/\/))/.test(url)) { + if ( + !/^((#)|(\/(?!\/))|(((steem|esteem|https?):)?\/\/))/.test(url) + ) { child.setAttribute('href', 'https://' + url); } @@ -255,7 +257,7 @@ function linkifyNode(child, state) { return newChild; } } catch (error) { - console.log(error); + console.error('linkify_error', error); } } @@ -330,7 +332,7 @@ function embedYouTubeNode(child, links, images) { if (links) links.add(yt.url); if (images) images.add(yt.thumbnail); } catch (error) { - console.log(error); + console.error('yt_node', error); } return child; } @@ -379,7 +381,7 @@ function embedVimeoNode(child, links /*images*/) { if (links) links.add(vimeo.canonical); // if(images) images.add(vimeo.thumbnail) // not available } catch (error) { - console.log(error); + console.error('vimeo_embed', error); } return child; } @@ -413,7 +415,7 @@ function embedTwitchNode(child, links /*images*/) { if (links) links.add(twitch.canonical); } catch (error) { - console.error(error); + console.error('twitch_error', error); } return child; } @@ -443,7 +445,7 @@ function embedDTubeNode(child, links /*images*/) { if (links) links.add(dtube.canonical); } catch (error) { - console.log(error); + console.error('dtube_embed', error); } return child; } diff --git a/src/shared/UniversalRender.jsx b/src/shared/UniversalRender.jsx index 33cbce4ab17026c8a473953c8934ee6a1d3cf6ec..ce0d2b9dfa33cfa6586cb4d261e8422891cb9cdd 100644 --- a/src/shared/UniversalRender.jsx +++ b/src/shared/UniversalRender.jsx @@ -243,7 +243,7 @@ export async function serverRender( } if (error || !renderProps) { - console.log('Router error [404]', error, 'props?', !!renderProps); + console.error('Router error [404]', error, 'props?', !!renderProps); return { title: 'Page Not Found - Steemit', statusCode: 404, @@ -466,14 +466,14 @@ async function apiFetchState(url) { const last = feed[feed.length - 1]; onchain['feed_price'] = last; } catch (error) { - console.log('Error fetching feed price:', error); + console.error('Error fetching feed price:', error); } try { const dgpo = await api.getDynamicGlobalPropertiesAsync(); onchain['props'] = { sbd_print_rate: dgpo['sbd_print_rate'] }; } catch (error) { - console.log('Error fetching dgpo:', error); + console.error('Error fetching dgpo:', error); } return onchain; diff --git a/yarn.lock b/yarn.lock index 1adfa7f5215f88aafa6e046b72fc8c53cd062546..e2a9d3b5cf7fbbe1f5fdd44042bcace9e70909a5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -291,10 +291,6 @@ acorn@^5.0.0, acorn@^5.1.1, acorn@^5.3.0, acorn@^5.4.0: version "5.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.4.1.tgz#fdc58d9d17f4a4e98d102ded826a9b9759125102" -addressparser@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/addressparser/-/addressparser-1.0.1.tgz#47afbe1a2a9262191db6838e4fd1d39b40821746" - airbnb-js-shims@^1.4.0: version "1.4.1" resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-1.4.1.tgz#cc3e8eb8d35877f9d0fdc6583e26b0ee75b98ad0" @@ -501,7 +497,7 @@ arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" -asap@^2.0.0, asap@~2.0.3: +asap@~2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -555,64 +551,6 @@ async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" -async.ensureasync@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/async.ensureasync/-/async.ensureasync-0.5.2.tgz#c3c7e4a4e9b31d96875d56b8504598446e1e305d" - dependencies: - async.util.ensureasync "0.5.2" - -async.queue@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/async.queue/-/async.queue-0.5.2.tgz#8d5d90812e1481066bc0904e8cc1712b17c3bd7c" - dependencies: - async.util.queue "0.5.2" - -async.util.arrayeach@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/async.util.arrayeach/-/async.util.arrayeach-0.5.2.tgz#58c4e98028d55d69bfb05aeb3af44e0a555a829c" - -async.util.ensureasync@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/async.util.ensureasync/-/async.util.ensureasync-0.5.2.tgz#10907f2cbd067a061f99ae6d22e08ced30db0d68" - dependencies: - async.util.restparam "0.5.2" - async.util.setimmediate "0.5.2" - -async.util.isarray@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/async.util.isarray/-/async.util.isarray-0.5.2.tgz#e62dac8f2636f65875dcf7521c2d24d0dfb2bbdf" - -async.util.map@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/async.util.map/-/async.util.map-0.5.2.tgz#e588ef86e0b3ab5f027d97af4d6835d055ca69d6" - -async.util.noop@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/async.util.noop/-/async.util.noop-0.5.2.tgz#bdd62b97cb0aa3f60b586ad148468698975e58b9" - -async.util.onlyonce@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/async.util.onlyonce/-/async.util.onlyonce-0.5.2.tgz#b8e6fc004adc923164d79e32f2813ee465c24ff2" - -async.util.queue@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/async.util.queue/-/async.util.queue-0.5.2.tgz#57f65abe1a3cdf273d31abd28ab95425f8222ee5" - dependencies: - async.util.arrayeach "0.5.2" - async.util.isarray "0.5.2" - async.util.map "0.5.2" - async.util.noop "0.5.2" - async.util.onlyonce "0.5.2" - async.util.setimmediate "0.5.2" - -async.util.restparam@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/async.util.restparam/-/async.util.restparam-0.5.2.tgz#03efebf3c0277b97220e525aba750f5e04fc80cd" - -async.util.setimmediate@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/async.util.setimmediate/-/async.util.setimmediate-0.5.2.tgz#2812ebabf2a58027758d4bc7793d1ccfaf10255f" - async@^1.4.0: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -1828,10 +1766,6 @@ boom@5.x.x: dependencies: hoek "4.x.x" -bottleneck@^1.12.0: - version "1.16.0" - resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-1.16.0.tgz#d6ce13808527afc80b69092f15606655e5b21f1a" - bowser@^1.0.0, bowser@^1.7.3: version "1.9.2" resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.9.2.tgz#d66fc868ca5f4ba895bee1363c343fe7b37d3394" @@ -2858,10 +2792,6 @@ depd@~1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" -deprecate@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/deprecate/-/deprecate-1.0.0.tgz#661490ed2428916a6c8883d8834e5646f4e4a4a8" - des.js@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" @@ -3124,7 +3054,7 @@ encodeurl@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" -encoding@^0.1.11, encoding@^0.1.12, encoding@~0.1.12: +encoding@^0.1.11: version "0.1.12" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" dependencies: @@ -3286,7 +3216,7 @@ escape-html@~1.0.1, escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5, escape-string-regexp@~1.0.5: +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -4263,10 +4193,6 @@ hide-powered-by@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b" -highcharts@4.2.7, highcharts@^4.2.3: - version "4.2.7" - resolved "https://registry.yarnpkg.com/highcharts/-/highcharts-4.2.7.tgz#45cbed8e99c9c042e95f9c51076726496f686862" - history@^3.0.0: version "3.3.0" resolved "https://registry.yarnpkg.com/history/-/history-3.3.0.tgz#fcedcce8f12975371545d735461033579a6dae9c" @@ -5234,8 +5160,9 @@ jest@22.0.6: jest-cli "^22.0.6" jquery@>=3.0.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" + version "3.4.1" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2" + integrity sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw== js-base64@^2.1.8, js-base64@^2.1.9: version "2.4.3" @@ -5370,21 +5297,6 @@ jsonpointer@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" -jsonwebtoken@^8.1.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.1.1.tgz#b04d8bb2ad847bc93238c3c92170ffdbdd1cb2ea" - dependencies: - jws "^3.1.4" - lodash.includes "^4.3.0" - lodash.isboolean "^3.0.3" - lodash.isinteger "^4.0.4" - lodash.isnumber "^3.0.3" - lodash.isplainobject "^4.0.6" - lodash.isstring "^4.0.1" - lodash.once "^4.0.0" - ms "^2.1.1" - xtend "^4.0.1" - jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -5413,7 +5325,7 @@ jwa@^1.1.4: ecdsa-sig-formatter "1.0.9" safe-buffer "^5.0.1" -jws@^3.1.3, jws@^3.1.4: +jws@^3.1.3: version "3.1.4" resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.4.tgz#f9e8b9338e8a847277d6444b1464f61880e050a2" dependencies: @@ -5806,10 +5718,6 @@ lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" -lodash.chunk@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.chunk/-/lodash.chunk-4.2.0.tgz#66e5ce1f76ed27b4303d8c6512e8d1216e8106bc" - lodash.clonedeep@^4.3.2: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" @@ -5846,10 +5754,6 @@ lodash.foreach@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" integrity sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM= -lodash.includes@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" - lodash.isarguments@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" @@ -5858,26 +5762,10 @@ lodash.isarray@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" -lodash.isboolean@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" - -lodash.isinteger@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" - -lodash.isnumber@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" - lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" -lodash.isstring@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" - lodash.keys@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" @@ -5904,10 +5792,6 @@ lodash.mergewith@^4.6.0: version "4.6.1" resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927" -lodash.once@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" - lodash.pick@^4.2.1, lodash.pick@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" @@ -5951,7 +5835,7 @@ lodash@^3.10.1: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.0, lodash@^4.17.10, lodash@^4.3.0, lodash@^4.6.1, lodash@~4.17.4: +lodash@^4.0.0, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.0, lodash@^4.3.0, lodash@^4.6.1, lodash@~4.17.4: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -6018,15 +5902,6 @@ macaddress@^0.2.8: version "0.2.8" resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" -mailparser@^0.6.1: - version "0.6.2" - resolved "https://registry.yarnpkg.com/mailparser/-/mailparser-0.6.2.tgz#03c486039bdf4df6cd3b6adcaaac4107dfdbc068" - dependencies: - encoding "^0.1.12" - mime "^1.3.4" - mimelib "^0.3.0" - uue "^3.1.0" - make-dir@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.1.0.tgz#19b4369fe48c116f53c2af95ad102c0e39e85d51" @@ -6179,13 +6054,6 @@ mime@^1.3.4, mime@^1.4.1, mime@^1.5.0: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" -mimelib@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/mimelib/-/mimelib-0.3.1.tgz#787add2415d827acb3af6ec4bca1ea9596418853" - dependencies: - addressparser "~1.0.1" - encoding "~0.1.12" - mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" @@ -6242,10 +6110,6 @@ mock-local-storage@1.0.5: core-js "^0.8.3" global "^4.3.2" -moment@2.19.3: - version "2.19.3" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.19.3.tgz#bdb99d270d6d7fda78cc0fbace855e27fe7da69f" - moment@^2.20.1: version "2.20.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.20.1.tgz#d6eb1a46cbcc14a2b2f9434112c1ff8907f313fd" @@ -6917,10 +6781,6 @@ podda@^1.2.2: babel-runtime "^6.11.6" immutable "^3.8.1" -pop-iterate@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/pop-iterate/-/pop-iterate-1.0.1.tgz#ceacfdab4abf353d7a0f2aaa2c1fc7b3f9413ba3" - postcss-calc@^5.2.0: version "5.3.1" resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e" @@ -7326,14 +7186,6 @@ punycode@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" -q@2.0.x: - version "2.0.3" - resolved "https://registry.yarnpkg.com/q/-/q-2.0.3.tgz#75b8db0255a1a5af82f58c3f3aaa1efec7d0d134" - dependencies: - asap "^2.0.0" - pop-iterate "^1.0.1" - weak-map "^1.0.5" - q@^1.1.2: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -7567,12 +7419,6 @@ react-headroom@^2.2.7: raf "^3.3.0" shallowequal "^1.1.0" -react-highcharts@8.4.2: - version "8.4.2" - resolved "https://registry.yarnpkg.com/react-highcharts/-/react-highcharts-8.4.2.tgz#1d43865e7669ddd7b89a4b77c56d8554d8635036" - dependencies: - highcharts "^4.2.3" - react-html-attributes@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/react-html-attributes/-/react-html-attributes-1.4.1.tgz#97b5ec710da68833598c8be6f89ac436216840a5" @@ -8053,7 +7899,7 @@ request-promise-native@^1.0.5: stealthy-require "^1.1.0" tough-cookie ">=2.3.3" -request@*, request@2, request@2.85.x, request@^2.79.0, request@^2.83.0: +request@*, request@2, request@^2.79.0, request@^2.83.0: version "2.85.0" resolved "https://registry.yarnpkg.com/request/-/request-2.85.0.tgz#5a03615a47c61420b3eb99b7dba204f83603e1fa" dependencies: @@ -8235,10 +8081,6 @@ rndm@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/rndm/-/rndm-1.2.0.tgz#f33fe9cfb52bbfd520aa18323bc65db110a1b76c" -rootpath@0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/rootpath/-/rootpath-0.1.2.tgz#5b379a87dca906e9b91d690a599439bef267ea6b" - rst-selector-parser@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz#81b230ea2fcc6066c89e3472de794285d9b03d91" @@ -8338,10 +8180,6 @@ schema-utils@^0.4.0: ajv "^5.0.0" ajv-keywords "^2.1.0" -scmp@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/scmp/-/scmp-0.0.3.tgz#3648df2d7294641e7f78673ffc29681d9bad9073" - scroll-behavior@^0.9.5: version "0.9.9" resolved "https://registry.yarnpkg.com/scroll-behavior/-/scroll-behavior-0.9.9.tgz#ebfe0658455b82ad885b66195215416674dacce2" @@ -8391,22 +8229,6 @@ send@0.16.1: range-parser "~1.2.0" statuses "~1.3.1" -sendgrid-rest@^2.3.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/sendgrid-rest/-/sendgrid-rest-2.4.0.tgz#88e11a86375ec0e14b5faf1b4a0a191639ce90ef" - -sendgrid@4.10.0: - version "4.10.0" - resolved "https://registry.yarnpkg.com/sendgrid/-/sendgrid-4.10.0.tgz#fd64ae3b3f3a94e14aa0ee587db2a01333b07f53" - dependencies: - async.ensureasync "^0.5.2" - async.queue "^0.5.2" - bottleneck "^1.12.0" - debug "^2.2.0" - lodash.chunk "^4.2.0" - mailparser "^0.6.1" - sendgrid-rest "^2.3.0" - serve-favicon@^2.4.5: version "2.4.5" resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.4.5.tgz#49d9a46863153a9240691c893d2b0e7d85d6d436" @@ -9125,20 +8947,6 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" -twilio@3.17.0: - version "3.17.0" - resolved "https://registry.yarnpkg.com/twilio/-/twilio-3.17.0.tgz#9fafde5657c52bd28ddb133a56c55df5c42fd227" - dependencies: - deprecate "1.0.0" - jsonwebtoken "^8.1.0" - lodash "^4.17.10" - moment "2.19.3" - q "2.0.x" - request "2.85.x" - rootpath "0.1.2" - scmp "0.0.3" - xmlbuilder "9.0.1" - type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -9212,9 +9020,10 @@ uncontrollable@3.3.1: dependencies: invariant "^2.1.0" -underscore.string@3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" +underscore.string@3.3.5: + version "3.3.5" + resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.5.tgz#fc2ad255b8bd309e239cbc5816fd23a9b7ea4023" + integrity sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg== dependencies: sprintf-js "^1.0.3" util-deprecate "^1.0.2" @@ -9299,13 +9108,6 @@ utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" -uue@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/uue/-/uue-3.1.1.tgz#cebb18980e005769ac7254a0a158a49ad173a518" - dependencies: - escape-string-regexp "~1.0.5" - extend "~3.0.0" - uuid@^3.0.0, uuid@^3.1.0: version "3.2.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" @@ -9397,10 +9199,6 @@ watchpack@^1.4.0: chokidar "^1.7.0" graceful-fs "^4.1.2" -weak-map@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/weak-map/-/weak-map-1.0.5.tgz#79691584d98607f5070bd3b70a40e6bb22e401eb" - web-push@3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/web-push/-/web-push-3.2.3.tgz#269492aa06d1481a8222425baf4c68fe23fcbefc" @@ -9679,15 +9477,11 @@ xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" -xmlbuilder@9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.1.tgz#91cd70897755363eba57c12ddeeab4a341a61f65" - xmldom@0.1.27: version "0.1.27" resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" -xtend@^4.0.0, xtend@^4.0.1: +xtend@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"