diff --git a/src/assets/stylesheets/entry.scss b/src/assets/stylesheets/entry.scss index 04d1bbfadcb30a3e78bb7d73f00c7b8e0061537c..abed31db312891d5d0d4c425b42310851df21553 100644 --- a/src/assets/stylesheets/entry.scss +++ b/src/assets/stylesheets/entry.scss @@ -20,28 +20,18 @@ justify-content: center; &__screen-sharing { - font-size: 1.4em; - margin-left: 2.95em; - margin-top: 0.6em; - } + font-size: 1.4em; + margin-left: 2.95em; + margin-top: 0.6em; - &__screen-sharing-checkbox { - appearance: none; - -moz-appearance: none; - -webkit-appearance: none; - width: 2em; - height: 2em; - border: 3px solid white; - border-radius: 9px; - vertical-align: sub; - margin: 0 0.6em + &__checkbox { + @extend %checkbox; + } + &__checkbox:checked { + @extend %checkbox-checked; + } } - &__screen-sharing-checkbox:checked { - border: 9px double white; - outline: 9px solid white; - outline-offset: -18px; - } &__secondary { width: 100%; diff --git a/src/assets/stylesheets/profile.scss b/src/assets/stylesheets/profile.scss index 53af72edee17d527bbffdbd73f5efb19b36dd5e6..c0e48ffd2f172c9f017cf0331e5a576ba9ecf207 100644 --- a/src/assets/stylesheets/profile.scss +++ b/src/assets/stylesheets/profile.scss @@ -41,6 +41,10 @@ color: $grey-text; } + &__display-name-label { + font-size: 1.2em; + margin-right: 0.5em; + } &__form-field-text { @extend %rounded-border; @extend %default-font; @@ -54,6 +58,31 @@ margin: 0.5em 0; } + &__terms { + margin-bottom: 16px; + + &__checkbox { + @extend %checkbox; + vertical-align: unset; + } + &__checkbox:checked { + @extend %checkbox-checked; + } + + &__text { + display: inline-block; + max-width: 20em; + } + + &__link { + color: white; + } + + &__link:visited { + color: grey; + } + } + &__form-submit { @extend %bottom-button; margin: 0; diff --git a/src/assets/stylesheets/shared.scss b/src/assets/stylesheets/shared.scss index 796dc23b87193ee76e707228346087b190024202..f959943585bbfacf37791586f5485add3e524cd1 100644 --- a/src/assets/stylesheets/shared.scss +++ b/src/assets/stylesheets/shared.scss @@ -23,8 +23,8 @@ $darker-grey: rgba(64, 64, 64, 1.0); margin-top: auto; margin-bottom: 30px; cursor: pointer; - border: 4px solid white; - border-radius: 16px; + border: 3px solid white; + border-radius: 14px; padding: 12px; background: none; color: white; @@ -48,3 +48,21 @@ $darker-grey: rgba(64, 64, 64, 1.0); border: none; font-size: 64pt; } + +%checkbox { + appearance: none; + -moz-appearance: none; + -webkit-appearance: none; + width: 2em; + height: 2em; + border: 3px solid white; + border-radius: 9px; + vertical-align: sub; + margin: 0 0.6em +} + +%checkbox-checked { + border: 9px double white; + outline: 9px solid white; + outline-offset: -18px; +} diff --git a/src/assets/translations.data.json b/src/assets/translations.data.json index 9201daed28e62f6e2ac6df1ddfda5d83137f4ad0..1b9844c8abf2dc7d9ed7c089f84923faa601fd96 100644 --- a/src/assets/translations.data.json +++ b/src/assets/translations.data.json @@ -14,8 +14,14 @@ "entry.daydream-via-chrome": "Using Google Chrome", "entry.enable-screen-sharing": "Share my desktop", "profile.save": "SAVE", + "profile.display_name.label": "Display name:", "profile.display_name.validation_warning": "Alphanumerics and hyphens. At least 3 characters, no more than 32", "profile.header": "Your identity", + "profile.terms.prefix": "I confirm that I am over the age of 13 and agree to the", + "profile.terms.privacy": "privacy policy", + "profile.terms.conjunction": "and", + "profile.terms.tou": "terms of use", + "profile.terms.suffix": ".", "profile.avatar-selector.loading": "Loading Avatars...", "audio.title": "Test your audio", "audio.subtitle-desktop": "Confirm HMD speaker output", diff --git a/src/react-components/profile-entry-panel.js b/src/react-components/profile-entry-panel.js index af1c7382f9ecb56b5a58bec0d623f9b35aa97562..96016e0a552f7846903094efab30974f98737b4f 100644 --- a/src/react-components/profile-entry-panel.js +++ b/src/react-components/profile-entry-panel.js @@ -28,9 +28,11 @@ class ProfileEntryPanel extends Component { saveStateAndFinish = e => { e.preventDefault(); + if (!this.state.has_agreed_to_terms) return; this.props.store.update({ profile: { has_saved_profile: true, + has_agreed_to_terms: true, display_name: this.state.display_name, avatar_id: this.state.avatar_id } @@ -75,20 +77,47 @@ class ProfileEntryPanel extends Component { <div className="profile-entry__subtitle"> <FormattedMessage id="profile.header" /> </div> - <input - className="profile-entry__form-field-text" - value={this.state.display_name} - onChange={e => this.setState({ display_name: e.target.value })} - required - pattern={SCHEMA.definitions.profile.properties.display_name.pattern} - title={formatMessage({ id: "profile.display_name.validation_warning" })} - ref={inp => (this.nameInput = inp)} - /> + <label> + <span className="profile-entry__display-name-label"> + <FormattedMessage id="profile.display_name.label" /> + </span> + <input + className="profile-entry__form-field-text" + value={this.state.display_name} + onChange={e => this.setState({ display_name: e.target.value })} + required + pattern={SCHEMA.definitions.profile.properties.display_name.pattern} + title={formatMessage({ id: "profile.display_name.validation_warning" })} + ref={inp => (this.nameInput = inp)} + /> + </label> <iframe className="profile-entry__avatar-selector" src={`/${this.props.htmlPrefix}avatar-selector.html#avatar_id=${this.state.avatar_id}`} ref={ifr => (this.avatarSelector = ifr)} /> + {!this.props.store.state.profile.has_agreed_to_terms && ( + <label className="profile-entry__terms"> + <input + className="profile-entry__terms__checkbox" + type="checkbox" + required + value={this.state.has_agreed_to_terms} + onChange={e => this.setState({ has_agreed_to_terms: e.target.value })} + /> + <span className="profile-entry__terms__text"> + <FormattedMessage id="profile.terms.prefix" />{" "} + <a className="profile-entry__terms__link" target="_blank" href="/privacy"> + <FormattedMessage id="profile.terms.privacy" /> + </a>{" "} + <FormattedMessage id="profile.terms.conjunction" />{" "} + <a className="profile-entry__terms__link" target="_blank" href="/terms"> + <FormattedMessage id="profile.terms.tou" /> + </a> + <FormattedMessage id="profile.terms.suffix" /> + </span> + </label> + )} <input className="profile-entry__form-submit" type="submit" value={formatMessage({ id: "profile.save" })} /> </div> </form> diff --git a/src/react-components/ui-root.js b/src/react-components/ui-root.js index f0d364dbc6ac3c148391e17135b5cffce0938c5b..07488ced3d668b051c21cd1274416b647654c69a 100644 --- a/src/react-components/ui-root.js +++ b/src/react-components/ui-root.js @@ -539,7 +539,7 @@ class UIRoot extends Component { /firefox/i.test(navigator.userAgent) && ( <label className="entry-panel__screen-sharing"> <input - className="entry-panel__screen-sharing-checkbox" + className="entry-panel__screen-sharing__checkbox" type="checkbox" value={this.state.shareScreen} onChange={this.setStateAndRequestScreen} diff --git a/src/storage/store.js b/src/storage/store.js index b9f7366abf0aa01d0cec7836bcef541bf3fe8ee8..0e76ee5a0449c85b374d0b46e7fadbf8d9e1050c 100644 --- a/src/storage/store.js +++ b/src/storage/store.js @@ -17,6 +17,7 @@ export const SCHEMA = { additionalProperties: false, properties: { has_saved_profile: { type: "boolean" }, + has_agreed_to_terms: { type: "boolean" }, display_name: { type: "string", pattern: "^[A-Za-z0-9-]{3,32}$" }, avatar_id: { type: "string" } } diff --git a/src/utils/identity.js b/src/utils/identity.js index e4d79896c1dce8e8175fe0e6420f1c88aac2a858..917553d7c2f13c647349eea95c6e0743814314f3 100644 --- a/src/utils/identity.js +++ b/src/utils/identity.js @@ -172,6 +172,7 @@ export const avatarIds = avatars.map(av => av.id); export function generateDefaultProfile() { const name = selectRandom(names); return { + has_agreed_to_terms: false, has_saved_profile: false, display_name: name.replace(/^./, name[0].toUpperCase()), avatar_id: selectRandom(avatarIds)