From 04b01bf1c622211b2799e42ed2f4de062d10209b Mon Sep 17 00:00:00 2001 From: miteruzo Date: Wed, 25 Mar 2026 00:39:07 +0900 Subject: [PATCH] #47 --- .../app/controllers/wiki_pages_controller.rb | 6 +- frontend/src/components/WikiEditForm.tsx | 57 +++++++++++++++++++ frontend/src/pages/wiki/WikiEditPage.tsx | 38 +++---------- frontend/src/pages/wiki/WikiNewPage.tsx | 48 +++++----------- 4 files changed, 81 insertions(+), 68 deletions(-) create mode 100644 frontend/src/components/WikiEditForm.tsx diff --git a/backend/app/controllers/wiki_pages_controller.rb b/backend/app/controllers/wiki_pages_controller.rb index dc6c47f..e19557d 100644 --- a/backend/app/controllers/wiki_pages_controller.rb +++ b/backend/app/controllers/wiki_pages_controller.rb @@ -96,7 +96,7 @@ class WikiPagesController < ApplicationController message = params[:message].presence Wiki::Commit.content!(page:, body:, created_user: current_user, message:) - render json: WikiPageRepr.base(page), status: :created + render json: WikiPageRepr.base(page).merge(body:), status: :created else render json: { errors: page.errors.full_messages }, status: :unprocessable_entity @@ -107,7 +107,7 @@ class WikiPagesController < ApplicationController return head :unauthorized unless current_user return head :forbidden unless current_user.gte_member? - title = params[:title]&.strip + title = params[:title].to_s.strip body = params[:body].to_s return head :unprocessable_entity if title.blank? || body.blank? @@ -126,7 +126,7 @@ class WikiPagesController < ApplicationController message:, base_revision_id:) - head :ok + render json: WikiPageRepr.base(page).merge(body:), status: :created end def search diff --git a/frontend/src/components/WikiEditForm.tsx b/frontend/src/components/WikiEditForm.tsx new file mode 100644 index 0000000..14cd4da --- /dev/null +++ b/frontend/src/components/WikiEditForm.tsx @@ -0,0 +1,57 @@ +import MarkdownIt from 'markdown-it' +import { useEffect, useState } from 'react' +import MdEditor from 'react-markdown-editor-lite' + +import Label from '@/components/common/Label' + +import type { FC } from 'react' + +const mdParser = new MarkdownIt + +type Props = { + title: string + body: string + onSubmit: (title: string, body: string) => void + forEdit?: boolean } + + +export default (({ title: initTitle, body: initBody, onSubmit, forEdit }: Props) => { + const [title, setTitle] = useState (initTitle) + const [body, setBody] = useState (initBody) + + useEffect (() => { + setTitle (initTitle) + setBody (initBody) + }, [initTitle, initBody]) + + return ( + <> + {/* タイトル */} + {/* TODO: タグ補完 */} +
+ + setTitle (e.target.value)} + className="w-full border p-2 rounded"/> +
+ + {/* 本文 */} +
+ + mdParser.render (text)} + onChange={({ text }) => setBody (text)}/> +
+ + {/* 送信 */} + + ) +}) satisfies FC diff --git a/frontend/src/pages/wiki/WikiEditPage.tsx b/frontend/src/pages/wiki/WikiEditPage.tsx index 0fcc2b0..cef9c4a 100644 --- a/frontend/src/pages/wiki/WikiEditPage.tsx +++ b/frontend/src/pages/wiki/WikiEditPage.tsx @@ -1,10 +1,9 @@ import { useQueryClient } from '@tanstack/react-query' -import MarkdownIt from 'markdown-it' import { useEffect, useState } from 'react' import { Helmet } from 'react-helmet-async' -import MdEditor from 'react-markdown-editor-lite' import { useParams, useNavigate } from 'react-router-dom' +import WikiEditForm from '@/components/WikiEditForm' import MainArea from '@/components/layout/MainArea' import { toast } from '@/components/ui/use-toast' import { SITE_TITLE } from '@/config' @@ -18,8 +17,6 @@ import type { FC } from 'react' import type { User, WikiPage } from '@/types' -const mdParser = new MarkdownIt - type Props = { user: User | null } @@ -37,7 +34,7 @@ export default (({ user }: Props) => { const [loading, setLoading] = useState (true) const [title, setTitle] = useState ('') - const handleSubmit = async () => { + const handleSubmit = async (title: string, body: string) => { const formData = new FormData () formData.append ('title', title) formData.append ('body', body) @@ -77,32 +74,11 @@ export default (({ user }: Props) => {

Wiki ページを編輯

{loading ? 'Loading...' : ( - <> - {/* タイトル */} - {/* TODO: タグ補完 */} -
- - setTitle (e.target.value)} - className="w-full border p-2 rounded"/> -
- - {/* 本文 */} -
- - mdParser.render (text)} - onChange={({ text }) => setBody (text)}/> -
- - {/* 送信 */} - - )} + )} ) }) satisfies FC diff --git a/frontend/src/pages/wiki/WikiNewPage.tsx b/frontend/src/pages/wiki/WikiNewPage.tsx index 54a76d1..307b1a1 100644 --- a/frontend/src/pages/wiki/WikiNewPage.tsx +++ b/frontend/src/pages/wiki/WikiNewPage.tsx @@ -1,21 +1,19 @@ -import MarkdownIt from 'markdown-it' -import { useState } from 'react' +import { useQueryClient } from '@tanstack/react-query' import { Helmet } from 'react-helmet-async' -import MdEditor from 'react-markdown-editor-lite' import { useLocation, useNavigate } from 'react-router-dom' +import WikiEditForm from '@/components/WikiEditForm' import MainArea from '@/components/layout/MainArea' import { toast } from '@/components/ui/use-toast' import { SITE_TITLE } from '@/config' import { apiPost } from '@/lib/api' +import { wikiKeys } from '@/lib/queryKeys' import Forbidden from '@/pages/Forbidden' import 'react-markdown-editor-lite/lib/index.css' import type { User, WikiPage } from '@/types' -const mdParser = new MarkdownIt - type Props = { user: User | null } @@ -26,13 +24,12 @@ export default ({ user }: Props) => { const location = useLocation () const navigate = useNavigate () + const qc = useQueryClient () + const query = new URLSearchParams (location.search) const titleQuery = query.get ('title') ?? '' - const [title, setTitle] = useState (titleQuery) - const [body, setBody] = useState ('') - - const handleSubmit = async () => { + const handleSubmit = async (title: string, body: string) => { const formData = new FormData formData.append ('title', title) formData.append ('body', body) @@ -40,7 +37,10 @@ export default ({ user }: Props) => { try { const data = await apiPost ('/wiki', formData, - { headers: { 'Content-Type': 'multipart/form-data' } }) + { headers: { 'Content-Type': 'multipart/form-data' } }) + qc.setQueryData (wikiKeys.show (data.title, { }), + (prev: WikiPage) => ({ ...prev, title: data.title, body: data.body })) + qc.invalidateQueries ({ queryKey: wikiKeys.root }) toast ({ title: '投稿成功!' }) navigate (`/wiki/${ data.title }`) } @@ -58,30 +58,10 @@ export default ({ user }: Props) => {

新規 Wiki ページ

- {/* タイトル */} - {/* TODO: タグ補完 */} -
- - setTitle (e.target.value)} - className="w-full border p-2 rounded"/> -
- - {/* 本文 */} -
- - mdParser.render (text)} - onChange={({ text }) => setBody (text)}/> -
- - {/* 送信 */} - +
) }