From 7f69a641a2b78eb986b9475c14bde34a3bd3dc65 Mon Sep 17 00:00:00 2001 From: Arnaud Robin Date: Fri, 21 Nov 2025 01:19:14 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(frontend)=20add=20/new=20route=20for?= =?UTF-8?q?=20document=20creation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a /new route that automatically creates a document and redirects users to it. This enables direct document creation via URL, bookmarks, or automation scripts. When unauthenticated users access /new, they are redirected to login instead of home page since user intent is explicit. This addresses user requests for programmatic document creation and provides a shareable link for "create new document" actions. --- CHANGELOG.md | 2 +- .../apps/impress/src/pages/new/index.tsx | 79 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/frontend/apps/impress/src/pages/new/index.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f3b5e6f02..7cb127bb66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ and this project adheres to - ♿(frontend) improve accessibility: - ♿(frontend) improve share modal button accessibility #1626 - +- ✨(frontend) add /new route for document creation #1641 ## [3.10.0] - 2025-11-18 ### Added diff --git a/src/frontend/apps/impress/src/pages/new/index.tsx b/src/frontend/apps/impress/src/pages/new/index.tsx new file mode 100644 index 0000000000..603312e8ad --- /dev/null +++ b/src/frontend/apps/impress/src/pages/new/index.tsx @@ -0,0 +1,79 @@ +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; + +import { Loading } from '@/components'; +import { gotoLogin, useAuth } from '@/features/auth'; +import { useCreateDoc } from '@/features/docs/doc-management'; +import { useSkeletonStore } from '@/features/skeletons'; +import { NextPageWithLayout } from '@/types/next'; + +const Page: NextPageWithLayout = () => { + const router = useRouter(); + const { authenticated } = useAuth(); + const { setIsSkeletonVisible } = useSkeletonStore(); + const [isNavigating, setIsNavigating] = useState(false); + const [hasCreated, setHasCreated] = useState(false); + + const { mutate: createDoc, isPending: isDocCreating } = useCreateDoc({ + onSuccess: (doc) => { + setIsNavigating(true); + setHasCreated(true); + // Wait for navigation to complete + router + .replace(`/docs/${doc.id}`) + .then(() => { + // The skeleton will be disabled by the [id] page once the data is loaded + setIsNavigating(false); + }) + .catch(() => { + // In case of navigation error, disable the skeleton + setIsSkeletonVisible(false); + setIsNavigating(false); + }); + }, + onError: () => { + // If there's an error, disable the skeleton + setIsSkeletonVisible(false); + setIsNavigating(false); + }, + }); + + /** + * Redirect to login if user is not authenticated + */ + useEffect(() => { + // If not authenticated, redirect to login + if (!authenticated) { + gotoLogin(); + return; + } + }, [authenticated]); + + /** + * Create a new document when the page is visited + * Only create if user is authenticated + */ + useEffect(() => { + // Don't create if not authenticated (will be redirected) + if (!authenticated) { + return; + } + + // Create document only if authenticated and not already created + if (!hasCreated && !isDocCreating && !isNavigating) { + setIsSkeletonVisible(true); + createDoc(); + } + }, [ + authenticated, + hasCreated, + isDocCreating, + isNavigating, + createDoc, + setIsSkeletonVisible, + ]); + + return ; +}; + +export default Page;