mirror of
https://github.com/Ategon/Jamjar.git
synced 2025-02-12 06:16:21 +00:00
Add post creation
This commit is contained in:
parent
2178675f2a
commit
047d630b14
6 changed files with 160 additions and 15 deletions
src
app
components
types
108
src/app/create-post/page.tsx
Normal file
108
src/app/create-post/page.tsx
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { getCookies, hasCookie } from "@/helpers/cookie";
|
||||||
|
import { Button, Form, Input, Textarea } from "@nextui-org/react";
|
||||||
|
import { redirect } from "next/navigation";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
|
export default function CreatePostPage() {
|
||||||
|
const [title, setTitle] = useState("");
|
||||||
|
const [content, setContent] = useState("");
|
||||||
|
const [errors, setErrors] = useState({});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="absolute flex items-center justify-center top-0 left-0 w-screen h-screen">
|
||||||
|
<Form
|
||||||
|
className="w-full max-w-xs flex flex-col gap-4"
|
||||||
|
validationErrors={errors}
|
||||||
|
onReset={() => {
|
||||||
|
setTitle("");
|
||||||
|
setContent("");
|
||||||
|
}}
|
||||||
|
onSubmit={async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!title && !content) {
|
||||||
|
setErrors({
|
||||||
|
title: "Please enter a valid title",
|
||||||
|
content: "Please enter valid content",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!title) {
|
||||||
|
setErrors({ title: "Please enter a valid title" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!content) {
|
||||||
|
setErrors({ content: "Please enter valid content" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasCookie()) {
|
||||||
|
setErrors({ content: "You are not logged in" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
process.env.NEXT_PUBLIC_MODE === "PROD"
|
||||||
|
? "https://d2jam.com/api/v1/post"
|
||||||
|
: "http://localhost:3005/api/v1/post",
|
||||||
|
{
|
||||||
|
body: JSON.stringify({
|
||||||
|
title: title,
|
||||||
|
content: content,
|
||||||
|
username: getCookies().user,
|
||||||
|
}),
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
authorization: `Bearer ${getCookies().token}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.status == 401) {
|
||||||
|
setErrors({ content: "Invalid user" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.success("Successfully created post");
|
||||||
|
|
||||||
|
redirect("/app");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
isRequired
|
||||||
|
label="Title"
|
||||||
|
labelPlacement="outside"
|
||||||
|
name="title"
|
||||||
|
placeholder="Enter a title"
|
||||||
|
type="text"
|
||||||
|
value={title}
|
||||||
|
onValueChange={setTitle}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Textarea
|
||||||
|
isRequired
|
||||||
|
label="Content"
|
||||||
|
labelPlacement="outside"
|
||||||
|
name="content"
|
||||||
|
placeholder="Enter the post body"
|
||||||
|
value={content}
|
||||||
|
onValueChange={setContent}
|
||||||
|
/>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button color="primary" type="submit">
|
||||||
|
Create
|
||||||
|
</Button>
|
||||||
|
<Button type="reset" variant="flat">
|
||||||
|
Reset
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -57,8 +57,10 @@ export default function UserPage() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = await response.json();
|
const { token, user } = await response.json();
|
||||||
|
|
||||||
document.cookie = `token=${token}`;
|
document.cookie = `token=${token}`;
|
||||||
|
document.cookie = `user=${user.slug}`;
|
||||||
|
|
||||||
toast.success("Successfully logged in");
|
toast.success("Successfully logged in");
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,12 @@ export default function UserPage() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (username.length > 32) {
|
||||||
|
setPassword2("");
|
||||||
|
setErrors({ password: "Usernames can be maximum 32 characters" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (password.length < 8) {
|
if (password.length < 8) {
|
||||||
setPassword2("");
|
setPassword2("");
|
||||||
setErrors({ password: "Password must be minimum 8 characters" });
|
setErrors({ password: "Password must be minimum 8 characters" });
|
||||||
|
@ -71,8 +77,15 @@ export default function UserPage() {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const token = await response.json();
|
if (response.status == 409) {
|
||||||
|
setErrors({ username: "User already exists" });
|
||||||
|
setPassword2("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { token, user } = await response.json();
|
||||||
document.cookie = `token=${token}`;
|
document.cookie = `token=${token}`;
|
||||||
|
document.cookie = `user=${user.slug}`;
|
||||||
|
|
||||||
toast.success("Successfully signed up");
|
toast.success("Successfully signed up");
|
||||||
|
|
||||||
|
|
|
@ -16,39 +16,41 @@ import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownTrigger,
|
DropdownTrigger,
|
||||||
Image,
|
Image,
|
||||||
|
Spacer,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from "@nextui-org/react";
|
} from "@nextui-org/react";
|
||||||
import { SiDiscord, SiForgejo, SiGithub } from "@icons-pack/react-simple-icons";
|
import { SiDiscord, SiForgejo, SiGithub } from "@icons-pack/react-simple-icons";
|
||||||
import { LogInIcon, NotebookPen } from "lucide-react";
|
import { LogInIcon, NotebookPen, SquarePen } from "lucide-react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { hasCookie, getCookies } from "@/helpers/cookie";
|
import { hasCookie, getCookies } from "@/helpers/cookie";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
|
import { UserType } from "@/types/UserType";
|
||||||
|
|
||||||
export default function Navbar() {
|
export default function Navbar() {
|
||||||
const [user, setUser] = useState("");
|
const [user, setUser] = useState<UserType>();
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadUser();
|
loadUser();
|
||||||
async function loadUser() {
|
async function loadUser() {
|
||||||
if (!hasCookie()) {
|
if (!hasCookie()) {
|
||||||
setUser("");
|
setUser(undefined);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
process.env.NEXT_PUBLIC_MODE === "PROD"
|
process.env.NEXT_PUBLIC_MODE === "PROD"
|
||||||
? "https://d2jam.com/api/v1/self"
|
? `https://d2jam.com/api/v1/self?username=${getCookies().user}`
|
||||||
: "http://localhost:3005/api/v1/self",
|
: `http://localhost:3005/api/v1/self?username=${getCookies().user}`,
|
||||||
{
|
{
|
||||||
headers: { authorization: `Bearer ${getCookies().token}` },
|
headers: { authorization: `Bearer ${getCookies().token}` },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if ((await response.text()) == "ok") {
|
if (response.status == 200) {
|
||||||
setUser("ok");
|
setUser(await response.json());
|
||||||
} else {
|
} else {
|
||||||
setUser("");
|
setUser(undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [pathname]);
|
}, [pathname]);
|
||||||
|
@ -78,6 +80,20 @@ export default function Navbar() {
|
||||||
</NavbarItem>
|
</NavbarItem>
|
||||||
</NavbarContent>
|
</NavbarContent>
|
||||||
<NavbarContent justify="end">
|
<NavbarContent justify="end">
|
||||||
|
{user && (
|
||||||
|
<NavbarItem>
|
||||||
|
<Link href="/create-post">
|
||||||
|
<Button
|
||||||
|
endContent={<SquarePen />}
|
||||||
|
className="text-white border-white/50 hover:border-green-100/50 hover:text-green-100 hover:scale-110 transition-all transform duration-500 ease-in-out"
|
||||||
|
variant="bordered"
|
||||||
|
>
|
||||||
|
Create Post
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
<Spacer x={32} />
|
||||||
|
</NavbarItem>
|
||||||
|
)}
|
||||||
<NavbarItem>
|
<NavbarItem>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
delay={1000}
|
delay={1000}
|
||||||
|
@ -154,7 +170,7 @@ export default function Navbar() {
|
||||||
) : (
|
) : (
|
||||||
<Dropdown>
|
<Dropdown>
|
||||||
<DropdownTrigger>
|
<DropdownTrigger>
|
||||||
<Avatar />
|
<Avatar src={user.profilePicture} />
|
||||||
</DropdownTrigger>
|
</DropdownTrigger>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
{/* <DropdownItem
|
{/* <DropdownItem
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { Avatar, Button, Card, CardBody, Spacer } from "@nextui-org/react";
|
import { Avatar, Card, CardBody, Spacer } from "@nextui-org/react";
|
||||||
import { Heart, MessageCircle } from "lucide-react";
|
|
||||||
import { formatDistance } from "date-fns";
|
import { formatDistance } from "date-fns";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PostType } from "@/types/PostType";
|
import { PostType } from "@/types/PostType";
|
||||||
|
@ -36,14 +35,14 @@ export default function PostCard({ post }: { post: PostType }) {
|
||||||
|
|
||||||
<Spacer y={4} />
|
<Spacer y={4} />
|
||||||
|
|
||||||
<div className="flex gap-3">
|
{/* <div className="flex gap-3">
|
||||||
<Button size="sm">
|
<Button size="sm">
|
||||||
<Heart size={16} /> {post.likers.length}
|
<Heart size={16} /> {post.likers.length}
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="sm">
|
<Button size="sm">
|
||||||
<MessageCircle size={16} /> {0}
|
<MessageCircle size={16} /> {0}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div> */}
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|
7
src/types/UserType.ts
Normal file
7
src/types/UserType.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export interface UserType {
|
||||||
|
id: number;
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
profilePicture: string;
|
||||||
|
createdAt: Date;
|
||||||
|
}
|
Loading…
Reference in a new issue