mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-10 02:54:15 +00:00
use new tab methods
This commit is contained in:
parent
089f0826a8
commit
2aa5c70de6
@ -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>
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user