✨ Post own page
This commit is contained in:
parent
d3adb20b0e
commit
bbdc8e6aa6
@ -48,6 +48,42 @@ func listPost(c *fiber.Ctx) error {
|
||||
})
|
||||
}
|
||||
|
||||
func getPost(c *fiber.Ctx) error {
|
||||
id, _ := c.ParamsInt("postId", 0)
|
||||
take := c.QueryInt("take", 0)
|
||||
offset := c.QueryInt("offset", 0)
|
||||
|
||||
var post models.Post
|
||||
if err := services.PreloadRelatedPost(database.C.Where(&models.Post{
|
||||
BaseModel: models.BaseModel{ID: uint(id)},
|
||||
})).First(&post).Error; err != nil {
|
||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||
}
|
||||
|
||||
tx := database.C.
|
||||
Where(&models.Post{ReplyID: &post.ID}).
|
||||
Where("published_at <= ? OR published_at IS NULL", time.Now()).
|
||||
Order("created_at desc")
|
||||
|
||||
var count int64
|
||||
if err := tx.
|
||||
Model(&models.Post{}).
|
||||
Count(&count).Error; err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
posts, err := services.ListPost(tx, take, offset)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"data": post,
|
||||
"count": count,
|
||||
"related": posts,
|
||||
})
|
||||
}
|
||||
|
||||
func createPost(c *fiber.Ctx) error {
|
||||
user := c.Locals("principal").(models.Account)
|
||||
|
||||
|
@ -69,6 +69,7 @@ func NewServer() {
|
||||
api.Post("/attachments", auth, uploadAttachment)
|
||||
|
||||
api.Get("/posts", listPost)
|
||||
api.Get("/posts/:postId", getPost)
|
||||
api.Post("/posts", auth, createPost)
|
||||
api.Post("/posts/:postId/react/:reactType", auth, reactPost)
|
||||
api.Put("/posts/:postId", auth, editPost)
|
||||
|
@ -5,8 +5,10 @@ import { SolidMarkdown } from "solid-markdown";
|
||||
|
||||
export default function PostItem(props: {
|
||||
post: any,
|
||||
noClick?: boolean,
|
||||
noAuthor?: boolean,
|
||||
noControl?: boolean,
|
||||
noRelated?: boolean,
|
||||
onRepost?: (post: any) => void,
|
||||
onReply?: (post: any) => void,
|
||||
onEdit?: (post: any) => void,
|
||||
@ -33,8 +35,8 @@ export default function PostItem(props: {
|
||||
setReacting(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="post-item">
|
||||
const element = (
|
||||
<>
|
||||
<Show when={!props.noAuthor}>
|
||||
<a href={`/accounts/${props.post.author.name}`}>
|
||||
<div class="flex bg-base-200">
|
||||
@ -55,7 +57,6 @@ export default function PostItem(props: {
|
||||
</div>
|
||||
</a>
|
||||
</Show>
|
||||
|
||||
<div class="px-7">
|
||||
<h2 class="card-title">{props.post.title}</h2>
|
||||
<article class="prose">
|
||||
@ -77,7 +78,7 @@ export default function PostItem(props: {
|
||||
|
||||
<PostAttachments attachments={props.post.attachments ?? []} />
|
||||
|
||||
<Show when={props.post.repost_to}>
|
||||
<Show when={!props.noRelated && props.post.repost_to}>
|
||||
<p class="text-xs mt-3 mb-2">
|
||||
<i class="fa-solid fa-retweet me-2"></i>
|
||||
Reposted a post
|
||||
@ -87,11 +88,10 @@ export default function PostItem(props: {
|
||||
noControl
|
||||
post={props.post.repost_to}
|
||||
onError={props.onError}
|
||||
onReact={props.onReact}
|
||||
/>
|
||||
onReact={props.onReact} />
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={props.post.reply_to}>
|
||||
<Show when={!props.noRelated && props.post.reply_to}>
|
||||
<p class="text-xs mt-3 mb-2">
|
||||
<i class="fa-solid fa-reply me-2"></i>
|
||||
Replied a post
|
||||
@ -101,12 +101,10 @@ export default function PostItem(props: {
|
||||
noControl
|
||||
post={props.post.reply_to}
|
||||
onError={props.onError}
|
||||
onReact={props.onReact}
|
||||
/>
|
||||
onReact={props.onReact} />
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
<Show when={!props.noControl}>
|
||||
<div class="relative">
|
||||
<Show when={!userinfo?.isLoggedIn}>
|
||||
@ -168,7 +166,20 @@ export default function PostItem(props: {
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
if (props.noClick) {
|
||||
return (
|
||||
<div class="post-item">
|
||||
{element}
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<a class="post-item" href={`/posts/${props.post.id}`}>
|
||||
{element}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import PostItem from "./PostItem.tsx";
|
||||
import { getAtk } from "../stores/userinfo.tsx";
|
||||
|
||||
export default function PostList(props: {
|
||||
noRelated?: boolean,
|
||||
info: { data: any[], count: number } | null,
|
||||
onRepost?: (post: any) => void,
|
||||
onReply?: (post: any) => void,
|
||||
@ -58,6 +59,7 @@ export default function PostList(props: {
|
||||
<For each={posts()}>
|
||||
{item => <PostItem
|
||||
post={item}
|
||||
noRelated={props.noRelated}
|
||||
onRepost={props.onRepost}
|
||||
onReply={props.onReply}
|
||||
onEdit={props.onEdit}
|
||||
|
@ -13,6 +13,7 @@ import "@fortawesome/fontawesome-free/css/all.css";
|
||||
import RootLayout from "./layouts/RootLayout.tsx";
|
||||
import Feed from "./pages/feed.tsx";
|
||||
import Global from "./pages/global.tsx";
|
||||
import PostReference from "./pages/post.tsx";
|
||||
import { UserinfoProvider } from "./stores/userinfo.tsx";
|
||||
import { WellKnownProvider } from "./stores/wellKnown.tsx";
|
||||
|
||||
@ -24,8 +25,9 @@ render(() => (
|
||||
<Router root={RootLayout}>
|
||||
<Route path="/" component={Feed}>
|
||||
<Route path="/" component={Global} />
|
||||
<Route path="/realms" component={lazy(() => import("./pages/realms.tsx"))} />
|
||||
<Route path="/realms/:realmId" component={lazy(() => import("./pages/realm.tsx"))} />
|
||||
<Route path="/posts/:postId" component={PostReference} />
|
||||
<Route path="/realms" component={lazy(() => import("./pages/realms"))} />
|
||||
<Route path="/realms/:realmId" component={lazy(() => import("./pages/realms/realm.tsx"))} />
|
||||
<Route path="/accounts/:accountId" component={lazy(() => import("./pages/account.tsx"))} />
|
||||
</Route>
|
||||
<Route path="/auth" component={lazy(() => import("./pages/auth/callout.tsx"))} />
|
||||
|
@ -2,7 +2,7 @@ import Navbar from "./shared/Navbar.tsx";
|
||||
import { readProfiles, useUserinfo } from "../stores/userinfo.tsx";
|
||||
import { createEffect, createMemo, createSignal, Show } from "solid-js";
|
||||
import { readWellKnown } from "../stores/wellKnown.tsx";
|
||||
import { BeforeLeaveEventArgs, useBeforeLeave, useLocation, useNavigate, useSearchParams } from "@solidjs/router";
|
||||
import { BeforeLeaveEventArgs, useLocation, useNavigate, useSearchParams } from "@solidjs/router";
|
||||
|
||||
export default function RootLayout(props: any) {
|
||||
const [ready, setReady] = createSignal(false);
|
||||
@ -17,21 +17,19 @@ export default function RootLayout(props: any) {
|
||||
|
||||
createEffect(() => {
|
||||
if (ready()) {
|
||||
keepGate(location.pathname);
|
||||
keepGate(location.pathname + location.search);
|
||||
}
|
||||
}, [ready, userinfo]);
|
||||
|
||||
function keepGate(path: string, e?: BeforeLeaveEventArgs) {
|
||||
const whitelist = ["/auth", "/auth/callback"];
|
||||
const blacklist = ["/creator"];
|
||||
|
||||
if (!userinfo?.isLoggedIn && !whitelist.includes(path)) {
|
||||
if (!userinfo?.isLoggedIn && blacklist.includes(path)) {
|
||||
if (!e?.defaultPrevented) e?.preventDefault();
|
||||
navigate(`/auth/login?redirect_uri=${path}`);
|
||||
navigate(`/auth?redirect_uri=${path}`);
|
||||
}
|
||||
}
|
||||
|
||||
useBeforeLeave((e: BeforeLeaveEventArgs) => keepGate(e.to.toString().split("?")[0], e));
|
||||
|
||||
const mainContentStyles = createMemo(() => {
|
||||
if(!searchParams["noTitle"]) {
|
||||
return "h-[calc(100vh-64px)] mt-[64px]"
|
||||
|
@ -7,7 +7,7 @@ import PostPublish from "../components/PostPublish.tsx";
|
||||
import { createStore } from "solid-js/store";
|
||||
import { closeModel, openModel } from "../scripts/modals.ts";
|
||||
|
||||
export default function DashboardPage() {
|
||||
export default function AccountPage() {
|
||||
const [error, setError] = createSignal<string | null>(null);
|
||||
|
||||
const [page, setPage] = createSignal(0);
|
||||
|
132
pkg/view/src/pages/post.tsx
Normal file
132
pkg/view/src/pages/post.tsx
Normal file
@ -0,0 +1,132 @@
|
||||
import { createSignal, Show } from "solid-js";
|
||||
import { useNavigate, useParams } from "@solidjs/router";
|
||||
import { createStore } from "solid-js/store";
|
||||
import { closeModel, openModel } from "../scripts/modals.ts";
|
||||
import PostPublish from "../components/PostPublish.tsx";
|
||||
import PostList from "../components/PostList.tsx";
|
||||
import PostItem from "../components/PostItem.tsx";
|
||||
|
||||
export default function PostPage() {
|
||||
const [error, setError] = createSignal<string | null>(null);
|
||||
|
||||
const [page, setPage] = createSignal(0);
|
||||
const [related, setRelated] = createSignal<any>(null);
|
||||
const [info, setInfo] = createSignal<any>(null);
|
||||
|
||||
const params = useParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
async function readPost(pn?: number) {
|
||||
if (pn) setPage(pn);
|
||||
const res = await fetch(`/api/posts/${params["postId"]}?` + new URLSearchParams({
|
||||
take: (10).toString(),
|
||||
offset: ((page() - 1) * 10).toString()
|
||||
}));
|
||||
if (res.status !== 200) {
|
||||
setError(await res.text());
|
||||
} else {
|
||||
setError(null);
|
||||
const data = await res.json();
|
||||
setInfo(data["data"]);
|
||||
setRelated({
|
||||
count: data["count"],
|
||||
data: data["related"]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
readPost();
|
||||
|
||||
function setMeta(data: any, field: string, open = true) {
|
||||
const meta: { [id: string]: any } = {
|
||||
reposting: null,
|
||||
replying: null,
|
||||
editing: null
|
||||
};
|
||||
meta[field] = data;
|
||||
setPublishMeta(meta);
|
||||
|
||||
if (open) openModel("#post-publish");
|
||||
else closeModel("#post-publish");
|
||||
}
|
||||
|
||||
const [publishMeta, setPublishMeta] = createStore<any>({
|
||||
replying: null,
|
||||
reposting: null,
|
||||
editing: null
|
||||
});
|
||||
|
||||
function back() {
|
||||
if (window.history.length > 0) {
|
||||
window.history.back();
|
||||
} else {
|
||||
navigate("/");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id="alerts">
|
||||
<Show when={error()}>
|
||||
<div role="alert" class="alert alert-error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<span class="capitalize">{error()}</span>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
<div class="flex pt-1">
|
||||
<button class="btn btn-ghost ml-[20px] w-12 h-12" onClick={() => back()}>
|
||||
<i class="fa-solid fa-angle-left"></i>
|
||||
</button>
|
||||
<div class="px-5 flex items-center">
|
||||
<p>Post #{info()?.id}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<dialog id="post-publish" class="modal">
|
||||
<div class="modal-box p-0 w-[540px]">
|
||||
<PostPublish
|
||||
reposting={publishMeta.reposting}
|
||||
replying={publishMeta.replying}
|
||||
editing={publishMeta.editing}
|
||||
onReset={() => setMeta(null, "none", false)}
|
||||
onError={setError}
|
||||
onPost={() => readPost()}
|
||||
/>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<Show when={info()} fallback={
|
||||
<div class="w-full border-b border-base-200 pt-5 pb-7 text-center">
|
||||
<p class="loading loading-lg loading-infinity"></p>
|
||||
<p>Creating fake news...</p>
|
||||
</div>
|
||||
}>
|
||||
<PostItem
|
||||
noClick
|
||||
post={info()}
|
||||
onError={setError}
|
||||
onReact={readPost}
|
||||
onRepost={(item) => setMeta(item, "reposting")}
|
||||
onReply={(item) => setMeta(item, "replying")}
|
||||
onEdit={(item) => setMeta(item, "editing")}
|
||||
/>
|
||||
|
||||
<PostList
|
||||
noRelated
|
||||
info={related()}
|
||||
onUpdate={readPost}
|
||||
onError={setError}
|
||||
onRepost={(item) => setMeta(item, "reposting")}
|
||||
onReply={(item) => setMeta(item, "replying")}
|
||||
onEdit={(item) => setMeta(item, "editing")}
|
||||
/>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
}
|
@ -2,8 +2,8 @@ import { createSignal, Show } from "solid-js";
|
||||
import { createStore } from "solid-js/store";
|
||||
import { useParams } from "@solidjs/router";
|
||||
|
||||
import PostList from "../components/PostList.tsx";
|
||||
import PostPublish from "../components/PostPublish.tsx";
|
||||
import PostList from "../../components/PostList.tsx";
|
||||
import PostPublish from "../../components/PostPublish.tsx";
|
||||
|
||||
import styles from "./realm.module.css";
|
||||
|
Loading…
Reference in New Issue
Block a user