Renamed Dashboards to Posts
This commit is contained in:
parent
9c3b3920ef
commit
2aff501c66
|
@ -1,6 +1,6 @@
|
||||||
import { JSONContent } from '@tiptap/core'
|
import { JSONContent } from '@tiptap/core'
|
||||||
|
|
||||||
export type Dashboard = {
|
export type Post = {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
content: JSONContent
|
content: JSONContent
|
||||||
|
@ -9,4 +9,4 @@ export type Dashboard = {
|
||||||
slug: string
|
slug: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MAX_DASHBOARD_NAME_LENGTH = 480
|
export const MAX_POST_NAME_LENGTH = 480
|
|
@ -170,7 +170,7 @@ service cloud.firestore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match /dashboards/{dashboardId} {
|
match /posts/{postId} {
|
||||||
allow read;
|
allow read;
|
||||||
allow update: if request.auth.uid == resource.data.creatorId
|
allow update: if request.auth.uid == resource.data.creatorId
|
||||||
&& request.resource.data.diff(resource.data)
|
&& request.resource.data.diff(resource.data)
|
||||||
|
|
|
@ -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 { Dashboard, MAX_DASHBOARD_NAME_LENGTH } from '../../common/dashboard'
|
import { Post, MAX_POST_NAME_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'
|
||||||
|
@ -31,27 +31,27 @@ const contentSchema: z.ZodType<JSONContent> = z.lazy(() =>
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
const dashboardSchema = z.object({
|
const postSchema = z.object({
|
||||||
name: z.string().min(1).max(MAX_DASHBOARD_NAME_LENGTH),
|
name: z.string().min(1).max(MAX_POST_NAME_LENGTH),
|
||||||
content: contentSchema,
|
content: contentSchema,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const createdashboard = newEndpoint({}, async (req, auth) => {
|
export const createpost = newEndpoint({}, async (req, auth) => {
|
||||||
const firestore = admin.firestore()
|
const firestore = admin.firestore()
|
||||||
const { name, content } = validate(dashboardSchema, req.body)
|
const { name, 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 dashboard owned by', creator.username, 'named', name)
|
console.log('creating post owned by', creator.username, 'named', name)
|
||||||
|
|
||||||
const slug = await getSlug(name)
|
const slug = await getSlug(name)
|
||||||
|
|
||||||
const dashboardRef = firestore.collection('dashboards').doc()
|
const postRef = firestore.collection('posts').doc()
|
||||||
|
|
||||||
const dashboard: Dashboard = {
|
const post: Post = {
|
||||||
id: dashboardRef.id,
|
id: postRef.id,
|
||||||
creatorId: creator.id,
|
creatorId: creator.id,
|
||||||
slug,
|
slug,
|
||||||
name,
|
name,
|
||||||
|
@ -59,27 +59,25 @@ export const createdashboard = newEndpoint({}, async (req, auth) => {
|
||||||
content: content,
|
content: content,
|
||||||
}
|
}
|
||||||
|
|
||||||
await dashboardRef.create(dashboard)
|
await postRef.create(post)
|
||||||
|
|
||||||
return { status: 'success', dashboard: dashboard }
|
return { status: 'success', post: post }
|
||||||
})
|
})
|
||||||
|
|
||||||
export const getSlug = async (name: string) => {
|
export const getSlug = async (name: string) => {
|
||||||
const proposedSlug = slugify(name)
|
const proposedSlug = slugify(name)
|
||||||
|
|
||||||
const preexistingDashboard = await getDashboardFromSlug(proposedSlug)
|
const preexistingPost = await getPostFromSlug(proposedSlug)
|
||||||
|
|
||||||
return preexistingDashboard
|
return preexistingPost ? proposedSlug + '-' + randomString() : proposedSlug
|
||||||
? proposedSlug + '-' + randomString()
|
|
||||||
: proposedSlug
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getDashboardFromSlug(slug: string) {
|
export async function getPostFromSlug(slug: string) {
|
||||||
const firestore = admin.firestore()
|
const firestore = admin.firestore()
|
||||||
const snap = await firestore
|
const snap = await firestore
|
||||||
.collection('dashboards')
|
.collection('posts')
|
||||||
.where('slug', '==', slug)
|
.where('slug', '==', slug)
|
||||||
.get()
|
.get()
|
||||||
|
|
||||||
return snap.empty ? undefined : (snap.docs[0].data() as Dashboard)
|
return snap.empty ? undefined : (snap.docs[0].data() as Post)
|
||||||
}
|
}
|
|
@ -71,7 +71,7 @@ import { stripewebhook, createcheckoutsession } from './stripe'
|
||||||
import { getcurrentuser } from './get-current-user'
|
import { getcurrentuser } from './get-current-user'
|
||||||
import { acceptchallenge } from './accept-challenge'
|
import { acceptchallenge } from './accept-challenge'
|
||||||
import { getcustomtoken } from './get-custom-token'
|
import { getcustomtoken } from './get-custom-token'
|
||||||
import { createdashboard } from './create-dashboard'
|
import { createpost } from './create-post'
|
||||||
|
|
||||||
const toCloudFunction = ({ opts, handler }: EndpointDefinition) => {
|
const toCloudFunction = ({ opts, handler }: EndpointDefinition) => {
|
||||||
return onRequest(opts, handler as any)
|
return onRequest(opts, handler as any)
|
||||||
|
@ -97,7 +97,7 @@ const createCheckoutSessionFunction = toCloudFunction(createcheckoutsession)
|
||||||
const getCurrentUserFunction = toCloudFunction(getcurrentuser)
|
const getCurrentUserFunction = toCloudFunction(getcurrentuser)
|
||||||
const acceptChallenge = toCloudFunction(acceptchallenge)
|
const acceptChallenge = toCloudFunction(acceptchallenge)
|
||||||
const getCustomTokenFunction = toCloudFunction(getcustomtoken)
|
const getCustomTokenFunction = toCloudFunction(getcustomtoken)
|
||||||
const createDashboardFunction = toCloudFunction(createdashboard)
|
const createPostFunction = toCloudFunction(createpost)
|
||||||
|
|
||||||
export {
|
export {
|
||||||
healthFunction as health,
|
healthFunction as health,
|
||||||
|
@ -121,5 +121,5 @@ export {
|
||||||
getCurrentUserFunction as getcurrentuser,
|
getCurrentUserFunction as getcurrentuser,
|
||||||
acceptChallenge as acceptchallenge,
|
acceptChallenge as acceptchallenge,
|
||||||
getCustomTokenFunction as getcustomtoken,
|
getCustomTokenFunction as getcustomtoken,
|
||||||
createDashboardFunction as createdashboard,
|
createPostFunction as createpost,
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ import { unsubscribe } from './unsubscribe'
|
||||||
import { stripewebhook, createcheckoutsession } from './stripe'
|
import { stripewebhook, createcheckoutsession } from './stripe'
|
||||||
import { getcurrentuser } from './get-current-user'
|
import { getcurrentuser } from './get-current-user'
|
||||||
import { getcustomtoken } from './get-custom-token'
|
import { getcustomtoken } from './get-custom-token'
|
||||||
import { createdashboard } from './create-dashboard'
|
import { createpost } from './create-post'
|
||||||
|
|
||||||
type Middleware = (req: Request, res: Response, next: NextFunction) => void
|
type Middleware = (req: Request, res: Response, next: NextFunction) => void
|
||||||
const app = express()
|
const app = express()
|
||||||
|
@ -68,7 +68,7 @@ addJsonEndpointRoute('/createcheckoutsession', createcheckoutsession)
|
||||||
addJsonEndpointRoute('/getcurrentuser', getcurrentuser)
|
addJsonEndpointRoute('/getcurrentuser', getcurrentuser)
|
||||||
addEndpointRoute('/getcustomtoken', getcustomtoken)
|
addEndpointRoute('/getcustomtoken', getcustomtoken)
|
||||||
addEndpointRoute('/stripewebhook', stripewebhook, express.raw())
|
addEndpointRoute('/stripewebhook', stripewebhook, express.raw())
|
||||||
addEndpointRoute('/createdashboard', createdashboard)
|
addEndpointRoute('/createpost', createpost)
|
||||||
|
|
||||||
app.listen(PORT)
|
app.listen(PORT)
|
||||||
console.log(`Serving functions on port ${PORT}.`)
|
console.log(`Serving functions on port ${PORT}.`)
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { chunk } from 'lodash'
|
||||||
import { Contract } from '../../common/contract'
|
import { Contract } from '../../common/contract'
|
||||||
import { PrivateUser, User } from '../../common/user'
|
import { PrivateUser, User } from '../../common/user'
|
||||||
import { Group } from '../../common/group'
|
import { Group } from '../../common/group'
|
||||||
import { Dashboard } from 'common/dashboard'
|
import { Post } from 'common/post'
|
||||||
|
|
||||||
export const log = (...args: unknown[]) => {
|
export const log = (...args: unknown[]) => {
|
||||||
console.log(`[${new Date().toISOString()}]`, ...args)
|
console.log(`[${new Date().toISOString()}]`, ...args)
|
||||||
|
@ -81,8 +81,8 @@ export const getGroup = (groupId: string) => {
|
||||||
return getDoc<Group>('groups', groupId)
|
return getDoc<Group>('groups', groupId)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getDashboard = (dashboardId: string) => {
|
export const getPost = (postId: string) => {
|
||||||
return getDoc<Dashboard>('dashboards', dashboardId)
|
return getDoc<Post>('posts', postId)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getUser = (userId: string) => {
|
export const getUser = (userId: string) => {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { Button } from './button'
|
||||||
import { TweetButton } from './tweet-button'
|
import { TweetButton } from './tweet-button'
|
||||||
import { Row } from './layout/row'
|
import { Row } from './layout/row'
|
||||||
|
|
||||||
export function ShareDashboardModal(props: {
|
export function SharePostModal(props: {
|
||||||
shareUrl: string
|
shareUrl: string
|
||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
setOpen: (open: boolean) => void
|
setOpen: (open: boolean) => void
|
||||||
|
@ -21,7 +21,7 @@ export function ShareDashboardModal(props: {
|
||||||
return (
|
return (
|
||||||
<Modal open={isOpen} setOpen={setOpen} size="md">
|
<Modal open={isOpen} setOpen={setOpen} size="md">
|
||||||
<Col className="gap-4 rounded bg-white p-4">
|
<Col className="gap-4 rounded bg-white p-4">
|
||||||
<Title className="!mt-0 !mb-2" text="Share this dashboard" />
|
<Title className="!mt-0 !mb-2" text="Share this post" />
|
||||||
<Button
|
<Button
|
||||||
size="2xl"
|
size="2xl"
|
||||||
color="gradient"
|
color="gradient"
|
||||||
|
@ -31,7 +31,7 @@ export function ShareDashboardModal(props: {
|
||||||
toast.success('Link copied!', {
|
toast.success('Link copied!', {
|
||||||
icon: linkIcon,
|
icon: linkIcon,
|
||||||
})
|
})
|
||||||
track('copy share dashboard link')
|
track('copy share post link')
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{linkIcon} Copy link
|
{linkIcon} Copy link
|
|
@ -89,6 +89,6 @@ export function getCurrentUser(params: any) {
|
||||||
return call(getFunctionUrl('getcurrentuser'), 'GET', params)
|
return call(getFunctionUrl('getcurrentuser'), 'GET', params)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createDashboard(params: any) {
|
export function createPost(params: any) {
|
||||||
return call(getFunctionUrl('createdashboard'), 'POST', params)
|
return call(getFunctionUrl('createpost'), 'POST', params)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
import {
|
|
||||||
deleteDoc,
|
|
||||||
doc,
|
|
||||||
getDocs,
|
|
||||||
query,
|
|
||||||
updateDoc,
|
|
||||||
where,
|
|
||||||
} from 'firebase/firestore'
|
|
||||||
import { Dashboard } from 'common/dashboard'
|
|
||||||
import { coll, getValue } from './utils'
|
|
||||||
|
|
||||||
export const dashboards = coll<Dashboard>('dashboards')
|
|
||||||
|
|
||||||
export function dashboardPath(dashboardSlug: string) {
|
|
||||||
return `/dashboard/${dashboardSlug}`
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateDashboard(
|
|
||||||
dashboard: Dashboard,
|
|
||||||
updates: Partial<Dashboard>
|
|
||||||
) {
|
|
||||||
return updateDoc(doc(dashboards, dashboard.id), updates)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteDashboard(dashboard: Dashboard) {
|
|
||||||
return deleteDoc(doc(dashboards, dashboard.id))
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDashboard(dashboardId: string) {
|
|
||||||
return getValue<Dashboard>(doc(dashboards, dashboardId))
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getDashboardBySlug(slug: string) {
|
|
||||||
const q = query(dashboards, where('slug', '==', slug))
|
|
||||||
const docs = (await getDocs(q)).docs
|
|
||||||
return docs.length === 0 ? null : docs[0].data()
|
|
||||||
}
|
|
34
web/lib/firebase/posts.ts
Normal file
34
web/lib/firebase/posts.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import {
|
||||||
|
deleteDoc,
|
||||||
|
doc,
|
||||||
|
getDocs,
|
||||||
|
query,
|
||||||
|
updateDoc,
|
||||||
|
where,
|
||||||
|
} from 'firebase/firestore'
|
||||||
|
import { Post } from 'common/post'
|
||||||
|
import { coll, getValue } from './utils'
|
||||||
|
|
||||||
|
export const posts = coll<Post>('posts')
|
||||||
|
|
||||||
|
export function postPath(postSlug: string) {
|
||||||
|
return `/post/${postSlug}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updatePost(post: Post, updates: Partial<Post>) {
|
||||||
|
return updateDoc(doc(posts, post.id), updates)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deletePost(post: Post) {
|
||||||
|
return deleteDoc(doc(posts, post.id))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPost(postId: string) {
|
||||||
|
return getValue<Post>(doc(posts, postId))
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPostBySlug(slug: string) {
|
||||||
|
const q = query(posts, where('slug', '==', slug))
|
||||||
|
const docs = (await getDocs(q)).docs
|
||||||
|
return docs.length === 0 ? null : docs[0].data()
|
||||||
|
}
|
|
@ -5,13 +5,13 @@ import { Title } from 'web/components/title'
|
||||||
import Textarea from 'react-expanding-textarea'
|
import Textarea from 'react-expanding-textarea'
|
||||||
|
|
||||||
import { TextEditor, useTextEditor } from 'web/components/editor'
|
import { TextEditor, useTextEditor } from 'web/components/editor'
|
||||||
import { createDashboard } 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 { useRouter } from 'next/router'
|
||||||
import { Dashboard, MAX_DASHBOARD_NAME_LENGTH } from 'common/dashboard'
|
import { Post, MAX_POST_NAME_LENGTH } from 'common/post'
|
||||||
import { dashboardPath } from 'web/lib/firebase/dashboards'
|
import { postPath } from 'web/lib/firebase/posts'
|
||||||
|
|
||||||
export default function CreateDashboard() {
|
export default function CreatePost() {
|
||||||
const [name, setName] = useState('')
|
const [name, setName] = useState('')
|
||||||
const [error, setError] = useState('')
|
const [error, setError] = useState('')
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
|
@ -23,20 +23,20 @@ export default function CreateDashboard() {
|
||||||
|
|
||||||
const isValid = editor && name.length > 0 && editor.isEmpty === false
|
const isValid = editor && name.length > 0 && editor.isEmpty === false
|
||||||
|
|
||||||
async function saveDashboard(name: string) {
|
async function savePost(name: string) {
|
||||||
if (!editor) return
|
if (!editor) return
|
||||||
const newDashboard = {
|
const newPost = {
|
||||||
name: name,
|
name: name,
|
||||||
content: editor.getJSON(),
|
content: editor.getJSON(),
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await createDashboard(newDashboard).catch((e) => {
|
const result = await createPost(newPost).catch((e) => {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
setError('There was an error creating the dashboard, please try again')
|
setError('There was an error creating the post, please try again')
|
||||||
return e
|
return e
|
||||||
})
|
})
|
||||||
if (result.dashboard) {
|
if (result.post) {
|
||||||
await router.push(dashboardPath((result.dashboard as Dashboard).slug))
|
await router.push(postPath((result.post as Post).slug))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ export default function CreateDashboard() {
|
||||||
<Page>
|
<Page>
|
||||||
<div className="mx-auto w-full max-w-2xl">
|
<div className="mx-auto w-full max-w-2xl">
|
||||||
<div className="rounded-lg px-6 py-4 sm:py-0">
|
<div className="rounded-lg px-6 py-4 sm:py-0">
|
||||||
<Title className="!mt-0" text="Create a dashboard" />
|
<Title className="!mt-0" text="Create a post" />
|
||||||
<form>
|
<form>
|
||||||
<div className="form-control w-full">
|
<div className="form-control w-full">
|
||||||
<label className="label">
|
<label className="label">
|
||||||
|
@ -53,10 +53,10 @@ export default function CreateDashboard() {
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<Textarea
|
<Textarea
|
||||||
placeholder="e.g. Elon Mania Dashboard"
|
placeholder="e.g. Elon Mania Post"
|
||||||
className="input input-bordered resize-none"
|
className="input input-bordered resize-none"
|
||||||
autoFocus
|
autoFocus
|
||||||
maxLength={MAX_DASHBOARD_NAME_LENGTH}
|
maxLength={MAX_POST_NAME_LENGTH}
|
||||||
value={name}
|
value={name}
|
||||||
onChange={(e) => setName(e.target.value || '')}
|
onChange={(e) => setName(e.target.value || '')}
|
||||||
/>
|
/>
|
||||||
|
@ -78,11 +78,11 @@ export default function CreateDashboard() {
|
||||||
disabled={isSubmitting || !isValid || upload.isLoading}
|
disabled={isSubmitting || !isValid || upload.isLoading}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setIsSubmitting(true)
|
setIsSubmitting(true)
|
||||||
await saveDashboard(name)
|
await savePost(name)
|
||||||
setIsSubmitting(false)
|
setIsSubmitting(false)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isSubmitting ? 'Creating...' : 'Create a dashboard'}
|
{isSubmitting ? 'Creating...' : 'Create a post'}
|
||||||
</button>
|
</button>
|
||||||
{error !== '' && <div className="text-red-700">{error}</div>}
|
{error !== '' && <div className="text-red-700">{error}</div>}
|
||||||
</div>
|
</div>
|
|
@ -1,8 +1,8 @@
|
||||||
import { Page } from 'web/components/page'
|
import { Page } from 'web/components/page'
|
||||||
|
|
||||||
import { fromPropz, usePropz } from 'web/hooks/use-propz'
|
import { fromPropz, usePropz } from 'web/hooks/use-propz'
|
||||||
import { dashboardPath, getDashboardBySlug } from 'web/lib/firebase/dashboards'
|
import { postPath, getPostBySlug } from 'web/lib/firebase/posts'
|
||||||
import { Dashboard } from 'common/dashboard'
|
import { Post } from 'common/post'
|
||||||
import { Title } from 'web/components/title'
|
import { Title } from 'web/components/title'
|
||||||
import { Spacer } from 'web/components/layout/spacer'
|
import { Spacer } from 'web/components/layout/spacer'
|
||||||
import { Content } from 'web/components/editor'
|
import { Content } from 'web/components/editor'
|
||||||
|
@ -12,7 +12,7 @@ import { ShareIcon } from '@heroicons/react/solid'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { Button } from 'web/components/button'
|
import { Button } from 'web/components/button'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { ShareDashboardModal } from 'web/components/share-dashboard-modal'
|
import { SharePostModal } from 'web/components/share-post-modal'
|
||||||
import { Row } from 'web/components/layout/row'
|
import { Row } from 'web/components/layout/row'
|
||||||
import { Col } from 'web/components/layout/col'
|
import { Col } from 'web/components/layout/col'
|
||||||
import { ENV_CONFIG } from 'common/envs/constants'
|
import { ENV_CONFIG } from 'common/envs/constants'
|
||||||
|
@ -22,13 +22,13 @@ export const getStaticProps = fromPropz(getStaticPropz)
|
||||||
export async function getStaticPropz(props: { params: { slugs: string[] } }) {
|
export async function getStaticPropz(props: { params: { slugs: string[] } }) {
|
||||||
const { slugs } = props.params
|
const { slugs } = props.params
|
||||||
|
|
||||||
const dashboard = await getDashboardBySlug(slugs[0])
|
const post = await getPostBySlug(slugs[0])
|
||||||
const creatorPromise = dashboard ? getUser(dashboard.creatorId) : null
|
const creatorPromise = post ? getUser(post.creatorId) : null
|
||||||
const creator = await creatorPromise
|
const creator = await creatorPromise
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
dashboard: dashboard,
|
post: post,
|
||||||
creator: creator,
|
creator: creator,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -40,28 +40,23 @@ export async function getStaticPaths() {
|
||||||
return { paths: [], fallback: 'blocking' }
|
return { paths: [], fallback: 'blocking' }
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function DashboardPage(props: {
|
export default function PostPage(props: { post: Post; creator: User }) {
|
||||||
dashboard: Dashboard
|
|
||||||
creator: User
|
|
||||||
}) {
|
|
||||||
props = usePropz(props, getStaticPropz) ?? {
|
props = usePropz(props, getStaticPropz) ?? {
|
||||||
dashboard: null,
|
post: null,
|
||||||
}
|
}
|
||||||
const [isShareOpen, setShareOpen] = useState(false)
|
const [isShareOpen, setShareOpen] = useState(false)
|
||||||
|
|
||||||
if (props.dashboard === null) {
|
if (props.post === null) {
|
||||||
return <Custom404 />
|
return <Custom404 />
|
||||||
}
|
}
|
||||||
|
|
||||||
const shareUrl = `https://${ENV_CONFIG.domain}${dashboardPath(
|
const shareUrl = `https://${ENV_CONFIG.domain}${postPath(props?.post.slug)}`
|
||||||
props?.dashboard.slug
|
|
||||||
)}`
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<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.dashboard.name} />
|
<Title className="!mt-0" text={props.post.name} />
|
||||||
<Row>
|
<Row>
|
||||||
<Col className="flex-1">
|
<Col className="flex-1">
|
||||||
<div className={'inline-flex'}>
|
<div className={'inline-flex'}>
|
||||||
|
@ -87,7 +82,7 @@ export default function DashboardPage(props: {
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
Share
|
Share
|
||||||
<ShareDashboardModal
|
<SharePostModal
|
||||||
isOpen={isShareOpen}
|
isOpen={isShareOpen}
|
||||||
setOpen={setShareOpen}
|
setOpen={setShareOpen}
|
||||||
shareUrl={shareUrl}
|
shareUrl={shareUrl}
|
||||||
|
@ -99,7 +94,7 @@ export default function DashboardPage(props: {
|
||||||
<Spacer h={2} />
|
<Spacer h={2} />
|
||||||
<div className="rounded-lg bg-white px-6 py-4 sm:py-0">
|
<div className="rounded-lg bg-white px-6 py-4 sm:py-0">
|
||||||
<div className="form-control w-full py-2">
|
<div className="form-control w-full py-2">
|
||||||
<Content content={props.dashboard.content} />
|
<Content content={props.post.content} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
Loading…
Reference in New Issue
Block a user