From de834cd586f3e7cdc6fef2a41bb05cb8e6b6f004 Mon Sep 17 00:00:00 2001
From: mgabdev <>
Date: Tue, 14 Jul 2020 22:31:54 -0500
Subject: [PATCH] Updated Introduction/onboarding flow
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
• Updated:
- Introduction/onboarding flow
• Added:
- autoJoinGroup to default "Introduce Yourself" group in gab.com if you post the welcome post in introduction last slide
---
app/controllers/api/v1/statuses_controller.rb | 2 +
app/javascript/gabsocial/actions/compose.js | 6 +-
.../gabsocial/actions/onboarding.js | 3 -
app/javascript/gabsocial/constants.js | 5 +-
.../gabsocial/containers/gabsocial.js | 41 +++-
.../compose/components/compose_form.js | 5 +-
.../containers/compose_form_container.js | 4 +-
.../gabsocial/features/introduction.js | 199 ++++++++++++++----
.../gabsocial/layouts/introduction_layout.js | 32 ++-
app/javascript/gabsocial/reducers/settings.js | 2 +-
app/services/post_status_service.rb | 2 +
11 files changed, 236 insertions(+), 65 deletions(-)
diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb
index cdee103e..96930bb4 100644
--- a/app/controllers/api/v1/statuses_controller.rb
+++ b/app/controllers/api/v1/statuses_controller.rb
@@ -56,6 +56,7 @@ class Api::V1::StatusesController < Api::BaseController
@status = PostStatusService.new.call(current_user.account,
text: status_params[:status],
markdown: markdown,
+ autoJoinGroup: status_params[:autoJoinGroup],
thread: status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id]),
media_ids: status_params[:media_ids],
sensitive: status_params[:sensitive],
@@ -109,6 +110,7 @@ class Api::V1::StatusesController < Api::BaseController
params.permit(
:status,
:markdown,
+ :autoJoinGroup,
:in_reply_to_id,
:quote_of_id,
:sensitive,
diff --git a/app/javascript/gabsocial/actions/compose.js b/app/javascript/gabsocial/actions/compose.js
index 860f6268..ac562ac7 100644
--- a/app/javascript/gabsocial/actions/compose.js
+++ b/app/javascript/gabsocial/actions/compose.js
@@ -7,6 +7,7 @@ import { isMobile } from '../utils/is_mobile'
import { search as emojiSearch } from '../components/emoji/emoji_mart_search_light';
import { urlRegex } from '../features/ui/util/url_regex'
import { tagHistory } from '../settings';
+import { joinGroup } from './groups'
import { useEmoji } from './emojis';
import resizeImage from '../utils/resize_image';
import { importFetchedAccounts } from './importer';
@@ -260,10 +261,12 @@ export function handleComposeSubmit(dispatch, getState, response, status) {
}
}
-export function submitCompose(groupId, replyToId = null, router, isStandalone) {
+export function submitCompose(groupId, replyToId = null, router, isStandalone, autoJoinGroup) {
return function (dispatch, getState) {
if (!me) return;
+ if (autoJoinGroup) dispatch(joinGroup(groupId))
+
let status = getState().getIn(['compose', 'text'], '');
let markdown = getState().getIn(['compose', 'markdown'], '');
const media = getState().getIn(['compose', 'media_attachments']);
@@ -304,6 +307,7 @@ export function submitCompose(groupId, replyToId = null, router, isStandalone) {
status,
markdown,
scheduled_at,
+ autoJoinGroup,
in_reply_to_id: inReplyToId,
quote_of_id: getState().getIn(['compose', 'quote_of_id'], null),
media_ids: media.map(item => item.get('id')),
diff --git a/app/javascript/gabsocial/actions/onboarding.js b/app/javascript/gabsocial/actions/onboarding.js
index cf8c2d9b..52733a44 100644
--- a/app/javascript/gabsocial/actions/onboarding.js
+++ b/app/javascript/gabsocial/actions/onboarding.js
@@ -1,8 +1,5 @@
-import moment from 'moment-mini'
import { changeSetting, saveSettings } from './settings'
-export const MIN_ACCOUNT_CREATED_AT_ONBOARDING = moment('2020-07-14').valueOf()
-
export const saveShownOnboarding = () => (dispatch) => {
dispatch(changeSetting(['shownOnboarding'], true))
dispatch(saveSettings())
diff --git a/app/javascript/gabsocial/constants.js b/app/javascript/gabsocial/constants.js
index c7c046a9..9f9d2fca 100644
--- a/app/javascript/gabsocial/constants.js
+++ b/app/javascript/gabsocial/constants.js
@@ -108,4 +108,7 @@ export const NOTIFICATION_FILTERS = [
'follow_requests',
]
-export const GAB_COM_INTRODUCE_YOURSELF_GROUP_ID = '12'
\ No newline at end of file
+export const GAB_COM_INTRODUCE_YOURSELF_GROUP_ID = '12'
+
+// export const MIN_ACCOUNT_CREATED_AT_ONBOARDING = 1594789200000 // 2020-07-15
+export const MIN_ACCOUNT_CREATED_AT_ONBOARDING = 1594782839825 // 2020-07-14
\ No newline at end of file
diff --git a/app/javascript/gabsocial/containers/gabsocial.js b/app/javascript/gabsocial/containers/gabsocial.js
index e607493e..2a04acb0 100644
--- a/app/javascript/gabsocial/containers/gabsocial.js
+++ b/app/javascript/gabsocial/containers/gabsocial.js
@@ -3,18 +3,21 @@
import { Provider } from 'react-redux'
import configureStore from '../store/configureStore'
import { BrowserRouter, Route } from 'react-router-dom'
+import moment from 'moment-mini'
import { ScrollContext } from 'react-router-scroll-4'
import { IntlProvider, addLocaleData } from 'react-intl'
import { fetchCustomEmojis } from '../actions/custom_emojis'
import { hydrateStore } from '../actions/store'
+import { MIN_ACCOUNT_CREATED_AT_ONBOARDING } from '../constants'
import {
connectUserStream,
connectStatusUpdateStream,
} from '../actions/streaming'
import { getLocale } from '../locales'
import initialState from '../initial_state'
-import { me } from '../initial_state'
+import { me, isFirstSession } from '../initial_state'
import UI from '../features/ui'
+import IntroductionPage from '../pages/introduction_page'
import ErrorBoundary from '../components/error_boundary'
import Display from './display'
@@ -27,9 +30,45 @@ const hydrateAction = hydrateStore(initialState)
store.dispatch(hydrateAction)
store.dispatch(fetchCustomEmojis())
+const mapStateToProps = (state) => ({
+ accountCreatedAt: !!me ? state.getIn(['accounts', me, 'created_at']) : undefined,
+ shownOnboarding: state.getIn(['settings', 'shownOnboarding']),
+})
+
+@connect(mapStateToProps)
class GabSocialMount extends PureComponent {
+ static propTypes = {
+ shownOnboarding: PropTypes.bool.isRequired,
+ accountCreatedAt: PropTypes.string,
+ }
+
+ state = {
+ shownOnboarding: this.props.shownOnboarding,
+ shouldShow: false,
+ }
+
+ componentDidMount() {
+ if (!!me && this.props.accountCreatedAt) {
+ //If first time opening app, and is new user, show onboarding
+ const accountCreatedAtValue = moment(this.props.accountCreatedAt).valueOf()
+ const shouldShow = isFirstSession && !this.state.shownOnboarding && accountCreatedAtValue > MIN_ACCOUNT_CREATED_AT_ONBOARDING
+
+ if (shouldShow) this.setState({ shouldShow })
+ }
+ }
+
render () {
+ const { shownOnboarding, shouldShow } = this.state
+
+ if (!shownOnboarding && shouldShow) {
+ return (
+
+
+
+ )
+ }
+
return (
diff --git a/app/javascript/gabsocial/features/compose/components/compose_form.js b/app/javascript/gabsocial/features/compose/components/compose_form.js
index c5f4005a..30a36987 100644
--- a/app/javascript/gabsocial/features/compose/components/compose_form.js
+++ b/app/javascript/gabsocial/features/compose/components/compose_form.js
@@ -90,6 +90,7 @@ class ComposeForm extends ImmutablePureComponent {
selectedGifSrc: PropTypes.string,
isPro: PropTypes.bool,
hidePro: PropTypes.bool,
+ autoJoinGroup: PropTypes.bool,
}
static defaultProps = {
@@ -142,14 +143,14 @@ class ComposeForm extends ImmutablePureComponent {
// }
// Submit disabled:
- const { isSubmitting, isChangingUpload, isUploading, anyMedia, groupId } = this.props;
+ const { isSubmitting, isChangingUpload, isUploading, anyMedia, groupId, autoJoinGroup } = this.props
const fulltext = [this.props.spoilerText, countableText(this.props.text)].join('');
if (isSubmitting || isUploading || isChangingUpload || length(fulltext) > MAX_POST_CHARACTER_COUNT || (fulltext.length !== 0 && fulltext.trim().length === 0 && !anyMedia)) {
return;
}
- this.props.onSubmit(groupId, this.props.replyToId, this.context.router);
+ this.props.onSubmit(groupId, this.props.replyToId, this.context.router, autoJoinGroup)
}
onSuggestionsClearRequested = () => {
diff --git a/app/javascript/gabsocial/features/compose/containers/compose_form_container.js b/app/javascript/gabsocial/features/compose/containers/compose_form_container.js
index 9f336551..18ae2ac1 100644
--- a/app/javascript/gabsocial/features/compose/containers/compose_form_container.js
+++ b/app/javascript/gabsocial/features/compose/containers/compose_form_container.js
@@ -102,8 +102,8 @@ const mapDispatchToProps = (dispatch, { isStandalone }) => ({
dispatch(changeCompose(text, markdown, newReplyToId, isStandalone, position))
},
- onSubmit(groupId, replyToId, router) {
- dispatch(submitCompose(groupId, replyToId, router, isStandalone))
+ onSubmit(groupId, replyToId, router, autoJoinGroup) {
+ dispatch(submitCompose(groupId, replyToId, router, isStandalone, autoJoinGroup))
},
onClearSuggestions() {
diff --git a/app/javascript/gabsocial/features/introduction.js b/app/javascript/gabsocial/features/introduction.js
index 92671e24..8bedafd1 100644
--- a/app/javascript/gabsocial/features/introduction.js
+++ b/app/javascript/gabsocial/features/introduction.js
@@ -1,17 +1,22 @@
+import { Fragment } from 'react'
import ReactSwipeableViews from 'react-swipeable-views'
import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component'
-import { CX } from '../constants'
+import {
+ CX,
+ BREAKPOINT_EXTRA_SMALL,
+ GAB_COM_INTRODUCE_YOURSELF_GROUP_ID,
+} from '../constants'
import { me } from '../initial_state'
import { saveShownOnboarding } from '../actions/onboarding'
import { fetchGroups } from '../actions/groups'
+import { saveUserProfileInformation } from '../actions/user'
import {
changeCompose,
clearCompose,
} from '../actions/compose'
import { makeGetAccount } from '../selectors'
import Button from '../components/button'
-import DisplayName from '../components/display_name'
import Divider from '../components/divider'
import FileInput from '../components/file_input'
import GroupListItem from '../components/group_list_item'
@@ -21,12 +26,15 @@ import Image from '../components/image'
import Input from '../components/input'
import Text from '../components/text'
import ComposeFormContainer from './compose/containers/compose_form_container'
+import Responsive from './ui/util/responsive_component'
class SlideWelcome extends PureComponent {
render() {
return (
+
+
Gab is the home of free speech online and a place where users shape their own experience.
@@ -41,10 +49,6 @@ class SlideWelcome extends PureComponent {
- Now let's make your very first Gab post! Please introduce yourself to the Gab community. How did you hear about Gab? What are you interested in?
-
+ {
+ !submitted &&
+
+ Now let's make your very first Gab post! Please introduce yourself to the Gab community. How did you hear about Gab? What are you interested in?
+
-
+
-
-
-
+
+
+
+
+ }
+ {
+ submitted &&
+
+ Your gab was posted!
+
+ Click the checkbox in the top right to go to your home page.
+
+
+
+ }