tie it all together
This commit is contained in:
@@ -1,13 +1,17 @@
|
|||||||
import { useAuth } from "../providers/AuthProvider";
|
import { useAuth } from "../providers/AuthProvider";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
const auth = useAuth();
|
const auth = useAuth();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap items-center justify-between gap-x-4 gap-y-1 py-4">
|
<div className="flex flex-wrap items-center justify-between gap-x-4 gap-y-1 py-4">
|
||||||
<h1 className="font-bold">
|
<a href="#" onClick={() => navigate("/")}>
|
||||||
Alex <span className="font-normal text-blue-500">/</span> dev + QA
|
<h1 className="font-bold">
|
||||||
</h1>
|
Alex <span className="font-normal text-blue-500">/</span> dev + QA
|
||||||
|
</h1>
|
||||||
|
</a>
|
||||||
<div className="flex gap-3 text-sm sm:text-base">
|
<div className="flex gap-3 text-sm sm:text-base">
|
||||||
{auth.user !== null ? (
|
{auth.user !== null ? (
|
||||||
<a href="#" onClick={() => auth.logout()}>
|
<a href="#" onClick={() => auth.logout()}>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ type InputType = {
|
|||||||
forLabel: string;
|
forLabel: string;
|
||||||
type: "password" | "email" | "text";
|
type: "password" | "email" | "text";
|
||||||
dark?: boolean;
|
dark?: boolean;
|
||||||
|
defaultValue?: string;
|
||||||
onChange?: (v: string) => void;
|
onChange?: (v: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@ export default function Input({
|
|||||||
label,
|
label,
|
||||||
forLabel,
|
forLabel,
|
||||||
type,
|
type,
|
||||||
|
defaultValue,
|
||||||
dark = true,
|
dark = true,
|
||||||
onChange,
|
onChange,
|
||||||
}: InputType) {
|
}: InputType) {
|
||||||
@@ -23,6 +25,7 @@ export default function Input({
|
|||||||
onChange={onChange ? (e) => onChange(e.target.value) : undefined}
|
onChange={onChange ? (e) => onChange(e.target.value) : undefined}
|
||||||
type={type}
|
type={type}
|
||||||
required
|
required
|
||||||
|
defaultValue={defaultValue}
|
||||||
name={forLabel}
|
name={forLabel}
|
||||||
className={`${dark ? "bg-black text-white" : "bg-white text-black"} rounded-lg border-white block`}
|
className={`${dark ? "bg-black text-white" : "bg-white text-black"} rounded-lg border-white block`}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ export default function Editor() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
async function createPost() {
|
async function createPost() {
|
||||||
console.log(values);
|
|
||||||
|
|
||||||
if (!values?.title || !values.content || !values.description) {
|
if (!values?.title || !values.content || !values.description) {
|
||||||
setError("Missing required value");
|
setError("Missing required value");
|
||||||
return;
|
return;
|
||||||
@@ -66,7 +64,13 @@ export default function Editor() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout isProtected={true}>
|
<Layout isProtected={true}>
|
||||||
<h1 className="text-2xl font-bold">
|
<p
|
||||||
|
className="text-sm opacity-50 hover:underline hover:cursor-pointer"
|
||||||
|
onClick={() => history.back()}
|
||||||
|
>
|
||||||
|
<- Back
|
||||||
|
</p>
|
||||||
|
<h1 className="text-2xl font-bold mb-4">
|
||||||
{editingPost ? "Edit" : "Create"} Post
|
{editingPost ? "Edit" : "Create"} Post
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@@ -76,6 +80,7 @@ export default function Editor() {
|
|||||||
label="Title"
|
label="Title"
|
||||||
type="text"
|
type="text"
|
||||||
dark={false}
|
dark={false}
|
||||||
|
defaultValue={editingPost?.title}
|
||||||
onChange={(v) =>
|
onChange={(v) =>
|
||||||
setValues((prevState) => {
|
setValues((prevState) => {
|
||||||
return {
|
return {
|
||||||
@@ -88,6 +93,7 @@ export default function Editor() {
|
|||||||
<Input
|
<Input
|
||||||
forLabel="description"
|
forLabel="description"
|
||||||
label="Description"
|
label="Description"
|
||||||
|
defaultValue={editingPost?.description}
|
||||||
type="text"
|
type="text"
|
||||||
dark={false}
|
dark={false}
|
||||||
onChange={(v) =>
|
onChange={(v) =>
|
||||||
@@ -131,7 +137,7 @@ export default function Editor() {
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="prose prose-invert">
|
<div className="prose prose-invert">
|
||||||
<Markdown>{values.content}</Markdown>
|
<Markdown>{values.content || editingPost?.content}</Markdown>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -142,6 +148,7 @@ export default function Editor() {
|
|||||||
>
|
>
|
||||||
Submit
|
Submit
|
||||||
</button>
|
</button>
|
||||||
|
<p className="text-red-300 font-semibold">{error}</p>
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
import Layout from "../components/layout";
|
import Layout from "../components/layout";
|
||||||
import PostRow from "../components/postRow";
|
import PostRow from "../components/postRow";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { useAuth } from "../providers/AuthProvider";
|
||||||
import type { Post } from "../utils/types";
|
import type { Post } from "../utils/types";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const [posts, setPosts] = useState<Post[] | null>(null);
|
const [posts, setPosts] = useState<Post[] | null>(null);
|
||||||
const [loaded, setLoaded] = useState<boolean>(false);
|
const [loaded, setLoaded] = useState<boolean>(false);
|
||||||
|
const auth = useAuth();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetch("/api/posts", {
|
fetch("/api/posts", {
|
||||||
@@ -51,7 +55,17 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<h1 className="font-semibold">Posts</h1>
|
<div className="flex justify-between">
|
||||||
|
<h1 className="font-semibold">Posts</h1>
|
||||||
|
{auth.user && (
|
||||||
|
<p
|
||||||
|
className="text-sm opacity-50 hover:cursor-pointer hover:underline"
|
||||||
|
onClick={() => navigate("/editor")}
|
||||||
|
>
|
||||||
|
Create
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<PostList />
|
<PostList />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import Layout from "../components/layout";
|
import Layout from "../components/layout";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams, useNavigate } from "react-router-dom";
|
||||||
|
import { useAuth } from "../providers/AuthProvider";
|
||||||
import type { Post } from "../utils/types";
|
import type { Post } from "../utils/types";
|
||||||
import Markdown from "react-markdown";
|
import Markdown from "react-markdown";
|
||||||
|
|
||||||
export default function Post() {
|
export default function Post() {
|
||||||
const [post, setPost] = useState<Post | null>(null);
|
const [post, setPost] = useState<Post | null>(null);
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const auth = useAuth();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (params.slug) {
|
if (params.slug) {
|
||||||
@@ -32,6 +35,13 @@ export default function Post() {
|
|||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<div className="my-2">
|
<div className="my-2">
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
onClick={() => navigate("/")}
|
||||||
|
className="text-sm opacity-50 hover:underline"
|
||||||
|
>
|
||||||
|
<- Home
|
||||||
|
</a>
|
||||||
<h1 className="text-2xl font-bold">{post.title}</h1>
|
<h1 className="text-2xl font-bold">{post.title}</h1>
|
||||||
<p className="text-sm opacity-50">{post.description}</p>
|
<p className="text-sm opacity-50">{post.description}</p>
|
||||||
|
|
||||||
@@ -46,6 +56,14 @@ export default function Post() {
|
|||||||
{post.updatedAt !== post.createdAt &&
|
{post.updatedAt !== post.createdAt &&
|
||||||
"- updated on " + new Date(post.updatedAt).toLocaleString()}
|
"- updated on " + new Date(post.updatedAt).toLocaleString()}
|
||||||
</p>
|
</p>
|
||||||
|
{auth.user && (
|
||||||
|
<p
|
||||||
|
className="text-sm opacity-50 underline hover:cursor-pointer"
|
||||||
|
onClick={() => navigate(`/editor/${post.slug}`)}
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user