mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-18 06:54:15 +00:00
Restructure account pages and convert class to function
This commit is contained in:
parent
8b9afae7eb
commit
0f70bf43fd
@ -1,8 +0,0 @@
|
||||
import React from "react"
|
||||
import Account from "."
|
||||
|
||||
export default (props) => {
|
||||
const username = props.params.username
|
||||
|
||||
return <Account username={username} />
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import React from "react"
|
||||
import Account from "./index.mobile"
|
||||
|
||||
export default (props) => {
|
||||
const username = props.params.username
|
||||
|
||||
return <Account username={username} />
|
||||
}
|
256
packages/app/src/pages/account/[username]/index.jsx
Normal file
256
packages/app/src/pages/account/[username]/index.jsx
Normal file
@ -0,0 +1,256 @@
|
||||
import React, { useState, useEffect, useRef } from "react"
|
||||
import * as antd from "antd"
|
||||
import classnames from "classnames"
|
||||
import { motion, AnimatePresence } from "motion/react"
|
||||
|
||||
import { Icons } from "@components/Icons"
|
||||
import FollowButton from "@components/FollowButton"
|
||||
import UserCard from "@components/UserCard"
|
||||
|
||||
import GenerateMenuItems from "@utils/generateMenuItems"
|
||||
|
||||
import UserModel from "@models/user"
|
||||
import FollowsModel from "@models/follows"
|
||||
|
||||
import DetailsTab from "./tabs/details"
|
||||
import PostsTab from "./tabs/posts"
|
||||
import MusicTab from "./tabs/music"
|
||||
import FollowersTab from "./tabs/followers"
|
||||
|
||||
import "./index.less"
|
||||
|
||||
const TabsComponent = {
|
||||
posts: PostsTab,
|
||||
followers: FollowersTab,
|
||||
details: DetailsTab,
|
||||
music: MusicTab,
|
||||
}
|
||||
|
||||
const Account = ({ params }) => {
|
||||
const [requestedUser, setRequestedUser] = useState(null)
|
||||
const [user, setUser] = useState(null)
|
||||
const [isSelf, setIsSelf] = useState(false)
|
||||
const [followersCount, setFollowersCount] = useState(0)
|
||||
const [following, setFollowing] = useState(false)
|
||||
const [tabActiveKey, setTabActiveKey] = useState("posts")
|
||||
const [isNotExistent, setIsNotExistent] = useState(false)
|
||||
const [coverExpanded, setCoverExpanded] = useState(false)
|
||||
|
||||
const contentRef = useRef()
|
||||
|
||||
const loadUserData = async () => {
|
||||
const requestedUsername = params.username ?? app.userData.username
|
||||
|
||||
let isSelfUser = false
|
||||
let userData = null
|
||||
let followersCountData = 0
|
||||
|
||||
if (requestedUsername != null) {
|
||||
if (app.userData.username === requestedUsername) {
|
||||
isSelfUser = true
|
||||
}
|
||||
|
||||
userData = await UserModel.data({
|
||||
username: requestedUsername,
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
return false
|
||||
})
|
||||
|
||||
if (!userData) {
|
||||
setIsNotExistent(true)
|
||||
return false
|
||||
}
|
||||
|
||||
console.log(`Loaded User [${userData.username}] >`, userData)
|
||||
|
||||
const followersResult = await FollowsModel.getFollowers(
|
||||
userData._id,
|
||||
).catch(() => false)
|
||||
|
||||
if (followersResult) {
|
||||
followersCountData = followersResult.count
|
||||
}
|
||||
}
|
||||
|
||||
setIsSelf(isSelfUser)
|
||||
setRequestedUser(requestedUsername)
|
||||
setUser(userData)
|
||||
setFollowing(userData?.following || false)
|
||||
setFollowersCount(followersCountData)
|
||||
}
|
||||
|
||||
const onClickFollow = async () => {
|
||||
const result = await FollowsModel.toggleFollow({
|
||||
user_id: user._id,
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
antd.message.error(error.message)
|
||||
return false
|
||||
})
|
||||
|
||||
setFollowing(result.following)
|
||||
setFollowersCount(result.count)
|
||||
}
|
||||
|
||||
const toggleCoverExpanded = (to) => {
|
||||
setCoverExpanded(to ?? !coverExpanded)
|
||||
}
|
||||
|
||||
const handlePageTransition = (key) => {
|
||||
if (typeof key !== "string") {
|
||||
console.error(
|
||||
"Cannot handle page transition. Invalid key, only valid passing string",
|
||||
key,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
const normalizedKey = key.toLowerCase()
|
||||
|
||||
if (tabActiveKey === normalizedKey) {
|
||||
return false
|
||||
}
|
||||
|
||||
setTabActiveKey(normalizedKey)
|
||||
}
|
||||
|
||||
const onPostListTopVisibility = () => {
|
||||
// This function was referenced but not defined in the original component
|
||||
// You may need to implement this based on your requirements
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadUserData()
|
||||
}, [params.username])
|
||||
|
||||
if (isNotExistent) {
|
||||
return (
|
||||
<antd.Result
|
||||
status="404"
|
||||
title="This user does not exist, yet..."
|
||||
></antd.Result>
|
||||
)
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return <antd.Skeleton active />
|
||||
}
|
||||
|
||||
const state = {
|
||||
requestedUser,
|
||||
user,
|
||||
isSelf,
|
||||
followersCount,
|
||||
following,
|
||||
tabActiveKey,
|
||||
isNotExistent,
|
||||
coverExpanded,
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
id="profile"
|
||||
className={classnames("account-profile", {
|
||||
["withCover"]: user.cover,
|
||||
})}
|
||||
>
|
||||
{user.cover && (
|
||||
<div
|
||||
className={classnames("cover", {
|
||||
["expanded"]: coverExpanded,
|
||||
})}
|
||||
style={{ backgroundImage: `url("${user.cover}")` }}
|
||||
onClick={() => toggleCoverExpanded()}
|
||||
id="profile-cover"
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="panels">
|
||||
<div className="left-panel">
|
||||
<UserCard user={user} />
|
||||
|
||||
<div className="actions">
|
||||
<FollowButton
|
||||
count={followersCount}
|
||||
onClick={onClickFollow}
|
||||
followed={following}
|
||||
self={isSelf}
|
||||
/>
|
||||
|
||||
{!isSelf && (
|
||||
<antd.Button
|
||||
icon={<Icons.MdMessage />}
|
||||
onClick={() =>
|
||||
app.location.push(`/messages/${user._id}`)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="center-panel" ref={contentRef}>
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{
|
||||
duration: 0.15,
|
||||
}}
|
||||
key={tabActiveKey}
|
||||
style={{
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
{React.createElement(TabsComponent[tabActiveKey], {
|
||||
onTopVisibility: onPostListTopVisibility,
|
||||
state: state,
|
||||
})}
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
<div className="right-panel">
|
||||
<antd.Menu
|
||||
className="tabMenu"
|
||||
mode={app.isMobile ? "horizontal" : "vertical"}
|
||||
selectedKeys={[tabActiveKey]}
|
||||
onClick={(e) => handlePageTransition(e.key)}
|
||||
items={GenerateMenuItems([
|
||||
{
|
||||
id: "posts",
|
||||
label: "Posts",
|
||||
icon: "FiBookOpen",
|
||||
},
|
||||
{
|
||||
id: "music",
|
||||
label: "Music",
|
||||
icon: "MdAlbum",
|
||||
},
|
||||
{
|
||||
id: "followers",
|
||||
label: "Followers",
|
||||
icon: "FiUsers",
|
||||
},
|
||||
{
|
||||
id: "details",
|
||||
label: "Details",
|
||||
icon: "FiInfo",
|
||||
},
|
||||
])}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Account.options = {
|
||||
layout: {
|
||||
type: "default",
|
||||
centeredContent: false,
|
||||
},
|
||||
}
|
||||
|
||||
export default Account
|
31
packages/app/src/pages/account/[username]/tabs/posts/index.jsx
Executable file
31
packages/app/src/pages/account/[username]/tabs/posts/index.jsx
Executable file
@ -0,0 +1,31 @@
|
||||
import React from "react"
|
||||
import { Result } from "antd"
|
||||
|
||||
import PostsList from "@components/PostsList"
|
||||
import { Icons } from "@components/Icons"
|
||||
|
||||
import PostModel from "@models/post"
|
||||
|
||||
const emptyListRender = () => {
|
||||
return (
|
||||
<Result icon={<Icons.FiUserX style={{ fontSize: "50px" }} />}>
|
||||
<h2>It's seems this user has no public post, yet.</h2>
|
||||
</Result>
|
||||
)
|
||||
}
|
||||
|
||||
export default class UserPosts extends React.Component {
|
||||
render() {
|
||||
console.log(this.props.state)
|
||||
return (
|
||||
<PostsList
|
||||
onTopVisibility={this.props.onTopVisibility}
|
||||
emptyListRender={emptyListRender}
|
||||
loadFromModel={PostModel.getUserPosts}
|
||||
loadFromModelProps={{
|
||||
user_id: this.props.state.user._id,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
@ -1,260 +0,0 @@
|
||||
import React from "react"
|
||||
import * as antd from "antd"
|
||||
import classnames from "classnames"
|
||||
import { motion, AnimatePresence } from "motion/react"
|
||||
|
||||
import { Icons } from "@components/Icons"
|
||||
import FollowButton from "@components/FollowButton"
|
||||
import UserCard from "@components/UserCard"
|
||||
|
||||
import GenerateMenuItems from "@utils/generateMenuItems"
|
||||
|
||||
import SessionModel from "@models/session"
|
||||
import UserModel from "@models/user"
|
||||
import FollowsModel from "@models/follows"
|
||||
|
||||
import DetailsTab from "./tabs/details"
|
||||
import PostsTab from "./tabs/posts"
|
||||
import MusicTab from "./tabs/music"
|
||||
import FollowersTab from "./tabs/followers"
|
||||
|
||||
import "./index.less"
|
||||
|
||||
const TabsComponent = {
|
||||
posts: PostsTab,
|
||||
followers: FollowersTab,
|
||||
details: DetailsTab,
|
||||
music: MusicTab,
|
||||
}
|
||||
|
||||
export default class Account extends React.Component {
|
||||
state = {
|
||||
requestedUser: null,
|
||||
|
||||
user: null,
|
||||
isSelf: false,
|
||||
|
||||
followersCount: 0,
|
||||
following: false,
|
||||
|
||||
tabActiveKey: "posts",
|
||||
|
||||
isNotExistent: false,
|
||||
}
|
||||
|
||||
contentRef = React.createRef()
|
||||
|
||||
componentDidMount = async () => {
|
||||
app.layout.toggleCenteredContent(false)
|
||||
|
||||
const token = await SessionModel.getDecodedToken()
|
||||
const requestedUser = this.props.username ?? token?.username
|
||||
|
||||
let isSelf = false
|
||||
let user = null
|
||||
let followersCount = 0
|
||||
|
||||
if (requestedUser != null) {
|
||||
if (token.username === requestedUser) {
|
||||
isSelf = true
|
||||
}
|
||||
|
||||
user = await UserModel.data({
|
||||
username: requestedUser,
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
if (!user) {
|
||||
this.setState({
|
||||
isNotExistent: true,
|
||||
})
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
console.log(`Loaded User [${user.username}] >`, user)
|
||||
|
||||
const followersResult = await FollowsModel.getFollowers(
|
||||
user._id,
|
||||
).catch(() => false)
|
||||
|
||||
if (followersResult) {
|
||||
followersCount = followersResult.count
|
||||
}
|
||||
}
|
||||
|
||||
await this.setState({
|
||||
isSelf,
|
||||
requestedUser,
|
||||
user,
|
||||
|
||||
following: user.following,
|
||||
followersCount: followersCount,
|
||||
})
|
||||
}
|
||||
|
||||
onClickFollow = async () => {
|
||||
const result = await FollowsModel.toggleFollow({
|
||||
user_id: this.state.user._id,
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
antd.message.error(error.message)
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
await this.setState({
|
||||
following: result.following,
|
||||
followersCount: result.count,
|
||||
})
|
||||
}
|
||||
|
||||
toggleCoverExpanded = async (to) => {
|
||||
this.setState({
|
||||
coverExpanded: to ?? !this.state.coverExpanded,
|
||||
})
|
||||
}
|
||||
|
||||
handlePageTransition = (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
|
||||
}
|
||||
|
||||
this.setState({
|
||||
tabActiveKey: key,
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const user = this.state.user
|
||||
|
||||
if (this.state.isNotExistent) {
|
||||
return (
|
||||
<antd.Result
|
||||
status="404"
|
||||
title="This user does not exist, yet..."
|
||||
></antd.Result>
|
||||
)
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return <antd.Skeleton active />
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
id="profile"
|
||||
className={classnames("account-profile", {
|
||||
["withCover"]: user.cover,
|
||||
})}
|
||||
>
|
||||
{user.cover && (
|
||||
<div
|
||||
className={classnames("cover", {
|
||||
["expanded"]: this.state.coverExpanded,
|
||||
})}
|
||||
style={{ backgroundImage: `url("${user.cover}")` }}
|
||||
onClick={() => this.toggleCoverExpanded()}
|
||||
id="profile-cover"
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="panels">
|
||||
<div className="left-panel">
|
||||
<UserCard user={user} />
|
||||
|
||||
<div className="actions">
|
||||
<FollowButton
|
||||
count={this.state.followersCount}
|
||||
onClick={this.onClickFollow}
|
||||
followed={this.state.following}
|
||||
self={this.state.isSelf}
|
||||
/>
|
||||
|
||||
{!this.state.isSelf && (
|
||||
<antd.Button
|
||||
icon={<Icons.MdMessage />}
|
||||
onClick={() =>
|
||||
app.location.push(
|
||||
`/messages/${user._id}`,
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="center-panel" ref={this.contentRef}>
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{
|
||||
duration: 0.15,
|
||||
}}
|
||||
key={this.state.tabActiveKey}
|
||||
style={{
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
{React.createElement(
|
||||
TabsComponent[this.state.tabActiveKey],
|
||||
{
|
||||
onTopVisibility:
|
||||
this.onPostListTopVisibility,
|
||||
state: this.state,
|
||||
},
|
||||
)}
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
<div className="right-panel">
|
||||
<antd.Menu
|
||||
className="tabMenu"
|
||||
mode={app.isMobile ? "horizontal" : "vertical"}
|
||||
selectedKeys={[this.state.tabActiveKey]}
|
||||
onClick={(e) => this.handlePageTransition(e.key)}
|
||||
items={GenerateMenuItems([
|
||||
{
|
||||
id: "posts",
|
||||
label: "Posts",
|
||||
icon: "FiBookOpen",
|
||||
},
|
||||
{
|
||||
id: "music",
|
||||
label: "Music",
|
||||
icon: "MdAlbum",
|
||||
},
|
||||
{
|
||||
id: "followers",
|
||||
label: "Followers",
|
||||
icon: "FiUsers",
|
||||
},
|
||||
{
|
||||
id: "details",
|
||||
label: "Details",
|
||||
icon: "FiInfo",
|
||||
},
|
||||
])}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
import React from "react"
|
||||
import { Result } from "antd"
|
||||
|
||||
import PostsList from "@components/PostsList"
|
||||
import { Icons } from "@components/Icons"
|
||||
|
||||
import PostModel from "@models/post"
|
||||
|
||||
const emptyListRender = () => {
|
||||
return <Result
|
||||
icon={<Icons.FiUserX style={{ fontSize: "50px" }} />}
|
||||
>
|
||||
<h2>
|
||||
It's seems this user has no public post, yet.
|
||||
</h2>
|
||||
</Result>
|
||||
}
|
||||
|
||||
export default class UserPosts extends React.Component {
|
||||
render() {
|
||||
return <PostsList
|
||||
onTopVisibility={this.props.onTopVisibility}
|
||||
emptyListRender={emptyListRender}
|
||||
loadFromModel={PostModel.getUserPosts}
|
||||
loadFromModelProps={{
|
||||
user_id: this.props.state.user._id,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user