Fix nits
This commit is contained in:
parent
2aff501c66
commit
cc2a1962bc
|
@ -2,11 +2,11 @@ import { JSONContent } from '@tiptap/core'
|
||||||
|
|
||||||
export type Post = {
|
export type Post = {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
title: string
|
||||||
content: JSONContent
|
content: JSONContent
|
||||||
creatorId: string // User id
|
creatorId: string // User id
|
||||||
createdTime: number
|
createdTime: number
|
||||||
slug: string
|
slug: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MAX_POST_NAME_LENGTH = 480
|
export const MAX_POST_TITLE_LENGTH = 480
|
||||||
|
|
|
@ -3,7 +3,7 @@ import * as admin from 'firebase-admin'
|
||||||
import { getUser } from './utils'
|
import { getUser } from './utils'
|
||||||
import { slugify } from '../../common/util/slugify'
|
import { slugify } from '../../common/util/slugify'
|
||||||
import { randomString } from '../../common/util/random'
|
import { randomString } from '../../common/util/random'
|
||||||
import { Post, MAX_POST_NAME_LENGTH } from '../../common/post'
|
import { Post, MAX_POST_TITLE_LENGTH } from '../../common/post'
|
||||||
import { APIError, newEndpoint, validate } from './api'
|
import { APIError, newEndpoint, validate } from './api'
|
||||||
import { JSONContent } from '@tiptap/core'
|
import { JSONContent } from '@tiptap/core'
|
||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
|
@ -32,21 +32,21 @@ const contentSchema: z.ZodType<JSONContent> = z.lazy(() =>
|
||||||
)
|
)
|
||||||
|
|
||||||
const postSchema = z.object({
|
const postSchema = z.object({
|
||||||
name: z.string().min(1).max(MAX_POST_NAME_LENGTH),
|
title: z.string().min(1).max(MAX_POST_TITLE_LENGTH),
|
||||||
content: contentSchema,
|
content: contentSchema,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const createpost = newEndpoint({}, async (req, auth) => {
|
export const createpost = newEndpoint({}, async (req, auth) => {
|
||||||
const firestore = admin.firestore()
|
const firestore = admin.firestore()
|
||||||
const { name, content } = validate(postSchema, req.body)
|
const { title, content } = validate(postSchema, req.body)
|
||||||
|
|
||||||
const creator = await getUser(auth.uid)
|
const creator = await getUser(auth.uid)
|
||||||
if (!creator)
|
if (!creator)
|
||||||
throw new APIError(400, 'No user exists with the authenticated user ID.')
|
throw new APIError(400, 'No user exists with the authenticated user ID.')
|
||||||
|
|
||||||
console.log('creating post owned by', creator.username, 'named', name)
|
console.log('creating post owned by', creator.username, 'titled', title)
|
||||||
|
|
||||||
const slug = await getSlug(name)
|
const slug = await getSlug(title)
|
||||||
|
|
||||||
const postRef = firestore.collection('posts').doc()
|
const postRef = firestore.collection('posts').doc()
|
||||||
|
|
||||||
|
@ -54,18 +54,18 @@ export const createpost = newEndpoint({}, async (req, auth) => {
|
||||||
id: postRef.id,
|
id: postRef.id,
|
||||||
creatorId: creator.id,
|
creatorId: creator.id,
|
||||||
slug,
|
slug,
|
||||||
name,
|
title,
|
||||||
createdTime: Date.now(),
|
createdTime: Date.now(),
|
||||||
content: content,
|
content: content,
|
||||||
}
|
}
|
||||||
|
|
||||||
await postRef.create(post)
|
await postRef.create(post)
|
||||||
|
|
||||||
return { status: 'success', post: post }
|
return { status: 'success', post }
|
||||||
})
|
})
|
||||||
|
|
||||||
export const getSlug = async (name: string) => {
|
export const getSlug = async (title: string) => {
|
||||||
const proposedSlug = slugify(name)
|
const proposedSlug = slugify(title)
|
||||||
|
|
||||||
const preexistingPost = await getPostFromSlug(proposedSlug)
|
const preexistingPost = await getPostFromSlug(proposedSlug)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { auth } from './users'
|
import { auth } from './users'
|
||||||
import { APIError, getFunctionUrl } from 'common/api'
|
import { APIError, getFunctionUrl } from 'common/api'
|
||||||
|
import { JSONContent } from '@tiptap/core'
|
||||||
export { APIError } from 'common/api'
|
export { APIError } from 'common/api'
|
||||||
|
|
||||||
export async function call(url: string, method: string, params: any) {
|
export async function call(url: string, method: string, params: any) {
|
||||||
|
@ -89,6 +90,6 @@ export function getCurrentUser(params: any) {
|
||||||
return call(getFunctionUrl('getcurrentuser'), 'GET', params)
|
return call(getFunctionUrl('getcurrentuser'), 'GET', params)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createPost(params: any) {
|
export function createPost(params: { title: string; content: JSONContent }) {
|
||||||
return call(getFunctionUrl('createpost'), 'POST', params)
|
return call(getFunctionUrl('createpost'), 'POST', params)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,26 +7,25 @@ import Textarea from 'react-expanding-textarea'
|
||||||
import { TextEditor, useTextEditor } from 'web/components/editor'
|
import { TextEditor, useTextEditor } from 'web/components/editor'
|
||||||
import { createPost } from 'web/lib/firebase/api'
|
import { createPost } from 'web/lib/firebase/api'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { useRouter } from 'next/router'
|
import Router from 'next/router'
|
||||||
import { Post, MAX_POST_NAME_LENGTH } from 'common/post'
|
import { MAX_POST_TITLE_LENGTH } from 'common/post'
|
||||||
import { postPath } from 'web/lib/firebase/posts'
|
import { postPath } from 'web/lib/firebase/posts'
|
||||||
|
|
||||||
export default function CreatePost() {
|
export default function CreatePost() {
|
||||||
const [name, setName] = useState('')
|
const [title, setTitle] = useState('')
|
||||||
const [error, setError] = useState('')
|
const [error, setError] = useState('')
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const { editor, upload } = useTextEditor({
|
const { editor, upload } = useTextEditor({
|
||||||
disabled: isSubmitting,
|
disabled: isSubmitting,
|
||||||
})
|
})
|
||||||
|
|
||||||
const isValid = editor && name.length > 0 && editor.isEmpty === false
|
const isValid = editor && title.length > 0 && editor.isEmpty === false
|
||||||
|
|
||||||
async function savePost(name: string) {
|
async function savePost(title: string) {
|
||||||
if (!editor) return
|
if (!editor) return
|
||||||
const newPost = {
|
const newPost = {
|
||||||
name: name,
|
title: title,
|
||||||
content: editor.getJSON(),
|
content: editor.getJSON(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +35,7 @@ export default function CreatePost() {
|
||||||
return e
|
return e
|
||||||
})
|
})
|
||||||
if (result.post) {
|
if (result.post) {
|
||||||
await router.push(postPath((result.post as Post).slug))
|
await Router.push(postPath(result.post.slug))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,16 +48,16 @@ export default function CreatePost() {
|
||||||
<div className="form-control w-full">
|
<div className="form-control w-full">
|
||||||
<label className="label">
|
<label className="label">
|
||||||
<span className="mb-1">
|
<span className="mb-1">
|
||||||
Name<span className={'text-red-700'}>*</span>
|
Title<span className={'text-red-700'}> *</span>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<Textarea
|
<Textarea
|
||||||
placeholder="e.g. Elon Mania Post"
|
placeholder="e.g. Elon Mania Post"
|
||||||
className="input input-bordered resize-none"
|
className="input input-bordered resize-none"
|
||||||
autoFocus
|
autoFocus
|
||||||
maxLength={MAX_POST_NAME_LENGTH}
|
maxLength={MAX_POST_TITLE_LENGTH}
|
||||||
value={name}
|
value={title}
|
||||||
onChange={(e) => setName(e.target.value || '')}
|
onChange={(e) => setTitle(e.target.value || '')}
|
||||||
/>
|
/>
|
||||||
<Spacer h={6} />
|
<Spacer h={6} />
|
||||||
<label className="label">
|
<label className="label">
|
||||||
|
@ -78,7 +77,7 @@ export default function CreatePost() {
|
||||||
disabled={isSubmitting || !isValid || upload.isLoading}
|
disabled={isSubmitting || !isValid || upload.isLoading}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setIsSubmitting(true)
|
setIsSubmitting(true)
|
||||||
await savePost(name)
|
await savePost(title)
|
||||||
setIsSubmitting(false)
|
setIsSubmitting(false)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { Page } from 'web/components/page'
|
import { Page } from 'web/components/page'
|
||||||
|
|
||||||
import { fromPropz, usePropz } from 'web/hooks/use-propz'
|
|
||||||
import { postPath, getPostBySlug } from 'web/lib/firebase/posts'
|
import { postPath, getPostBySlug } from 'web/lib/firebase/posts'
|
||||||
import { Post } from 'common/post'
|
import { Post } from 'common/post'
|
||||||
import { Title } from 'web/components/title'
|
import { Title } from 'web/components/title'
|
||||||
|
@ -18,13 +17,11 @@ import { Col } from 'web/components/layout/col'
|
||||||
import { ENV_CONFIG } from 'common/envs/constants'
|
import { ENV_CONFIG } from 'common/envs/constants'
|
||||||
import Custom404 from 'web/pages/404'
|
import Custom404 from 'web/pages/404'
|
||||||
|
|
||||||
export const getStaticProps = fromPropz(getStaticPropz)
|
export async function getStaticProps(props: { params: { slugs: string[] } }) {
|
||||||
export async function getStaticPropz(props: { params: { slugs: string[] } }) {
|
|
||||||
const { slugs } = props.params
|
const { slugs } = props.params
|
||||||
|
|
||||||
const post = await getPostBySlug(slugs[0])
|
const post = await getPostBySlug(slugs[0])
|
||||||
const creatorPromise = post ? getUser(post.creatorId) : null
|
const creator = post ? await getUser(post.creatorId) : null
|
||||||
const creator = await creatorPromise
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
|
@ -41,12 +38,9 @@ export async function getStaticPaths() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PostPage(props: { post: Post; creator: User }) {
|
export default function PostPage(props: { post: Post; creator: User }) {
|
||||||
props = usePropz(props, getStaticPropz) ?? {
|
|
||||||
post: null,
|
|
||||||
}
|
|
||||||
const [isShareOpen, setShareOpen] = useState(false)
|
const [isShareOpen, setShareOpen] = useState(false)
|
||||||
|
|
||||||
if (props.post === null) {
|
if (props.post == null) {
|
||||||
return <Custom404 />
|
return <Custom404 />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +50,7 @@ export default function PostPage(props: { post: Post; creator: User }) {
|
||||||
<Page>
|
<Page>
|
||||||
<div className="mx-auto w-full max-w-3xl ">
|
<div className="mx-auto w-full max-w-3xl ">
|
||||||
<Spacer h={1} />
|
<Spacer h={1} />
|
||||||
<Title className="!mt-0" text={props.post.name} />
|
<Title className="!mt-0" text={props.post.title} />
|
||||||
<Row>
|
<Row>
|
||||||
<Col className="flex-1">
|
<Col className="flex-1">
|
||||||
<div className={'inline-flex'}>
|
<div className={'inline-flex'}>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user