cookies fixes, hook improvement, more porting
This commit is contained in:
parent
95d1ef31ef
commit
cf7d89eb20
31 changed files with 138 additions and 277 deletions
|
@ -1,67 +1,33 @@
|
||||||
import styles from "@styles/Home.module.css"
|
|
||||||
import NewPost from "@components/new-post"
|
import NewPost from "@components/new-post"
|
||||||
import PageSeo from "@components/page-seo"
|
import { useRouter } from "next/navigation"
|
||||||
import { Page } from "@geist-ui/core/dist"
|
import { cookies } from "next/headers"
|
||||||
import Head from "next/head"
|
import { TOKEN_COOKIE_NAME } from "@lib/constants"
|
||||||
import { GetServerSideProps } from "next"
|
import { getPostWithFiles } from "app/prisma"
|
||||||
import { Post } from "@lib/types"
|
import { useRedirectIfNotAuthed } from "@lib/server/hooks/use-redirect-if-not-authed"
|
||||||
import cookie from "cookie"
|
const NewFromExisting = async ({
|
||||||
|
params
|
||||||
|
}: {
|
||||||
|
params: {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
}) => {
|
||||||
|
const { id } = params
|
||||||
|
const router = useRouter()
|
||||||
|
const cookieList = cookies()
|
||||||
|
useRedirectIfNotAuthed()
|
||||||
|
const driftToken = cookieList.get(TOKEN_COOKIE_NAME)
|
||||||
|
|
||||||
|
if (!driftToken) {
|
||||||
|
return router.push("/signin")
|
||||||
|
}
|
||||||
|
|
||||||
const NewFromExisting = async () => {
|
if (!id) {
|
||||||
return (
|
return router.push("/new")
|
||||||
// <Head>
|
}
|
||||||
// {/* TODO: solve this. */}
|
|
||||||
// {/* eslint-disable-next-line @next/next/no-css-tags */}
|
const post = await getPostWithFiles(id)
|
||||||
// <link rel="stylesheet" href="/css/react-datepicker.css" />
|
|
||||||
// </Head>
|
return <NewPost initialPost={post} newPostParent={id} />
|
||||||
<NewPost initialPost={post} newPostParent={parentId} />
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// export const getServerSideProps: GetServerSideProps = async ({
|
|
||||||
// req,
|
|
||||||
// params
|
|
||||||
// }) => {
|
|
||||||
// const id = params?.id
|
|
||||||
// const redirect = {
|
|
||||||
// redirect: {
|
|
||||||
// destination: "/new",
|
|
||||||
// permanent: false
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (!id) {
|
|
||||||
// return redirect
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const driftToken = cookie.parse(req.headers.cookie || "")[`drift-token`]
|
|
||||||
|
|
||||||
// const post = await fetch(`${process.env.API_URL}/posts/${id}`, {
|
|
||||||
// method: "GET",
|
|
||||||
// headers: {
|
|
||||||
// "Content-Type": "application/json",
|
|
||||||
// Authorization: `Bearer ${driftToken}`,
|
|
||||||
// "x-secret-key": process.env.SECRET_KEY || ""
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
|
|
||||||
// if (!post.ok) {
|
|
||||||
// return redirect
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const data = await post.json()
|
|
||||||
|
|
||||||
// if (!data) {
|
|
||||||
// return redirect
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return {
|
|
||||||
// props: {
|
|
||||||
// post: data,
|
|
||||||
// parentId: id
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
export default NewFromExisting
|
export default NewFromExisting
|
||||||
|
|
4
client/app/(posts)/new/layout.tsx
Normal file
4
client/app/(posts)/new/layout.tsx
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export default function NewLayout({ children }: { children: React.ReactNode }) {
|
||||||
|
// useRedirectIfNotAuthed()
|
||||||
|
return <>{children}</>;
|
||||||
|
}
|
|
@ -1,10 +1,6 @@
|
||||||
import NewPost from "@components/new-post"
|
import NewPost from "@components/new-post"
|
||||||
import '@styles/react-datepicker.css'
|
import '@styles/react-datepicker.css'
|
||||||
|
|
||||||
const New = () => {
|
const New = () => <NewPost />
|
||||||
return (
|
|
||||||
<NewPost />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default New
|
export default New
|
||||||
|
|
34
client/app/mine/page.tsx
Normal file
34
client/app/mine/page.tsx
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import styles from "@styles/Home.module.css"
|
||||||
|
|
||||||
|
import MyPosts from "@components/my-posts"
|
||||||
|
import type { GetServerSideProps } from "next"
|
||||||
|
import { Post } from "@lib/types"
|
||||||
|
import { Page } from "@geist-ui/core/dist"
|
||||||
|
import { getCookie } from "cookies-next"
|
||||||
|
import { TOKEN_COOKIE_NAME } from "@lib/constants"
|
||||||
|
import { useRouter } from "next/navigation"
|
||||||
|
import { cookies } from "next/headers"
|
||||||
|
export default function Mine() {
|
||||||
|
const router = useRouter()
|
||||||
|
const driftToken = cookies().get(TOKEN_COOKIE_NAME)
|
||||||
|
if (!driftToken) {
|
||||||
|
return router.push("/signin")
|
||||||
|
}
|
||||||
|
|
||||||
|
// const posts = await fetch(process.env.API_URL + `/posts/mine`, {
|
||||||
|
// method: "GET",
|
||||||
|
// headers: {
|
||||||
|
// "Content-Type": "application/json",
|
||||||
|
// Authorization: `Bearer ${driftToken}`,
|
||||||
|
// "x-secret-key": process.env.SECRET_KEY || ""
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
if (!posts.ok) {
|
||||||
|
return router.push("/signin")
|
||||||
|
}
|
||||||
|
|
||||||
|
const { posts, error, hasMore } = await posts.json()
|
||||||
|
|
||||||
|
return <MyPosts morePosts={hasMore} error={error} posts={posts} />
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import Cookies from "js-cookie"
|
import { TOKEN_COOKIE_NAME } from "@lib/constants"
|
||||||
|
import { getCookie } from "cookies-next"
|
||||||
import styles from "./admin.module.css"
|
import styles from "./admin.module.css"
|
||||||
import PostTable from "./post-table"
|
import PostTable from "./post-table"
|
||||||
import UserTable from "./user-table"
|
import UserTable from "./user-table"
|
||||||
|
@ -14,7 +15,7 @@ export const adminFetcher = async (
|
||||||
method: options?.method || "GET",
|
method: options?.method || "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${Cookies.get("drift-token")}`
|
Authorization: `Bearer ${getCookie(TOKEN_COOKIE_NAME)}`
|
||||||
},
|
},
|
||||||
body: options?.body && JSON.stringify(options.body)
|
body: options?.body && JSON.stringify(options.body)
|
||||||
})
|
})
|
||||||
|
|
|
@ -10,6 +10,7 @@ import Input from "@components/input"
|
||||||
import Button from "@components/button"
|
import Button from "@components/button"
|
||||||
import Note from "@components/note"
|
import Note from "@components/note"
|
||||||
import { USER_COOKIE_NAME } from "@lib/constants"
|
import { USER_COOKIE_NAME } from "@lib/constants"
|
||||||
|
import { setCookie } from "cookies-next"
|
||||||
|
|
||||||
const NO_EMPTY_SPACE_REGEX = /^\S*$/
|
const NO_EMPTY_SPACE_REGEX = /^\S*$/
|
||||||
const ERROR_MESSAGE =
|
const ERROR_MESSAGE =
|
||||||
|
@ -33,7 +34,7 @@ const Auth = ({
|
||||||
|
|
||||||
const handleJson = (json: any) => {
|
const handleJson = (json: any) => {
|
||||||
signin(json.token)
|
signin(json.token)
|
||||||
Cookies.set(USER_COOKIE_NAME, json.userId)
|
setCookie(USER_COOKIE_NAME, json.userId)
|
||||||
|
|
||||||
router.push("/new")
|
router.push("/new")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import PasswordModal from "@components/new-post/password-modal"
|
import PasswordModal from "@components/new-post/password-modal"
|
||||||
import { Button, ButtonGroup, Loading, useToasts } from "@geist-ui/core/dist"
|
import { Button, ButtonGroup, Loading, useToasts } from "@geist-ui/core/dist"
|
||||||
|
import { TOKEN_COOKIE_NAME } from "@lib/constants"
|
||||||
import type { PostVisibility } from "@lib/types"
|
import type { PostVisibility } from "@lib/types"
|
||||||
import Cookies from "js-cookie"
|
import { getCookie } from "cookies-next"
|
||||||
import { useCallback, useState } from "react"
|
import { useCallback, useState } from "react"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -21,7 +22,7 @@ const VisibilityControl = ({ postId, visibility, setVisibility }: Props) => {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${Cookies.get("drift-token")}`
|
Authorization: `Bearer ${getCookie(TOKEN_COOKIE_NAME)}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ visibility, password })
|
body: JSON.stringify({ visibility, password })
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,12 +2,11 @@
|
||||||
|
|
||||||
import { Button, useToasts, Input, ButtonDropdown } from "@geist-ui/core/dist"
|
import { Button, useToasts, Input, ButtonDropdown } from "@geist-ui/core/dist"
|
||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
|
import { useCallback, useState } from "react"
|
||||||
import generateUUID from "@lib/generate-uuid"
|
import generateUUID from "@lib/generate-uuid"
|
||||||
import FileDropzone from "./drag-and-drop"
|
import FileDropzone from "./drag-and-drop"
|
||||||
import styles from "./post.module.css"
|
import styles from "./post.module.css"
|
||||||
import Title from "./title"
|
import Title from "./title"
|
||||||
import Cookies from "js-cookie"
|
|
||||||
import type { PostVisibility, Document as DocumentType } from "@lib/types"
|
import type { PostVisibility, Document as DocumentType } from "@lib/types"
|
||||||
import PasswordModal from "./password-modal"
|
import PasswordModal from "./password-modal"
|
||||||
import EditDocumentList from "@components/edit-document-list"
|
import EditDocumentList from "@components/edit-document-list"
|
||||||
|
@ -16,7 +15,8 @@ import DatePicker from "react-datepicker"
|
||||||
import getTitleForPostCopy from "@lib/get-title-for-post-copy"
|
import getTitleForPostCopy from "@lib/get-title-for-post-copy"
|
||||||
import Description from "./description"
|
import Description from "./description"
|
||||||
import { PostWithFiles } from "app/prisma"
|
import { PostWithFiles } from "app/prisma"
|
||||||
import { USER_COOKIE_NAME } from "@lib/constants"
|
import { TOKEN_COOKIE_NAME, USER_COOKIE_NAME } from "@lib/constants"
|
||||||
|
import { getCookie } from "cookies-next"
|
||||||
|
|
||||||
const emptyDoc = {
|
const emptyDoc = {
|
||||||
title: "",
|
title: "",
|
||||||
|
@ -68,7 +68,7 @@ const Post = ({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${Cookies.get("drift-token")}`
|
Authorization: `Bearer ${getCookie(TOKEN_COOKIE_NAME)}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
title,
|
title,
|
||||||
|
@ -140,12 +140,13 @@ const Post = ({
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cookieName = getCookie(USER_COOKIE_NAME)
|
||||||
await sendRequest("/api/posts/create", {
|
await sendRequest("/api/posts/create", {
|
||||||
title,
|
title,
|
||||||
files: docs,
|
files: docs,
|
||||||
visibility,
|
visibility,
|
||||||
password,
|
password,
|
||||||
userId: Cookies.get(USER_COOKIE_NAME) || "",
|
userId: cookieName ? String(getCookie(USER_COOKIE_NAME)) : "",
|
||||||
expiresAt: expiresAt || null,
|
expiresAt: expiresAt || null,
|
||||||
parentId: newPostParent
|
parentId: newPostParent
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,9 +5,10 @@ import ListItemSkeleton from "./list-item-skeleton"
|
||||||
import ListItem from "./list-item"
|
import ListItem from "./list-item"
|
||||||
import { Post } from "@lib/types"
|
import { Post } from "@lib/types"
|
||||||
import { ChangeEvent, useCallback, useEffect, useMemo, useState } from "react"
|
import { ChangeEvent, useCallback, useEffect, useMemo, useState } from "react"
|
||||||
import Cookies from "js-cookie"
|
|
||||||
import useDebounce from "@lib/hooks/use-debounce"
|
import useDebounce from "@lib/hooks/use-debounce"
|
||||||
import Link from "@components/link"
|
import Link from "@components/link"
|
||||||
|
import { TOKEN_COOKIE_NAME } from "@lib/constants"
|
||||||
|
import { getCookie } from "cookies-next"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
initialPosts: Post[]
|
initialPosts: Post[]
|
||||||
|
@ -32,7 +33,7 @@ const PostList = ({ morePosts, initialPosts, error }: Props) => {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${Cookies.get("drift-token")}`,
|
Authorization: `Bearer ${getCookie(TOKEN_COOKIE_NAME)}`,
|
||||||
"x-page": `${posts.length / 10 + 1}`
|
"x-page": `${posts.length / 10 + 1}`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -61,7 +62,7 @@ const PostList = ({ morePosts, initialPosts, error }: Props) => {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${Cookies.get("drift-token")}`
|
Authorization: `Bearer ${getCookie(TOKEN_COOKIE_NAME)}`
|
||||||
// "tok": process.env.SECRET_KEY || ''
|
// "tok": process.env.SECRET_KEY || ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,7 +98,7 @@ const PostList = ({ morePosts, initialPosts, error }: Props) => {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${Cookies.get("drift-token")}`
|
Authorization: `Bearer ${getCookie(TOKEN_COOKIE_NAME)}`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,10 @@ import ScrollToTop from "@components/scroll-to-top"
|
||||||
import { useRouter } from "next/router"
|
import { useRouter } from "next/router"
|
||||||
import ExpirationBadge from "@components/badges/expiration-badge"
|
import ExpirationBadge from "@components/badges/expiration-badge"
|
||||||
import CreatedAgoBadge from "@components/badges/created-ago-badge"
|
import CreatedAgoBadge from "@components/badges/created-ago-badge"
|
||||||
import Cookies from "js-cookie"
|
|
||||||
import PasswordModalPage from "./password-modal-wrapper"
|
import PasswordModalPage from "./password-modal-wrapper"
|
||||||
import VisibilityControl from "@components/badges/visibility-control"
|
import VisibilityControl from "@components/badges/visibility-control"
|
||||||
import { USER_COOKIE_NAME } from "@lib/constants"
|
import { USER_COOKIE_NAME } from "@lib/constants"
|
||||||
|
import { getCookie } from "cookies-next"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
post: Post
|
post: Post
|
||||||
|
@ -33,7 +33,7 @@ const PostPage = ({ post: initialPost, isProtected }: Props) => {
|
||||||
)
|
)
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
const [isOwner] = useState(
|
const [isOwner] = useState(
|
||||||
post.users ? post.users[0].id === Cookies.get(USER_COOKIE_NAME) : false
|
post.users ? post.users[0].id === getCookie(USER_COOKIE_NAME) : false
|
||||||
)
|
)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const isMobile = useMediaQuery("mobile")
|
const isMobile = useMediaQuery("mobile")
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { getCookie } from "cookies-next"
|
||||||
import Cookies from "js-cookie"
|
import Cookies from "js-cookie"
|
||||||
import { memo, useEffect, useState } from "react"
|
import { memo, useEffect, useState } from "react"
|
||||||
import styles from "./preview.module.css"
|
import styles from "./preview.module.css"
|
||||||
|
@ -35,7 +36,7 @@ const MarkdownPreview = ({ height = 500, fileId, content, title }: Props) => {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${Cookies.get("drift-token") || ""}`
|
Authorization: `Bearer ${getCookie("drift-token")}`
|
||||||
},
|
},
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { Input, Button, useToasts } from "@geist-ui/core/dist"
|
import { Input, Button, useToasts } from "@geist-ui/core/dist"
|
||||||
|
import { TOKEN_COOKIE_NAME } from "@lib/constants"
|
||||||
|
import { getCookie } from "cookies-next"
|
||||||
import Cookies from "js-cookie"
|
import Cookies from "js-cookie"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
|
||||||
|
@ -43,7 +45,7 @@ const Password = () => {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${Cookies.get("drift-token")}`
|
Authorization: `Bearer ${getCookie(TOKEN_COOKIE_NAME)}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
oldPassword: password,
|
oldPassword: password,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import { Note, Input, Textarea, Button, useToasts } from "@geist-ui/core/dist"
|
import { Note, Input, Textarea, Button, useToasts } from "@geist-ui/core/dist"
|
||||||
|
import { TOKEN_COOKIE_NAME } from "@lib/constants"
|
||||||
import useUserData from "@lib/hooks/use-user-data"
|
import useUserData from "@lib/hooks/use-user-data"
|
||||||
|
import { getCookie } from "cookies-next"
|
||||||
import Cookies from "js-cookie"
|
import Cookies from "js-cookie"
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
|
|
||||||
|
@ -50,7 +52,7 @@ const Profile = () => {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${Cookies.get("drift-token")}`
|
Authorization: `Bearer ${getCookie(TOKEN_COOKIE_NAME)}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data)
|
body: JSON.stringify(data)
|
||||||
})
|
})
|
||||||
|
|
|
@ -9,6 +9,7 @@ const useSignedIn = () => {
|
||||||
"signedIn",
|
"signedIn",
|
||||||
typeof window === "undefined" ? false : !!token
|
typeof window === "undefined" ? false : !!token
|
||||||
)
|
)
|
||||||
|
|
||||||
const signin = (token: string) => {
|
const signin = (token: string) => {
|
||||||
setSignedIn(true)
|
setSignedIn(true)
|
||||||
// TODO: investigate SameSite / CORS cookie security
|
// TODO: investigate SameSite / CORS cookie security
|
||||||
|
|
|
@ -1,25 +1,26 @@
|
||||||
import { User } from "@lib/types"
|
import { User } from "@lib/types"
|
||||||
import Cookies from "js-cookie"
|
import { deleteCookie, getCookie } from "cookies-next"
|
||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
|
|
||||||
const useUserData = () => {
|
const useUserData = () => {
|
||||||
|
const cookie = getCookie("drift-token")
|
||||||
const [authToken, setAuthToken] = useState<string>(
|
const [authToken, setAuthToken] = useState<string>(
|
||||||
Cookies.get("drift-token") || ""
|
cookie ? String(cookie) : ""
|
||||||
)
|
)
|
||||||
const [user, setUser] = useState<User>()
|
const [user, setUser] = useState<User>()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const token = Cookies.get("drift-token")
|
const token = getCookie("drift-token")
|
||||||
if (token) {
|
if (token) {
|
||||||
setAuthToken(token)
|
setAuthToken(String(token))
|
||||||
}
|
}
|
||||||
}, [setAuthToken])
|
}, [setAuthToken])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (authToken) {
|
if (authToken) {
|
||||||
const fetchUser = async () => {
|
const fetchUser = async () => {
|
||||||
const response = await fetch(`/server-api/user/self`, {
|
const response = await fetch(`/api/user/self`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${authToken}`
|
Authorization: `Bearer ${authToken}`
|
||||||
}
|
}
|
||||||
|
@ -28,7 +29,7 @@ const useUserData = () => {
|
||||||
const user = await response.json()
|
const user = await response.json()
|
||||||
setUser(user)
|
setUser(user)
|
||||||
} else {
|
} else {
|
||||||
Cookies.remove("drift-token")
|
deleteCookie("drift-token")
|
||||||
setAuthToken("")
|
setAuthToken("")
|
||||||
router.push("/")
|
router.push("/")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
import clsx from "clsx";
|
|
||||||
import type {
|
|
||||||
ChangeEventHandler,
|
|
||||||
FunctionComponent,
|
|
||||||
PropsWithChildren,
|
|
||||||
} from "react";
|
|
||||||
import Cookies from "js-cookie";
|
|
||||||
import React, { useContext, useState, createContext } from "react";
|
|
||||||
import { DEFAULT_THEME, Theme, THEME_COOKIE_NAME } from "./theme";
|
|
||||||
|
|
||||||
const ThemeContext = createContext<Theme | null>(null);
|
|
||||||
|
|
||||||
export function useTheme(): Theme {
|
|
||||||
return useContext(ThemeContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props extends PropsWithChildren {
|
|
||||||
defaultTheme: Theme;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ThemeClientContextProvider: FunctionComponent<Props> = ({
|
|
||||||
defaultTheme,
|
|
||||||
children,
|
|
||||||
}) => {
|
|
||||||
const [theme, setTheme] = useState<Theme>(defaultTheme);
|
|
||||||
const onChange: ChangeEventHandler<HTMLSelectElement> = (e) => {
|
|
||||||
const value = e.target.value as Theme;
|
|
||||||
setTheme(value);
|
|
||||||
|
|
||||||
if (value === DEFAULT_THEME) {
|
|
||||||
Cookies.remove(THEME_COOKIE_NAME);
|
|
||||||
} else {
|
|
||||||
Cookies.set(THEME_COOKIE_NAME, value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const onReset = () => {
|
|
||||||
setTheme(DEFAULT_THEME);
|
|
||||||
Cookies.remove(THEME_COOKIE_NAME);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={clsx(theme === "dark" && "dark")}>
|
|
||||||
<div className="mb-2">
|
|
||||||
<h2 className="mb-2 font-bold text-xl">Theme Switcher</h2>
|
|
||||||
<select value={theme} onChange={onChange} className="mr-2 inline-block">
|
|
||||||
<option value="light">Light</option>
|
|
||||||
<option value="dark">Dark</option>
|
|
||||||
</select>
|
|
||||||
<button className="bg-gray-300 p-2" onClick={onReset}>
|
|
||||||
Reset
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ThemeClientContextProvider;
|
|
|
@ -1,27 +0,0 @@
|
||||||
import { FunctionComponent, PropsWithChildren } from "react";
|
|
||||||
import ThemeClientContextProvider from "./ThemeClientContextProvider";
|
|
||||||
import ThemeServerContextProvider, {
|
|
||||||
useServerTheme,
|
|
||||||
} from "./ThemeServerContextProvider";
|
|
||||||
|
|
||||||
const ThemeProviderWrapper: FunctionComponent<PropsWithChildren> = ({
|
|
||||||
children,
|
|
||||||
}) => {
|
|
||||||
const theme = useServerTheme();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ThemeClientContextProvider defaultTheme={theme}>
|
|
||||||
{children}
|
|
||||||
</ThemeClientContextProvider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ThemeProvider: FunctionComponent<PropsWithChildren> = ({ children }) => {
|
|
||||||
return (
|
|
||||||
<ThemeServerContextProvider>
|
|
||||||
<ThemeProviderWrapper>{children}</ThemeProviderWrapper>
|
|
||||||
</ThemeServerContextProvider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ThemeProvider;
|
|
|
@ -1,25 +0,0 @@
|
||||||
import type { FunctionComponent, PropsWithChildren } from "react";
|
|
||||||
// @ts-ignore -- createServerContext is not in @types/react atm
|
|
||||||
import { useContext, createServerContext } from "react";
|
|
||||||
import { cookies } from "next/headers";
|
|
||||||
import { Theme, THEME_COOKIE_NAME } from "./theme";
|
|
||||||
import { DEFAULT_THEME } from "./theme";
|
|
||||||
|
|
||||||
const ThemeContext = createServerContext<Theme | null>(null);
|
|
||||||
|
|
||||||
export function useServerTheme(): Theme {
|
|
||||||
return useContext(ThemeContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ThemeServerContextProvider: FunctionComponent<PropsWithChildren> = ({
|
|
||||||
children,
|
|
||||||
}) => {
|
|
||||||
const cookiesList = cookies();
|
|
||||||
const theme = cookiesList.get(THEME_COOKIE_NAME) ?? DEFAULT_THEME;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ThemeServerContextProvider;
|
|
|
@ -9,7 +9,7 @@ export async function generateAndExpireAccessToken(userId: User["id"]) {
|
||||||
await prisma.authTokens.create({
|
await prisma.authTokens.create({
|
||||||
data: {
|
data: {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
token: token
|
token: token,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
12
client/lib/server/hooks/use-redirect-if-not-authed.ts
Normal file
12
client/lib/server/hooks/use-redirect-if-not-authed.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
import { isSignedIn } from "../is-signed-in"
|
||||||
|
|
||||||
|
export const useRedirectIfNotAuthed = (to = '/signin') => {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const signedIn = isSignedIn();
|
||||||
|
|
||||||
|
if (!signedIn) {
|
||||||
|
router.push(to);
|
||||||
|
}
|
||||||
|
}
|
6
client/lib/server/is-signed-in.ts
Normal file
6
client/lib/server/is-signed-in.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { cookies } from "next/headers"
|
||||||
|
|
||||||
|
export const isSignedIn = () => {
|
||||||
|
const cookieList = cookies()
|
||||||
|
return cookieList.has("drift-token") && cookieList.has("drift-userid")
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import { NextApiRequest, NextApiResponse } from "next"
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
import prisma from "app/prisma"
|
import prisma from "app/prisma"
|
||||||
import bcrypt from "bcrypt"
|
import bcrypt from "bcrypt"
|
||||||
import { signin } from "@lib/api/signin"
|
import { signin } from "@lib/server/signin"
|
||||||
|
|
||||||
export default async function handler(
|
export default async function handler(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import config from "@lib/config"
|
||||||
import { NextApiRequest, NextApiResponse } from "next"
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
import prisma from "app/prisma"
|
import prisma from "app/prisma"
|
||||||
import bcrypt, { genSalt } from "bcrypt"
|
import bcrypt, { genSalt } from "bcrypt"
|
||||||
import { generateAndExpireAccessToken } from "@lib/api/generate-access-token"
|
import { generateAndExpireAccessToken } from "@lib/server/generate-access-token"
|
||||||
|
|
||||||
export default async function handler(
|
export default async function handler(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
|
@ -35,7 +35,7 @@ export default async function handler(
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const token = await generateAndExpireAccessToken(user)
|
const token = await generateAndExpireAccessToken(user.id)
|
||||||
|
|
||||||
return res.status(201).json({ token: token, userId: user.id })
|
return res.status(201).json({ token: token, userId: user.id })
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import getHtmlFromFile from "@lib/api/get-html-from-drift-file"
|
import getHtmlFromFile from "@lib/server/get-html-from-drift-file"
|
||||||
import { parseUrlQuery } from "@lib/api/parse-url-query"
|
import { parseUrlQuery } from "@lib/server/parse-url-query"
|
||||||
import prisma from "app/prisma"
|
import prisma from "app/prisma"
|
||||||
import { NextApiRequest, NextApiResponse } from "next"
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
|
||||||
|
|
11
client/pages/api/posts/users-posts.ts
Normal file
11
client/pages/api/posts/users-posts.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import prisma from "app/prisma"
|
||||||
|
|
||||||
|
export const getPostsByUser = async (userId: number) => {
|
||||||
|
const posts = await prisma.post.findMany({
|
||||||
|
where: {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return posts
|
||||||
|
}
|
|
@ -13,7 +13,6 @@ export const getWelcomeContent = async () => {
|
||||||
|
|
||||||
console.log(introContent)
|
console.log(introContent)
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: introTitle,
|
title: introTitle,
|
||||||
content: introContent,
|
content: introContent,
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
import styles from "@styles/Home.module.css"
|
|
||||||
|
|
||||||
import Header from "@components/header"
|
|
||||||
import MyPosts from "@components/my-posts"
|
|
||||||
import cookie from "cookie"
|
|
||||||
import type { GetServerSideProps } from "next"
|
|
||||||
import { Post } from "@lib/types"
|
|
||||||
import { Page } from "@geist-ui/core/dist"
|
|
||||||
|
|
||||||
const Home = ({
|
|
||||||
morePosts,
|
|
||||||
posts,
|
|
||||||
error
|
|
||||||
}: {
|
|
||||||
morePosts: boolean
|
|
||||||
posts: Post[]
|
|
||||||
error: boolean
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<Page className={styles.wrapper}>
|
|
||||||
<Page.Content className={styles.main}>
|
|
||||||
<MyPosts morePosts={morePosts} error={error} posts={posts} />
|
|
||||||
</Page.Content>
|
|
||||||
</Page>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// get server side props
|
|
||||||
export const getServerSideProps: GetServerSideProps = async ({ req }) => {
|
|
||||||
const driftToken = cookie.parse(req.headers.cookie || "")[`drift-token`]
|
|
||||||
if (!driftToken) {
|
|
||||||
return {
|
|
||||||
redirect: {
|
|
||||||
destination: "/",
|
|
||||||
permanent: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const posts = await fetch(process.env.API_URL + `/posts/mine`, {
|
|
||||||
method: "GET",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authorization: `Bearer ${driftToken}`,
|
|
||||||
"x-secret-key": process.env.SECRET_KEY || ""
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!posts.ok) {
|
|
||||||
return {
|
|
||||||
redirect: {
|
|
||||||
destination: "/",
|
|
||||||
permanent: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await posts.json()
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
posts: data.posts,
|
|
||||||
error: posts.status !== 200,
|
|
||||||
morePosts: data.hasMore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Home
|
|
Loading…
Reference in a new issue