diff --git a/common/dashboard.ts b/common/dashboard.ts index 4b172040..6ccd15d4 100644 --- a/common/dashboard.ts +++ b/common/dashboard.ts @@ -9,4 +9,4 @@ export type Dashboard = { slug: string } -export const MAX_DASHBOARD_NAME_LENGTH = 75 +export const MAX_DASHBOARD_NAME_LENGTH = 480 diff --git a/functions/src/create-dashboard.ts b/functions/src/create-dashboard.ts index 229406c6..34c066bc 100644 --- a/functions/src/create-dashboard.ts +++ b/functions/src/create-dashboard.ts @@ -1,7 +1,6 @@ import * as admin from 'firebase-admin' import { getUser } from './utils' -import { Contract } from '../../common/contract' import { slugify } from '../../common/util/slugify' import { randomString } from '../../common/util/random' import { Dashboard, MAX_DASHBOARD_NAME_LENGTH } from '../../common/dashboard' @@ -45,7 +44,7 @@ export const createdashboard = newEndpoint({}, async (req, auth) => { if (!creator) throw new APIError(400, 'No user exists with the authenticated user ID.') - console.log('creating dashboard for', creator.username, 'named', name) + console.log('creating dashboard owned by', creator.username, 'named', name) const slug = await getSlug(name) @@ -82,5 +81,5 @@ export async function getDashboardFromSlug(slug: string) { .where('slug', '==', slug) .get() - return snap.empty ? undefined : (snap.docs[0].data() as Contract) + return snap.empty ? undefined : (snap.docs[0].data() as Dashboard) } diff --git a/web/components/file-upload-button.tsx b/web/components/file-upload-button.tsx index 3ff15d91..0872fc1b 100644 --- a/web/components/file-upload-button.tsx +++ b/web/components/file-upload-button.tsx @@ -10,7 +10,11 @@ export function FileUploadButton(props: { const ref = useRef(null) return ( <> - {linkIcon} Copy link diff --git a/web/lib/firebase/dashboards.ts b/web/lib/firebase/dashboards.ts index f231b784..9f2dd33e 100644 --- a/web/lib/firebase/dashboards.ts +++ b/web/lib/firebase/dashboards.ts @@ -33,6 +33,5 @@ export function getDashboard(dashboardId: string) { export async function getDashboardBySlug(slug: string) { const q = query(dashboards, where('slug', '==', slug)) const docs = (await getDocs(q)).docs - console.log(docs.length === 0 ? null : docs[0].data()) return docs.length === 0 ? null : docs[0].data() } diff --git a/web/pages/create-dashboard.tsx b/web/pages/create-dashboard.tsx index c27f8834..13849745 100644 --- a/web/pages/create-dashboard.tsx +++ b/web/pages/create-dashboard.tsx @@ -4,26 +4,25 @@ import { Page } from 'web/components/page' import { Title } from 'web/components/title' import Textarea from 'react-expanding-textarea' -import { useTracking } from 'web/hooks/use-tracking' import { TextEditor, useTextEditor } from 'web/components/editor' import { createDashboard } from 'web/lib/firebase/api' import clsx from 'clsx' import { useRouter } from 'next/router' -import { Dashboard } from 'common/dashboard' +import { Dashboard, MAX_DASHBOARD_NAME_LENGTH } from 'common/dashboard' import { dashboardPath } from 'web/lib/firebase/dashboards' export default function CreateDashboard() { - useTracking('view create dashboards page') const [name, setName] = useState('') + const [error, setError] = useState('') const [isSubmitting, setIsSubmitting] = useState(false) const router = useRouter() const { editor, upload } = useTextEditor({ - max: 1000, - defaultValue: '', disabled: isSubmitting, }) + const isValid = editor && name.length > 0 && editor.isEmpty === false + async function saveDashboard(name: string) { if (!editor) return const newDashboard = { @@ -32,11 +31,13 @@ export default function CreateDashboard() { } const result = await createDashboard(newDashboard).catch((e) => { - console.error(e) + console.log(e) + setError('There was an error creating the dashboard, please try again') return e }) - console.log(result.dashboard as Dashboard) - await router.push(dashboardPath((result.dashboard as Dashboard).slug)) + if (result.dashboard) { + await router.push(dashboardPath((result.dashboard as Dashboard).slug)) + } } return ( @@ -44,7 +45,6 @@ export default function CreateDashboard() {
- <form> <div className="form-control w-full"> <label className="label"> @@ -56,7 +56,7 @@ export default function CreateDashboard() { placeholder="e.g. Elon Mania Dashboard" className="input input-bordered resize-none" autoFocus - maxLength={100} + maxLength={MAX_DASHBOARD_NAME_LENGTH} value={name} onChange={(e) => setName(e.target.value || '')} /> @@ -75,7 +75,7 @@ export default function CreateDashboard() { 'btn btn-primary normal-case', isSubmitting && 'loading disabled' )} - disabled={isSubmitting || upload.isLoading} + disabled={isSubmitting || !isValid || upload.isLoading} onClick={async () => { setIsSubmitting(true) await saveDashboard(name) @@ -84,9 +84,9 @@ export default function CreateDashboard() { > {isSubmitting ? 'Creating...' : 'Create a dashboard'} </button> + {error !== '' && <div className="text-red-700">{error}</div>} </div> </form> - <Spacer h={6} /> </div> </div> </Page> diff --git a/web/pages/dashboard/[...slugs]/index.tsx b/web/pages/dashboard/[...slugs]/index.tsx index 8d4728b9..8ff78b67 100644 --- a/web/pages/dashboard/[...slugs]/index.tsx +++ b/web/pages/dashboard/[...slugs]/index.tsx @@ -13,10 +13,10 @@ import clsx from 'clsx' import { Button } from 'web/components/button' import { useState } from 'react' import { ShareDashboardModal } from 'web/components/share-dashboard-modal' -import { useRouter } from 'next/router' import { Row } from 'web/components/layout/row' import { Col } from 'web/components/layout/col' import { ENV_CONFIG } from 'common/envs/constants' +import Custom404 from 'web/pages/404' export const getStaticProps = fromPropz(getStaticPropz) export async function getStaticPropz(props: { params: { slugs: string[] } }) { @@ -47,20 +47,24 @@ export default function DashboardPage(props: { props = usePropz(props, getStaticPropz) ?? { dashboard: null, } + const [isShareOpen, setShareOpen] = useState(false) + + if (props.dashboard === null) { + return <Custom404 /> + } const shareUrl = `https://${ENV_CONFIG.domain}${dashboardPath( props?.dashboard.slug )}` - const [isShareOpen, setShareOpen] = useState(false) return ( <Page> <div className="mx-auto w-full max-w-3xl "> <Spacer h={1} /> - <Title className="!mt-0" text={props.dashboard?.name ?? ''} /> + <Title className="!mt-0" text={props.dashboard.name} /> <Row> - <Col className=" flex-1"> - <div className={'items-right inline-flex'}> + <Col className="flex-1"> + <div className={'inline-flex'}> <div className="mr-1 text-gray-500">Created by</div> <UserLink className="text-neutral" @@ -91,14 +95,11 @@ export default function DashboardPage(props: { </Button> </Col> </Row> - <Spacer h={1} /> - <Spacer h={1} /> + <Spacer h={2} /> <div className="rounded-lg bg-white px-6 py-4 sm:py-0"> - <div className="form-control w-full"> - <Spacer h={6} /> - <Content content={props.dashboard?.content ?? ''} /> - <Spacer h={6} /> + <div className="form-control w-full py-2"> + <Content content={props.dashboard.content} /> </div> </div> </div>