feat: simplify user guiding triggers

- Change exposed handler names to correspond to performed action
- Simplify method of picking random survey on interaction with Editor
- Move GUI useEffect hook to WWW in IntlGUIWithProjectHandler
- Remove onClick property from ComposeComment component
This commit is contained in:
Aleksandar Shumakov 2024-08-22 15:28:54 +03:00
parent d97d3143e0
commit 6fb0e3491d
7 changed files with 111 additions and 146 deletions

7
package-lock.json generated
View file

@ -80,6 +80,7 @@
"lodash.merge": "4.6.2",
"lodash.mergewith": "4.6.2",
"lodash.omit": "3.1.0",
"lodash.sample": "4.2.1",
"lodash.uniqby": "4.7.0",
"mini-css-extract-plugin": "1.6.2",
"minilog": "2.1.0",
@ -17081,6 +17082,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/lodash.sample": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/lodash.sample/-/lodash.sample-4.2.1.tgz",
"integrity": "sha512-odCZufa8jYDBZQ+JOSePWRs+iApPdvIp3qAiKc9F22RdSCMLuUu60Jvgs2M6qMisKAeBZoumAkqDiGr9HDym/Q==",
"dev": true
},
"node_modules/lodash.throttle": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",

View file

@ -116,6 +116,7 @@
"lodash.mergewith": "4.6.2",
"lodash.omit": "3.1.0",
"lodash.uniqby": "4.7.0",
"lodash.sample": "4.2.1",
"mini-css-extract-plugin": "1.6.2",
"minilog": "2.1.0",
"pako": "0.2.8",

View file

@ -1,7 +1,12 @@
const api = require('./api');
const sample = require('lodash.sample');
const USER_GUIDING_ID = process.env.USER_GUIDING_ID;
const SCRIPT_ID = 'UserGuiding';
const AUTONOMY_SURVEY_ID = 3048;
const RELATIONSHIP_SURVEY_ID = 3049;
const JOY_SURVEY_ID = 3050;
const COMPETENCE_SURVEY_ID = 3045;
const EDITOR_INTERACTION_SURVEY_IDS = [COMPETENCE_SURVEY_ID, JOY_SURVEY_ID];
const CONDITIONS = {condition_list: [
'IsLoggedIn',
@ -9,78 +14,58 @@ const CONDITIONS = {condition_list: [
'NotMuted'
]};
const getUserGuidingSnippet = () => (
`
(function(g, u, i, d, e, s) {
g[e] = g[e] || [];
var f = u.getElementsByTagName(i)[0];
var k = u.createElement(i);
k.async = true;
k.src = 'https://static.userguiding.com/media/user-guiding-' + s + '-embedded.js';
f.parentNode.insertBefore(k, f);
if (g[d]) return;
var ug = g[d] = {
q: []
const USER_GUIDING_SNIPPET = `
(function(g, u, i, d, e, s) {
g[e] = g[e] || [];
var f = u.getElementsByTagName(i)[0];
var k = u.createElement(i);
k.async = true;
k.src = 'https://static.userguiding.com/media/user-guiding-' + s + '-embedded.js';
f.parentNode.insertBefore(k, f);
if (g[d]) return;
var ug = g[d] = {
q: []
};
ug.c = function(n) {
return function() {
ug.q.push([n, arguments])
};
ug.c = function(n) {
return function() {
ug.q.push([n, arguments])
};
};
var m = ['previewGuide', 'finishPreview', 'track', 'identify', 'hideChecklist', 'launchChecklist'];
for (var j = 0; j < m.length; j += 1) {
ug[m[j]] = ug.c(m[j]);
}
})(window, document, 'script', 'userGuiding', 'userGuidingLayer', '${USER_GUIDING_ID}');
`
);
const identifyUser = userId => {
window.userGuiding.identify(userId.toString());
};
const launchSurvey = surveyId => {
window.userGuiding.launchSurvey(surveyId);
};
const probabilityPicker = data => {
let generatedValue = Math.random();
for (const tmp of data) {
if (tmp.probability < generatedValue) {
generatedValue -= tmp.probability;
} else {
return tmp.prompt;
};
var m = ['previewGuide', 'finishPreview', 'track', 'identify', 'hideChecklist', 'launchChecklist'];
for (var j = 0; j < m.length; j += 1) {
ug[m[j]] = ug.c(m[j]);
}
}
};
})(window, document, 'script', 'userGuiding', 'userGuidingLayer', '${USER_GUIDING_ID}');
`;
const activateUserGuiding = (userId, callback) => {
if (USER_GUIDING_ID && !document.getElementById(SCRIPT_ID)) {
const userGuidingScript = document.createElement('script');
userGuidingScript.id = SCRIPT_ID;
userGuidingScript.innerHTML = getUserGuidingSnippet();
document.head.insertBefore(userGuidingScript, document.head.firstChild);
window.userGuidingSettings = {
disablePageViewAutoCapture: true
};
window.userGuidingLayer.push({
event: 'onload',
fn: () => identifyUser(userId)
});
window.userGuidingLayer.push({
event: 'onIdentificationComplete',
fn: callback
});
} else if (window.userGuiding) {
if (window.userGuiding) {
callback();
return;
}
const userGuidingScript = document.createElement('script');
userGuidingScript.innerHTML = USER_GUIDING_SNIPPET;
document.head.insertBefore(userGuidingScript, document.head.firstChild);
window.userGuidingSettings = {disablePageViewAutoCapture: true};
window.userGuidingLayer.push({
event: 'onload',
fn: () => window.userGuiding.identify(userId.toString())
});
window.userGuidingLayer.push({
event: 'onIdentificationComplete',
fn: callback
});
};
const displayUserGuiding = (userId, permissions, guideId, callback) => (
const attemptDisplayUserGuidingSurvey = (userId, permissions, guideId, callback) => {
if (!USER_GUIDING_ID || !process.env.SORTING_HAT_HOST) {
return;
}
api({
uri: '/user_guiding',
method: 'GET',
@ -97,66 +82,43 @@ const displayUserGuiding = (userId, permissions, guideId, callback) => (
return;
}
if (body?.result === "true") {
if (body?.result === 'true') {
activateUserGuiding(userId, callback);
}
})
);
const loadCompetenceSurvey = (userId, permissions) => {
const COMPETENCE_SURVEY_ID = 3045;
displayUserGuiding(
userId,
permissions,
COMPETENCE_SURVEY_ID,
() => launchSurvey(COMPETENCE_SURVEY_ID)
);
});
};
const loadAutonomySurvey = (userId, permissions) => {
const AUTONOMY_SURVEY_ID = 3048;
displayUserGuiding(
const onCommented = (userId, permissions) => {
attemptDisplayUserGuidingSurvey(
userId,
permissions,
AUTONOMY_SURVEY_ID,
() => launchSurvey(AUTONOMY_SURVEY_ID)
() => window.userGuiding.launchSurvey(AUTONOMY_SURVEY_ID)
);
};
const loadRelationshipsSurvey = (userId, permissions) => {
const RELATIONSHIP_SURVEY_ID = 3049;
displayUserGuiding(
const onProjectShared = (userId, permissions) => {
attemptDisplayUserGuidingSurvey(
userId,
permissions,
RELATIONSHIP_SURVEY_ID,
() => launchSurvey(RELATIONSHIP_SURVEY_ID)
() => window.userGuiding.launchSurvey(RELATIONSHIP_SURVEY_ID)
);
};
const loadJoySurvey = (userId, permissions) => {
const JOY_SURVEY_ID = 3050;
const onProjectLoaded = (userId, permissions) => {
const surveyId = sample(EDITOR_INTERACTION_SURVEY_IDS);
displayUserGuiding(
attemptDisplayUserGuidingSurvey(
userId,
permissions,
JOY_SURVEY_ID,
() => launchSurvey(JOY_SURVEY_ID)
surveyId,
() => window.userGuiding.launchSurvey(surveyId)
);
};
const loadRandomPrompt = (userId, permissions, data) => {
const prompt = probabilityPicker(data);
prompt(userId, permissions);
};
module.exports = {
loadCompetenceSurvey,
loadAutonomySurvey,
loadRelationshipsSurvey,
loadJoySurvey,
loadRandomPrompt
onProjectLoaded,
onCommented,
onProjectShared
};

View file

@ -360,7 +360,6 @@ class ComposeComment extends React.Component {
type="textarea"
value={this.state.message}
onInput={this.handleInput}
onClick={this.props.onClick}
autoFocus={this.props.isReply}
/>
<FlexRow className="compose-bottom-row">
@ -438,7 +437,6 @@ ComposeComment.propTypes = {
}),
onAddComment: PropTypes.func,
onCancel: PropTypes.func,
onClick: PropTypes.func,
parentId: PropTypes.number,
postURI: PropTypes.string,
user: PropTypes.shape({

View file

@ -34,7 +34,7 @@ const thumbnailUrl = require('../../lib/user-thumbnail');
const FormsyProjectUpdater = require('./formsy-project-updater.jsx');
const EmailConfirmationModal = require('../../components/modal/email-confirmation/modal.jsx');
const EmailConfirmationBanner = require('../../components/dropdown-banner/email-confirmation/banner.jsx');
const {loadAutonomySurvey} = require('../../lib/user-guiding.js');
const {onCommented} = require('../../lib/user-guiding.js');
const projectShape = require('./projectshape.jsx').projectShape;
require('./preview.scss');
@ -147,7 +147,7 @@ const PreviewPresentation = ({
userOwnsProject,
visibilityInfo
}) => {
const [interactionWithComment, setInteractionWithComment] = useState(false);
const [hasSubmittedComment, setHasSubmittedComment] = useState(false);
const shareDate = ((projectInfo.history && projectInfo.history.shared)) ? projectInfo.history.shared : '';
const revisedDate = ((projectInfo.history && projectInfo.history.modified)) ? projectInfo.history.modified : '';
const showInstructions = editable || projectInfo.instructions ||
@ -221,13 +221,14 @@ const PreviewPresentation = ({
</FlexRow>
);
const onCommentClick = useCallback(() => {
if (!interactionWithComment && user) {
setInteractionWithComment(!interactionWithComment);
loadAutonomySurvey(user.id, permissions);
const onAddCommentWrapper = useCallback(body => {
onAddComment(body);
if (!hasSubmittedComment && user) {
setHasSubmittedComment(true);
onCommented(user.id, permissions);
}
}, [interactionWithComment, user]);
}, [hasSubmittedComment, user]);
return (
<div className="preview">
{showEmailConfirmationModal && <EmailConfirmationModal
@ -623,8 +624,7 @@ const PreviewPresentation = ({
isLoggedIn ? (
isShared && <ComposeComment
postURI={`/proxy/comments/project/${projectId}`}
onAddComment={onAddComment}
onClick={onCommentClick}
onAddComment={onAddCommentWrapper}
/>
) : (
/* TODO add box for signing in to leave a comment */
@ -816,15 +816,7 @@ PreviewPresentation.propTypes = {
singleCommentId: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
socialOpen: PropTypes.bool,
user: PropTypes.shape({
id: PropTypes.number,
banned: PropTypes.bool,
vpn_required: PropTypes.bool,
username: PropTypes.string,
token: PropTypes.string,
thumbnailUrl: PropTypes.string,
dateJoined: PropTypes.string,
email: PropTypes.string,
classroomId: PropTypes.string
id: PropTypes.number
}),
userOwnsProject: PropTypes.bool,
visibilityInfo: PropTypes.shape({

View file

@ -26,10 +26,8 @@ const CanceledDeletionModal = require('../../components/login/canceled-deletion-
const NotAvailable = require('../../components/not-available/not-available.jsx');
const Meta = require('./meta.jsx');
const {
loadRelationshipsSurvey,
loadCompetenceSurvey,
loadJoySurvey,
loadRandomPrompt
onProjectShared,
onProjectLoaded
} = require('../../lib/user-guiding.js');
const sessionActions = require('../../redux/session.js');
@ -46,6 +44,25 @@ const IntlGUI = injectIntl(GUI.default);
const localStorageAvailable = 'localStorage' in window && window.localStorage !== null;
const xhr = require('xhr');
const {useEffect} = require('react');
const IntlGUIWithProjectHandler = ({user, permissions, ...props}) => {
useEffect(() => {
if (props.projectId && props.projectId !== '0') {
onProjectLoaded(user.id, permissions);
}
}, [props.projectId, user.id, permissions]);
return <IntlGUI {...props} />;
};
IntlGUIWithProjectHandler.propTypes = {
...GUI.propTypes,
user: PropTypes.shape({
id: PropTypes.number
}),
permissions: PropTypes.object
};
class Preview extends React.Component {
constructor (props) {
@ -89,7 +106,6 @@ class Preview extends React.Component {
'handleUpdateProjectId',
'handleUpdateProjectTitle',
'handleToggleComments',
'handleLoadRandomPrompt',
'initCounts',
'pushHistory',
'renderLogin',
@ -634,7 +650,7 @@ class Preview extends React.Component {
justRemixed: false,
justShared: true
});
loadRelationshipsSurvey(this.props.user.id, this.props.permissions);
onProjectShared(this.props.user.id, this.props.permissions);
}
handleShareAttempt () {
this.setState({
@ -702,18 +718,6 @@ class Preview extends React.Component {
this.props.user.token
);
}
handleLoadRandomPrompt () {
loadRandomPrompt(this.props.user.id, this.props.permissions, [
{
prompt: loadCompetenceSurvey,
probability: 0.5
},
{
prompt: loadJoySurvey,
probability: 0.5
}
]);
}
initCounts (favorites, loves) {
this.setState({
favoriteCount: favorites,
@ -863,7 +867,7 @@ class Preview extends React.Component {
</Page> :
<React.Fragment>
{showGUI && (
<IntlGUI
<IntlGUIWithProjectHandler
assetHost={this.props.assetHost}
authorId={this.props.authorId}
authorThumbnailUrl={this.props.authorThumbnailUrl}
@ -901,7 +905,8 @@ class Preview extends React.Component {
onUpdateProjectId={this.handleUpdateProjectId}
onUpdateProjectThumbnail={this.props.handleUpdateProjectThumbnail}
onUpdateProjectTitle={this.handleUpdateProjectTitle}
onLoadRandomPrompt={this.handleLoadRandomPrompt}
user={this.props.user}
permissions={this.props.permissions}
/>
)}
{this.props.registrationOpen && (

View file

@ -281,7 +281,7 @@ module.exports = {
'process.env.GTM_ENV_AUTH': `"${process.env.GTM_ENV_AUTH || ''}"`,
'process.env.GTM_ID': process.env.GTM_ID ? `"${process.env.GTM_ID}"` : null,
'process.env.USER_GUIDING_ID': `"${process.env.USER_GUIDING_ID || ''}"`,
'process.env.SORTING_HAT_HOST': `"${process.env.SORTING_HAT_HOST || 'http://127.0.0.1:7676'}"`
'process.env.SORTING_HAT_HOST': `"${process.env.SORTING_HAT_HOST || ''}"`
})
])
.concat(process.env.ANALYZE_BUNDLE === 'true' ? [