added profile page

This commit is contained in:
Martina 2021-11-30 13:46:00 -08:00
parent b2a5670a56
commit 538b931309
9 changed files with 211 additions and 13 deletions

View File

@ -5,8 +5,8 @@ import { css } from "@emotion/react";
const STYLES_EMPTY_STATE = css`
width: 100%;
height: 328px;
border: 1px solid ${Constants.semantic.borderGrayLight};
height: 50vh;
color: ${Constants.semantic.textGray};
display: flex;
align-items: center;
justify-content: center;

View File

@ -2,10 +2,14 @@ import * as React from "react";
import * as SVG from "~/common/svg";
import * as Styles from "~/common/styles";
import * as Typography from "~/components/system/components/Typography";
import * as Utilities from "~/common/utilities";
import ProfilePhoto from "~/components/core/ProfilePhoto";
import { css } from "@emotion/react";
import { useFilterContext } from "~/components/core/Filter/Provider";
import { Link } from "~/components/core/Link";
import { ButtonPrimary, ButtonSecondary } from "~/components/system/components/Buttons";
/* -------------------------------------------------------------------------------------------------
* Shared components between filters
@ -115,4 +119,115 @@ function Tags({ viewer, data, onAction, ...props }) {
);
}
export { Library, Tags };
function Profile({ viewer, data, page, onAction, ...props }) {
if (page.id === "NAV_SLATE") {
data = data.owner;
}
const [, { hidePopup }] = useFilterContext();
const isAuthenticated = !!viewer;
const isOwner = viewer?.id === data.id;
const [isFollowing, setIsFollowing] = React.useState(() =>
isOwner
? false
: !!viewer?.following.some((entry) => {
return entry.id === data.id;
})
);
React.useEffect(() => {
let updatedIsFollowing = isOwner
? false
: !!viewer?.following.some((entry) => {
return entry.id === data.id;
});
setIsFollowing(updatedIsFollowing);
}, [viewer?.following, data?.id]);
const handleFollow = async () => {
if (!isAuthenticated) {
Events.dispatchCustomEvent({ name: "slate-global-open-cta", detail: {} });
return;
}
await Actions.createSubscription({
userId: data.id,
});
};
const username = Utilities.getUserDisplayName(data);
let { twitterUsername, body } = data;
return (
<FilterSection style={{ marginBottom: "24px" }}>
<div css={Styles.VERTICAL_CONTAINER_CENTERED} style={{ gap: "12px" }}>
<ProfilePhoto user={data} style={{ borderRadius: "20px" }} size={80} />
<div css={Styles.VERTICAL_CONTAINER_CENTERED} style={{ gap: "4px" }}>
<Typography.H4 color="textGrayDark" style={{ marginTop: 10 }}>
{username}
</Typography.H4>
{twitterUsername && (
<div css={Styles.HORIZONTAL_CONTAINER_CENTERED} style={{ gap: "4px" }}>
<SVG.Twitter style={{ width: "16px" }} />
<Typography.P2 color="textGrayDark">{twitterUsername}</Typography.P2>
</div>
)}
{body && (
<Typography.P2 color="textGrayDark" nbrOflines={4} style={{ textAlign: "center" }}>
{body}
</Typography.P2>
)}
</div>
{isFollowing ? (
<ButtonSecondary
full
onClick={() => {
setIsFollowing(false);
handleFollow();
}}
>
Unfollow
</ButtonSecondary>
) : (
<ButtonPrimary
full
onClick={() => {
setIsFollowing(true);
handleFollow();
}}
>
Follow
</ButtonPrimary>
)}
</div>
</FilterSection>
);
}
function ProfileTags({ viewer, data, page, onAction, ...props }) {
const [, { hidePopup }] = useFilterContext();
let user = data;
if (page.id === "NAV_SLATE") {
user = data.owner;
}
return (
<FilterSection {...props}>
{user?.slates?.map((slate) => (
<FilterButton
key={slate.id}
href={`/$/slate/${slate.id}`}
isSelected={slate.id === data?.id}
onAction={onAction}
Icon={slate.isPublic ? SVG.Hash : SVG.SecurityLock}
onClick={hidePopup}
>
{slate.slatename}
</FilterButton>
))}
</FilterSection>
);
}
export { Library, Tags, Profile, ProfileTags };

View File

@ -61,6 +61,24 @@ export function Sidebar({ viewer, onAction, data, page, isMobile }) {
if (!sidebarState.isVisible || isMobile) return null;
if (
(page.id === "NAV_SLATE" && data?.ownerId !== viewer?.id) ||
(page.id === "NAV_PROFILE" && data?.id !== viewer?.id)
) {
return (
<div css={STYLES_SIDEBAR_FILTER_WRAPPER}>
<Filters.Profile page={page} data={data} viewer={viewer} onAction={onAction} />
<Filters.ProfileTags
page={page}
onAction={onAction}
data={data}
viewer={viewer}
style={{ marginTop: 12 }}
/>
</div>
);
}
return (
<div css={STYLES_SIDEBAR_FILTER_WRAPPER}>
<Filters.Library page={page} onAction={onAction} />

View File

@ -12,6 +12,7 @@ import { ButtonPrimary, ButtonSecondary } from "~/components/system/components/B
import { SecondaryTabGroup } from "~/components/core/TabGroup";
import { LoaderSpinner } from "~/components/system/components/Loaders";
import DataView from "~/components/core/DataView";
import ProcessedText from "~/components/core/ProcessedText";
import EmptyState from "~/components/core/EmptyState";
import ProfilePhoto from "~/components/core/ProfilePhoto";
@ -300,6 +301,24 @@ export default class Profile extends React.Component {
const showStatusIndicator = this.props.isAuthenticated;
return (
<div>
{this.props.data.slates?.length && (
<DataView
key="scene-files-folder"
type="collection"
collection={this.props.data.slates[0]}
onAction={this.props.onAction}
viewer={this.props.viewer}
items={this.props.data.slates[0].objects}
view={"grid"}
isOwner={isOwner}
page={this.props.page}
/>
)}
</div>
);
return (
<div>
<div css={STYLES_PROFILE_BACKGROUND}>

View File

@ -42,7 +42,17 @@ export default async (req, res) => {
});
}
slate.user = owner;
let slates = await Data.getSlatesByUserId({
ownerId: owner.id,
// includeFiles: true,
publicOnly: true,
});
if (slates && !slates.error) {
owner.slates = slates;
}
slate.owner = owner;
return res.status(200).send({
decorator: "SERVER_GET_SERIALIZED_SLATE",

View File

@ -42,7 +42,7 @@ export default async (req, res) => {
let slates = await Data.getSlatesByUserId({
ownerId: user.id,
includeFiles: true,
// includeFiles: true,
publicOnly: true,
});

View File

@ -9,6 +9,7 @@ import * as SVG from "~/common/svg";
import { css } from "@emotion/react";
import { LoaderSpinner } from "~/components/system/components/Loaders";
import DataView from "~/components/core/DataView";
import ScenePage from "~/components/core/ScenePage";
import Profile from "~/components/core/Profile";
import EmptyState from "~/components/core/EmptyState";
@ -22,6 +23,15 @@ const STYLES_LOADER = css`
width: 100%;
`;
const STYLES_DATAVIEWER_WRAPPER = (theme) => css`
width: 100%;
min-height: calc(100vh - ${theme.sizes.filterNavbar}px);
padding: calc(20px + ${theme.sizes.filterNavbar}px) 24px 44px;
@media (max-width: ${theme.sizes.mobile}px) {
padding: calc(31px + ${theme.sizes.filterNavbar}px) 16px 44px;
}
`;
export default class SceneProfile extends React.Component {
state = {
notFound: false,
@ -135,6 +145,7 @@ export default class SceneProfile extends React.Component {
// };
render() {
const viewer = this.props.viewer;
let user = this.props.data;
if (!user) {
return (
@ -151,6 +162,7 @@ export default class SceneProfile extends React.Component {
</WebsitePrototypeWrapper>
);
}
const isOwner = user.id === viewer.id;
let name = user.name || `@${user.username}`;
let description, title;
const image = user.photo;
@ -172,13 +184,28 @@ export default class SceneProfile extends React.Component {
url={`${Constants.hostname}${this.props.page.pathname}`}
image={image}
>
<Profile
<div css={STYLES_DATAVIEWER_WRAPPER}>
{user.library?.length ? (
<DataView
key="scene-files-folder"
isOwner={this.props.viewer.id === this.props.user.id}
items={user.library}
onAction={this.props.onAction}
viewer={this.props.viewer}
page={this.props.page}
view="grid"
/>
) : (
<EmptyState>This user doesn't have any public content</EmptyState>
)}
</div>
{/* <Profile
{...this.props}
user={user}
isOwner={this.props.viewer ? user.id === this.props.viewer.id : false}
isAuthenticated={this.props.viewer !== null}
key={user.id}
/>
/> */}
</WebsitePrototypeWrapper>
);

View File

@ -411,7 +411,7 @@ class SlatePage extends React.Component {
};
render() {
const { user, name, objects, body, isPublic, ownerId } = this.props.data;
const { owner: user, name, objects, body, isPublic, ownerId } = this.props.data;
const isOwner = this.props.viewer ? ownerId === this.props.viewer.id : false;
return (

View File

@ -292,7 +292,7 @@ app.prepare().then(async () => {
const slates = await Data.getSlatesByUserId({
ownerId: user.id,
includeFiles: true,
// includeFiles: true,
publicOnly: true,
});
@ -401,20 +401,29 @@ app.prepare().then(async () => {
return res.redirect("/_/404");
}
const user = await Data.getUserById({
const owner = await Data.getUserById({
id: slate.ownerId,
sanitize: true,
});
if (!user) {
if (!owner) {
return res.redirect("/_/404");
}
if (user.error) {
if (owner.error) {
return res.redirect("/_/404");
}
slate.user = user;
let slates = await Data.getSlatesByUserId({
ownerId: owner.id,
publicOnly: true,
});
if (slates && !slates.error) {
owner.slates = slates;
}
slate.owner = owner;
return app.render(req, res, "/_", {
viewer,