use PostsFeed component

This commit is contained in:
srgooglo 2022-03-11 22:52:44 +01:00
parent 4da1a0b506
commit 81167c455e
4 changed files with 52 additions and 222 deletions

View File

@ -3,67 +3,15 @@ import * as antd from "antd"
import { Translation } from "react-i18next" import { Translation } from "react-i18next"
import { Icons } from "components/Icons" import { Icons } from "components/Icons"
import { Skeleton, ActionsBar, AdminTools } from "components" import { Skeleton, PostsFeed } from "components"
import { Session, User } from "models" import { Session, User } from "models"
import { SessionsView, StatisticsView } from "./components"
import "./index.less" import "./index.less"
const SelfViewComponents = {
sessionsView: SessionsView,
statisticsView: StatisticsView,
}
const SelfViewTabDecorators = {
sessionsView: (
<div>
<Icons.Key /> Sessions
</div>
),
statisticsView: (
<div>
<Icons.PieChart /> Statistics
</div>
),
}
class SelfView extends React.Component {
renderComponents = () => {
const renderTagDecorator = (key) => {
if (typeof this.props.decorators[key] !== "undefined") {
return this.props.decorators[key]
}
return key
}
return Object.keys(this.props.components).map((key, index) => {
const Component = this.props.components[key]
return (
<antd.Tabs.TabPane tab={renderTagDecorator(key)} key={index}>
<div key={key}>
<Component {...this.props.componentProps} />
</div>
</antd.Tabs.TabPane>
)
})
}
render() {
return (
<antd.Tabs defaultActiveKey="0" centered>
{this.renderComponents()}
</antd.Tabs>
)
}
}
export default class Account extends React.Component { export default class Account extends React.Component {
static bindApp = ["userController", "sessionController"] static bindApp = ["userController", "sessionController"]
state = { state = {
hasManager: false,
isSelf: false, isSelf: false,
user: null, user: null,
sessions: null sessions: null
@ -88,28 +36,11 @@ export default class Account extends React.Component {
state.user = await this.props.contexts.app.userController.getData({ username: requestedUser }) state.user = await this.props.contexts.app.userController.getData({ username: requestedUser })
} }
state.hasManager = await User.hasRole("manager")
state.hasAdmin = await User.hasRole("admin") state.hasAdmin = await User.hasRole("admin")
this.setState(state) this.setState(state)
} }
handleSignOutAll = () => {
return this.props.contexts.app.sessionController.destroyAllSessions()
}
openUserEdit = async () => {
const result = await AdminTools.open.dataManager(this.state.user)
if (result) {
this.setState({ user: result })
}
}
openRolesManager = async () => {
await AdminTools.open.rolesManager(this.state.user._id)
}
render() { render() {
const user = this.state.user const user = this.state.user
@ -136,47 +67,19 @@ export default class Account extends React.Component {
</div> </div>
</div> </div>
<div className="extension"> <div className="extension">
<div className="rolesList"> <div className="badgesList">
{user.roles.map((role, index) => { {user.badges.map((role, index) => {
return <antd.Tag>{role}</antd.Tag> return <antd.Tag>{role}</antd.Tag>
})} })}
</div> </div>
</div> </div>
</div> </div>
<div className="posts">
{(this.state.isSelf || this.state.hasManager) && <ActionsBar spaced padding="8px"> <PostsFeed
<antd.Button fromUserId={user._id}
icon={<Icons.Edit />} />
shape="round" </div>
onClick={this.openUserEdit}
>
<Translation>
{(t) => <>{t("Edit")}</>}
</Translation>
</antd.Button>
{this.state.hasAdmin && <antd.Button
icon={<Icons.Link />}
shape="round"
onClick={this.openRolesManager}
>
<Translation>
{(t) => <>{t("Manage roles")}</>}
</Translation>
</antd.Button>}
</ActionsBar>}
{this.state.isSelf && (
<SelfView
components={SelfViewComponents}
decorators={SelfViewTabDecorators}
componentProps={{
sessions: this.state.sessions,
user: this.state.user,
handleSignOutAll: this.handleSignOutAll,
}}
/>
)}
</div> </div>
) )
} }

View File

@ -1,67 +1,76 @@
@borderColor: #33333396; @borderColor : #dddddd;
@borderRadius: 12px; @borderRadius: 12px;
.account_wrapper { .account_wrapper {
.card { .card {
display: flex; display : flex;
flex-direction: column; flex-direction: column;
color: var(--background-color-contrast); color : var(--background-color-contrast);
h1,h2,h3,h4,h5,h6,span { h1,
h2,
h3,
h4,
h5,
h6,
span {
color: var(--background-color-contrast); color: var(--background-color-contrast);
} }
.header { .header {
position: relative; position : relative;
display: inline-flex; display : inline-flex;
align-items: center; align-items: center;
z-index: 15; z-index: 15;
width: 100%; width : 100%;
padding: 12px; padding: 12px;
font-family: "Roboto Mono", monospace; font-family: "Roboto Mono", monospace;
//color: #333;
color: var(--background-color-contrast); color : var(--background-color-contrast);
border : 1px solid var(--border-color);
border: 1px solid @borderColor;
border-radius: @borderRadius; border-radius: @borderRadius;
word-break: break-all; word-break: break-all;
img { img {
width: 70px; width : 70px;
height: 70px; height: 70px;
} }
h1 { h1 {
margin: 0; margin : 0;
font-size: 35px; font-size: 35px;
span { span {
font-size: 12px; font-size: 12px;
} }
} }
} }
.extension { .extension {
position: relative; position: relative;
display: inline-flex; display : inline-flex;
top: -10px; top : -10px;
width: 100%; width : 100%;
padding: 19px 10px 10px 10px; padding: 19px 10px 10px 10px;
border-top: 0; border-top : 0;
border-right: 0; border-right: 0;
border-style: solid; border-style: solid;
border-width: 1px; border-width: 1px;
border-color: transparent @borderColor @borderColor @borderColor;
border-color : var(--border-color);
border-top-color: transparent;
border-radius: 0 0 @borderRadius @borderRadius; border-radius: 0 0 @borderRadius @borderRadius;
} }
} }
> div { >div {
margin-bottom: 10px; margin-bottom: 10px;
} }
} }

View File

@ -1,88 +1,15 @@
import React from "react" import React from "react"
import * as antd from "antd" import { PostCreator, PostsFeed } from "components"
import { PostCard, PostCreator } from "components"
import { InfiniteScroll } from "antd-mobile"
import "./index.less" import "./index.less"
export default class PostsExplorer extends React.Component { export default class PostsExplorer extends React.Component {
state = {
loading: true,
skipStep: 0,
lastLength: 0,
posts: [],
}
api = window.app.request
componentDidMount = async () => {
this.toogleLoading(true)
await this.fetchPosts()
window.app.ws.listen(`new.post`, (data) => {
this.addPost(data)
})
this.toogleLoading(false)
}
toogleLoading = (to) => {
this.setState({ loading: to ?? !this.state.loading })
}
addPost = (post) => {
this.setState({
posts: [post, ...this.state.posts],
})
}
fetchPosts = async () => {
const posts = await this.api.get.feed(undefined, {
feedSkip: this.state.skipStep,
}).catch(error => {
console.error(error)
antd.message.error(error)
return false
})
if (posts) {
console.log(posts)
this.setState({ posts: [...posts, ...this.state.posts,], lastLength: posts.length })
}
}
hasMore = () => {
return this.state.posts.length < this.state.lastLength
}
loadMore = async () => {
await this.setState({ skipStep: this.state.skipStep + 1 })
await this.fetchPosts()
}
render() { render() {
if (this.state.loading) {
return <antd.Skeleton active />
}
return <div className="explore"> return <div className="explore">
<div className="wrapper"> <div className="header">
<div className="header"> <PostCreator />
<PostCreator />
</div>
{
this.state.posts.map(post => {
return <PostCard data={post} />
})
}
<InfiniteScroll loadMore={this.loadMore} hasMore={this.hasMore} >
<div>Loading more...</div>
</InfiniteScroll>
</div> </div>
<PostsFeed />
</div> </div>
} }
} }

View File

@ -6,7 +6,7 @@
width: 100%; width: 100%;
.wrapper { .header {
display : flex; display : flex;
flex-direction : column; flex-direction : column;
align-items : center; align-items : center;
@ -14,18 +14,9 @@
width : 100%; width : 100%;
max-width: 40vw; max-width: 40vw;
}
.header { >div {
display : flex; margin-bottom: 15px;
flex-direction : column;
align-items : center;
justify-content: center;
width: 100%;
}
>div {
margin-bottom: 15px;
}
} }
} }