From aa96ec95d1f218aaf40f9dd563441c0bf2485d8b Mon Sep 17 00:00:00 2001 From: miteruzo Date: Sun, 12 Jul 2026 14:03:05 +0900 Subject: [PATCH] #399 --- frontend/src/App.tsx | 12 +- .../posts/import/PostImportRowDialog.tsx | 203 ++++++ .../posts/import/PostImportRowSummary.tsx | 149 ++++ .../posts/import/PostImportStatusBadge.tsx | 70 ++ .../posts/import/ThumbnailPreview.tsx | 48 ++ frontend/src/lib/postImportSession.ts | 221 ++++++ frontend/src/pages/posts/PostImportPage.tsx | 636 ------------------ .../src/pages/posts/PostImportResultPage.tsx | 253 +++++++ .../src/pages/posts/PostImportReviewPage.tsx | 363 ++++++++++ .../src/pages/posts/PostImportSourcePage.tsx | 153 +++++ 10 files changed, 1469 insertions(+), 639 deletions(-) create mode 100644 frontend/src/components/posts/import/PostImportRowDialog.tsx create mode 100644 frontend/src/components/posts/import/PostImportRowSummary.tsx create mode 100644 frontend/src/components/posts/import/PostImportStatusBadge.tsx create mode 100644 frontend/src/components/posts/import/ThumbnailPreview.tsx create mode 100644 frontend/src/lib/postImportSession.ts delete mode 100644 frontend/src/pages/posts/PostImportPage.tsx create mode 100644 frontend/src/pages/posts/PostImportResultPage.tsx create mode 100644 frontend/src/pages/posts/PostImportReviewPage.tsx create mode 100644 frontend/src/pages/posts/PostImportSourcePage.tsx diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index afccd62..e260bff 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -41,9 +41,11 @@ import NotFound from '@/pages/NotFound' import TOSPage from '@/pages/TOSPage.mdx' import PostDetailPage from '@/pages/posts/PostDetailPage' import PostHistoryPage from '@/pages/posts/PostHistoryPage' +import PostImportResultPage from '@/pages/posts/PostImportResultPage' +import PostImportReviewPage from '@/pages/posts/PostImportReviewPage' +import PostImportSourcePage from '@/pages/posts/PostImportSourcePage' import PostListPage from '@/pages/posts/PostListPage' import PostNewPage from '@/pages/posts/PostNewPage' -import PostImportPage from '@/pages/posts/PostImportPage' import PostSearchPage from '@/pages/posts/PostSearchPage' import ServiceUnavailable from '@/pages/ServiceUnavailable' import SettingPage from '@/pages/users/SettingPage' @@ -76,7 +78,9 @@ const RouteTransitionWrapper = ({ animationMode, user, setUser }: { }/> }/> }/> - }/> + }/> + }/> + }/> }/> }/> }/> @@ -115,7 +119,9 @@ const RouteTransitionWrapper = ({ animationMode, user, setUser }: { }/> }/> }/> - }/> + }/> + }/> + }/> }/> }/> }/> diff --git a/frontend/src/components/posts/import/PostImportRowDialog.tsx b/frontend/src/components/posts/import/PostImportRowDialog.tsx new file mode 100644 index 0000000..232d308 --- /dev/null +++ b/frontend/src/components/posts/import/PostImportRowDialog.tsx @@ -0,0 +1,203 @@ +import FieldError from '@/components/common/FieldError' +import PostImportStatusBadge from '@/components/posts/import/PostImportStatusBadge' +import ThumbnailPreview from '@/components/posts/import/ThumbnailPreview' +import { Button } from '@/components/ui/button' +import { Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle } from '@/components/ui/dialog' +import { inputClass } from '@/lib/utils' + +import type { FC } from 'react' +import { useEffect, useState } from 'react' + +import type { PostImportOrigin, + PostImportRow } from '@/lib/postImportSession' + +type Draft = { + url: string + title: string + thumbnailBase: string + originalCreatedFrom: string + originalCreatedBefore: string + duration: string + tags: string + parentPostIds: string } + +type Props = { + open: boolean + row: PostImportRow | null + saving: boolean + onOpenChange: (open: boolean) => void + onSave: (draft: Draft) => Promise } + +const originOf = ( + row: PostImportRow, + field: string, +): PostImportOrigin => + row.provenance[field] ?? 'automatic' + +const buildDraft = (row: PostImportRow): Draft => ({ + url: row.url, + title: String (row.attributes.title ?? ''), + thumbnailBase: String (row.attributes.thumbnailBase ?? ''), + originalCreatedFrom: String (row.attributes.originalCreatedFrom ?? ''), + originalCreatedBefore: String (row.attributes.originalCreatedBefore ?? ''), + duration: String (row.attributes.duration ?? ''), + tags: String (row.attributes.tags ?? ''), + parentPostIds: String (row.attributes.parentPostIds ?? '') }) + + +const PostImportRowDialog: FC = ( + { open, row, saving, onOpenChange, onSave }, +) => { + const [draft, setDraft] = useState (null) + + useEffect (() => { + if (open && row) + setDraft (buildDraft (row)) + }, [open, row]) + + if (!(row) || !(draft)) + return null + + const update = ( + key: Key, + value: Draft[Key], + ) => { + setDraft (current => + current ? { ...current, [key]: value } : current) + } + + const save = async () => { + if (await onSave (draft)) + onOpenChange (false) + } + + return ( + + + + 投稿 {row.sourceRow} を編集 + + 自動取得結果を確認し、必要な項目だけ修正してください. + + + +
+
+ +
+ + +
+
+ +
+ update ('url', value)}/> + update ('title', value)}/> + update ('thumbnailBase', value)}/> +
+ update ('originalCreatedFrom', value)}/> + update ('originalCreatedBefore', value)}/> +
+ update ('duration', value)}/> + update ('tags', value)}/> + update ('parentPostIds', value)}/> + + +
+
+ + + + + +
+
) +} + +const DialogField = ( + { label, value, origin, onChange }: { + label: string + value: string + origin: PostImportOrigin + onChange: (value: string) => void }, +) => ( + ) + +const DialogArea = ( + { label, value, origin, onChange }: { + label: string + value: string + origin: PostImportOrigin + onChange: (value: string) => void }, +) => ( +