Remove unused onboarding files (#4254)
* Remove commented code * Format onboarding SCSS * Remove old onboarding files * Remove tests for deleted React components * Remove outdated onboarding stories
This commit is contained in:
parent
691faf78ac
commit
742d50f524
34 changed files with 52 additions and 3464 deletions
|
|
@ -1,7 +1,9 @@
|
|||
@import 'variables';
|
||||
|
||||
#onboarding-container {
|
||||
min-height: calc(100vh - 350px);
|
||||
}
|
||||
|
||||
.onboarding-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
|
|
@ -40,4 +42,4 @@
|
|||
input[type='checkbox'] {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,12 +24,15 @@
|
|||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
background-position: center; /* Center the image */
|
||||
background-repeat: no-repeat; /* Do not repeat the image */
|
||||
/* Center the image */
|
||||
background-position: center;
|
||||
/* Do not repeat the image */
|
||||
background-repeat: no-repeat;
|
||||
|
||||
a {
|
||||
@include themeable(color, theme-anchor-color, #2e3b9e);
|
||||
}
|
||||
|
||||
.sticker-logo {
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
|
|
@ -39,6 +42,7 @@
|
|||
top: -10px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.onboarding-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -61,6 +65,7 @@
|
|||
width: 100%;
|
||||
height: 440px;
|
||||
margin-top: 5px;
|
||||
|
||||
h1 {
|
||||
margin-top: 15px;
|
||||
line-height: 1.1em;
|
||||
|
|
@ -83,12 +88,15 @@
|
|||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 15px;
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
font-size: 26px;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.25em;
|
||||
}
|
||||
|
|
@ -122,6 +130,7 @@
|
|||
|
||||
.about {
|
||||
width: 100%;
|
||||
|
||||
label,
|
||||
input,
|
||||
textarea {
|
||||
|
|
@ -161,6 +170,7 @@
|
|||
margin: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type='checkbox']:checked {
|
||||
@include themeable(background, theme-anchor-color, #66e2d5);
|
||||
}
|
||||
|
|
@ -200,15 +210,19 @@
|
|||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
||||
Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
||||
'Segoe UI Symbol';
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
width: 255px;
|
||||
}
|
||||
|
||||
&.tag-selected {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.onboarding-tag-follow-indicator {
|
||||
position: absolute;
|
||||
bottom: 22px;
|
||||
|
|
@ -221,6 +235,7 @@
|
|||
|
||||
.select-all-button-wrapper {
|
||||
width: 100%;
|
||||
|
||||
button {
|
||||
width: 300px;
|
||||
line-height: 1em;
|
||||
|
|
@ -243,6 +258,7 @@
|
|||
margin-right: 5px;
|
||||
position: relative;
|
||||
color: $black;
|
||||
|
||||
.onboarding-user-follow-status {
|
||||
position: absolute;
|
||||
color: #32a99c;
|
||||
|
|
@ -250,17 +266,21 @@
|
|||
top: 5px;
|
||||
font-size: 0.88em;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
p {
|
||||
font-weight: 400;
|
||||
height: 55px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
width: 365px;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
|
|
@ -270,9 +290,11 @@
|
|||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.user:active {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.badge-image {
|
||||
position: absolute;
|
||||
}
|
||||
|
|
@ -282,9 +304,11 @@
|
|||
flex-direction: column;
|
||||
height: 250px;
|
||||
overflow: auto;
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
a {
|
||||
background: #d9e7ff;
|
||||
padding: 15px 4px 0px 12px;
|
||||
|
|
@ -297,12 +321,14 @@
|
|||
font-weight: bold;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
height: 220px;
|
||||
margin: 4px 4px;
|
||||
text-align: left;
|
||||
padding: 20px 4px 0px 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.whatnext-emoji {
|
||||
display: none;
|
||||
text-align: center;
|
||||
|
|
@ -311,20 +337,24 @@
|
|||
left: 0;
|
||||
right: 0;
|
||||
font-size: 50px;
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.onboarding-previous-location {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
font-weight: bold;
|
||||
display: none;
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.6em;
|
||||
margin-top: -10px;
|
||||
|
|
@ -332,14 +362,17 @@
|
|||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.onboarding-main {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url('/assets/mobile-onboarding-background.png');
|
||||
background-size: cover;
|
||||
background-position: center; /* Center the image */
|
||||
background-repeat: no-repeat; /* Do not repeat the image */
|
||||
/* Center the image */
|
||||
background-position: center;
|
||||
/* Do not repeat the image */
|
||||
background-repeat: no-repeat;
|
||||
border: none;
|
||||
color: $black;
|
||||
}
|
||||
|
|
@ -347,7 +380,8 @@
|
|||
.onboarding-content {
|
||||
flex: 0 0 auto;
|
||||
|
||||
h1, h2 {
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: initial;
|
||||
}
|
||||
}
|
||||
|
|
@ -356,7 +390,7 @@
|
|||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: 650px) {
|
||||
.onboarding-main {
|
||||
font-size: 18px;
|
||||
|
|
@ -394,4 +428,4 @@
|
|||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,475 +0,0 @@
|
|||
import { h, Component } from 'preact';
|
||||
import OnboardingWelcome from './components/OnboardingWelcome';
|
||||
import OnboardingFollowTags from './components/OnboardingFollowTags';
|
||||
import OnboardingFollowUsers from './components/OnboardingFollowUsers';
|
||||
import OnboardingWelcomeThread from './components/OnboardingWelcomeThread';
|
||||
import cancelSvg from '../../assets/images/cancel.svg';
|
||||
import OnboardingProfile from './components/OnboardingProfile';
|
||||
|
||||
const getContentOfToken = token =>
|
||||
document.querySelector(`meta[name='${token}']`).content;
|
||||
const getFormDataAndAppend = array => {
|
||||
const form = new FormData();
|
||||
array.forEach(item => form.append(item.key, item.value));
|
||||
return form;
|
||||
};
|
||||
|
||||
class Onboarding extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.handleNextButton = this.handleNextButton.bind(this);
|
||||
this.handleBackButton = this.handleBackButton.bind(this);
|
||||
this.closeOnboarding = this.closeOnboarding.bind(this);
|
||||
this.handleFollowTag = this.handleFollowTag.bind(this);
|
||||
this.handleNextHover = this.handleNextHover.bind(this);
|
||||
this.updateUserData = this.updateUserData.bind(this);
|
||||
this.getUserTags = this.getUserTags.bind(this);
|
||||
this.handleCheckAllUsers = this.handleCheckAllUsers.bind(this);
|
||||
this.handleCheckUser = this.handleCheckUser.bind(this);
|
||||
this.handleSaveAllArticles = this.handleSaveAllArticles.bind(this);
|
||||
this.handleSaveArticle = this.handleSaveArticle.bind(this);
|
||||
this.handleProfileChange = this.handleProfileChange.bind(this);
|
||||
this.getUsersToFollow = this.getUsersToFollow.bind(this);
|
||||
this.state = {
|
||||
pageNumber: 1,
|
||||
showOnboarding: false,
|
||||
userData: null,
|
||||
allTags: [],
|
||||
users: [],
|
||||
checkedUsers: [],
|
||||
followRequestSent: false,
|
||||
articles: [],
|
||||
savedArticles: [],
|
||||
profileInfo: {},
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.updateUserData();
|
||||
this.getUserTags();
|
||||
document.getElementsByTagName('body')[0].classList.add('modal-open');
|
||||
}
|
||||
|
||||
getUserTags() {
|
||||
fetch('/api/tags/onboarding')
|
||||
.then(response => response.json())
|
||||
.then(json => {
|
||||
const followedTagNames = JSON.parse(
|
||||
document.body.getAttribute('data-user'),
|
||||
).followed_tag_names;
|
||||
function checkFollowingStatus(followedTags, jsonTags) {
|
||||
if (!followedTags || !followedTags.length) return jsonTags;
|
||||
const newJSON = jsonTags;
|
||||
jsonTags.map((tag, index) => {
|
||||
if (followedTags.includes(tag.name)) {
|
||||
newJSON[index].following = true;
|
||||
} else {
|
||||
newJSON[index].following = false;
|
||||
}
|
||||
return newJSON;
|
||||
});
|
||||
return newJSON;
|
||||
}
|
||||
const updatedJSON = checkFollowingStatus(followedTagNames, json);
|
||||
this.setState({ allTags: updatedJSON });
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
getUsersToFollow() {
|
||||
const { users } = this.state;
|
||||
fetch('/api/users?state=follow_suggestions', {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(json => {
|
||||
if (users.length === 0) {
|
||||
this.setState({ users: json, checkedUsers: json });
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
handleBulkFollowUsers(users) {
|
||||
const { checkedUsers, followRequestSent } = this.state;
|
||||
if (checkedUsers.length > 0 && !followRequestSent) {
|
||||
const csrfToken = getContentOfToken('csrf-token');
|
||||
const formData = getFormDataAndAppend([
|
||||
{ key: 'users', value: JSON.stringify(users) },
|
||||
]);
|
||||
|
||||
fetch('/api/follows', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-Token': csrfToken,
|
||||
},
|
||||
body: formData,
|
||||
credentials: 'same-origin',
|
||||
}).then(response => {
|
||||
if (response.ok) {
|
||||
this.setState({ followRequestSent: true });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleUserProfileSave() {
|
||||
const csrfToken = getContentOfToken('csrf-token');
|
||||
const { profileInfo } = this.state;
|
||||
const formData = getFormDataAndAppend([
|
||||
{ key: 'user', value: JSON.stringify(profileInfo) },
|
||||
]);
|
||||
fetch('/onboarding_update', {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'X-CSRF-Token': csrfToken,
|
||||
},
|
||||
body: formData,
|
||||
credentials: 'same-origin',
|
||||
});
|
||||
}
|
||||
|
||||
updateUserData() {
|
||||
const userData = JSON.parse(document.body.getAttribute('data-user'));
|
||||
const { saw_onboarding: sawOnboarding } = userData;
|
||||
this.setState({
|
||||
userData,
|
||||
showOnboarding: !sawOnboarding,
|
||||
});
|
||||
}
|
||||
|
||||
handleFollowTag(tag) {
|
||||
const csrfToken = getContentOfToken('csrf-token');
|
||||
const formData = getFormDataAndAppend([
|
||||
{ key: 'followable_type', value: 'Tag' },
|
||||
{ key: 'followable_id', value: tag.id },
|
||||
{ key: 'verb', value: tag.following ? 'unfollow' : 'follow' },
|
||||
]);
|
||||
|
||||
this.setState(prevState => ({
|
||||
allTags: prevState.allTags.map(currentTag => {
|
||||
const newTag = currentTag;
|
||||
if (currentTag.name === tag.name) {
|
||||
newTag.following = true;
|
||||
}
|
||||
return newTag;
|
||||
}),
|
||||
}));
|
||||
|
||||
fetch('/follows', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-Token': csrfToken,
|
||||
},
|
||||
body: formData,
|
||||
credentials: 'same-origin',
|
||||
})
|
||||
.then(response =>
|
||||
response.json().then(json => {
|
||||
this.setState(prevState => ({
|
||||
allTags: prevState.allTags.map(currentTag => {
|
||||
const newTag = currentTag;
|
||||
if (currentTag.name === tag.name) {
|
||||
newTag.following = json.outcome === 'followed';
|
||||
}
|
||||
return newTag;
|
||||
// add in optimistic rendering
|
||||
}),
|
||||
}));
|
||||
}),
|
||||
)
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
handleCheckAllUsers() {
|
||||
const { users, checkedUsers: prevCheckedUsers } = this.state;
|
||||
let checkedUsers = [];
|
||||
|
||||
if (prevCheckedUsers.length < users.length) {
|
||||
checkedUsers = users.slice();
|
||||
}
|
||||
this.setState({ checkedUsers });
|
||||
}
|
||||
|
||||
handleProfileChange(event) {
|
||||
const { name, value } = event.target;
|
||||
|
||||
this.setState(prevState => ({
|
||||
profileInfo: {
|
||||
...prevState.profileInfo,
|
||||
[name]: value,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
handleCheckUser(user) {
|
||||
const { checkedUsers } = this.state;
|
||||
const newCheckedUsers = checkedUsers.slice();
|
||||
const index = checkedUsers.indexOf(user);
|
||||
|
||||
if (index > -1) {
|
||||
newCheckedUsers.splice(index, 1);
|
||||
} else {
|
||||
newCheckedUsers.push(user);
|
||||
}
|
||||
this.setState({ checkedUsers: newCheckedUsers });
|
||||
}
|
||||
|
||||
handleSaveAllArticles() {
|
||||
const { savedArticles: prevSavedArticles, articles } = this.state;
|
||||
let savedArticles = [];
|
||||
if (prevSavedArticles.length < articles.length) {
|
||||
savedArticles = articles.slice();
|
||||
}
|
||||
this.setState({ savedArticles });
|
||||
}
|
||||
|
||||
handleSaveArticle(article) {
|
||||
const { savedArticles } = this.state;
|
||||
const newSavedArticles = savedArticles.slice();
|
||||
const index = newSavedArticles.indexOf(article);
|
||||
if (index > -1) {
|
||||
newSavedArticles.splice(index, 1);
|
||||
} else {
|
||||
newSavedArticles.push(article);
|
||||
}
|
||||
this.setState({ savedArticles: newSavedArticles });
|
||||
}
|
||||
|
||||
handleNextHover() {
|
||||
const { pageNumber, users } = this.state;
|
||||
if (pageNumber === 2 && users.length === 0) {
|
||||
this.getUsersToFollow();
|
||||
}
|
||||
}
|
||||
|
||||
handleNextButton() {
|
||||
const { users, articles, checkedUsers, profileInfo } = this.state;
|
||||
let { pageNumber } = this.state;
|
||||
if (pageNumber === 2 && users.length === 0 && articles.length === 0) {
|
||||
this.getUsersToFollow();
|
||||
}
|
||||
if (pageNumber < 5) {
|
||||
pageNumber += 1;
|
||||
this.setState({ pageNumber });
|
||||
if (pageNumber === 4 && checkedUsers.length > 0) {
|
||||
this.handleBulkFollowUsers(checkedUsers);
|
||||
} else if (pageNumber === 5) {
|
||||
this.handleUserProfileSave(profileInfo);
|
||||
}
|
||||
} else if (pageNumber === 5) {
|
||||
this.closeOnboarding();
|
||||
}
|
||||
}
|
||||
|
||||
handleBackButton() {
|
||||
const { pageNumber } = this.state;
|
||||
if (pageNumber > 1) {
|
||||
this.setState({ pageNumber: pageNumber - 1 });
|
||||
}
|
||||
}
|
||||
|
||||
closeOnboarding() {
|
||||
const { pageNumber } = this.state;
|
||||
document.getElementsByTagName('body')[0].classList.remove('modal-open');
|
||||
const csrfToken = getContentOfToken('csrf-token');
|
||||
const formData = getFormDataAndAppend([
|
||||
{ key: 'saw_onboarding', value: true },
|
||||
]);
|
||||
|
||||
if (window.ga && ga.create) {
|
||||
ga('send', 'event', 'click', 'close onboarding slide', pageNumber, null);
|
||||
}
|
||||
fetch('/onboarding_update', {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'X-CSRF-Token': csrfToken,
|
||||
},
|
||||
body: formData,
|
||||
credentials: 'same-origin',
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(json => {
|
||||
this.setState({ showOnboarding: json.outcome === 'onboarding opened' });
|
||||
// console.log('this is special')
|
||||
// console.log(this.state)
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
toggleOnboardingSlide() {
|
||||
const ONBOARDING = {
|
||||
WELCOME_SCREEN: 1,
|
||||
FOLLOW_TAG_SCREEN: 2,
|
||||
FOLLOW_USERS_SCREEN: 3,
|
||||
PROFILE_SCREEN: 4,
|
||||
WELCOME_THREAD: 5,
|
||||
};
|
||||
|
||||
const {
|
||||
pageNumber,
|
||||
userData,
|
||||
allTags,
|
||||
followedTags,
|
||||
users,
|
||||
checkedUsers,
|
||||
} = this.state;
|
||||
switch (pageNumber) {
|
||||
case ONBOARDING.WELCOME_SCREEN:
|
||||
return <OnboardingWelcome />;
|
||||
case ONBOARDING.FOLLOW_TAG_SCREEN:
|
||||
return (
|
||||
<OnboardingFollowTags
|
||||
userData={userData}
|
||||
allTags={allTags}
|
||||
followedTags={followedTags}
|
||||
handleFollowTag={this.handleFollowTag}
|
||||
/>
|
||||
);
|
||||
case ONBOARDING.FOLLOW_USERS_SCREEN:
|
||||
return (
|
||||
<OnboardingFollowUsers
|
||||
users={users}
|
||||
checkedUsers={checkedUsers}
|
||||
handleCheckUser={this.handleCheckUser}
|
||||
handleCheckAllUsers={this.handleCheckAllUsers}
|
||||
/>
|
||||
);
|
||||
case ONBOARDING.PROFILE_SCREEN:
|
||||
return <OnboardingProfile onChange={this.handleProfileChange} />;
|
||||
case ONBOARDING.WELCOME_THREAD:
|
||||
return <OnboardingWelcomeThread />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
renderCloseButton() {
|
||||
const btnClassName = 'close-button';
|
||||
return (
|
||||
<button
|
||||
className={btnClassName}
|
||||
type="button"
|
||||
onClick={this.closeOnboarding}
|
||||
>
|
||||
<img src={cancelSvg} alt="cancel button" />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
renderBackButton() {
|
||||
const { pageNumber } = this.state;
|
||||
if (pageNumber > 1) {
|
||||
return (
|
||||
<button
|
||||
className="button cta"
|
||||
type="button"
|
||||
onClick={this.handleBackButton}
|
||||
>
|
||||
BACK
|
||||
</button>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
renderNextButton() {
|
||||
const { pageNumber } = this.state;
|
||||
return (
|
||||
<button
|
||||
className="button cta"
|
||||
onClick={this.handleNextButton}
|
||||
onMouseOver={this.handleNextHover}
|
||||
onFocus={this.handleNextHover}
|
||||
type="button"
|
||||
>
|
||||
{pageNumber < 5 ? 'NEXT' : "LET'S GO"}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
renderPageIndicators() {
|
||||
const { pageNumber } = this.state;
|
||||
const firstIndicatorClassName =
|
||||
pageNumber === 2
|
||||
? 'pageindicator pageindicator--active'
|
||||
: 'pageindicator';
|
||||
const secondIndicatorClassName =
|
||||
pageNumber === 3
|
||||
? 'pageindicator pageindicator--active'
|
||||
: 'pageindicator';
|
||||
const thirdIndicatorClassName =
|
||||
pageNumber === 4
|
||||
? 'pageindicator pageindicator--active'
|
||||
: 'pageindicator';
|
||||
return (
|
||||
<div className="pageindicators">
|
||||
<div className={firstIndicatorClassName} />
|
||||
<div className={secondIndicatorClassName} />
|
||||
<div className={thirdIndicatorClassName} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderSloanMessage() {
|
||||
const messages = {
|
||||
1: 'WELCOME!',
|
||||
2: 'FOLLOW TAGS',
|
||||
3: 'FOLLOW DEVS',
|
||||
4: 'CREATE YOUR PROFILE',
|
||||
5: 'GET INVOLVED',
|
||||
};
|
||||
const { pageNumber } = this.state;
|
||||
|
||||
return messages[pageNumber];
|
||||
}
|
||||
|
||||
render() {
|
||||
const { showOnboarding } = this.state;
|
||||
if (!showOnboarding) return null;
|
||||
|
||||
return (
|
||||
<div className="global-modal" style={{ display: 'none' }}>
|
||||
<div className="global-modal-bg">{this.renderCloseButton()}</div>
|
||||
<div className="global-modal-inner">
|
||||
<div className="modal-header">
|
||||
<div className="triangle-isosceles">
|
||||
{this.renderSloanMessage()}
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<div id="sloan-mascot-onboarding-area" className="sloan-bar wiggle">
|
||||
<img
|
||||
src="https://res.cloudinary.com/practicaldev/image/fetch/s--iiubRINO--/c_imagga_scale,f_auto,fl_progressive,q_auto,w_300/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/sloan.png"
|
||||
className="sloan-img"
|
||||
alt="Sloan, the sloth mascot"
|
||||
/>
|
||||
</div>
|
||||
<div className="body-message">{this.toggleOnboardingSlide()}</div>
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<div className="modal-footer-left">{this.renderBackButton()}</div>
|
||||
<div className="modal-footer-center">
|
||||
{this.renderPageIndicators()}
|
||||
</div>
|
||||
<div className="modal-footer-right">{this.renderNextButton()}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Onboarding;
|
||||
|
|
@ -1,318 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
import { shallow, deep } from 'preact-render-spy';
|
||||
import fetch from 'jest-fetch-mock';
|
||||
import Onboarding from '../Onboarding';
|
||||
|
||||
global.fetch = fetch;
|
||||
|
||||
function flushPromises() {
|
||||
return new Promise(resolve => setImmediate(resolve));
|
||||
}
|
||||
|
||||
describe('<Onboarding />', () => {
|
||||
beforeEach(() => {
|
||||
document.body.setAttribute('data-user', null);
|
||||
fetch.resetMocks();
|
||||
});
|
||||
|
||||
const fakeTagResponse = JSON.stringify([
|
||||
{
|
||||
bg_color_hex: '#000000',
|
||||
id: 715,
|
||||
name: 'discuss',
|
||||
text_color_hex: '#ffffff',
|
||||
},
|
||||
{
|
||||
bg_color_hex: '#f7df1e',
|
||||
id: 6,
|
||||
name: 'javascript',
|
||||
text_color_hex: '#000000',
|
||||
},
|
||||
{
|
||||
bg_color_hex: '#2a2566',
|
||||
id: 630,
|
||||
name: 'career',
|
||||
text_color_hex: '#ffffff',
|
||||
},
|
||||
]);
|
||||
|
||||
const dataUser = JSON.stringify({
|
||||
followed_tag_names: ['javascript'],
|
||||
});
|
||||
|
||||
const fakeUsersToFollowResponse = JSON.stringify([
|
||||
{
|
||||
id: 1,
|
||||
name: 'Ben Halpern',
|
||||
profile_image_url: 'ben.jpg',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Krusty the Clown',
|
||||
profile_image_url: 'clown.jpg',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'dev.to staff',
|
||||
profile_image_url: 'dev.jpg',
|
||||
},
|
||||
]);
|
||||
|
||||
describe('when user is not logged in', () => {
|
||||
beforeEach(() => {
|
||||
fetch.once(fakeTagResponse);
|
||||
document.body.setAttribute(
|
||||
'data-user',
|
||||
JSON.stringify({ saw_onboarding: true }),
|
||||
);
|
||||
});
|
||||
|
||||
test('showOnboarding is false', () => {
|
||||
const context = shallow(<Onboarding />);
|
||||
expect(context.state('showOnboarding')).toEqual(false);
|
||||
});
|
||||
|
||||
test('nothing should be rendered', async () => {
|
||||
// TODO: dataUser should be {};
|
||||
const context = shallow(<Onboarding />);
|
||||
await flushPromises();
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Welcome page', () => {
|
||||
let context;
|
||||
beforeEach(async () => {
|
||||
fetch.once(fakeTagResponse);
|
||||
document.body.setAttribute('data-user', dataUser);
|
||||
context = deep(<Onboarding />);
|
||||
await flushPromises();
|
||||
});
|
||||
|
||||
test('renders properly', () => {
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('NEXT button should work', () => {
|
||||
context.find('.button').simulate('click');
|
||||
expect(context.state('pageNumber')).toEqual(2);
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// TODO: test closing button
|
||||
});
|
||||
|
||||
describe('Follow tag page', () => {
|
||||
let context;
|
||||
const meta = document.createElement('meta');
|
||||
meta.setAttribute('name', 'csrf-token');
|
||||
document.body.appendChild(meta);
|
||||
|
||||
beforeEach(async () => {
|
||||
fetch.once(fakeTagResponse);
|
||||
document.body.setAttribute('data-user', dataUser);
|
||||
context = deep(<Onboarding />);
|
||||
context.setState({ pageNumber: 2 });
|
||||
await flushPromises();
|
||||
});
|
||||
|
||||
test('renders properly', () => {
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('BACK button works', () => {
|
||||
context
|
||||
.find('.button')
|
||||
.at(0)
|
||||
.simulate('click');
|
||||
expect(context.state('pageNumber')).toEqual(1);
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('NEXT button works', async () => {
|
||||
fetch.once(fakeUsersToFollowResponse);
|
||||
context
|
||||
.find('.button')
|
||||
.at(1)
|
||||
.simulate('click');
|
||||
await flushPromises();
|
||||
expect(context.state('pageNumber')).toEqual(3);
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('each tag can be clicked', async () => {
|
||||
fetch.mockResponse(JSON.stringify({ outcome: 'followed' }));
|
||||
context.find('.onboarding-tag-link').map(tag => tag.simulate('click'));
|
||||
await flushPromises();
|
||||
expect(context.state('allTags').map(tag => tag.following)).toEqual([
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
]);
|
||||
});
|
||||
|
||||
test('each tag can be clicked (in weird combinations)', async () => {
|
||||
fetch.mockResponse(JSON.stringify({ outcome: 'followed' }));
|
||||
context
|
||||
.find('.onboarding-tag-link')
|
||||
.at(1)
|
||||
.simulate('click');
|
||||
await flushPromises();
|
||||
expect(context.state('allTags').map(tag => tag.following)).toEqual([
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Follow dev members page', () => {
|
||||
let context;
|
||||
beforeEach(async () => {
|
||||
fetch.once(fakeTagResponse);
|
||||
document.body.setAttribute('data-user', dataUser);
|
||||
context = deep(<Onboarding />);
|
||||
fetch.once(fakeUsersToFollowResponse);
|
||||
context.setState({ pageNumber: 2 });
|
||||
context
|
||||
.find('.button')
|
||||
.at(1)
|
||||
.simulate('click');
|
||||
await flushPromises();
|
||||
});
|
||||
|
||||
test('renders properly', () => {
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('BACK button works', () => {
|
||||
context
|
||||
.find('.button')
|
||||
.at(0)
|
||||
.simulate('click');
|
||||
expect(context.state('pageNumber')).toEqual(2);
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('NEXT button works', async () => {
|
||||
fetch.once(JSON.stringify({}));
|
||||
context
|
||||
.find('.button')
|
||||
.at(1)
|
||||
.simulate('click');
|
||||
await flushPromises();
|
||||
expect(context.state('pageNumber')).toEqual(4);
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('User info page', () => {
|
||||
let context;
|
||||
beforeEach(async () => {
|
||||
fetch.once(fakeTagResponse);
|
||||
document.body.setAttribute('data-user', dataUser);
|
||||
context = deep(<Onboarding />);
|
||||
context.setState({ pageNumber: 4 });
|
||||
await flushPromises();
|
||||
});
|
||||
|
||||
test('renders properly', () => {
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('NEXT button works', async () => {
|
||||
fetch.once({});
|
||||
context
|
||||
.find('.button')
|
||||
.at(1)
|
||||
.simulate('click');
|
||||
await flushPromises();
|
||||
expect(context.state('pageNumber')).toEqual(5);
|
||||
});
|
||||
|
||||
test('BACK button works', () => {
|
||||
context
|
||||
.find('.button')
|
||||
.at(0)
|
||||
.simulate('click');
|
||||
expect(context.state('pageNumber')).toEqual(3);
|
||||
});
|
||||
|
||||
test('forms can be filled and submitted', async () => {
|
||||
fetch.once({});
|
||||
const targets = [
|
||||
'summary',
|
||||
'location',
|
||||
'employment_title',
|
||||
'employer_name',
|
||||
'mostly_work_with',
|
||||
'currently_learning',
|
||||
];
|
||||
const findAndUpdate = target => {
|
||||
// TODO: we shouldn't have to add name. This might have to do with preact-render-spy
|
||||
const event = { target: { value: 'TEST', name: target } };
|
||||
context.find(<input name={target} />).simulate('change', event);
|
||||
};
|
||||
|
||||
targets.forEach(findAndUpdate);
|
||||
context
|
||||
.find('.button')
|
||||
.at(1)
|
||||
.simulate('click');
|
||||
await flushPromises();
|
||||
expect(context.state('pageNumber')).toEqual(5);
|
||||
const idealResult = {};
|
||||
targets.forEach(attr => {
|
||||
idealResult[attr] = 'TEST';
|
||||
});
|
||||
expect(context.state('profileInfo')).toEqual(idealResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Final page', () => {
|
||||
let context;
|
||||
beforeEach(async () => {
|
||||
fetch.once(fakeTagResponse);
|
||||
document.body.setAttribute('data-user', dataUser);
|
||||
const meta = document.createElement('meta');
|
||||
meta.setAttribute('name', 'csrf-token');
|
||||
document.body.appendChild(meta);
|
||||
context = deep(<Onboarding />);
|
||||
context.setState({ pageNumber: 5, profileInfo: { summary: 'hi there' } });
|
||||
await flushPromises();
|
||||
});
|
||||
|
||||
it('renders properly', () => {
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('special next button exists and should reroute user', async () => {
|
||||
fetch.once(JSON.stringify({ outcome: 'onboarding closed' }));
|
||||
const next = context.find('.button').at(1);
|
||||
expect(next.text()).toEqual("LET'S GO");
|
||||
next.simulate('click');
|
||||
await flushPromises();
|
||||
expect(context.state('pageNumber')).toEqual(5);
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('sends proper update on close', async () => {
|
||||
fetch.once(JSON.stringify({ outcome: 'onboarding closed' }));
|
||||
context
|
||||
.find('.button')
|
||||
.at(1)
|
||||
.simulate('click');
|
||||
await flushPromises();
|
||||
expect(context.state('showOnboarding')).toEqual(false);
|
||||
});
|
||||
|
||||
it('BACK button works', () => {
|
||||
context
|
||||
.find('.button')
|
||||
.at(0)
|
||||
.simulate('click');
|
||||
expect(context.state('pageNumber')).toEqual(4);
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -10,7 +10,8 @@ export const ItemListTags = ({ availableTags, selectedTags, onClick }) => {
|
|||
data-no-instant
|
||||
onClick={e => onClick(e, tag)}
|
||||
>
|
||||
#{tag}
|
||||
#
|
||||
{tag}
|
||||
</a>
|
||||
));
|
||||
return <div className="tags">{tagsHTML}</div>;
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
import PropTypes from 'prop-types';
|
||||
import { userPropTypes } from './common-prop-types';
|
||||
|
||||
const MAX_ARTICLE_DESCRIPTION_LENGTH = 75;
|
||||
|
||||
export const ARTICLE_PROP_TYPE = {
|
||||
user: userPropTypes,
|
||||
title: PropTypes.string.isRequired,
|
||||
description: PropTypes.string.isRequired,
|
||||
positive_reactions_count: PropTypes.number.isRequired,
|
||||
comments_count: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
const OnboardingArticle = ({ article, isSaved, onSaveArticle }) => (
|
||||
<div className="onboarding-user-list-row" key={article.user.id}>
|
||||
<div className="onboarding-user-list-key article">
|
||||
<h3>{article.title}</h3>
|
||||
<img src={article.user.profile_image_url} alt={article.user.name} />
|
||||
<span>{article.user.name}</span>
|
||||
<p>
|
||||
{article.description.length < MAX_ARTICLE_DESCRIPTION_LENGTH
|
||||
? article.description
|
||||
: `${article.description.substring(
|
||||
0,
|
||||
MAX_ARTICLE_DESCRIPTION_LENGTH,
|
||||
)}...`}
|
||||
</p>
|
||||
<div className="onboarding-article-engagement">
|
||||
<img
|
||||
src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/reactions-stack-4bb9c1e4b3e71b7aa135d6f9a5ef29a6494141da882edd4fa971a77abe13dbe7.png"
|
||||
alt="Reactions"
|
||||
/>
|
||||
{' '}
|
||||
{article.positive_reactions_count}
|
||||
<img
|
||||
src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/comments-bubble-7448082accd39cfe9db9b977f38fa6e8f8d26dc43e142c5d160400d6f952ee47.png"
|
||||
alt="Comments"
|
||||
/>
|
||||
{' '}
|
||||
{article.comments_count}
|
||||
</div>
|
||||
</div>
|
||||
<div className="onboarding-user-list-checkbox article">
|
||||
<button
|
||||
onClick={onSaveArticle}
|
||||
className={`article save-single ${isSaved ? 'saved' : ''}`}
|
||||
>
|
||||
{isSaved ? 'SAVED' : 'SAVE'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
OnboardingArticle.propTypes = {
|
||||
article: PropTypes.shape(ARTICLE_PROP_TYPE).isRequired,
|
||||
isSaved: PropTypes.bool.isRequired,
|
||||
onSaveArticle: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default OnboardingArticle;
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
import { h, Component } from 'preact';
|
||||
import PropTypes from 'prop-types';
|
||||
import OnboardingArticle, { ARTICLE_PROP_TYPE } from './OnboardingArticle';
|
||||
|
||||
class OnboardingArticles extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleAllClick = this.handleAllClick.bind(this);
|
||||
}
|
||||
|
||||
handleAllClick() {
|
||||
this.props.handleSaveAllArticles();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { articles, savedArticles, handleSaveArticle } = this.props;
|
||||
const onboardingArticles = articles.map(article => (
|
||||
<OnboardingArticle
|
||||
article={article}
|
||||
isSaved={savedArticles.indexOf(article) > -1}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onSaveArticle={handleSaveArticle.bind(this, article)}
|
||||
/>
|
||||
));
|
||||
const areAllSaved = savedArticles.length === articles.length;
|
||||
|
||||
return (
|
||||
<div className="onboarding-user-container">
|
||||
<div className="onboarding-user-cta">
|
||||
When you see an interesting post, you can
|
||||
{' '}
|
||||
<strong className="purple">SAVE</strong>
|
||||
{' '}
|
||||
it. To get started, here are
|
||||
pre-selected suggestions.
|
||||
</div>
|
||||
<div className="onboarding-user-list">
|
||||
<div className="onboarding-user-list-header onboarding-user-list-row">
|
||||
<div className="onboarding-user-list-key">Save All</div>
|
||||
<div className="onboarding-user-list-checkbox">
|
||||
<button
|
||||
onClick={this.handleAllClick}
|
||||
className={`article save-all ${areAllSaved ? 'saved' : ''}`}
|
||||
>
|
||||
{areAllSaved ? '✓' : '+'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="onboarding-user-list-body">{onboardingArticles}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
OnboardingArticles.propTypes = {
|
||||
articles: PropTypes.arrayOf(PropTypes.shape(ARTICLE_PROP_TYPE)).isRequired,
|
||||
savedArticles: PropTypes.arrayOf(PropTypes.shape(ARTICLE_PROP_TYPE))
|
||||
.isRequired,
|
||||
handleSaveArticle: PropTypes.func.isRequired,
|
||||
handleSaveAllArticles: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default OnboardingArticles;
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
import OnboardingTags from './OnboardingTags';
|
||||
|
||||
// component of page 2
|
||||
const OnboardingFollowTags = ({ userData, allTags, followedTags, handleFollowTag }) => (
|
||||
<OnboardingTags
|
||||
userData={userData}
|
||||
allTags={allTags}
|
||||
followedTags={followedTags}
|
||||
handleFollowTag={handleFollowTag}
|
||||
/>
|
||||
);
|
||||
|
||||
export default OnboardingFollowTags;
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
import OnboardingUsers from './OnboardingUsers';
|
||||
|
||||
const OnboardingFollowUsers = ({ users, checkedUsers, handleCheckUser, handleCheckAllUsers }) => (
|
||||
<OnboardingUsers
|
||||
users={users}
|
||||
checkedUsers={checkedUsers}
|
||||
handleCheckUser={handleCheckUser}
|
||||
handleCheckAllUsers={handleCheckAllUsers}
|
||||
/>
|
||||
);
|
||||
|
||||
export default OnboardingFollowUsers;
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
import { h, render, Component } from 'preact';
|
||||
|
||||
// page 1
|
||||
const OnboardingProfile = ({ onChange }) => {
|
||||
return (
|
||||
<div className="onboarding-profile-page">
|
||||
<div className="onboarding-user-cta">
|
||||
Tell the us a bit about yourself ❤️
|
||||
</div>
|
||||
<div className="onboarding-profile-question">What's your quick bio?</div>
|
||||
<input
|
||||
name="summary"
|
||||
placeholder="e.g. I'm a passionate hacker wizard unicorn ninja"
|
||||
maxLength="120"
|
||||
onChange={onChange}
|
||||
/>
|
||||
<div className="onboarding-profile-question">Where are you located?</div>
|
||||
<input
|
||||
name="location"
|
||||
placeholder="e.g. New York City"
|
||||
maxLength="60"
|
||||
onChange={onChange}
|
||||
/>
|
||||
<div className="onboarding-profile-question">What is your title?</div>
|
||||
<input
|
||||
name="employment_title"
|
||||
placeholder="e.g. Frontend developer"
|
||||
maxLength="60"
|
||||
onChange={onChange}
|
||||
/>
|
||||
<div className="onboarding-profile-question">Where do you work?</div>
|
||||
<input
|
||||
name="employer_name"
|
||||
placeholder="e.g. Google"
|
||||
maxLength="60"
|
||||
onChange={onChange}
|
||||
/>
|
||||
<div className="onboarding-profile-question">
|
||||
What are your core skills/languages?
|
||||
</div>
|
||||
<input
|
||||
name="mostly_work_with"
|
||||
placeholder="e.g. JavaScript and MongoDB"
|
||||
maxLength="200"
|
||||
onChange={onChange}
|
||||
/>
|
||||
<div className="onboarding-profile-question">
|
||||
What are you currently learning/playing with?
|
||||
</div>
|
||||
<input
|
||||
name="currently_learning"
|
||||
placeholder="e.g. Rust and Docker"
|
||||
maxLength="200"
|
||||
onChange={onChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OnboardingProfile;
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
import { h, Component } from 'preact';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class OnboardingSingleTag extends Component {
|
||||
propTypes = {
|
||||
onTagClick: PropTypes.func.isRequired,
|
||||
tag: PropTypes.objectOf().isRequired,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onClick = this.onClick.bind(this);
|
||||
}
|
||||
|
||||
onClick() {
|
||||
const { onTagClick, tag } = this.props;
|
||||
onTagClick(tag);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { tag } = this.props;
|
||||
const backgroundColor = tag.following ? tag.bg_color_hex : '';
|
||||
const textroundColor = tag.following ? tag.text_color_hex : '';
|
||||
return (
|
||||
<div
|
||||
className={`onboarding-tag-container${
|
||||
tag.following ? ' followed-tag' : ''
|
||||
}`}
|
||||
id={`onboarding-tag-container-${tag.name}`}
|
||||
style={`background: ${backgroundColor}`}
|
||||
>
|
||||
<a
|
||||
className="onboarding-tag-link"
|
||||
href="#0"
|
||||
style={`color:${textroundColor}`}
|
||||
onClick={this.onClick}
|
||||
>
|
||||
#{tag.name}
|
||||
</a>
|
||||
<a
|
||||
className="onboarding-tag-link-follow"
|
||||
href="#0"
|
||||
id={`onboarding-tag-link-follow-${tag.name}`}
|
||||
style={`color:${textroundColor}`}
|
||||
onClick={this.onClick}
|
||||
>
|
||||
{tag.following ? '✓' : '+'}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default OnboardingSingleTag;
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
import PropTypes from 'prop-types';
|
||||
import OnboardingSingleTag from './OnboardingSingleTag';
|
||||
|
||||
// page 2
|
||||
function OnboardingTags({ allTags, handleFollowTag }) {
|
||||
const tags = allTags.map(tag => {
|
||||
return (
|
||||
<OnboardingSingleTag
|
||||
key={tag.id}
|
||||
tag={tag}
|
||||
onTagClick={handleFollowTag.bind(this, tag)} // eslint-disable-line react/jsx-no-bind
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="tags-slide">
|
||||
<div className="onboarding-user-cta">Personalize your home feed</div>
|
||||
<div className="tags-col-container">{tags}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
OnboardingTags.propTypes = {
|
||||
handleFollowTag: PropTypes.func.isRequired,
|
||||
allTags: PropTypes.objectOf().isRequired,
|
||||
};
|
||||
|
||||
export default OnboardingTags;
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
import { h, render, Component } from 'preact';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class OnboardingUsers extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleAllClick = this.handleAllClick.bind(this);
|
||||
}
|
||||
|
||||
handleAllClick() {
|
||||
this.props.handleCheckAllUsers();
|
||||
}
|
||||
|
||||
render() {
|
||||
const followList = this.props.users.map(user => {
|
||||
return (
|
||||
<div className="onboarding-user-list-row" key={user.id}>
|
||||
<div className="onboarding-user-list-key">
|
||||
<img src={user.profile_image_url} alt={user.name} />
|
||||
<div>{user.name}</div>
|
||||
<div className="onboarding-user-list-row__summary">
|
||||
<em>{user.summary}</em>
|
||||
</div>
|
||||
</div>
|
||||
<div className="onboarding-user-list-checkbox">
|
||||
<button
|
||||
onClick={this.props.handleCheckUser.bind(this, user)}
|
||||
className={
|
||||
this.props.checkedUsers.indexOf(user) > -1 ? 'checked' : ''
|
||||
}
|
||||
>
|
||||
{this.props.checkedUsers.indexOf(user) > -1 ? '✓' : '+'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
const renderLoadingOrList = () => {
|
||||
if (this.props.users.length === 0) {
|
||||
return <div className="onboarding-user-loading">Loading...</div>;
|
||||
}
|
||||
return followList;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="onboarding-user-container">
|
||||
<div className="onboarding-user-cta">
|
||||
Here are some suggestions based on your interests
|
||||
</div>
|
||||
<div className="onboarding-user-list">
|
||||
<div className="onboarding-user-list-header">
|
||||
<div className="onboarding-user-list-key">Follow All</div>
|
||||
<div className="onboarding-user-list-checkbox">
|
||||
<button
|
||||
id="onboarding-user-follow-all-btn"
|
||||
onClick={this.handleAllClick}
|
||||
className={
|
||||
this.props.checkedUsers.length === this.props.users.length
|
||||
? 'checked'
|
||||
: ''
|
||||
}
|
||||
>
|
||||
{this.props.checkedUsers.length === this.props.users.length
|
||||
? '✓'
|
||||
: '+'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="onboarding-user-list-body">
|
||||
{renderLoadingOrList()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
OnboardingUsers.propTypes = {
|
||||
handleCheckUser: PropTypes.func.isRequired,
|
||||
handleCheckAllUsers: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default OnboardingUsers;
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
import { h, render, Component } from 'preact';
|
||||
|
||||
// page 1
|
||||
const OnboardingWelcome = () => {
|
||||
const messages = [
|
||||
'Thank you for joining the DEV Community.',
|
||||
'Keep up with the people and software trends you care about. ❤️',
|
||||
];
|
||||
|
||||
const specialMessage = "Let's get started!";
|
||||
|
||||
return (
|
||||
<div className="onboarding-initial-welcome">
|
||||
{messages.map(item => (
|
||||
<p>{item}</p>
|
||||
))}
|
||||
<p>
|
||||
<em>
|
||||
<strong className="green">{specialMessage}</strong>
|
||||
</em>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OnboardingWelcome;
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
|
||||
const OnboardingWelcomeThread = () => {
|
||||
const wrapInYellow = message => <strong className="yellow">{message}</strong>;
|
||||
|
||||
return (
|
||||
<div className="onboarding-final-message">
|
||||
<p>Software is driven by community.</p>
|
||||
<p>Don't hesitate to find a discussion and jump right in.</p>
|
||||
<p>
|
||||
<em className="green">Everyone is welcome!</em>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OnboardingWelcomeThread;
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import faker from 'faker';
|
||||
import GlobalModalWrapper from './GlobalModalWrapper';
|
||||
import OnboardingArticle from '../OnboardingArticle';
|
||||
import { defaultChildrenPropTypes } from '../common-prop-types';
|
||||
|
||||
const article = {
|
||||
user: {
|
||||
id: faker.internet.userName(),
|
||||
name: faker.name.firstName(),
|
||||
profile_image_url: './images/storm-trooper-33x33.png',
|
||||
},
|
||||
description: faker.random.words(5),
|
||||
title: faker.random.words(2),
|
||||
positive_reactions_count: 100,
|
||||
comments_count: 8,
|
||||
};
|
||||
|
||||
const commonProps = {
|
||||
article,
|
||||
isSaved: false,
|
||||
onSaveArticle: action('Saving article'),
|
||||
};
|
||||
|
||||
const ArticleWrapper = ({ children }) => (
|
||||
<div className="onboarding-user-container">
|
||||
<div className="onboarding-user-list">
|
||||
<div className="onboarding-user-list-body">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
ArticleWrapper.propTypes = {
|
||||
// Diabling linting below because of https://github.com/yannickcr/eslint-plugin-react/issues/1389
|
||||
// eslint-disable-next-line react/no-typos
|
||||
children: defaultChildrenPropTypes.isRequired,
|
||||
};
|
||||
|
||||
storiesOf('Onboarding/OnboardingArticle', module)
|
||||
.addDecorator(storyFn => (
|
||||
<GlobalModalWrapper>
|
||||
<ArticleWrapper>{storyFn()}</ArticleWrapper>
|
||||
</GlobalModalWrapper>
|
||||
))
|
||||
.add('Already saved article', () => (
|
||||
<OnboardingArticle
|
||||
{...commonProps}
|
||||
onSaveArticle={action('Unsaving article')}
|
||||
isSaved
|
||||
/>
|
||||
))
|
||||
.add('Short title', () => <OnboardingArticle {...commonProps} />)
|
||||
.add('Medium length title', () => (
|
||||
<OnboardingArticle
|
||||
{...commonProps}
|
||||
article={{ ...article, title: faker.random.words(10) }}
|
||||
/>
|
||||
))
|
||||
.add('Long title', () => (
|
||||
<OnboardingArticle
|
||||
{...commonProps}
|
||||
article={{ ...article, title: faker.random.words(15) }}
|
||||
/>
|
||||
))
|
||||
.add('Short description', () => (
|
||||
<OnboardingArticle
|
||||
{...commonProps}
|
||||
article={{ ...article, description: faker.random.words(5) }}
|
||||
/>
|
||||
))
|
||||
.add('Medium length description', () => (
|
||||
<OnboardingArticle
|
||||
{...commonProps}
|
||||
article={{ ...article, description: faker.random.words(10) }}
|
||||
/>
|
||||
))
|
||||
.add('Long description', () => (
|
||||
<OnboardingArticle
|
||||
{...commonProps}
|
||||
article={{ ...article, description: faker.random.words(20) }}
|
||||
/>
|
||||
))
|
||||
.add('No reactions/comments count', () => (
|
||||
<OnboardingArticle
|
||||
{...commonProps}
|
||||
article={{
|
||||
...article,
|
||||
positive_reactions_count: 0,
|
||||
comments_count: 0,
|
||||
}}
|
||||
/>
|
||||
))
|
||||
.add('10 reactions/comments', () => (
|
||||
<OnboardingArticle
|
||||
{...commonProps}
|
||||
article={{
|
||||
...article,
|
||||
positive_reactions_count: 10,
|
||||
comments_count: 10,
|
||||
}}
|
||||
/>
|
||||
))
|
||||
.add('999 reactions/comments', () => (
|
||||
<OnboardingArticle
|
||||
{...commonProps}
|
||||
article={{
|
||||
...article,
|
||||
positive_reactions_count: 999,
|
||||
comments_count: 999,
|
||||
}}
|
||||
/>
|
||||
))
|
||||
.add('9999 reactions/comments', () => (
|
||||
<OnboardingArticle
|
||||
{...commonProps}
|
||||
article={{
|
||||
...article,
|
||||
positive_reactions_count: 9999,
|
||||
comments_count: 9999,
|
||||
}}
|
||||
/>
|
||||
))
|
||||
.add('99999 reactions/comments', () => (
|
||||
<OnboardingArticle
|
||||
{...commonProps}
|
||||
article={{
|
||||
...article,
|
||||
positive_reactions_count: 99999,
|
||||
comments_count: 99999,
|
||||
}}
|
||||
/>
|
||||
))
|
||||
.add('999999 reactions/comments', () => (
|
||||
<OnboardingArticle
|
||||
{...commonProps}
|
||||
article={{
|
||||
...article,
|
||||
positive_reactions_count: 999999,
|
||||
comments_count: 999999,
|
||||
}}
|
||||
/>
|
||||
));
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import faker from 'faker';
|
||||
import { globalModalDecorator } from './story-decorators';
|
||||
import OnboardingArticles from '../OnboardingArticles';
|
||||
|
||||
const getArticles = (numberOfArticles = 5) =>
|
||||
new Array(numberOfArticles).fill('').map(() => ({
|
||||
user: {
|
||||
id: faker.internet.userName(),
|
||||
name: faker.name.firstName(),
|
||||
profile_image_url: './images/storm-trooper-33x33.png',
|
||||
},
|
||||
description: faker.random.words(5),
|
||||
title: faker.random.words(2),
|
||||
positive_reactions_count: faker.random.number(),
|
||||
comments_count: faker.random.number(),
|
||||
}));
|
||||
const unsavedArticles = getArticles();
|
||||
const commonProps = {
|
||||
articles: unsavedArticles,
|
||||
savedArticles: unsavedArticles.slice(),
|
||||
handleSaveArticle: action('Handling save article'),
|
||||
handleSaveAllArticles: action('Saving all articles'),
|
||||
};
|
||||
|
||||
storiesOf('Onboarding/OnboardingArticles', module)
|
||||
.addDecorator(globalModalDecorator)
|
||||
.add('All articles saved', () => <OnboardingArticles {...commonProps} />)
|
||||
.add('Some unsaved articles', () => {
|
||||
const { articles } = commonProps;
|
||||
const savedArticles = articles.slice(0, 1).concat(articles.slice(3));
|
||||
|
||||
return (
|
||||
<OnboardingArticles {...commonProps} savedArticles={savedArticles} />
|
||||
);
|
||||
})
|
||||
.add('20 articles articles', () => {
|
||||
const articles = getArticles(20);
|
||||
const savedArticles = articles.slice(0, 5).concat(articles.slice(10, 13));
|
||||
|
||||
return (
|
||||
<OnboardingArticles
|
||||
{...commonProps}
|
||||
articles={articles}
|
||||
savedArticles={savedArticles}
|
||||
/>
|
||||
);
|
||||
})
|
||||
.add('100 articles', () => {
|
||||
const articles = getArticles(100);
|
||||
const savedArticles = articles.slice(0, 5).concat(articles.slice(10, 13));
|
||||
|
||||
return (
|
||||
<OnboardingArticles
|
||||
{...commonProps}
|
||||
articles={articles}
|
||||
savedArticles={savedArticles}
|
||||
/>
|
||||
);
|
||||
})
|
||||
.add('500 articles', () => {
|
||||
const articles = getArticles(500);
|
||||
const savedArticles = articles.slice(0, 5).concat(articles.slice(10, 13));
|
||||
|
||||
return (
|
||||
<OnboardingArticles
|
||||
{...commonProps}
|
||||
articles={articles}
|
||||
savedArticles={savedArticles}
|
||||
/>
|
||||
);
|
||||
})
|
||||
.add('1000 articles', () => {
|
||||
const articles = getArticles(1000);
|
||||
const savedArticles = articles.slice(0, 5).concat(articles.slice(10, 13));
|
||||
|
||||
return (
|
||||
<OnboardingArticles
|
||||
{...commonProps}
|
||||
articles={articles}
|
||||
savedArticles={savedArticles}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { globalModalDecorator } from './story-decorators';
|
||||
import OnboardingWelcome from '../OnboardingWelcome';
|
||||
|
||||
storiesOf('OnboardingWelcome', module)
|
||||
.addDecorator(globalModalDecorator)
|
||||
.add('Default', () => <OnboardingWelcome />);
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { globalModalDecorator } from './story-decorators';
|
||||
import OnboardingWelcomeThread from '../OnboardingWelcomeThread';
|
||||
|
||||
storiesOf('OnboardingWelcomeThread', module)
|
||||
.addDecorator(globalModalDecorator)
|
||||
.add('Default', () => <OnboardingWelcomeThread />);
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
import render from 'preact-render-to-json';
|
||||
import OnboardingFollowTags from '../OnboardingFollowTags';
|
||||
|
||||
describe('<OnboardingFollowTags />', () => {
|
||||
it('renders properly when given a tag', () => {
|
||||
const userData = {};
|
||||
const allTags = [{
|
||||
bg_color_hex: '#000000',
|
||||
id: 715,
|
||||
name: 'discuss',
|
||||
text_color_hex: '#ffffff',
|
||||
}, {
|
||||
bg_color_hex: '#f7df1e',
|
||||
id: 6,
|
||||
name: 'javascript',
|
||||
text_color_hex: '#000000',
|
||||
}, {
|
||||
bg_color_hex: '#f7df1e',
|
||||
id: 6,
|
||||
name: 'javascript',
|
||||
text_color_hex: '#000000',
|
||||
}];
|
||||
const followedTags = {};
|
||||
const handleFollowTag = jest.fn();
|
||||
const tree = render(<OnboardingFollowTags
|
||||
userData={userData}
|
||||
allTags={allTags}
|
||||
followedTags={followedTags}
|
||||
handleFollowTag={handleFollowTag}
|
||||
/>);
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
import render from 'preact-render-to-json';
|
||||
import OnboardingFollowUsers from '../OnboardingFollowUsers';
|
||||
|
||||
describe('<OnboardingFollowUsers />', () => {
|
||||
it('renders properly when given users', () => {
|
||||
const users = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Ben Halpern',
|
||||
profile_image_url: 'ben.jpg',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Krusty the Clown',
|
||||
profile_image_url: 'clown.jpg',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'dev.to staff',
|
||||
profile_image_url: 'dev.jpg',
|
||||
},
|
||||
];
|
||||
const checkedUsers = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Ben Halpern',
|
||||
profile_image_url: 'ben.jpg',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Krusty the Clown',
|
||||
profile_image_url: 'clown.jpg',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'dev.to staff',
|
||||
profile_image_url: 'dev.jpg',
|
||||
},
|
||||
];
|
||||
const handleCheckUser = jest.fn();
|
||||
const handleCheckAllUsers = jest.fn();
|
||||
const tree = render(<OnboardingFollowUsers
|
||||
users={users}
|
||||
checkedUsers={checkedUsers}
|
||||
handleCheckUser={handleCheckUser}
|
||||
handleCheckAllUsers={handleCheckAllUsers}
|
||||
/>);
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
import { shallow } from 'preact-render-spy';
|
||||
import { render } from 'preact-render-to-json';
|
||||
import OnboardingSingleTag from '../OnboardingSingleTag';
|
||||
|
||||
describe('<OnboardingSingleTag />', () => {
|
||||
const followingTag = { following: true };
|
||||
const notFollowingTag = { following: false };
|
||||
|
||||
describe('when given a following tag', () => {
|
||||
it('renders correctly', () => {
|
||||
const context = render(<OnboardingSingleTag tag={followingTag} />);
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('responses to clicks', () => {
|
||||
const onClick = jest.fn();
|
||||
const context = shallow(<OnboardingSingleTag tag={followingTag} onTagClick={onClick} />);
|
||||
expect(context.find('a').text()).toEqual('#✓');
|
||||
context.find('.onboarding-tag-link-follow').simulate('click');
|
||||
expect(onClick).toHaveBeenCalledTimes(1);
|
||||
context.render(<OnboardingSingleTag tag={notFollowingTag} onTagClick={onClick} />);
|
||||
expect(context.find('a').text()).toEqual('#+');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when given a non-following tag', () => {
|
||||
it('renders correctly', () => {
|
||||
const context = render(<OnboardingSingleTag tag={notFollowingTag} />);
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('responses to clicks', () => {
|
||||
const onClick = jest.fn();
|
||||
const context = shallow(<OnboardingSingleTag tag={notFollowingTag} onTagClick={onClick} />);
|
||||
expect(context.find('a').text()).toEqual('#+');
|
||||
context.find('.onboarding-tag-link-follow').simulate('click');
|
||||
expect(onClick).toHaveBeenCalledTimes(1);
|
||||
context.render(<OnboardingSingleTag tag={followingTag} onTagClick={onClick} />);
|
||||
expect(context.find('a').text()).toEqual('#✓');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
import { shallow } from 'preact-render-spy';
|
||||
import { render } from 'preact-render-to-json';
|
||||
import OnboardingUsers from '../OnboardingUsers';
|
||||
|
||||
describe('<OnboardingUsers />', () => {
|
||||
const users = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Ben Halpern',
|
||||
profile_image_url: 'ben.jpg',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Krusty the Clown',
|
||||
profile_image_url: 'clown.jpg',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'dev.to staff',
|
||||
profile_image_url: 'dev.jpg',
|
||||
},
|
||||
];
|
||||
const checkedUsers = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Ben Halpern',
|
||||
profile_image_url: 'ben.jpg',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Krusty the Clown',
|
||||
profile_image_url: 'clown.jpg',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'dev.to staff',
|
||||
profile_image_url: 'dev.jpg',
|
||||
},
|
||||
];
|
||||
const handleCheckUser = jest.fn();
|
||||
const handleCheckAllUsers = jest.fn();
|
||||
|
||||
describe('when given users to follow', () => {
|
||||
it('renders correctly', () => {
|
||||
const context = render(<OnboardingUsers
|
||||
users={users}
|
||||
checkedUsers={checkedUsers}
|
||||
handleCheckUser={handleCheckUser}
|
||||
handleCheckAllUsers={handleCheckAllUsers}
|
||||
/>);
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('responds to clicking Follow All', () => {
|
||||
const context = shallow(<OnboardingUsers
|
||||
users={users}
|
||||
checkedUsers={checkedUsers}
|
||||
handleCheckUser={handleCheckUser}
|
||||
handleCheckAllUsers={handleCheckAllUsers}
|
||||
/>);
|
||||
expect(context.find('#onboarding-user-follow-all-btn').text()).toEqual('✓');
|
||||
context.find('#onboarding-user-follow-all-btn').simulate('click');
|
||||
expect(handleCheckAllUsers).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
import { render } from 'preact-render-to-json';
|
||||
import OnboardingWelcome from '../OnboardingWelcome';
|
||||
|
||||
describe('<OnboardingWelcome />', () => {
|
||||
it('renders correctly', () => {
|
||||
const tree = render(<OnboardingWelcome />);
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import { h } from 'preact';
|
||||
import { render } from 'preact-render-to-json';
|
||||
import OnboardingWelcomeThread from '../OnboardingWelcomeThread';
|
||||
|
||||
describe('<OnboardingWelcomeThread />', () => {
|
||||
it('renders correctly', () => {
|
||||
const tree = render(<OnboardingWelcomeThread />);
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<OnboardingFollowTags /> renders properly when given a tag 1`] = `
|
||||
<div
|
||||
class="tags-slide"
|
||||
>
|
||||
<div
|
||||
class="onboarding-user-cta"
|
||||
>
|
||||
Personalize your home feed
|
||||
</div>
|
||||
<div
|
||||
class="tags-col-container"
|
||||
>
|
||||
<div
|
||||
class="onboarding-tag-container"
|
||||
id="onboarding-tag-container-discuss"
|
||||
style="background: "
|
||||
>
|
||||
<a
|
||||
class="onboarding-tag-link"
|
||||
href="#0"
|
||||
onClick={[Function]}
|
||||
style="color:"
|
||||
>
|
||||
#discuss
|
||||
</a>
|
||||
<a
|
||||
class="onboarding-tag-link-follow"
|
||||
href="#0"
|
||||
id="onboarding-tag-link-follow-discuss"
|
||||
onClick={[Function]}
|
||||
style="color:"
|
||||
>
|
||||
+
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-tag-container"
|
||||
id="onboarding-tag-container-javascript"
|
||||
style="background: "
|
||||
>
|
||||
<a
|
||||
class="onboarding-tag-link"
|
||||
href="#0"
|
||||
onClick={[Function]}
|
||||
style="color:"
|
||||
>
|
||||
#javascript
|
||||
</a>
|
||||
<a
|
||||
class="onboarding-tag-link-follow"
|
||||
href="#0"
|
||||
id="onboarding-tag-link-follow-javascript"
|
||||
onClick={[Function]}
|
||||
style="color:"
|
||||
>
|
||||
+
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-tag-container"
|
||||
id="onboarding-tag-container-javascript"
|
||||
style="background: "
|
||||
>
|
||||
<a
|
||||
class="onboarding-tag-link"
|
||||
href="#0"
|
||||
onClick={[Function]}
|
||||
style="color:"
|
||||
>
|
||||
#javascript
|
||||
</a>
|
||||
<a
|
||||
class="onboarding-tag-link-follow"
|
||||
href="#0"
|
||||
id="onboarding-tag-link-follow-javascript"
|
||||
onClick={[Function]}
|
||||
style="color:"
|
||||
>
|
||||
+
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<OnboardingFollowUsers /> renders properly when given users 1`] = `
|
||||
<div
|
||||
class="onboarding-user-container"
|
||||
>
|
||||
<div
|
||||
class="onboarding-user-cta"
|
||||
>
|
||||
Here are some suggestions based on your interests
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list"
|
||||
>
|
||||
<div
|
||||
class="onboarding-user-list-header"
|
||||
>
|
||||
<div
|
||||
class="onboarding-user-list-key"
|
||||
>
|
||||
Follow All
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-checkbox"
|
||||
>
|
||||
<button
|
||||
class="checked"
|
||||
id="onboarding-user-follow-all-btn"
|
||||
onClick={[Function]}
|
||||
>
|
||||
✓
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-body"
|
||||
>
|
||||
<div
|
||||
class="onboarding-user-list-row"
|
||||
>
|
||||
<div
|
||||
class="onboarding-user-list-key"
|
||||
>
|
||||
<img
|
||||
alt="Ben Halpern"
|
||||
src="ben.jpg"
|
||||
/>
|
||||
<div>
|
||||
Ben Halpern
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-row__summary"
|
||||
>
|
||||
<em />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-checkbox"
|
||||
>
|
||||
<button
|
||||
onClick={[Function]}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-row"
|
||||
>
|
||||
<div
|
||||
class="onboarding-user-list-key"
|
||||
>
|
||||
<img
|
||||
alt="Krusty the Clown"
|
||||
src="clown.jpg"
|
||||
/>
|
||||
<div>
|
||||
Krusty the Clown
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-row__summary"
|
||||
>
|
||||
<em />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-checkbox"
|
||||
>
|
||||
<button
|
||||
onClick={[Function]}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-row"
|
||||
>
|
||||
<div
|
||||
class="onboarding-user-list-key"
|
||||
>
|
||||
<img
|
||||
alt="dev.to staff"
|
||||
src="dev.jpg"
|
||||
/>
|
||||
<div>
|
||||
dev.to staff
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-row__summary"
|
||||
>
|
||||
<em />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-checkbox"
|
||||
>
|
||||
<button
|
||||
onClick={[Function]}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<OnboardingSingleTag /> when given a following tag renders correctly 1`] = `
|
||||
<div
|
||||
class="onboarding-tag-container followed-tag"
|
||||
id="onboarding-tag-container-undefined"
|
||||
style="background: undefined"
|
||||
>
|
||||
<a
|
||||
class="onboarding-tag-link"
|
||||
href="#0"
|
||||
onClick={[Function]}
|
||||
style="color:undefined"
|
||||
>
|
||||
#
|
||||
</a>
|
||||
<a
|
||||
class="onboarding-tag-link-follow"
|
||||
href="#0"
|
||||
id="onboarding-tag-link-follow-undefined"
|
||||
onClick={[Function]}
|
||||
style="color:undefined"
|
||||
>
|
||||
✓
|
||||
</a>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<OnboardingSingleTag /> when given a non-following tag renders correctly 1`] = `
|
||||
<div
|
||||
class="onboarding-tag-container"
|
||||
id="onboarding-tag-container-undefined"
|
||||
style="background: "
|
||||
>
|
||||
<a
|
||||
class="onboarding-tag-link"
|
||||
href="#0"
|
||||
onClick={[Function]}
|
||||
style="color:"
|
||||
>
|
||||
#
|
||||
</a>
|
||||
<a
|
||||
class="onboarding-tag-link-follow"
|
||||
href="#0"
|
||||
id="onboarding-tag-link-follow-undefined"
|
||||
onClick={[Function]}
|
||||
style="color:"
|
||||
>
|
||||
+
|
||||
</a>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<OnboardingUsers /> when given users to follow renders correctly 1`] = `
|
||||
<div
|
||||
class="onboarding-user-container"
|
||||
>
|
||||
<div
|
||||
class="onboarding-user-cta"
|
||||
>
|
||||
Here are some suggestions based on your interests
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list"
|
||||
>
|
||||
<div
|
||||
class="onboarding-user-list-header"
|
||||
>
|
||||
<div
|
||||
class="onboarding-user-list-key"
|
||||
>
|
||||
Follow All
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-checkbox"
|
||||
>
|
||||
<button
|
||||
class="checked"
|
||||
id="onboarding-user-follow-all-btn"
|
||||
onClick={[Function]}
|
||||
>
|
||||
✓
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-body"
|
||||
>
|
||||
<div
|
||||
class="onboarding-user-list-row"
|
||||
>
|
||||
<div
|
||||
class="onboarding-user-list-key"
|
||||
>
|
||||
<img
|
||||
alt="Ben Halpern"
|
||||
src="ben.jpg"
|
||||
/>
|
||||
<div>
|
||||
Ben Halpern
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-row__summary"
|
||||
>
|
||||
<em />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-checkbox"
|
||||
>
|
||||
<button
|
||||
onClick={[Function]}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-row"
|
||||
>
|
||||
<div
|
||||
class="onboarding-user-list-key"
|
||||
>
|
||||
<img
|
||||
alt="Krusty the Clown"
|
||||
src="clown.jpg"
|
||||
/>
|
||||
<div>
|
||||
Krusty the Clown
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-row__summary"
|
||||
>
|
||||
<em />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-checkbox"
|
||||
>
|
||||
<button
|
||||
onClick={[Function]}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-row"
|
||||
>
|
||||
<div
|
||||
class="onboarding-user-list-key"
|
||||
>
|
||||
<img
|
||||
alt="dev.to staff"
|
||||
src="dev.jpg"
|
||||
/>
|
||||
<div>
|
||||
dev.to staff
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-row__summary"
|
||||
>
|
||||
<em />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="onboarding-user-list-checkbox"
|
||||
>
|
||||
<button
|
||||
onClick={[Function]}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<OnboardingWelcome /> renders correctly 1`] = `
|
||||
<div
|
||||
class="onboarding-initial-welcome"
|
||||
>
|
||||
<p>
|
||||
Thank you for joining the DEV Community.
|
||||
</p>
|
||||
<p>
|
||||
Keep up with the people and software trends you care about. ❤️
|
||||
</p>
|
||||
<p>
|
||||
<em>
|
||||
<strong
|
||||
class="green"
|
||||
>
|
||||
Let's get started!
|
||||
</strong>
|
||||
</em>
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<OnboardingWelcomeThread /> renders correctly 1`] = `
|
||||
<div
|
||||
class="onboarding-final-message"
|
||||
>
|
||||
<p>
|
||||
Software is driven by community.
|
||||
</p>
|
||||
<p>
|
||||
Don't hesitate to find a discussion and jump right in.
|
||||
</p>
|
||||
<p>
|
||||
<em
|
||||
class="green"
|
||||
>
|
||||
Everyone is welcome!
|
||||
</em>
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -118,7 +118,9 @@ class UnopenedChannelNotice extends Component {
|
|||
padding: '19px 5px 14px',
|
||||
}}
|
||||
>
|
||||
New Message from {channels}
|
||||
New Message from
|
||||
{' '}
|
||||
{channels}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,10 @@ export default function setupPusher(key, callbackObjects) {
|
|||
'client-initiatevideocall',
|
||||
callbackObjects.videoCallInitiated,
|
||||
);
|
||||
channel.bind('client-endvideocall', callbackObjects.videoCallEnded);
|
||||
|
||||
// channel.bind('pusher:subscription_succeeded', callbackObjects.channelSubscribed);
|
||||
channel.bind('client-endvideocall', callbackObjects.videoCallEnded);
|
||||
channel.bind('pusher:subscription_error', callbackObjects.channelError);
|
||||
|
||||
return channel;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue