このコミットが含まれているのは:
2026-07-15 22:26:58 +09:00
コミット 07ce19e32d
8個のファイルの変更784行の追加264行の削除
+75 -28
ファイルの表示
@@ -1,16 +1,16 @@
import { useEffect, useMemo, useState } from 'react'
import { useEffect, useMemo, useRef, useState } from 'react'
import { Helmet } from 'react-helmet-async'
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
import CommonDialogue from '@/components/dialogues/CommonDialogue'
import PageTitle from '@/components/common/PageTitle'
import MainArea from '@/components/layout/MainArea'
import PostImportRowForm from '@/components/posts/import/PostImportRowForm'
import PostImportRowForm, { buildDraft } from '@/components/posts/import/PostImportRowForm'
import PostImportRowSummary from '@/components/posts/import/PostImportRowSummary'
import { Button } from '@/components/ui/button'
import { toast } from '@/components/ui/use-toast'
import { SITE_TITLE } from '@/config'
import { apiPost } from '@/lib/api'
import useDialogue from '@/lib/dialogues/useDialogue'
import { canEditContent } from '@/lib/users'
import { loadPostImportSession,
creatableImportRows,
@@ -35,6 +35,7 @@ type Props = { user: User | null }
const PostImportReviewPage: FC<Props> = ({ user }) => {
const editable = canEditContent (user)
const dialogue = useDialogue ()
const navigate = useNavigate ()
const { sessionId } = useParams ()
const [searchParams, setSearchParams] = useSearchParams ()
@@ -44,6 +45,10 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
const [missing, setMissing] = useState (false)
const [savingRow, setSavingRow] = useState<number | null> (null)
const [dialogueMessageRow, setDialogueMessageRow] = useState<PostImportRow | null> (null)
const [dialogueDraft, setDialogueDraft] = useState<PostImportRowDraft | null> (null)
const [dialogueResetRequested, setDialogueResetRequested] = useState (false)
const dialogueDraftRef = useRef<PostImportRowDraft | null> (null)
const dialogueResetRequestedRef = useRef (false)
useEffect (() => {
if (sessionId == null)
@@ -63,6 +68,14 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
toast ({ title: '取込状態を保存できませんでした', description: message }))
}, [session, sessionId])
useEffect (() => {
dialogueDraftRef.current = dialogueDraft
}, [dialogueDraft])
useEffect (() => {
dialogueResetRequestedRef.current = dialogueResetRequested
}, [dialogueResetRequested])
const rows = session?.rows ?? []
const editingSourceRow = Number (searchParams.get ('edit') ?? '')
const editingRow =
@@ -98,10 +111,15 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
if (editingRow == null)
{
setDialogueMessageRow (null)
setDialogueDraft (null)
setDialogueResetRequested (false)
return
}
if (dialogueMessageRow?.sourceRow !== editingRow.sourceRow)
setDialogueMessageRow (null)
setDialogueDraft (current =>
current != null ? current : buildDraft (editingRow))
setDialogueResetRequested (false)
}, [editingRow, dialogueMessageRow])
const updateSessionRows = (nextRows: PostImportRow[]) =>
@@ -113,12 +131,13 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
draft: PostImportRowDraft
resetRequested: boolean
resetSnapshot: PostImportRow['resetSnapshot'] },
): Promise<boolean> => {
): Promise<{ saved: boolean
row: PostImportRow | null }> => {
if (session == null)
return false
return { saved: false, row: null }
if (editingRow == null)
return false
return { saved: false, row: null }
const baseRow =
resetRequested
@@ -159,17 +178,17 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
if (target != null && Object.keys (target.validationErrors).length > 0)
{
setDialogueMessageRow (target)
return false
return { saved: false, row: target }
}
updateSessionRows (mergeValidatedImportRows (nextRows, validatedRows))
setDialogueMessageRow (null)
setSearchParams ({ })
return true
return { saved: true, row: null }
}
catch
{
toast ({ title: '行の再検証に失敗しました' })
return false
return { saved: false, row: null }
}
finally
{
@@ -177,6 +196,53 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
}
}
const openEditingDialogue = async (row: PostImportRow) => {
let currentRow = row
while (true)
{
const initialDraft = buildDraft (currentRow)
setDialogueDraft (current => current != null ? current : initialDraft)
setDialogueResetRequested (false)
const action = await dialogue.choice ({
title: '投稿を編輯',
description: <PostImportRowForm
row={currentRow}
messageRow={dialogueMessageRow?.sourceRow === currentRow.sourceRow
? dialogueMessageRow
: null}
saving={savingRow === currentRow.sourceRow}
onDraftChange={setDialogueDraft}
onResetRequestedChange={setDialogueResetRequested}/>,
cancelText: '取消',
choices: [{ value: 'save', label: '編輯内容を保存' }] as const })
if (action !== 'save')
{
setSearchParams ({ })
return
}
const draft = dialogueDraftRef.current ?? initialDraft
const result = await saveDraft ({
draft,
resetRequested: dialogueResetRequestedRef.current,
resetSnapshot: currentRow.resetSnapshot })
if (result.saved)
return
currentRow = result.row ?? currentRow
}
}
useEffect (() => {
if (editingRow == null)
return
void openEditingDialogue (editingRow)
}, [editingRow])
const submit = async () => {
if (sessionId == null || session == null || processable.length === 0)
return
@@ -315,25 +381,6 @@ const PostImportReviewPage: FC<Props> = ({ user }) => {
onBack={() => navigate ('/posts/import')}
onSubmit={submit}/>
{editingRow != null && (
<CommonDialogue
open={true}
onOpenChange={open => {
if (!open)
setSearchParams ({ })
}}
title="投稿を編輯"
description={`投稿 ${ editingRow.sourceRow } の内容を確認し、必要な項目を編輯してください.`}
className="flex max-h-[calc(100dvh-1rem)] max-w-3xl flex-col overflow-hidden p-0"
bodyClassName="contents">
<PostImportRowForm
key={editingRow.sourceRow}
row={editingRow}
messageRow={dialogueMessageRow}
saving={savingRow != null}
onCancel={() => setSearchParams ({ })}
onSave={saveDraft}/>
</CommonDialogue>)}
</>)
}