diff --git a/src/components/community-guidelines/community-guidelines.jsx b/src/components/community-guidelines/community-guidelines.jsx index 387d0a917..8dede98bb 100644 --- a/src/components/community-guidelines/community-guidelines.jsx +++ b/src/components/community-guidelines/community-guidelines.jsx @@ -1,6 +1,6 @@ import React, {useEffect} from 'react'; import {FormattedMessage} from 'react-intl'; -import thumbnailUrl from '../../lib/user-thumbnail'; +import thumbnailUrl from '../../lib/user-thumbnail.js'; import OnboardingNavigation from '../onboarding-navigation/onboarding-navigation.jsx'; import './community-guidelines.scss'; @@ -60,16 +60,21 @@ export const communityGuidelines = [ } ]; -const CommunityGuidelines = ({constructHeader = () => null, userId, currentPage, onNextPage, onBackPage}) => { +export const CommunityGuidelines = ({ + constructHeader = () => null, + userId, + currentPage, + nextButtonText, + onNextPage, + onBackPage +}) => { useEffect(() => { communityGuidelines.forEach(guideline => { new Image().src = `/images/onboarding/${guideline.image}`; }); }, []); - console.log('==user id', userId); - - const guideline = communityGuidelines[currentPage - 2]; + const guideline = communityGuidelines[currentPage]; return (
{constructHeader(guideline)} @@ -95,7 +100,7 @@ const CommunityGuidelines = ({constructHeader = () => null, userId, currentPage, alt="" src={`/images/onboarding/${guideline.image}`} /> - {currentPage === 3 && } @@ -106,6 +111,7 @@ const CommunityGuidelines = ({constructHeader = () => null, userId, currentPage, @@ -117,8 +123,7 @@ CommunityGuidelines.propTypes = { currentPage: PropTypes.number, userId: PropTypes.string, constructHeader: PropTypes.func, + nextButtonText: PropTypes.string, onNextPage: PropTypes.func, onBackPage: PropTypes.func }; - -export default CommunityGuidelines; diff --git a/src/components/community-guidelines/community-guidelines.scss b/src/components/community-guidelines/community-guidelines.scss index d086cd093..93512b217 100644 --- a/src/components/community-guidelines/community-guidelines.scss +++ b/src/components/community-guidelines/community-guidelines.scss @@ -1,6 +1,11 @@ @import "../../colors"; @import "../../frameless"; +.col{ + display: flex; + flex-direction: column !important; +} + .onboarding { display: flex; flex-direction: row; @@ -14,7 +19,6 @@ margin-bottom: 20px; } - // TODO: Can we remove? button{ padding: .3em .9em; } @@ -53,32 +57,6 @@ .image-inner-content{ position: relative; } - - // TODO: Can we remove? - .image-content-1{ - display: flex; - flex: 4; - justify-content: center; - align-items: center; - @media #{$medium-and-smaller} { - flex: 12; - order: 1; - align-items: flex-end; - height: 250px; - } - - img{ - z-index: 100; - @media #{$medium-and-smaller} { - width: 300px; - height: 300px; - } - } - - @media #{$medium-and-smaller} { - background-color: #E9F1FC; - } - } .text-content{ flex: 8; diff --git a/src/components/onboarding-navigation/onboarding-navigation-wrapper.jsx b/src/components/onboarding-navigation/onboarding-navigation-wrapper.jsx new file mode 100644 index 000000000..305271934 --- /dev/null +++ b/src/components/onboarding-navigation/onboarding-navigation-wrapper.jsx @@ -0,0 +1,50 @@ +import React, {useCallback, useState, useEffect} from 'react'; +import {CommunityGuidelines, communityGuidelines} from './community-guidelines.jsx'; +import PropTypes from 'prop-types'; +import {injectIntl} from 'react-intl'; +const ReactModal = require('react-modal'); + +const CommunityGuidelinesModal = props => { + const [currentPage, setCurrentPage] = useState(0); + const onNextPage = useCallback(() => setCurrentPage(currentPage + 1), [currentPage]); + const onBackPage = useCallback(() => setCurrentPage(currentPage - 1), [currentPage]); + const onComplete = props.onComplete ?? (() => true); + + useEffect(() => { + const body = document.querySelector('body'); + body.style.overflow = props.isOpen ? 'hidden' : 'auto'; + }, [props.isOpen]); + + return ( + + 0 ? onBackPage : null} + /> + ); +}; + +CommunityGuidelinesModal.propTypes = { + userId: PropTypes.string, + onComplete: PropTypes.func, + isOpen: PropTypes.bool +}; + +export const IntlCommunityGuidelinesWrapper = injectIntl(CommunityGuidelinesModal); diff --git a/src/components/onboarding-navigation/onboarding-navigation.jsx b/src/components/onboarding-navigation/onboarding-navigation.jsx index 791eb5ad4..8a89ff135 100644 --- a/src/components/onboarding-navigation/onboarding-navigation.jsx +++ b/src/components/onboarding-navigation/onboarding-navigation.jsx @@ -4,8 +4,15 @@ import {FormattedMessage} from 'react-intl'; import PropTypes from 'prop-types'; import './onboarding-navigation.scss'; +import classNames from 'classnames'; -const OnboardingNavigation = ({currentPage, totalDots, onNextPage, onBackPage, nextButtonText}) => { +const OnboardingNavigation = ({ + currentPage, + totalDots, + onNextPage, + onBackPage, + nextButtonText +}) => { const dots = []; useEffect(() => { @@ -13,31 +20,36 @@ const OnboardingNavigation = ({currentPage, totalDots, onNextPage, onBackPage, n new Image().src = '/images/onboarding/left-arrow.svg'; }, []); - if (currentPage && totalDots){ + if (currentPage >= 0 && totalDots){ for (let i = 0; i < totalDots; i++){ - // First two pages don't have dots dots.push(
); } } return (
- - {(currentPage && totalDots) && + { + } + {(currentPage >= 0 && totalDots) &&
{dots}
} diff --git a/src/components/onboarding-navigation/onboarding-navigation.scss b/src/components/onboarding-navigation/onboarding-navigation.scss index f0b976cfc..dbfa2e11d 100644 --- a/src/components/onboarding-navigation/onboarding-navigation.scss +++ b/src/components/onboarding-navigation/onboarding-navigation.scss @@ -21,6 +21,10 @@ } } +.hidden{ + visibility: hidden; +} + .navigation{ display: flex; width: 100%; @@ -57,4 +61,8 @@ display: none; } } + + .buttonPlaceholder{ + width: 20px, + } } \ No newline at end of file diff --git a/src/l10n.json b/src/l10n.json index 0c66069e4..5f510f25a 100644 --- a/src/l10n.json +++ b/src/l10n.json @@ -479,5 +479,62 @@ "renameAccount.scratchsCommunityGuidelines": "Scratch's Community Guidelines", "renameAccount.change": "Change", "renameAccount.goToProfile": "Go to your profile", - "renameAccount.pastNotifications": "Here are your past admin notifications" + "renameAccount.pastNotifications": "Here are your past admin notifications", + + "becomeAScratcher.buttons.back": "Back", + "becomeAScratcher.buttons.next": "Next", + "becomeAScratcher.buttons.communityGuidelines": "Community Guidelines", + "becomeAScratcher.buttons.getStarted": "Get Started", + "becomeAScratcher.buttons.finishLater": "Finish Later", + "becomeAScratcher.buttons.goBack": "Go Back", + "becomeAScratcher.buttons.iAgree": "I Agree", + "becomeAScratcher.buttons.takeMeBack": "Take me back to Scratch", + "becomeAScratcher.buttons.backToProfile": "Back to Profile Page", + "becomeAScratcher.buttons.finishLater": "Finish Later", + "becomeAScratcher.congratulations.header": "Congratulations, {username}! You have shown that you are ready to become a Scratcher.", + "becomeAScratcher.congratulations.body": "Scratch is a friendly and welcoming community for everyone, where people create, share, and learn together. We welcome people of all ages, races, ethnicities, religions, abilities, sexual orientations, and gender identities.", + "becomeAScratcher.toBeAScratcher.header": "What does it mean to be a Scratcher?", + "becomeAScratcher.toBeAScratcher.body": "You might notice on your profile page that you are currently a “New Scratcher”. Now that you have spent some time on Scratch, we invite you to become a “Scratcher”.", + "becomeAScratcher.toBeAScratcher.definition": "Scratchers have a bit more experience on Scratch and are excited to both contribute to the community and to make it a supportive and welcoming space for others.", + "becomeAScratcher.toBeAScratcher.canDo": "Here are some things Scratchers do:", + "becomeAScratcher.toBeAScratcher.createStudios": "Create studios", + "becomeAScratcher.toBeAScratcher.helpOut": "Help out in the community", + "becomeAScratcher.toBeAScratcher.communityGuidelines": "Next, we will take you through the community guidelines and explain what these are.", + "becomeAScratcher.guidelines.respectSection": "Become a Scratcher - Treat everyone with respect", + "becomeAScratcher.guidelines.respectHeader": "Scratchers treat everyone with respect.", + "becomeAScratcher.guidelines.respectBody": "Everyone on Scratch is encouraged to share things that excite them and are important to them—we hope that you find ways to celebrate your own identity on Scratch, and allow others to do the same.", + "becomeAScratcher.guidelines.safeSection": "Become a Scratcher - Be safe", + "becomeAScratcher.guidelines.safeHeader": "Scratchers are safe: we keep personal and contact information private.", + "becomeAScratcher.guidelines.safeBody": "This includes not sharing real last names, phone numbers, addresses, hometowns, school names, email addresses, usernames or links to social media sites, video chatting applications, or websites with private chat functionality.", + "becomeAScratcher.guidelines.feedbackSection": "Become a Scratcher - Give helpful feedback", + "becomeAScratcher.guidelines.feedbackHeader": "Scratchers give helpful feedback.", + "becomeAScratcher.guidelines.feedbackBody": "When commenting on a project, remember to say something you like about it, offer suggestions, and be kind, not critical.", + "becomeAScratcher.guidelines.remix1Section": "Become a Scratcher - Embrace remix culture", + "becomeAScratcher.guidelines.remix1Header": "Scratchers embrace remix culture.", + "becomeAScratcher.guidelines.remix1Body": "Remixing is when you build upon someone else’s projects, code, ideas, images, or anything else they share on Scratch to make your own unique creation.", + "becomeAScratcher.guidelines.remix2Section": "Become a Scratcher - Embrace remix culture", + "becomeAScratcher.guidelines.remix2Header": "Remixing is a great way to collaborate and connect with other Scratchers.", + "becomeAScratcher.guidelines.remix2Body": "You are encouraged to use anything you find on Scratch in your own creations, as long as you provide credit to everyone whose work you used and make a meaningful change to it. ", + "becomeAScratcher.guidelines.remix3Section": "Become a Scratcher - Embrace remix culture", + "becomeAScratcher.guidelines.remix3Header": "Remixing means sharing with others.", + "becomeAScratcher.guidelines.remix3Body": "When you share something on Scratch, you are giving permission to all Scratchers to use your work in their creations, too.", + "becomeAScratcher.guidelines.honestSection": "Become a Scratcher - Be honest", + "becomeAScratcher.guidelines.honestHeader": "Scratchers are honest.", + "becomeAScratcher.guidelines.honestBody": "It’s important to be honest and authentic when interacting with others on Scratch, and remember that there is a person behind every Scratch account.", + "becomeAScratcher.guidelines.friendlySection": "Become a Scratcher - Keep the site friendly", + "becomeAScratcher.guidelines.friendlyHeader": "Scratchers help keep the site friendly.", + "becomeAScratcher.guidelines.friendlyBody": "It’s important to keep your creations and conversations friendly and appropriate for all ages. If you think something on Scratch is mean, insulting, too violent, or otherwise disruptive to the community, click “Report” to let us know about it.", + "becomeAScratcher.invitation.header": "{username}, we invite you to become a Scratcher.", + "becomeAScratcher.invitation.body": "Scratch is a friendly and welcoming community for everyone. If you agree to be respectful, be safe, give helpful feedback, embrace remix culture, be honest, and help keep the site friendly, click “I agree!”", + "becomeAScratcher.invitation.finishLater": "You get to decide if you want to become a Scratcher. If you do not want to be a Scratcher yet, just click “Finish Later” above.", + "registration.success.error": "Sorry, an unexpected error occurred.", + "becomeAScratcher.success.header": "Hooray! You are now officially a Scratcher.", + "becomeAScratcher.success.body": "Here are some links that might be helpful for you.", + "becomeAScratcher.success.communityGuidelines": "Community Guidelines", + "becomeAScratcher.success.createAProject": "Create a Project", + "becomeAScratcher.noInvitation.header": "Whoops! Looks like you haven’t received an invitation to become a Scratcher yet.", + "becomeAScratcher.noInvitation.body": "To become a Scratcher, you must be active on Scratch for a while, share several projects, and comment constructively in the community. After a few weeks, you will receive a notification inviting you to become a Scratcher. Scratch on!", + "becomeAScratcher.finishLater.header": "No worries, take your time!", + "becomeAScratcher.finishLater.body": "By leaving this page, you will not finish the process to become a Scratcher and will stay as a New Scratcher. If you change your mind later, you can always come back via your profile page.", + "becomeAScratcher.finishLater.clickBecomeAScratcher": "Just click on “★ Become a Scratcher!” below your username." } diff --git a/src/redux/navigation.js b/src/redux/navigation.js index 5c2c37623..a2fdeea6f 100644 --- a/src/redux/navigation.js +++ b/src/redux/navigation.js @@ -15,7 +15,9 @@ const Types = keyMirror({ TOGGLE_LOGIN_OPEN: null, SET_CANCELED_DELETION_OPEN: null, SET_REGISTRATION_OPEN: null, - HANDLE_REGISTRATION_REQUESTED: null + HANDLE_REGISTRATION_REQUESTED: null, + HANDLE_REGISTRATION_COMPLETED: null, + REVIEW_COMMUNITY_GUIDELINES: null }); module.exports.getInitialState = () => ({ @@ -25,6 +27,7 @@ module.exports.getInitialState = () => ({ loginError: null, loginOpen: false, registrationOpen: false, + shouldReviewCommunityGuidelines: false, searchTerm: '' }); @@ -56,6 +59,10 @@ module.exports.navigationReducer = (state, action) => { return state; } return defaults({registrationOpen: true}, state); + case Types.HANDLE_REGISTRATION_COMPLETED: + return defaults({shouldReviewCommunityGuidelines: true}, state); + case Types.REVIEW_COMMUNITY_GUIDELINES: + return defaults({shouldReviewCommunityGuidelines: false}, state); default: return state; } @@ -103,6 +110,14 @@ module.exports.handleRegistrationRequested = () => ({ type: Types.HANDLE_REGISTRATION_REQUESTED }); +module.exports.handleRegistrationCompleted = () => ({ + type: Types.HANDLE_REGISTRATION_COMPLETED +}); + +module.exports.reviewCommunityGuidelines = () => ({ + type: Types.REVIEW_COMMUNITY_GUIDELINES +}); + module.exports.handleCompleteRegistration = createProject => (dispatch => { if (createProject) { // TODO: Ideally this would take you to the editor with the getting started @@ -114,6 +129,7 @@ module.exports.handleCompleteRegistration = createProject => (dispatch => { dispatch(module.exports.setRegistrationOpen(false)) ); } + dispatch(module.exports.handleRegistrationCompleted()); }); module.exports.handleLogIn = (formData, callback) => (dispatch => { diff --git a/src/views/become-a-scratcher/become-a-scratcher.jsx b/src/views/become-a-scratcher/become-a-scratcher.jsx index e4c782e97..c4096a2c5 100644 --- a/src/views/become-a-scratcher/become-a-scratcher.jsx +++ b/src/views/become-a-scratcher/become-a-scratcher.jsx @@ -15,7 +15,10 @@ import Modal from '../../components/modal/base/modal.jsx'; import NotAvailable from '../../components/not-available/not-available.jsx'; import WarningBanner from '../../components/title-banner/warning-banner.jsx'; import OnboardingNavigation from '../../components/onboarding-navigation/onboarding-navigation.jsx'; -import CommunityGuidelines, {communityGuidelines} from '../../components/community-guidelines/community-guidelines.jsx'; +import { + CommunityGuidelines, + communityGuidelines +} from '../../components/community-guidelines/community-guidelines.jsx'; import './become-a-scratcher.scss'; @@ -174,25 +177,25 @@ const BecomeAScratcher = ({user, invitedScratcher, scratcher, sessionStatus}) => return (); } - // New scratcher who is not invited - if (!invitedScratcher && !scratcher){ - return (
- -

- -

-
- -
-
); - } + // // New scratcher who is not invited + // if (!invitedScratcher && !scratcher){ + // return (
+ // + //

+ // + //

+ //
+ // + //
+ //
); + // } // Invited Scratcher if (currentPage === 0){ @@ -289,7 +292,7 @@ const BecomeAScratcher = ({user, invitedScratcher, scratcher, sessionStatus}) => ); } else if (currentPage < 2 + communityGuidelines.length) { return (); + } + return ( ({ sessionStatus: state.session.status, shared: state.splash.shared.rows, studios: state.splash.studios.rows, - user: state.session.session.user + user: state.session.session.user, + shouldReviewCommunityGuidelines: state.navigation.shouldReviewCommunityGuidelines }); const mapDispatchToProps = dispatch => ({ @@ -308,19 +329,22 @@ const mapDispatchToProps = dispatch => ({ }, setRows: (type, rows) => { dispatch(splashActions.setRows(type, rows)); + }, + reviewCommunityGuidelines: () => { + dispatch(navigationActions.reviewCommunityGuidelines()); } }); -const ConnectedSplash = connect( +const IntlConnectedSplash = injectIntl(connect( mapStateToProps, mapDispatchToProps -)(Splash); +)(Splash)); render( - + , document.getElementById('app'), {splash: splashActions.splashReducer}