diff --git a/package-lock.json b/package-lock.json index de555f5a8..30b213d40 100644 --- a/package-lock.json +++ b/package-lock.json @@ -101,8 +101,8 @@ "regenerator-runtime": "0.13.9", "sass": "1.49.7", "sass-loader": "10.2.1", - "scratch-gui": "1.8.53", - "scratch-l10n": "3.15.20230507032520", + "scratch-gui": "1.8.91", + "scratch-l10n": "3.15.20230523032203", "selenium-webdriver": "4.1.0", "slick-carousel": "1.6.0", "style-loader": "0.12.3", @@ -23463,21 +23463,39 @@ } }, "node_modules/scratch-blocks": { - "version": "0.1.0-prerelease.20230507065123", - "resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-0.1.0-prerelease.20230507065123.tgz", - "integrity": "sha512-ESFkBv3EyyjXQbfgnbOXMCkLtlTzR1K+mPUANobSWim/evedSowx3l6uuqGVumEbo/9K2ullKyXQo7LDZDrvOw==", + "version": "0.1.0-prerelease.20230521064828", + "resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-0.1.0-prerelease.20230521064828.tgz", + "integrity": "sha512-9XOGQ51l0M0HLHy5flvxIXP3nPwaq/RexdDqm1sq3CIuHubWn243prerm7gzyzISMIfN5H8Jz+atk5NJ+fhDIw==", "dev": true, "dependencies": { "exports-loader": "0.7.0", "google-closure-library": "20190301.0.0", "imports-loader": "0.8.0", - "scratch-l10n": "3.15.20230507032520" + "scratch-l10n": "3.15.20230521032145" + } + }, + "node_modules/scratch-blocks/node_modules/scratch-l10n": { + "version": "3.15.20230521032145", + "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230521032145.tgz", + "integrity": "sha512-OoE7eME85ZNHZvOPU7wV8lx284YZD1eYTkfc11A5CTRHq27tbXqYCq2tqmZ/vmNtsEmBrIKK3Ogf/rPbwp9pEQ==", + "dev": true, + "dependencies": { + "@babel/cli": "^7.1.2", + "@babel/core": "^7.1.2", + "@transifex/api": "4.2.5", + "babel-plugin-react-intl": "^3.0.1", + "download": "^8.0.0", + "transifex": "1.6.6" + }, + "bin": { + "build-i18n-src": "scripts/build-i18n-src.js", + "tx-push-src": "scripts/tx-push-src.js" } }, "node_modules/scratch-gui": { - "version": "1.8.53", - "resolved": "https://registry.npmjs.org/scratch-gui/-/scratch-gui-1.8.53.tgz", - "integrity": "sha512-zqrSRAUhuODR0Qe2cFnQiXpDkIfFF9iEofRIswHSaP/MHj/oiEMINrpEDP+66ep+HivWRpwUumdUt8dOyUIw0A==", + "version": "1.8.91", + "resolved": "https://registry.npmjs.org/scratch-gui/-/scratch-gui-1.8.91.tgz", + "integrity": "sha512-hDd0DQy//LAanhMKlaiWwWoxmcduIKNEKmy2APcqIqmrbxQiTiNmpk5IiXGwGS/vd6Ib4bQsYfY3rMnr0I0+tw==", "dev": true, "dependencies": { "arraybuffer-loader": "^1.0.6", @@ -23529,14 +23547,14 @@ "redux": "3.7.2", "redux-throttle": "0.1.1", "scratch-audio": "0.1.0-prerelease.20221123180128", - "scratch-blocks": "0.1.0-prerelease.20230507065123", - "scratch-l10n": "3.15.20230507032520", - "scratch-paint": "1.1.54", + "scratch-blocks": "0.1.0-prerelease.20230521064828", + "scratch-l10n": "3.15.20230523032203", + "scratch-paint": "1.1.64", "scratch-render": "0.1.0-prerelease.20230318150639", "scratch-render-fonts": "1.0.0-prerelease.20221102164332", "scratch-storage": "2.2.1", "scratch-svg-renderer": "0.2.0-prerelease.20230224194137", - "scratch-vm": "1.5.48", + "scratch-vm": "1.5.68", "startaudiocontext": "1.2.1", "style-loader": "^0.23.0", "text-encoding": "0.7.0", @@ -23863,9 +23881,9 @@ } }, "node_modules/scratch-gui/node_modules/scratch-paint": { - "version": "1.1.54", - "resolved": "https://registry.npmjs.org/scratch-paint/-/scratch-paint-1.1.54.tgz", - "integrity": "sha512-23fylk1yn74TEpthDX1wGpnVGLRDNuQALhTD+Hrq5b0yfWDW1U+Ane6MuA6zOR2noFRcby357rvCdKNXU9p6zQ==", + "version": "1.1.64", + "resolved": "https://registry.npmjs.org/scratch-paint/-/scratch-paint-1.1.64.tgz", + "integrity": "sha512-vh7ZKXq4GJBNUS1WZP8X2sFjcC+r2uyQbY3i1G//tSKoLu+t7ADsYqk31X3o/9YJ+Drf72UmWVgAA+7PO/CLmQ==", "dev": true, "dependencies": { "@scratch/paper": "0.11.20200728195508", @@ -23944,9 +23962,9 @@ } }, "node_modules/scratch-l10n": { - "version": "3.15.20230507032520", - "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230507032520.tgz", - "integrity": "sha512-WpAXxJ6hZIXIvHiLCbReXq9FCGXojX+2uMBs+yWvUNDfTmg2jpuWkbRw0+Ovnzll6lZYc5D2ErUtyD90BI38JA==", + "version": "3.15.20230523032203", + "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230523032203.tgz", + "integrity": "sha512-UhnDzBzo5u4sxQ0Ax6Z5MP5lsKzPWq5B+VafSWOFpfH6fJIoJPBt4iAH9S/Dg9xHZzUfouwmf4QsKYz3I/3cNQ==", "dev": true, "dependencies": { "@babel/cli": "^7.1.2", @@ -24146,9 +24164,9 @@ "dev": true }, "node_modules/scratch-vm": { - "version": "1.5.48", - "resolved": "https://registry.npmjs.org/scratch-vm/-/scratch-vm-1.5.48.tgz", - "integrity": "sha512-xvIxNRruVTdDbgow1tjkM51+DYEfsE39oGrwG0hfKdLTTcF517gz30U3G3EK6vURivzlu+XvaO0RCHwxskSeeg==", + "version": "1.5.68", + "resolved": "https://registry.npmjs.org/scratch-vm/-/scratch-vm-1.5.68.tgz", + "integrity": "sha512-KND5BhWXVtaLgnbUo+LODsl5EXOrAhJhCPLCkdoNRJcyQII9kXyjOiJv12pO9x5469zDEd6eiMjuUVCvi/IWcw==", "dev": true, "dependencies": { "@vernier/godirect": "1.5.0", @@ -51927,21 +51945,37 @@ } }, "scratch-blocks": { - "version": "0.1.0-prerelease.20230507065123", - "resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-0.1.0-prerelease.20230507065123.tgz", - "integrity": "sha512-ESFkBv3EyyjXQbfgnbOXMCkLtlTzR1K+mPUANobSWim/evedSowx3l6uuqGVumEbo/9K2ullKyXQo7LDZDrvOw==", + "version": "0.1.0-prerelease.20230521064828", + "resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-0.1.0-prerelease.20230521064828.tgz", + "integrity": "sha512-9XOGQ51l0M0HLHy5flvxIXP3nPwaq/RexdDqm1sq3CIuHubWn243prerm7gzyzISMIfN5H8Jz+atk5NJ+fhDIw==", "dev": true, "requires": { "exports-loader": "0.7.0", "google-closure-library": "20190301.0.0", "imports-loader": "0.8.0", - "scratch-l10n": "3.15.20230507032520" + "scratch-l10n": "3.15.20230521032145" + }, + "dependencies": { + "scratch-l10n": { + "version": "3.15.20230521032145", + "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230521032145.tgz", + "integrity": "sha512-OoE7eME85ZNHZvOPU7wV8lx284YZD1eYTkfc11A5CTRHq27tbXqYCq2tqmZ/vmNtsEmBrIKK3Ogf/rPbwp9pEQ==", + "dev": true, + "requires": { + "@babel/cli": "^7.1.2", + "@babel/core": "^7.1.2", + "@transifex/api": "4.2.5", + "babel-plugin-react-intl": "^3.0.1", + "download": "^8.0.0", + "transifex": "1.6.6" + } + } } }, "scratch-gui": { - "version": "1.8.53", - "resolved": "https://registry.npmjs.org/scratch-gui/-/scratch-gui-1.8.53.tgz", - "integrity": "sha512-zqrSRAUhuODR0Qe2cFnQiXpDkIfFF9iEofRIswHSaP/MHj/oiEMINrpEDP+66ep+HivWRpwUumdUt8dOyUIw0A==", + "version": "1.8.91", + "resolved": "https://registry.npmjs.org/scratch-gui/-/scratch-gui-1.8.91.tgz", + "integrity": "sha512-hDd0DQy//LAanhMKlaiWwWoxmcduIKNEKmy2APcqIqmrbxQiTiNmpk5IiXGwGS/vd6Ib4bQsYfY3rMnr0I0+tw==", "dev": true, "requires": { "arraybuffer-loader": "^1.0.6", @@ -51993,14 +52027,14 @@ "redux": "3.7.2", "redux-throttle": "0.1.1", "scratch-audio": "0.1.0-prerelease.20221123180128", - "scratch-blocks": "0.1.0-prerelease.20230507065123", - "scratch-l10n": "3.15.20230507032520", - "scratch-paint": "1.1.54", + "scratch-blocks": "0.1.0-prerelease.20230521064828", + "scratch-l10n": "3.15.20230523032203", + "scratch-paint": "1.1.64", "scratch-render": "0.1.0-prerelease.20230318150639", "scratch-render-fonts": "1.0.0-prerelease.20221102164332", "scratch-storage": "2.2.1", "scratch-svg-renderer": "0.2.0-prerelease.20230224194137", - "scratch-vm": "1.5.48", + "scratch-vm": "1.5.68", "startaudiocontext": "1.2.1", "style-loader": "^0.23.0", "text-encoding": "0.7.0", @@ -52265,9 +52299,9 @@ } }, "scratch-paint": { - "version": "1.1.54", - "resolved": "https://registry.npmjs.org/scratch-paint/-/scratch-paint-1.1.54.tgz", - "integrity": "sha512-23fylk1yn74TEpthDX1wGpnVGLRDNuQALhTD+Hrq5b0yfWDW1U+Ane6MuA6zOR2noFRcby357rvCdKNXU9p6zQ==", + "version": "1.1.64", + "resolved": "https://registry.npmjs.org/scratch-paint/-/scratch-paint-1.1.64.tgz", + "integrity": "sha512-vh7ZKXq4GJBNUS1WZP8X2sFjcC+r2uyQbY3i1G//tSKoLu+t7ADsYqk31X3o/9YJ+Drf72UmWVgAA+7PO/CLmQ==", "dev": true, "requires": { "@scratch/paper": "0.11.20200728195508", @@ -52328,9 +52362,9 @@ } }, "scratch-l10n": { - "version": "3.15.20230507032520", - "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230507032520.tgz", - "integrity": "sha512-WpAXxJ6hZIXIvHiLCbReXq9FCGXojX+2uMBs+yWvUNDfTmg2jpuWkbRw0+Ovnzll6lZYc5D2ErUtyD90BI38JA==", + "version": "3.15.20230523032203", + "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.15.20230523032203.tgz", + "integrity": "sha512-UhnDzBzo5u4sxQ0Ax6Z5MP5lsKzPWq5B+VafSWOFpfH6fJIoJPBt4iAH9S/Dg9xHZzUfouwmf4QsKYz3I/3cNQ==", "dev": true, "requires": { "@babel/cli": "^7.1.2", @@ -52527,9 +52561,9 @@ "dev": true }, "scratch-vm": { - "version": "1.5.48", - "resolved": "https://registry.npmjs.org/scratch-vm/-/scratch-vm-1.5.48.tgz", - "integrity": "sha512-xvIxNRruVTdDbgow1tjkM51+DYEfsE39oGrwG0hfKdLTTcF517gz30U3G3EK6vURivzlu+XvaO0RCHwxskSeeg==", + "version": "1.5.68", + "resolved": "https://registry.npmjs.org/scratch-vm/-/scratch-vm-1.5.68.tgz", + "integrity": "sha512-KND5BhWXVtaLgnbUo+LODsl5EXOrAhJhCPLCkdoNRJcyQII9kXyjOiJv12pO9x5469zDEd6eiMjuUVCvi/IWcw==", "dev": true, "requires": { "@vernier/godirect": "1.5.0", diff --git a/package.json b/package.json index 2c0695a85..a9c55d448 100644 --- a/package.json +++ b/package.json @@ -35,14 +35,14 @@ }, "repository": { "type": "git", - "url": "git+ssh://git@github.com/llk/scratch-www.git" + "url": "git+ssh://git@github.com/scratchfoundation/scratch-www.git" }, "author": "Massachusetts Institute of Technology", "license": "BSD-3-Clause", "bugs": { - "url": "https://github.com/llk/scratch-www/issues" + "url": "https://github.com/scratchfoundation/scratch-www/issues" }, - "homepage": "https://github.com/llk/scratch-www#readme", + "homepage": "https://github.com/scratchfoundation/scratch-www#readme", "dependencies": { "bunyan": "1.8.15", "clipboard-copy": "2.0.1", @@ -136,8 +136,8 @@ "regenerator-runtime": "0.13.9", "sass": "1.49.7", "sass-loader": "10.2.1", - "scratch-gui": "1.8.53", - "scratch-l10n": "3.15.20230507032520", + "scratch-gui": "1.8.91", + "scratch-l10n": "3.15.20230523032203", "selenium-webdriver": "4.1.0", "slick-carousel": "1.6.0", "style-loader": "0.12.3", diff --git a/src/components/footer/www/footer.jsx b/src/components/footer/www/footer.jsx index 72f676193..bfded26f8 100644 --- a/src/components/footer/www/footer.jsx +++ b/src/components/footer/www/footer.jsx @@ -169,6 +169,11 @@ const Footer = props => ( +
+ + + +
diff --git a/src/components/page/www/page.jsx b/src/components/page/www/page.jsx index 1902a9bff..c5849a7f6 100644 --- a/src/components/page/www/page.jsx +++ b/src/components/page/www/page.jsx @@ -6,6 +6,7 @@ const Navigation = require('../../navigation/www/navigation.jsx'); const Footer = require('../../footer/www/footer.jsx'); const DonorRecognition = require('./donor-recognition.jsx'); const ErrorBoundary = require('../../errorboundary/errorboundary.jsx'); +const PrivacyBanner = require('../../privacy-banner/privacy-banner.jsx'); const today = new Date(); const semi = today.getDate() === 1 && today.getMonth() === 3; @@ -25,6 +26,7 @@ const Page = ({ > +
{children}
diff --git a/src/components/privacy-banner/privacy-banner.jsx b/src/components/privacy-banner/privacy-banner.jsx new file mode 100644 index 000000000..9c7aa4d3b --- /dev/null +++ b/src/components/privacy-banner/privacy-banner.jsx @@ -0,0 +1,107 @@ +const bindAll = require('lodash.bindall'); +const FormattedMessage = require('react-intl').FormattedMessage; +const injectIntl = require('react-intl').injectIntl; +const connect = require('react-redux').connect; +const PropTypes = require('prop-types'); +const React = require('react'); + +const TitleBanner = require('../title-banner/title-banner.jsx'); +const Button = require('../forms/button.jsx'); +const jar = require('../../lib/jar.js'); + +require('./privacy-banner.scss'); + +const PRIVACY_UPDATE_START_TIME = 1684987200000; // May 25 2023 0000 ET +const PRIVACY_UPDATE_END_TIME = 1686887999000; // Jun 15 2023 1159 ET + +class PrivacyBanner extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'shouldShowBanner', + 'handleCloseBanner' + ]); + } + + shouldShowBanner () { + const seen = jar.get('scratchpolicyseen'); + return ( + Date.now() >= PRIVACY_UPDATE_START_TIME && + Date.now() < PRIVACY_UPDATE_END_TIME && + typeof seen === 'undefined' && + typeof this.props.user !== 'undefined' + ); + } + + handleCloseBanner () { + const opts = { + expires: new Date(new Date().setDate(new Date().getDate + 21)) // expires after 3 weeks + }; + this.setState({dismissedPrivacyBanner: true}); + jar.set('scratchpolicyseen', true, opts); + } + render () { + const showBanner = this.shouldShowBanner(); + const privacyPolicyLink = chunks =>
{chunks}; + if (showBanner) { + return ( + + ); + } + + // if we're not showing the banner, return null to not render anything + return null; + } +} + +const mapStateToProps = state => ({ + user: state.session && state.session.session && state.session.session.user +}); + +PrivacyBanner.propTypes = { + // onRequestClose: PropTypes.func + user: PropTypes.shape({ + classroomId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + thumbnailUrl: PropTypes.string, + username: PropTypes.string + }) +}; + +const ConnectedPrivacyBanner = connect( + mapStateToProps +)(PrivacyBanner); + +module.exports = injectIntl(ConnectedPrivacyBanner); diff --git a/src/components/privacy-banner/privacy-banner.scss b/src/components/privacy-banner/privacy-banner.scss new file mode 100644 index 000000000..56a9ce35c --- /dev/null +++ b/src/components/privacy-banner/privacy-banner.scss @@ -0,0 +1,72 @@ +@import "../../colors"; +@import "../../frameless"; + + +.privacy-banner { + display: flex; + z-index: 8; + background-color: $ui-blue-dark; + padding: 0; + overflow: hidden; + align-items: center; + justify-content: center; + margin-bottom: -50px; + margin-top: 50px; + + .privacy-banner-container { + display: flex; + margin: 0.375rem auto; + align-items: center; + + .lightbulb-icon { + margin: 0.6875rem; + width: 1.75rem; + height: 1.75rem; + } + + .privacy-banner-centered { + width: 100%; + display: flex; + flex-direction: row; + align-items: center; + } + + .privacy-banner-text { + text-align: left; + color: $ui-white; + font-size: 1rem; + font-weight: bold; + margin-right: 1rem; + max-width: 70vw; + } + } + + .privacy-close-button { + right: 1rem; + top: auto; + } + + a { + color: $ui-white; + text-decoration: underline; + } +} + +@media only screen and (max-width: $mobileIntermediate) { + .privacy-banner .privacy-banner-container .privacy-banner-centered { + flex-wrap: wrap; + } + + .privacy-banner .privacy-banner-container .lightbulb-icon { + padding-bottom: 2rem; + } + + .privacy-banner .privacy-banner-container { + margin-left: 0; + margin-bottom: 1rem + } + + .privacy-banner .donate-close-button { + top: 1rem; + } +} \ No newline at end of file diff --git a/src/l10n.json b/src/l10n.json index 82ebe2b4b..4b6c25e6c 100644 --- a/src/l10n.json +++ b/src/l10n.json @@ -17,6 +17,7 @@ "general.contactUs": "Contact Us", "general.getHelp": "Get Help", "general.contact": "Contact", + "general.cookies": "Cookies", "general.done": "Done", "general.downloadPDF": "Download PDF", "general.emailUs": "Email Us", @@ -451,5 +452,6 @@ "extensions.otherComputerConnectedText": "Only one computer can be connected to a {deviceName} at a time. If you have another computer connected to your {deviceName}, disconnect the {deviceName} or close Scratch on that computer and try again.", "bluetooth.enableLocationServicesTitle": "Make sure you have location services enabled on Chromebooks or Android tablets", - "bluetooth.enableLocationServicesText": "Bluetooth can be used to provide location data to the app. In addition to granting the Scratch App permission to access location, location must be enabled in your general device settings. Search for 'Location' in your settings, and make sure it is on. On Chromebooks search for 'Location' in the Google Play Store Android preferences." + "bluetooth.enableLocationServicesText": "Bluetooth can be used to provide location data to the app. In addition to granting the Scratch App permission to access location, location must be enabled in your general device settings. Search for 'Location' in your settings, and make sure it is on. On Chromebooks search for 'Location' in the Google Play Store Android preferences.", + "privacyBanner.update": "The Scratch privacy policy has been updated, effective May 25, 2023. You can see the new policy here." } diff --git a/src/redux/session.js b/src/redux/session.js index e592465c5..162b230e7 100644 --- a/src/redux/session.js +++ b/src/redux/session.js @@ -13,6 +13,7 @@ const Types = keyMirror({ }); const banGoodListPaths = [ + '/ip_ban_appeal', '/vpn_required', '/accounts/banned-response', '/community_guidelines', @@ -72,6 +73,13 @@ const handleSessionResponse = (dispatch, body) => { ) { window.location = '/vpn_required/'; return; + } else if ( + body.banned && + body.redirectURL && + banGoodListPaths.every(goodPath => window.location.pathname.indexOf(goodPath) === -1) + ) { + window.location = body.redirectURL; + return; } else if ( body.user && body.user.banned && diff --git a/src/routes.json b/src/routes.json index 8120449db..06e47904d 100644 --- a/src/routes.json +++ b/src/routes.json @@ -138,6 +138,13 @@ "title": "Contact Us", "viewportWidth": "device-width" }, + { + "name": "cookies", + "pattern": "^/cookies/?$", + "routeAlias": "/cookies/?", + "view": "cookies/cookies", + "title": "Cookie Policy" + }, { "name": "credits", "pattern": "^/credits/?$", diff --git a/src/views/about/about.jsx b/src/views/about/about.jsx index ac146acec..c5c5d60a6 100644 --- a/src/views/about/about.jsx +++ b/src/views/about/about.jsx @@ -5,10 +5,12 @@ const render = require('../../lib/render.jsx'); const Button = require('../../components/forms/button.jsx'); const Page = require('../../components/page/www/page.jsx'); const Video = require('../../components/video/video.jsx'); +const injectIntl = require('react-intl').injectIntl; require('./about.scss'); -const About = () => ( +const tedLink = chunks => {chunks}; +const About = injectIntl(({intl}) => (

@@ -56,14 +58,22 @@ const About = () => (
  • -