diff options
| author | crupest <crupest@outlook.com> | 2021-06-15 18:25:17 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-06-15 18:25:17 +0800 |
| commit | 4645761c2090aeaf8c26789155b342c048f44535 (patch) | |
| tree | 1aab5ce94549f3f8b3fd1a31c84fb2dd8b6b2511 /FrontEnd/src/views/timeline-common/TimelinePostView.tsx | |
| parent | 485ef185153890b7c6ac4ed9798a3f2db80c8845 (diff) | |
| parent | b6afd5e8161126522bdfff876f5483fa97e94797 (diff) | |
| download | timeline-4645761c2090aeaf8c26789155b342c048f44535.tar.gz timeline-4645761c2090aeaf8c26789155b342c048f44535.tar.bz2 timeline-4645761c2090aeaf8c26789155b342c048f44535.zip | |
Merge pull request #620 from crupest/vite
Migrate to vite!
Diffstat (limited to 'FrontEnd/src/views/timeline-common/TimelinePostView.tsx')
| -rw-r--r-- | FrontEnd/src/views/timeline-common/TimelinePostView.tsx | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/FrontEnd/src/views/timeline-common/TimelinePostView.tsx b/FrontEnd/src/views/timeline-common/TimelinePostView.tsx new file mode 100644 index 00000000..ea40f80a --- /dev/null +++ b/FrontEnd/src/views/timeline-common/TimelinePostView.tsx @@ -0,0 +1,147 @@ +import React from "react"; +import classnames from "classnames"; +import { Link } from "react-router-dom"; + +import { getHttpTimelineClient, HttpTimelinePostInfo } from "@/http/timeline"; + +import { pushAlert } from "@/services/alert"; + +import UserAvatar from "../common/user/UserAvatar"; +import Card from "../common/Card"; +import FlatButton from "../common/button/FlatButton"; +import TimelineLine from "./TimelineLine"; +import TimelinePostContentView from "./TimelinePostContentView"; +import TimelinePostDeleteConfirmDialog from "./TimelinePostDeleteConfirmDialog"; +import PostPropertyChangeDialog from "./PostPropertyChangeDialog"; + +export interface TimelinePostViewProps { + post: HttpTimelinePostInfo; + current?: boolean; + className?: string; + style?: React.CSSProperties; + cardStyle?: React.CSSProperties; + onChanged: (post: HttpTimelinePostInfo) => void; + onDeleted: () => void; +} + +const TimelinePostView: React.FC<TimelinePostViewProps> = (props) => { + const { post, className, style, cardStyle, onChanged, onDeleted } = props; + const current = props.current === true; + + const [operationMaskVisible, setOperationMaskVisible] = + React.useState<boolean>(false); + const [dialog, setDialog] = React.useState< + "delete" | "changeproperty" | null + >(null); + + const cardRef = React.useRef<HTMLDivElement>(null); + React.useEffect(() => { + const cardIntersectionObserver = new IntersectionObserver(([e]) => { + if (e.intersectionRatio > 0) { + if (cardRef.current != null) { + cardRef.current.style.animationName = "timeline-post-enter"; + } + } + }); + if (cardRef.current) { + cardIntersectionObserver.observe(cardRef.current); + } + + return () => { + cardIntersectionObserver.disconnect(); + }; + }, []); + + return ( + <div + id={`timeline-post-${post.id}`} + className={classnames("timeline-item", current && "current", className)} + style={style} + > + <TimelineLine center="node" current={current} /> + <Card ref={cardRef} className="timeline-item-card" style={cardStyle}> + {post.editable ? ( + <i + className="bi-chevron-down text-info icon-button float-end" + onClick={(e) => { + setOperationMaskVisible(true); + e.stopPropagation(); + }} + /> + ) : null} + <div className="timeline-item-header"> + <span className="me-2"> + <span> + <Link to={"/users/" + props.post.author.username}> + <UserAvatar + username={post.author.username} + className="timeline-avatar me-1" + /> + </Link> + <small className="text-dark me-2">{post.author.nickname}</small> + <small className="text-secondary white-space-no-wrap"> + {new Date(post.time).toLocaleTimeString()} + </small> + </span> + </span> + </div> + <div className="timeline-content"> + <TimelinePostContentView post={post} /> + </div> + {operationMaskVisible ? ( + <div + className="timeline-post-item-options-mask d-flex justify-content-around align-items-center" + onClick={() => { + setOperationMaskVisible(false); + }} + > + <FlatButton + text="changeProperty" + onClick={(e) => { + setDialog("changeproperty"); + e.stopPropagation(); + }} + /> + <FlatButton + text="delete" + color="danger" + onClick={(e) => { + setDialog("delete"); + e.stopPropagation(); + }} + /> + </div> + ) : null} + </Card> + {dialog === "delete" ? ( + <TimelinePostDeleteConfirmDialog + onClose={() => { + setDialog(null); + setOperationMaskVisible(false); + }} + onConfirm={() => { + void getHttpTimelineClient() + .deletePost(post.timelineName, post.id) + .then(onDeleted, () => { + pushAlert({ + type: "danger", + message: "timeline.deletePostFailed", + }); + }); + }} + /> + ) : dialog === "changeproperty" ? ( + <PostPropertyChangeDialog + onClose={() => { + setDialog(null); + setOperationMaskVisible(false); + }} + post={post} + onSuccess={onChanged} + /> + ) : null} + </div> + ); +}; + +export default TimelinePostView; |
