Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add useful messages and call to actions for empty states on listens page #2039

Merged
merged 15 commits into from
Jul 6, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 9 additions & 2 deletions listenbrainz/webserver/static/css/follow.less
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,12 @@
}
}

.card-user-sn {
margin-bottom: 20px;
}

.follower-following-pills {
padding-bottom: 10px;
padding: 20px 0px;
}

.follower-following-list, .similar-users-list {
Expand All @@ -57,7 +61,6 @@
overflow-y: scroll;
border-radius: 2px;
box-shadow: inset 0px 11px 8px -10px #ccc;
margin-bottom: 20px;

> * {
display: flex;
Expand All @@ -75,3 +78,7 @@
}
}
}

.follower-following-empty, .similar-users-empty {
padding: 10px 20px;
}
41 changes: 41 additions & 0 deletions listenbrainz/webserver/static/css/listens-page.less
Original file line number Diff line number Diff line change
Expand Up @@ -601,4 +601,45 @@
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}

#spacer {
margin-top: 54px;
}

.empty-listens {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: @orange;

.empty-text {
text-align: center;
margin: 4px 0px 0px;
color: @asphalt;
}

.empty-message {
text-align: center;
}

.empty-action {
margin-top: 12px;
padding: 0px 8em;
text-align: center;
color: @asphalt;
}

@media (max-width: @screen-sm) {
.empty-action {
padding: 0px 6em;
}
}

@media (max-width: @screen-xs) {
.empty-action {
padding: 0px 3em;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { includes as _includes } from "lodash";

import Pill from "../components/Pill";
import UserListModalEntry from "./UserListModalEntry";
import GlobalAppContext from "../utils/GlobalAppContext";

export type FollowerFollowingModalProps = {
user: ListenBrainzUser;
Expand All @@ -23,6 +24,9 @@ export default class FollowerFollowingModal extends React.Component<
FollowerFollowingModalProps,
FollowerFollowingModalState
> {
static contextType = GlobalAppContext;
declare context: React.ContextType<typeof GlobalAppContext>;

constructor(props: FollowerFollowingModalProps) {
super(props);
this.state = {
Expand All @@ -40,8 +44,10 @@ export default class FollowerFollowingModal extends React.Component<
updateFollowingList,
followerList,
followingList,
user,
} = this.props;
const { activeMode } = this.state;
const { currentUser } = this.context;

const activeModeList =
activeMode === "follower" ? followerList : followingList;
Expand All @@ -50,13 +56,15 @@ export default class FollowerFollowingModal extends React.Component<
<div className="text-center follower-following-pills">
<div className="btn-group btn-group-justified" role="group">
<Pill
style={{ margin: "0px 6px" }}
MonkeyDo marked this conversation as resolved.
Show resolved Hide resolved
active={activeMode === "follower"}
type="secondary"
onClick={() => this.updateMode("follower")}
>
Followers ({followerList.length})
</Pill>
<Pill
style={{ margin: "0px 6px" }}
active={activeMode === "following"}
type="secondary"
onClick={() => this.updateMode("following")}
Expand All @@ -65,24 +73,46 @@ export default class FollowerFollowingModal extends React.Component<
</Pill>
</div>
</div>
<div className="follower-following-list">
{activeModeList.map((listEntry: string) => {
const formattedAsUser: ListenBrainzUser = {
name: listEntry,
};
return (
<UserListModalEntry
mode="follow-following"
key={listEntry}
user={formattedAsUser}
loggedInUserFollowsUser={loggedInUserFollowsUser(
formattedAsUser
)}
updateFollowingList={updateFollowingList}
/>
);
})}
</div>

{activeModeList.length === 0 ? (
<>
<hr style={{ margin: "0px 2em", borderTop: "1px solid #eee" }} />
MonkeyDo marked this conversation as resolved.
Show resolved Hide resolved
{activeMode === "follower" ? (
<div className="follower-following-empty text-center text-muted">
{user.name === currentUser?.name
? "You don't"
: `${user.name} doesn't`}{" "}
have any followers.
</div>
) : (
<div className="follower-following-empty text-center text-muted">
{user.name === currentUser?.name
? "You aren't"
: `${user.name} isn't`}{" "}
following anyone.
</div>
)}
</>
) : (
chinmaykunkikar marked this conversation as resolved.
Show resolved Hide resolved
<div className="follower-following-list">
{activeModeList.map((listEntry: string) => {
const formattedAsUser: ListenBrainzUser = {
name: listEntry,
};
return (
<UserListModalEntry
mode="follow-following"
key={listEntry}
user={formattedAsUser}
loggedInUserFollowsUser={loggedInUserFollowsUser(
formattedAsUser
)}
updateFollowingList={updateFollowingList}
/>
);
})}
</div>
)}
</>
);
}
Expand Down
41 changes: 26 additions & 15 deletions listenbrainz/webserver/static/js/src/follow/SimilarUsersModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,33 @@ const SimilarUsersModal = (props: SimilarUsersModalProps) => {

return (
<>
<h3 className="text-center">
Users similar to {user.name === currentUser?.name ? "you" : user.name}
<h3 className="text-center" style={{ marginTop: "10px" }}>
Similar Users
</h3>
<div className="similar-users-list">
{similarUsersList.map((listEntry: SimilarUser) => {
return (
<UserListModalEntry
mode="similar-users"
key={listEntry.name}
user={listEntry}
loggedInUserFollowsUser={loggedInUserFollowsUser(listEntry)}
updateFollowingList={updateFollowingList}
/>
);
})}
</div>
{similarUsersList.length === 0 ? (
chinmaykunkikar marked this conversation as resolved.
Show resolved Hide resolved
<>
<hr style={{ margin: "0px 2em", borderTop: "1px solid #eee" }} />
MonkeyDo marked this conversation as resolved.
Show resolved Hide resolved
<div className="similar-users-empty text-center text-muted">
Users with similar music tastes to{" "}
{user.name === currentUser?.name ? "you" : user.name} will appear
here.
</div>
</>
) : (
<div className="similar-users-list">
{similarUsersList.map((listEntry: SimilarUser) => {
return (
<UserListModalEntry
mode="similar-users"
key={listEntry.name}
user={listEntry}
loggedInUserFollowsUser={loggedInUserFollowsUser(listEntry)}
updateFollowingList={updateFollowingList}
/>
);
})}
</div>
)}
</>
);
};
Expand Down
31 changes: 18 additions & 13 deletions listenbrainz/webserver/static/js/src/follow/UserSocialNetwork.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { isEmpty, isNil } from "lodash";
import * as React from "react";
import Card from "../components/Card";

import GlobalAppContext from "../utils/GlobalAppContext";
import FollowerFollowingModal from "./FollowerFollowingModal";
Expand Down Expand Up @@ -148,19 +149,23 @@ export default class UserSocialNetwork extends React.Component<
const { followerList, followingList, similarUsersList } = this.state;
return (
<>
<FollowerFollowingModal
user={user}
followerList={followerList}
followingList={followingList}
loggedInUserFollowsUser={this.loggedInUserFollowsUser}
updateFollowingList={this.updateFollowingList}
/>
<SimilarUsersModal
user={user}
similarUsersList={similarUsersList}
loggedInUserFollowsUser={this.loggedInUserFollowsUser}
updateFollowingList={this.updateFollowingList}
/>
<Card className="card-user-sn hidden-xs hidden-sm">
<FollowerFollowingModal
user={user}
followerList={followerList}
followingList={followingList}
loggedInUserFollowsUser={this.loggedInUserFollowsUser}
updateFollowingList={this.updateFollowingList}
/>
</Card>
<Card className="card-user-sn hidden-xs hidden-sm">
<SimilarUsersModal
user={user}
similarUsersList={similarUsersList}
loggedInUserFollowsUser={this.loggedInUserFollowsUser}
updateFollowingList={this.updateFollowingList}
/>
</Card>
</>
);
}
Expand Down
19 changes: 11 additions & 8 deletions listenbrainz/webserver/static/js/src/listens/ListenCountCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ const ListenCountCard = (props: ListenCountCardProps) => {
if (listenCount) {
content = (
<div>
{isCurrentUser
? "You have listened to"
: `${user.name} has listened to`}
{isCurrentUser ? "You have" : `${user.name} has`} listened to
<hr />
{listenCount.toLocaleString()}
<br />
Expand All @@ -28,11 +26,16 @@ const ListenCountCard = (props: ListenCountCardProps) => {
);
} else {
content = (
<p>
{isCurrentUser
? "You have not listened to any songs so far"
: `${user.name} has not listened to any songs so far`}
</p>
<>
<p className="text-muted">
{isCurrentUser ? "Your" : `${user.name}'s`} listens count
</p>
<hr style={{ margin: "10px 0px" }} />
<div style={{ fontSize: "14px" }} className="text-muted">
{isCurrentUser ? "You haven't" : `${user.name} hasn't`} listened to
any songs.
MonkeyDo marked this conversation as resolved.
Show resolved Hide resolved
</div>
</>
);
}

Expand Down
34 changes: 23 additions & 11 deletions listenbrainz/webserver/static/js/src/user/Listens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { get, isEqual } from "lodash";
import { Integrations } from "@sentry/tracing";
import {
faPencilAlt,
faRecordVinyl,
faThumbtack,
faTrashAlt,
} from "@fortawesome/free-solid-svg-icons";
Expand Down Expand Up @@ -660,7 +661,7 @@ export default class Listens extends React.Component<
listens?.[listens?.length - 1]?.listened_at <= oldestListenTs;
return (
<div role="main">
<h3>Recent listens</h3>
{listens.length === 0 ? <div id="spacer" /> : <h3>Recent listens</h3>}
<div className="row">
<div className="col-md-4 col-md-push-8">
{playingNowListen && (
Expand All @@ -687,19 +688,30 @@ export default class Listens extends React.Component<
/>
)}
<ListenCountCard user={user} listenCount={listenCount} />
{user && (
<div
className="card hidden-xs hidden-sm"
style={{ paddingTop: "1.5em" }}
>
<UserSocialNetwork user={user} newAlert={newAlert} />
</div>
)}
{user && <UserSocialNetwork user={user} newAlert={newAlert} />}
</div>
<div className="col-md-8 col-md-pull-4">
{!listens.length && (
<div className="lead text-center">
<p>No listens yet</p>
<div className="empty-listens">
<FontAwesomeIcon icon={faRecordVinyl as IconProp} size="10x" />
<div className="lead empty-text">Empty record</div>
chinmaykunkikar marked this conversation as resolved.
Show resolved Hide resolved
<div className="empty-message text-muted">
{currentUser?.name === user?.name
? "You haven't"
: `${user.name} hasn't`}{" "}
listened to any songs yet.
</div>
{currentUser?.name === user?.name && (
<div className="empty-action">
Import <a href="/profile/import/">your listening history</a>{" "}
MonkeyDo marked this conversation as resolved.
Show resolved Hide resolved
and track your listens by{" "}
<a href="/profile/music-services/details/">
connecting to a music service
MonkeyDo marked this conversation as resolved.
Show resolved Hide resolved
</a>
, or use <a href="/add-data/">one of the players</a> to
MonkeyDo marked this conversation as resolved.
Show resolved Hide resolved
start submitting your listens.
</div>
)}
</div>
)}
{listens.length > 0 && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<FollowerFollowingModal /> renders 1`] = `"<div class=\\"text-center follower-following-pills\\"><div class=\\"btn-group btn-group-justified\\" role=\\"group\\"><button type=\\"button\\" style=\\"background: rgb(53, 48, 112); border: 2px solid #353070; font-weight: 700; color: white; border-radius: 24px; outline: none; padding: 3px 12px; margin: 2px 6px 12px 6px; box-sizing: border-box;\\">Followers (1)</button><button type=\\"button\\" style=\\"background: transparent; border: 2px solid #bbbbbb; color: rgb(187, 187, 187); border-radius: 24px; outline: none; padding: 3px 12px; margin: 2px 6px 12px 6px; box-sizing: border-box;\\">Following (1)</button></div></div><div class=\\"follower-following-list\\"><div><div><a href=\\"/user/foo/reports/?range=month\\" target=\\"_blank\\" rel=\\"noopener noreferrer\\">foo</a></div></div></div>"`;
exports[`<FollowerFollowingModal /> renders 1`] = `"<div class=\\"text-center follower-following-pills\\"><div class=\\"btn-group btn-group-justified\\" role=\\"group\\"><button type=\\"button\\" style=\\"background: rgb(53, 48, 112); border: 2px solid #353070; font-weight: 700; color: white; border-radius: 24px; outline: none; padding: 3px 12px; margin: 0px 6px; box-sizing: border-box;\\">Followers (1)</button><button type=\\"button\\" style=\\"background: transparent; border: 2px solid #bbbbbb; color: rgb(187, 187, 187); border-radius: 24px; outline: none; padding: 3px 12px; margin: 0px 6px; box-sizing: border-box;\\">Following (1)</button></div></div><div class=\\"follower-following-list\\"><div><div><a href=\\"/user/foo/reports/?range=month\\" target=\\"_blank\\" rel=\\"noopener noreferrer\\">foo</a></div></div></div>"`;
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<SimilarUsersModal /> renders 1`] = `"<h3 class=\\"text-center\\">Users similar to shivam-kapila</h3><div class=\\"similar-users-list\\"><div><div><a href=\\"/user/mr_monkey/reports/?range=month\\" target=\\"_blank\\" rel=\\"noopener noreferrer\\">mr_monkey</a></div></div></div>"`;
exports[`<SimilarUsersModal /> renders 1`] = `"<h3 class=\\"text-center\\" style=\\"margin-top: 10px;\\">Similar Users</h3><div class=\\"similar-users-list\\"><div><div><a href=\\"/user/mr_monkey/reports/?range=month\\" target=\\"_blank\\" rel=\\"noopener noreferrer\\">mr_monkey</a></div></div></div>"`;
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<UserSocialNetwork /> renders correctly 1`] = `"<div class=\\"text-center follower-following-pills\\"><div class=\\"btn-group btn-group-justified\\" role=\\"group\\"><button type=\\"button\\" style=\\"background: rgb(53, 48, 112); border: 2px solid #353070; font-weight: 700; color: white; border-radius: 24px; outline: none; padding: 3px 12px; margin: 2px 6px 12px 6px; box-sizing: border-box;\\">Followers (0)</button><button type=\\"button\\" style=\\"background: transparent; border: 2px solid #bbbbbb; color: rgb(187, 187, 187); border-radius: 24px; outline: none; padding: 3px 12px; margin: 2px 6px 12px 6px; box-sizing: border-box;\\">Following (0)</button></div></div><div class=\\"follower-following-list\\"></div><h3 class=\\"text-center\\">Users similar to bob</h3><div class=\\"similar-users-list\\"></div>"`;
exports[`<UserSocialNetwork /> renders correctly 1`] = `"<div class=\\"card card-user-sn hidden-xs hidden-sm\\"><div class=\\"text-center follower-following-pills\\"><div class=\\"btn-group btn-group-justified\\" role=\\"group\\"><button type=\\"button\\" style=\\"background: rgb(53, 48, 112); border: 2px solid #353070; font-weight: 700; color: white; border-radius: 24px; outline: none; padding: 3px 12px; margin: 0px 6px; box-sizing: border-box;\\">Followers (0)</button><button type=\\"button\\" style=\\"background: transparent; border: 2px solid #bbbbbb; color: rgb(187, 187, 187); border-radius: 24px; outline: none; padding: 3px 12px; margin: 0px 6px; box-sizing: border-box;\\">Following (0)</button></div></div><hr style=\\"margin: 0px 2em; border-top: 1px solid #eee;\\"><div class=\\"follower-following-empty text-center text-muted\\">bob doesn't have any followers.</div></div><div class=\\"card card-user-sn hidden-xs hidden-sm\\"><h3 class=\\"text-center\\" style=\\"margin-top: 10px;\\">Similar Users</h3><hr style=\\"margin: 0px 2em; border-top: 1px solid #eee;\\"><div class=\\"similar-users-empty text-center text-muted\\">Users with similar music tastes to bob will appear here.</div></div>"`;