From 5c770061f986264477102546e9f26479aae5af1d Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Fri, 31 Mar 2023 23:14:32 +0000 Subject: [PATCH] added `Timeline` feed --- .../PlaylistTimelineEntry/index.jsx | 47 +++++++ .../PlaylistTimelineEntry/index.less | 116 ++++++++++++++++++ .../app/src/components/PostsList/index.jsx | 25 ++-- packages/app/src/models/feed/index.js | 31 +++-- .../src/controllers/FeedController/index.js | 52 ++++++++ .../FeedController/services/getPosts.js | 4 +- 6 files changed, 248 insertions(+), 27 deletions(-) create mode 100644 packages/app/src/components/PlaylistTimelineEntry/index.jsx create mode 100644 packages/app/src/components/PlaylistTimelineEntry/index.less diff --git a/packages/app/src/components/PlaylistTimelineEntry/index.jsx b/packages/app/src/components/PlaylistTimelineEntry/index.jsx new file mode 100644 index 00000000..9101b603 --- /dev/null +++ b/packages/app/src/components/PlaylistTimelineEntry/index.jsx @@ -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
+
+
+ +
+ +
+
+

+ {data.title ?? "Untitled"} +

+
+ +
+

+ {data.description ?? "No description"} +

+
+ + +
+ +
+
+
+
+
+
+} \ No newline at end of file diff --git a/packages/app/src/components/PlaylistTimelineEntry/index.less b/packages/app/src/components/PlaylistTimelineEntry/index.less new file mode 100644 index 00000000..7e495d2e --- /dev/null +++ b/packages/app/src/components/PlaylistTimelineEntry/index.less @@ -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; + } +} \ No newline at end of file diff --git a/packages/app/src/components/PostsList/index.jsx b/packages/app/src/components/PostsList/index.jsx index f53dfe6d..61cc07a5 100755 --- a/packages/app/src/components/PostsList/index.jsx +++ b/packages/app/src/components/PostsList/index.jsx @@ -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) => , + "playlist": (args) => , +} + export class PostsListsComponent extends React.Component { state = { openPost: null, @@ -389,17 +398,17 @@ export class PostsListsComponent extends React.Component { } { - this.state.list.map((post) => { - return { + 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, - }} - /> + } + }) }) } diff --git a/packages/app/src/models/feed/index.js b/packages/app/src/models/feed/index.js index aab7886c..dca86425 100755 --- a/packages/app/src/models/feed/index.js +++ b/packages/app/src/models/feed/index.js @@ -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: { diff --git a/packages/server/src/controllers/FeedController/index.js b/packages/server/src/controllers/FeedController/index.js index e4b0e2c8..cd1bd225 100755 --- a/packages/server/src/controllers/FeedController/index.js +++ b/packages/server/src/controllers/FeedController/index.js @@ -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) => { diff --git a/packages/server/src/controllers/FeedController/services/getPosts.js b/packages/server/src/controllers/FeedController/services/getPosts.js index 2b8d429f..39aae9e5 100755 --- a/packages/server/src/controllers/FeedController/services/getPosts.js +++ b/packages/server/src/controllers/FeedController/services/getPosts.js @@ -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 {