use new tab methods

This commit is contained in:
srgooglo 2022-06-05 11:09:54 +02:00
parent 089f0826a8
commit 2aa5c70de6
2 changed files with 163 additions and 101 deletions

View File

@ -9,6 +9,63 @@ import { Session, User } from "models"
import "./index.less" import "./index.less"
const TabsComponent = {
"posts": React.memo((props) => {
return <div className="posts">
<PostsFeed
fromUserId={props.state.user._id}
/>
</div>
}),
"followers": React.memo((props) => {
return <FollowersList
followers={props.state.followers}
/>
}),
"details": React.memo((props) => {
return <div id="statistics" className="statistics">
<div>
<span><Icons.Users /> {props.state.followers.length} Followers</span>
</div>
<div>
<span><Icons.FileText /> 0 Posts</span>
</div>
<div>
<span>Joined at {moment(new Date(Number(props.state.user.createdAt))).format("YYYY")}</span>
</div>
</div>
})
}
const TabRender = React.memo((props) => {
const [transitionActive, setTransitionActive] = React.useState(false)
const [activeKey, setActiveKey] = React.useState(props.renderKey)
React.useEffect(() => {
setTransitionActive(true)
setTimeout(() => {
setActiveKey(props.renderKey)
setTimeout(() => {
setTransitionActive(false)
}, 100)
}, 100)
}, [props.renderKey])
const Tab = TabsComponent[activeKey]
if (!Tab) {
return <h1>Nothing to see here...</h1>
}
return <div className={classnames("fade-opacity-active", { "fade-opacity-leave": transitionActive })}>
<Tab {...props} />
</div>
})
// TODO: profileCard scroll effect (Hide description and wrap with entire body when cover image is not visible)
export default class Account extends React.Component { export default class Account extends React.Component {
state = { state = {
requestedUser: null, requestedUser: null,
@ -20,7 +77,7 @@ export default class Account extends React.Component {
isFollowed: false, isFollowed: false,
transitionActive: false, transitionActive: false,
activeKey: "posts", tabActiveKey: "posts",
isNotExistent: false, isNotExistent: false,
} }
@ -93,13 +150,12 @@ export default class Account extends React.Component {
onClickFollow = async () => { onClickFollow = async () => {
const result = await this.api.put.followUser({ const result = await this.api.put.followUser({
username: this.state.requestedUser, username: this.state.requestedUser,
}) }).catch((error) => {
.catch((error) => { console.error(error)
console.error(error) antd.message.error(error.message)
antd.message.error(error.message)
return false return false
}) })
await this.setState({ await this.setState({
isFollowed: result.following, isFollowed: result.following,
@ -108,25 +164,20 @@ export default class Account extends React.Component {
} }
handlePageTransition = (key) => { handlePageTransition = (key) => {
if (this.state.activeKey === key) { if (typeof key !== "string") {
console.error("Cannot handle page transition. Invalid key, only valid passing string", key)
return
}
key = key.toLowerCase()
if (this.state.tabActiveKey === key) {
return false return false
} }
this.setState({ this.setState({
transitionActive: true, tabActiveKey: key
}) })
setTimeout(() => {
this.setState({
activeKey: key
})
setTimeout(() => {
this.setState({
transitionActive: false,
})
}, 100)
}, 100)
} }
render() { render() {
@ -145,86 +196,61 @@ export default class Account extends React.Component {
return <Skeleton /> return <Skeleton />
} }
return ( return <div className="accountProfile">
<div className="accountProfile"> {user.cover && <div className="cover" style={{ backgroundImage: `url("${user.cover}")` }} />}
{user.cover && <div className="cover" style={{ backgroundImage: `url("${user.cover}")` }} />} <div className="profileCard">
<div className="profileCard"> <div className="basicData">
<div className="basicData"> <div className="title">
<div className="title"> <div className="field">
<div className="field"> <div className="avatar">
<div className="avatar"> <Image
<Image alt="ProfileImage"
alt="ProfileImage" src={user.avatar}
src={user.avatar}
/>
</div>
</div>
<div className="field">
<div>
<h1>{user.fullName ?? user.username}</h1>
{user.verified && <Icons.verifiedBadge />}
</div>
<span>@{user.username}</span>
</div>
</div>
{!this.state.isSelf && <div>
<FollowButton
count={this.state.followers.length}
onClick={this.onClickFollow}
followed={this.state.isFollowed}
/>
</div>}
</div>
<div className="description">
<p>
{user.description}
</p>
</div>
</div>
<antd.Tabs
className="tabs"
type="card"
activeKey={this.state.activeKey}
onTabClick={this.handlePageTransition}
destroyInactiveTabPane
>
<antd.Tabs.TabPane tab={<><Icons.Inbox /> Posts</>} key="posts">
<div className={classnames("fade-opacity-active", { "fade-opacity-leave": this.state.transitionActive })}>
<div className="posts">
<PostsFeed
fromUserId={user._id}
/> />
</div> </div>
</div> </div>
</antd.Tabs.TabPane>
<antd.Tabs.TabPane tab={<><Icons.Users /> Followers</>} key="followers"> <div className="field">
<div className={classnames("fade-opacity-active", { "fade-opacity-leave": this.state.transitionActive })}> <div>
<FollowersList <h1>{user.fullName ?? user.username}</h1>
followers={this.state.followers} {user.verified && <Icons.verifiedBadge />}
/>
</div>
</antd.Tabs.TabPane>
<antd.Tabs.TabPane tab={<><Icons.Info /> Details</>} key="details">
<div className={classnames("fade-opacity-active", { "fade-opacity-leave": this.state.transitionActive })}>
<div id="statistics" className="statistics">
<div>
<span><Icons.Users /> {this.state.followers.length} Followers</span>
</div>
<div>
<span><Icons.FileText /> 0 Posts</span>
</div>
<div>
<span>Joined at {moment(new Date(Number(user.createdAt))).format("YYYY")}</span>
</div>
</div> </div>
<span>@{user.username}</span>
</div> </div>
</antd.Tabs.TabPane> </div>
</antd.Tabs>
{!this.state.isSelf && <div>
<FollowButton
count={this.state.followers.length}
onClick={this.onClickFollow}
followed={this.state.isFollowed}
/>
</div>}
</div>
<div className="description">
<p>
{user.description}
</p>
</div>
<div className="switchTab">
<antd.Segmented
//block
options={Object.keys(TabsComponent).map((key) => key.toTitleCase())}
value={this.state.tabActiveKey.toTitleCase()}
onChange={this.handlePageTransition}
/>
</div>
</div> </div>
)
<div className="tabContent">
<TabRender
renderKey={this.state.tabActiveKey}
state={this.state}
/>
</div>
</div>
} }
} }

View File

@ -1,7 +1,11 @@
@borderRadius: 12px; @borderRadius: 12px;
.accountProfile { .accountProfile {
padding: 0 20px; width: 100%;
height: 100%;
// max-width: 70vw;
// min-width: 900px;
.cover { .cover {
z-index: 50; z-index: 50;
@ -16,14 +20,16 @@
background-position: center; background-position: center;
background-size: cover; background-size: cover;
height: 18vh; height: 25vh;
transform: translate(0, 10px); transform: translate(0, 10px);
} }
.profileCard { .profileCard {
z-index: 51; position: sticky;
position: relative; top: 0;
z-index: 151;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -32,7 +38,7 @@
background-color: var(--background-color-primary); background-color: var(--background-color-primary);
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
border-radius: @borderRadius; border-radius: @borderRadius @borderRadius 0 @borderRadius;
padding: 20px 15px; padding: 20px 15px;
@ -110,6 +116,27 @@
border-radius: 0 0 @borderRadius @borderRadius; border-radius: 0 0 @borderRadius @borderRadius;
} }
.switchTab {
position: absolute;
bottom: 0;
right: -1px;
border: 1px solid var(--border-color);
border-top: none;
transform: translate(0, 33px);
background-color: var(--background-color-primary);
border-radius: 0 0 8px 8px;
// .ant-segmented {
// background-color: transparent;
// }
// .ant-segmented-item-selected {
// background-color: var(--background-color-accent)!important;
// }
}
h1, h1,
h2, h2,
h3, h3,
@ -122,6 +149,10 @@
} }
} }
.tabContent {
margin-top: 45px;
}
.tabs { .tabs {
transform: translate(0, -20px); transform: translate(0, -20px);
position: relative; position: relative;
@ -133,6 +164,11 @@
.ant-tabs-nav { .ant-tabs-nav {
margin: 0 20px 20px 0; margin: 0 20px 20px 0;
z-index: 152;
position: sticky;
top: 0;
} }
.ant-tabs-nav::before { .ant-tabs-nav::before {