added Timeline feed

This commit is contained in:
SrGooglo 2023-03-31 23:14:32 +00:00
parent 6dc1223196
commit 5c770061f9
6 changed files with 248 additions and 27 deletions

View File

@ -0,0 +1,47 @@
import React from "react"
import { Button } from "antd"
import { Icons } from "components/Icons"
import UserPreview from "components/UserPreview"
import Image from "components/Image"
import "./index.less"
export default (props) => {
const { data } = props
return <div className="playlistTimelineEntry">
<div className="playlistTimelineEntry_content">
<div className="playlistTimelineEntry_thumbnail">
<Image src={data.thumbnail} />
</div>
<div className="playlistTimelineEntry_info">
<div className="playlistTimelineEntry_title">
<h1>
{data.title ?? "Untitled"}
</h1>
</div>
<div className="playlistTimelineEntry_description">
<p>
{data.description ?? "No description"}
</p>
</div>
<UserPreview
user_id={data.user_id}
/>
</div>
<div className="playlistTimelineEntry_actions">
<div className="playlistTimelineEntry_action">
<Button
type="primary"
size="large"
icon={<Icons.Play />}
/>
</div>
</div>
</div>
</div>
}

View File

@ -0,0 +1,116 @@
.playlistTimelineEntry {
display: flex;
flex-direction: column;
width: 35vw;
min-width: 300px;
max-width: 600px;
//min-height: 165px;
height: 100%;
max-width: 800px;
background-color: var(--background-color-accent);
transition: all 150ms ease-in-out;
padding: 17px;
border-bottom: 2px solid var(--border-color);
padding-bottom: 10px;
overflow: visible;
.playlistTimelineEntry_content {
display: flex;
flex-direction: row;
justify-items: center;
width: 100%;
gap: 20px;
.playlistTimelineEntry_thumbnail {
img {
width: 150px;
height: 150px;
object-fit: cover;
border-radius: 12px;
}
}
.playlistTimelineEntry_info {
display: flex;
flex-direction: column;
justify-content: center;
gap: 10px;
width: 100%;
.playlistTimelineEntry_title {
h1 {
font-size: 1.5rem;
font-weight: 600;
font-family: "Space Grotesk", sans-serif;
margin-top: 0;
margin-bottom: 5px;
color: var(--text-color);
}
}
.playlistTimelineEntry_description {
p {
font-size: 1rem;
font-weight: 400;
margin-top: 0;
margin-bottom: 5px;
color: var(--text-color);
}
}
}
.playlistTimelineEntry_actions {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 10px;
.playlistTimelineEntry_action {
display: flex;
flex-direction: row;
justify-content: center;
gap: 10px;
}
}
}
&:first-child {
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
&:last-child {
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom: none;
padding-bottom: 0;
}
}

View File

@ -1,7 +1,11 @@
import React from "react"
import * as antd from "antd"
import { Icons } from "components/Icons"
import { PostCard, LoadMore } from "components"
import PostCard from "components/PostCard"
import PlaylistTimelineEntry from "components/PlaylistTimelineEntry"
import LoadMore from "components/LoadMore"
//import { ViewportList } from "react-viewport-list"
import AutoSizer from "react-virtualized-auto-sizer"
@ -27,6 +31,11 @@ const NoResultComponent = () => {
/>
}
const typeToComponent = {
"post": (args) => <PostCard {...args} />,
"playlist": (args) => <PlaylistTimelineEntry {...args} />,
}
export class PostsListsComponent extends React.Component {
state = {
openPost: null,
@ -389,17 +398,17 @@ export class PostsListsComponent extends React.Component {
</div>
}
{
this.state.list.map((post) => {
return <PostCard
key={post._id}
data={post}
events={{
this.state.list.map((data) => {
return React.createElement(typeToComponent[data.type ?? "post"], {
key: data._id,
data: data,
events: {
onClickLike: this.onLikePost,
onClickSave: this.onSavePost,
onClickDelete: this.onDeletePost,
onClickEdit: this.onEditPost,
}}
/>
}
})
})
}
</LoadMore>

View File

@ -1,14 +1,19 @@
export default class FeedModel {
static get bridge() {
return window.app?.cores.api.withEndpoints()
static async getTimelineFeed({ trim, limit }) {
const { data } = await app.cores.api.customRequest({
method: "GET",
url: `/feed/timeline`,
params: {
trim: trim ?? 0,
limit: limit ?? window.app.cores.settings.get("feed_max_fetch"),
}
})
return data
}
static async getPostsFeed({ trim, limit }) {
if (!FeedModel.bridge) {
throw new Error("Bridge is not available")
}
const { data } = await app.cores.api.customRequest( {
const { data } = await app.cores.api.customRequest({
method: "GET",
url: `/feed/posts`,
params: {
@ -21,11 +26,7 @@ export default class FeedModel {
}
static async getPlaylistsFeed({ trim, limit }) {
if (!FeedModel.bridge) {
throw new Error("Bridge is not available")
}
const { data } = await app.cores.api.customRequest( {
const { data } = await app.cores.api.customRequest({
method: "GET",
url: `/feed/playlists`,
params: {
@ -38,11 +39,7 @@ export default class FeedModel {
}
static async search(keywords, params = {}) {
if (!FeedModel.bridge) {
throw new Error("Bridge is not available")
}
const { data } = await app.cores.api.customRequest( {
const { data } = await app.cores.api.customRequest({
method: "GET",
url: `/search`,
params: {

View File

@ -9,6 +9,58 @@ export default class FeedController extends Controller {
httpEndpoints = {
get: {
"/timeline": {
middlewares: ["withAuthentication"],
fn: async (req, res) => {
const for_user_id = req.user?._id.toString()
if (!for_user_id) {
return res.status(400).json({
error: "Invalid user id"
})
}
// fetch posts
let posts = await getPosts({
for_user_id,
limit: req.query?.limit,
skip: req.query?.trim,
})
// fetch playlists
let playlists = await getPlaylists({
for_user_id,
limit: req.query?.limit,
skip: req.query?.trim,
})
// add type to posts and playlists
posts = posts.map((data) => {
data.type = "post"
return data
})
playlists = playlists.map((data) => {
data.type = "playlist"
return data
})
let feed = [
...posts,
...playlists,
]
// sort feed
feed.sort((a, b) => {
return new Date(b.created_at) - new Date(a.created_at)
})
return res.json(feed)
}
},
"/posts": {
middlewares: ["withAuthentication"],
fn: async (req, res) => {

View File

@ -1,6 +1,6 @@
import { Post, UserFollow } from "../../../models"
import { Post, UserFollow } from "@models"
import fullfillPostsData from "../../../utils/fullfillPostsData"
import fullfillPostsData from "@utils/fullfillPostsData"
export default async (payload) => {
const {