Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions frontends/main/src/app-pages/Articles/ArticleDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@

import React from "react"
import { useArticleDetail } from "api/hooks/articles"
import { Container, LoadingSpinner, styled, Typography } from "ol-components"
import {
Container,
LoadingSpinner,
styled,
Typography,
TiptapEditorContainer,
} from "ol-components"
import { ButtonLink } from "@mitodl/smoot-design"
import { notFound } from "next/navigation"
import { Permission } from "api/hooks/user"
Expand All @@ -24,14 +30,6 @@ const WrapperContainer = styled.div({
paddingBottom: "10px",
})

const PreTag = styled.pre({
background: "#f6f6f6",
padding: "16px",
borderRadius: "8px",
fontSize: "14px",
overflowX: "auto",
})

export const ArticleDetailPage = ({ articleId }: { articleId: number }) => {
const id = Number(articleId)
const { data, isLoading } = useArticleDetail(id)
Expand All @@ -58,7 +56,11 @@ export const ArticleDetailPage = ({ articleId }: { articleId: number }) => {
</ButtonLink>
</ControlsContainer>
</WrapperContainer>
<PreTag>{JSON.stringify(data.content, null, 2)}</PreTag>
<TiptapEditorContainer
data-testid="editor"
value={data.content}
readOnly
/>
</Page>
</RestrictedRoute>
)
Expand Down
30 changes: 27 additions & 3 deletions frontends/main/src/app-pages/Articles/ArticleEditPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,15 @@ describe("ArticleEditPage", () => {
const article = factories.articles.article({
id: 42,
title: "Existing Title",
content: { id: 1, content: "Existing content" },
content: {
type: "doc",
content: [
{
type: "paragraph",
content: [{ type: "text", text: "Existing Title" }],
},
],
},
})
setMockResponse.get(urls.articles.details(article.id), article)

Expand All @@ -45,7 +53,15 @@ describe("ArticleEditPage", () => {
const article = factories.articles.article({
id: 123,
title: "Existing Title",
content: { id: 1, content: "Existing content" },
content: {
type: "doc",
content: [
{
type: "paragraph",
content: [{ type: "text", text: "Existing Title" }],
},
],
},
})
setMockResponse.get(urls.articles.details(article.id), article)

Expand Down Expand Up @@ -77,7 +93,15 @@ describe("ArticleEditPage", () => {
const article = factories.articles.article({
id: 7,
title: "Old Title",
content: { id: 1, content: "Bad content" },
content: {
type: "doc",
content: [
{
type: "paragraph",
content: [{ type: "text", text: "Existing Title" }],
},
],
},
})
setMockResponse.get(urls.articles.details(article.id), article)

Expand Down
67 changes: 28 additions & 39 deletions frontends/main/src/app-pages/Articles/ArticleEditPage.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
"use client"
import React, { useEffect, useState, ChangeEvent } from "react"
import React, { useEffect, useState } from "react"
import { Permission } from "api/hooks/user"
import { useRouter } from "next-nprogress-bar"
import { useArticleDetail, useArticlePartialUpdate } from "api/hooks/articles"
import { Button, Input, Alert } from "@mitodl/smoot-design"
import { Button, Alert } from "@mitodl/smoot-design"
import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute"
import { Container, Typography, styled, LoadingSpinner } from "ol-components"
import {
Container,
Typography,
styled,
LoadingSpinner,
TiptapEditorContainer,
JSONContent,
} from "ol-components"

import { notFound } from "next/navigation"
import { articlesView } from "@/common/urls"

Expand All @@ -19,20 +27,17 @@ const ClientContainer = styled.div({
margin: "10px 0",
})

const TitleInput = styled(Input)({
width: "100%",
margin: "10px 0",
})

const ArticleEditPage = ({ articleId }: { articleId: string }) => {
const router = useRouter()

const id = Number(articleId)
const { data: article, isLoading } = useArticleDetail(id)

const [title, setTitle] = useState<string>("")
const [text, setText] = useState("")
const [json, setJson] = useState({})
const [json, setJson] = useState<JSONContent>({
type: "doc",
content: [{ type: "paragraph", content: [] }],
})
const [alertText, setAlertText] = useState("")

const { mutate: updateArticle, isPending } = useArticlePartialUpdate()
Expand All @@ -57,7 +62,6 @@ const ArticleEditPage = ({ articleId }: { articleId: string }) => {
useEffect(() => {
if (article && !title) {
setTitle(article.title)
setText(article.content ? JSON.stringify(article.content, null, 2) : "")
setJson(article.content)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand All @@ -70,20 +74,13 @@ const ArticleEditPage = ({ articleId }: { articleId: string }) => {
return notFound()
}

const handleChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
const value = e.target.value
setText(value)

try {
const parsed = JSON.parse(value)
setJson(parsed)
} catch {
setJson({})
}
const handleChange = (json: object) => {
setJson(json)
}

return (
<RestrictedRoute requires={Permission.ArticleEditor}>
<Container className="article-wrapper">
<Container>
<Typography variant="h3" component="h1">
Edit Article
</Typography>
Expand All @@ -99,25 +96,17 @@ const ArticleEditPage = ({ articleId }: { articleId: string }) => {
</Typography>
</Alert>
)}
<TitleInput
type="text"
value={title}
onChange={(e) => {
console.log("Title input changed:", e.target.value)
setTitle(e.target.value)
setAlertText("")
}}
placeholder="Enter article title"
className="input-field"
/>

<ClientContainer className="editor-box">
<textarea

<ClientContainer>
<TiptapEditorContainer
data-testid="editor"
value={text}
value={json}
onChange={handleChange}
placeholder="Type or paste JSON here..."
style={{ width: "100%", height: 150 }}
title={title}
setTitle={(e) => {
setTitle(e.target.value)
setAlertText("")
}}
/>
</ClientContainer>

Expand Down
62 changes: 25 additions & 37 deletions frontends/main/src/app-pages/Articles/ArticleNewPage.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
"use client"
import React, { useState, ChangeEvent } from "react"
import React, { useState } from "react"
import { Permission } from "api/hooks/user"
import { useRouter } from "next-nprogress-bar"
import { useArticleCreate } from "api/hooks/articles"
import { Button, Input, Alert } from "@mitodl/smoot-design"
import { Button, Alert } from "@mitodl/smoot-design"
import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute"
import { Container, Typography, styled } from "ol-components"
import {
TiptapEditorContainer,
Container,
Typography,
styled,
JSONContent,
} from "ol-components"
import { articlesView } from "@/common/urls"

const SaveButton = styled.div({
Expand All @@ -18,17 +24,14 @@ const ClientContainer = styled.div({
margin: "10px 0",
})

const TitleInput = styled(Input)({
width: "100%",
margin: "10px 0",
})

const ArticleNewPage: React.FC = () => {
const router = useRouter()

const [title, setTitle] = React.useState<string>("")
const [text, setText] = useState("")
const [json, setJson] = useState({})
const [json, setJson] = useState<JSONContent>({
type: "doc",
content: [{ type: "paragraph", content: [] }],
})
const [alertText, setAlertText] = React.useState("")

const { mutate: createArticle, isPending } = useArticleCreate()
Expand Down Expand Up @@ -57,20 +60,13 @@ const ArticleNewPage: React.FC = () => {
},
)
}
const handleChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
const value = e.target.value
setText(value)

try {
const parsed = JSON.parse(value)
setJson(parsed)
} catch {
setJson({})
}
const handleChange = (json: object) => {
setJson(json)
}

return (
<RestrictedRoute requires={Permission.ArticleEditor}>
<Container className="article-wrapper">
<Container>
<h1>Write Article</h1>
{alertText && (
<Alert
Expand All @@ -84,27 +80,19 @@ const ArticleNewPage: React.FC = () => {
</Typography>
</Alert>
)}
<TitleInput
type="text"
value={title}
onChange={(e) => {
setTitle(e.target.value)
setAlertText("")
}}
placeholder="Enter article title"
className="input-field"
/>

<ClientContainer className="editor-box">
<textarea
<ClientContainer>
<TiptapEditorContainer
data-testid="editor"
value={text}
value={json}
title={title}
setTitle={(e) => {
setTitle(e.target.value)
setAlertText("")
}}
onChange={handleChange}
placeholder="Type or paste JSON here..."
style={{ width: "100%", height: 150 }}
/>
</ClientContainer>

<SaveButton>
<Button
variant="primary"
Expand Down
Loading
Loading