client: fix auth errors and wrap markdown headings in links

This commit is contained in:
Max Leiter 2022-03-20 14:09:56 -07:00
parent d75819a02a
commit 59d33042f2
No known key found for this signature in database
GPG key ID: A3512F2F2F17EBDA
6 changed files with 96 additions and 12 deletions

View file

@ -1,5 +1,5 @@
import { FormEvent, useState } from 'react' import { FormEvent, useState } from 'react'
import { Button, Input, Text, useToasts, Note } from '@geist-ui/core' import { Button, Input, Text, Note } from '@geist-ui/core'
import styles from './auth.module.css' import styles from './auth.module.css'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import Link from '../Link' import Link from '../Link'
@ -15,8 +15,6 @@ const Auth = ({ page }: { page: "signup" | "signin" }) => {
const [password, setPassword] = useState(''); const [password, setPassword] = useState('');
const [errorMsg, setErrorMsg] = useState(''); const [errorMsg, setErrorMsg] = useState('');
const { setToast } = useToasts();
const signingIn = page === 'signin' const signingIn = page === 'signin'
const handleJson = (json: any) => { const handleJson = (json: any) => {
@ -29,8 +27,7 @@ const Auth = ({ page }: { page: "signup" | "signin" }) => {
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => { const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault() e.preventDefault()
if (page === "signup" && (!NO_EMPTY_SPACE_REGEX.test(username) || password.length < 6)) return setErrorMsg(ERROR_MESSAGE)
if (!NO_EMPTY_SPACE_REGEX.test(username) || password.length < 6) return setErrorMsg(ERROR_MESSAGE)
else setErrorMsg(''); else setErrorMsg('');
const reqOpts = { const reqOpts = {
@ -45,12 +42,13 @@ const Auth = ({ page }: { page: "signup" | "signin" }) => {
const signUrl = signingIn ? '/server-api/auth/signin' : '/server-api/auth/signup'; const signUrl = signingIn ? '/server-api/auth/signin' : '/server-api/auth/signup';
const resp = await fetch(signUrl, reqOpts); const resp = await fetch(signUrl, reqOpts);
const json = await resp.json(); const json = await resp.json();
console.log(json)
if (!resp.ok) throw new Error(); if (!resp.ok) throw new Error(json.error.message);
handleJson(json) handleJson(json)
} catch (err: any) { } catch (err: any) {
setToast({ text: "Something went wrong", type: 'error' }) console.log(err)
setErrorMsg(err.message ?? "Something went wrong")
} }
} }

View file

@ -19,6 +19,30 @@
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
/* Auto-linked headers */
.markdownPreview h1 a,
.markdownPreview h2 a,
.markdownPreview h3 a,
.markdownPreview h4 a,
.markdownPreview h5 a,
.markdownPreview h6 a {
color: inherit;
}
/* Auto-linked headers */
.markdownPreview h1 a:hover::after,
.markdownPreview h2 a:hover::after,
.markdownPreview h3 a:hover::after,
.markdownPreview h4 a:hover::after,
.markdownPreview h5 a:hover::after,
.markdownPreview h6 a:hover::after {
content: " " attr(href);
filter: opacity(0.5);
font-size: 0.8em;
font-weight: normal;
text-decoration: none;
}
.markdownPreview h1 { .markdownPreview h1 {
font-size: 2rem; font-size: 2rem;
} }

View file

@ -1,9 +1,12 @@
import ReactMarkdown from "react-markdown" import ReactMarkdown from "react-markdown"
import remarkGfm from "remark-gfm" import remarkGfm from "remark-gfm"
import { PrismAsyncLight as SyntaxHighlighter } from 'react-syntax-highlighter'; import { PrismAsyncLight as SyntaxHighlighter } from 'react-syntax-highlighter';
import rehypeSlug from 'rehype-slug'
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
// @ts-ignore because of no types in remark-a11y-emoji // @ts-ignore because of no types in remark-a11y-emoji
import a11yEmoji from '@fec/remark-a11y-emoji'; import a11yEmoji from '@fec/remark-a11y-emoji';
import styles from './preview.module.css' import styles from './preview.module.css'
import { vscDarkPlus as dark, vs as light } from 'react-syntax-highlighter/dist/cjs/styles/prism' import { vscDarkPlus as dark, vs as light } from 'react-syntax-highlighter/dist/cjs/styles/prism'
import useSharedState from "@lib/hooks/use-shared-state"; import useSharedState from "@lib/hooks/use-shared-state";
@ -16,7 +19,9 @@ type Props = {
const ReactMarkdownPreview = ({ content, height }: Props) => { const ReactMarkdownPreview = ({ content, height }: Props) => {
const [themeType] = useSharedState<string>('theme') const [themeType] = useSharedState<string>('theme')
return (<div style={{ height }}> return (<div style={{ height }}>
<ReactMarkdown className={styles.markdownPreview} remarkPlugins={[remarkGfm, a11yEmoji]} <ReactMarkdown className={styles.markdownPreview}
remarkPlugins={[remarkGfm, a11yEmoji]}
rehypePlugins={[rehypeSlug, [rehypeAutolinkHeadings, { behavior: 'wrap' }]]}
components={{ components={{
code({ node, inline, className, children, ...props }) { code({ node, inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || '') const match = /language-(\w+)/.exec(className || '')
@ -50,4 +55,5 @@ const ReactMarkdownPreview = ({ content, height }: Props) => {
</ReactMarkdown></div>) </ReactMarkdown></div>)
} }
export default ReactMarkdownPreview export default ReactMarkdownPreview

View file

@ -27,7 +27,9 @@
"react-markdown": "^8.0.0", "react-markdown": "^8.0.0",
"react-syntax-highlighter": "^15.4.5", "react-syntax-highlighter": "^15.4.5",
"react-syntax-highlighter-virtualized-renderer": "^1.1.0", "react-syntax-highlighter-virtualized-renderer": "^1.1.0",
"rehype-autolink-headings": "^6.1.1",
"rehype-katex": "^6.0.2", "rehype-katex": "^6.0.2",
"rehype-slug": "^5.0.1",
"rehype-stringify": "^9.0.3", "rehype-stringify": "^9.0.3",
"remark-gfm": "^3.0.1", "remark-gfm": "^3.0.1",
"remark-math": "^5.1.1", "remark-math": "^5.1.1",

View file

@ -1026,6 +1026,11 @@ get-symbol-description@^1.0.0:
call-bind "^1.0.2" call-bind "^1.0.2"
get-intrinsic "^1.1.1" get-intrinsic "^1.1.1"
github-slugger@^1.1.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.4.0.tgz#206eb96cdb22ee56fdc53a28d5a302338463444e"
integrity sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==
glob-parent@^5.1.2: glob-parent@^5.1.2:
version "5.1.2" version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
@ -1126,6 +1131,18 @@ hast-util-from-parse5@^7.0.0:
vfile-location "^4.0.0" vfile-location "^4.0.0"
web-namespaces "^2.0.0" web-namespaces "^2.0.0"
hast-util-has-property@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/hast-util-has-property/-/hast-util-has-property-2.0.0.tgz#c15cd6180f3e535540739fcc9787bcffb5708cae"
integrity sha512-4Qf++8o5v14us4Muv3HRj+Er6wTNGA/N9uCaZMty4JWvyFKLdhULrv4KE1b65AthsSO9TXSZnjuxS8ecIyhb0w==
hast-util-heading-rank@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/hast-util-heading-rank/-/hast-util-heading-rank-2.1.0.tgz#c39f34fa8330ebfec03a08b5d5019ed56122029c"
integrity sha512-w+Rw20Q/iWp2Bcnr6uTrYU6/ftZLbHKhvc8nM26VIWpDqDMlku2iXUVTeOlsdoih/UKQhY7PHQ+vZ0Aqq8bxtQ==
dependencies:
"@types/hast" "^2.0.0"
hast-util-is-element@^2.0.0: hast-util-is-element@^2.0.0:
version "2.1.2" version "2.1.2"
resolved "https://registry.yarnpkg.com/hast-util-is-element/-/hast-util-is-element-2.1.2.tgz#fc0b0dc7cef3895e839b8d66979d57b0338c68f3" resolved "https://registry.yarnpkg.com/hast-util-is-element/-/hast-util-is-element-2.1.2.tgz#fc0b0dc7cef3895e839b8d66979d57b0338c68f3"
@ -1162,6 +1179,13 @@ hast-util-to-html@^8.0.0:
stringify-entities "^4.0.2" stringify-entities "^4.0.2"
unist-util-is "^5.0.0" unist-util-is "^5.0.0"
hast-util-to-string@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/hast-util-to-string/-/hast-util-to-string-2.0.0.tgz#b008b0a4ea472bf34dd390b7eea1018726ae152a"
integrity sha512-02AQ3vLhuH3FisaMM+i/9sm4OXGSq1UhOOCpTLLQtHdL3tZt7qil69r8M8iDkZYyC0HCFylcYoP+8IO7ddta1A==
dependencies:
"@types/hast" "^2.0.0"
hast-util-to-text@^3.1.0: hast-util-to-text@^3.1.0:
version "3.1.1" version "3.1.1"
resolved "https://registry.yarnpkg.com/hast-util-to-text/-/hast-util-to-text-3.1.1.tgz#b7699a75f7a61af6e0befb67660cd78460d96dc6" resolved "https://registry.yarnpkg.com/hast-util-to-text/-/hast-util-to-text-3.1.1.tgz#b7699a75f7a61af6e0befb67660cd78460d96dc6"
@ -2409,6 +2433,19 @@ regexpp@^3.2.0:
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
rehype-autolink-headings@^6.1.1:
version "6.1.1"
resolved "https://registry.yarnpkg.com/rehype-autolink-headings/-/rehype-autolink-headings-6.1.1.tgz#0cb874a56f3de6ead1c2268d7f0fc5006f244db5"
integrity sha512-NMYzZIsHM3sA14nC5rAFuUPIOfg+DFmf9EY1YMhaNlB7+3kK/ZlE6kqPfuxr1tsJ1XWkTrMtMoyHosU70d35mA==
dependencies:
"@types/hast" "^2.0.0"
extend "^3.0.0"
hast-util-has-property "^2.0.0"
hast-util-heading-rank "^2.0.0"
hast-util-is-element "^2.0.0"
unified "^10.0.0"
unist-util-visit "^4.0.0"
rehype-katex@^6.0.2: rehype-katex@^6.0.2:
version "6.0.2" version "6.0.2"
resolved "https://registry.yarnpkg.com/rehype-katex/-/rehype-katex-6.0.2.tgz#20197bbc10bdf79f6b999bffa6689d7f17226c35" resolved "https://registry.yarnpkg.com/rehype-katex/-/rehype-katex-6.0.2.tgz#20197bbc10bdf79f6b999bffa6689d7f17226c35"
@ -2433,6 +2470,19 @@ rehype-parse@^8.0.0:
parse5 "^6.0.0" parse5 "^6.0.0"
unified "^10.0.0" unified "^10.0.0"
rehype-slug@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/rehype-slug/-/rehype-slug-5.0.1.tgz#6e732d0c55b3b1e34187e74b7363fb53229e5f52"
integrity sha512-X5v3wV/meuOX9NFcGhJvUpEjIvQl2gDvjg3z40RVprYFt7q3th4qMmYLULiu3gXvbNX1ppx+oaa6JyY1W67pTA==
dependencies:
"@types/hast" "^2.0.0"
github-slugger "^1.1.1"
hast-util-has-property "^2.0.0"
hast-util-heading-rank "^2.0.0"
hast-util-to-string "^2.0.0"
unified "^10.0.0"
unist-util-visit "^4.0.0"
rehype-stringify@^9.0.3: rehype-stringify@^9.0.3:
version "9.0.3" version "9.0.3"
resolved "https://registry.yarnpkg.com/rehype-stringify/-/rehype-stringify-9.0.3.tgz#70e3bd6d4d29e7acf36b802deed350305d2c3c17" resolved "https://registry.yarnpkg.com/rehype-stringify/-/rehype-stringify-9.0.3.tgz#70e3bd6d4d29e7acf36b802deed350305d2c3c17"

View file

@ -43,13 +43,17 @@ auth.post('/signup', async (req, res, next) => {
}); });
auth.post('/signin', async (req, res, next) => { auth.post('/signin', async (req, res, next) => {
const error = "User does not exist or password is incorrect"
const errorToThrow = new Error(error);
try { try {
validateAuthPayload(req.body.username, req.body.password) if (!req.body.username || !req.body.password) {
throw errorToThrow
}
const username = req.body.username.toLowerCase(); const username = req.body.username.toLowerCase();
const user = await User.findOne({ where: { username: username } }); const user = await User.findOne({ where: { username: username } });
if (!user) { if (!user) {
throw new Error("User does not exist"); throw errorToThrow
} }
const password_valid = await compare(req.body.password, user.password); const password_valid = await compare(req.body.password, user.password);
@ -57,7 +61,7 @@ auth.post('/signin', async (req, res, next) => {
const token = generateAccessToken(user.id); const token = generateAccessToken(user.id);
res.status(200).json({ token: token, userId: user.id }); res.status(200).json({ token: token, userId: user.id });
} else { } else {
throw new Error("Password Incorrect"); throw errorToThrow
} }
} catch (e) { } catch (e) {