11"use client" ;
22
3- import { useState , FormEvent , useEffect } from "react" ;
3+ import { useState , FormEvent , useEffect , useRef , useCallback } from "react" ;
44// import useSWR from "swr";
55// import {
66// getQuestionExample,
@@ -9,9 +9,10 @@ import { useState, FormEvent, useEffect } from "react";
99// import { getLanguageName } from "../pagesList";
1010import { useEmbedContext } from "@/terminal/embedContext" ;
1111import { DynamicMarkdownSection , PagePath } from "@/lib/docs" ;
12- import { useRouter } from "next/navigation" ;
12+ import { usePathname , useRouter } from "next/navigation" ;
1313import { ChatStreamEvent } from "@/api/chat/route" ;
1414import { useStreamingChatContext } from "@/(docs)/streamingChatContext" ;
15+ import { revalidateChatAction } from "@/actions/revalidateChat" ;
1516
1617interface ChatFormProps {
1718 path : PagePath ;
@@ -32,6 +33,37 @@ export function ChatForm({ path, sectionContent, close }: ChatFormProps) {
3233 const router = useRouter ( ) ;
3334 const streamingChatContext = useStreamingChatContext ( ) ;
3435
36+ const pathname = usePathname ( ) ;
37+ const pendingRouterPushTarget = useRef < null | string > ( null ) ;
38+ const pendingRouterPushResolver = useRef < null | ( ( ) => void ) > ( null ) ;
39+ // router.pushの完了を待つ関数。pathnameの変化でページ遷移の完了を検知し、解決する。
40+ const asyncRouterPush = useCallback (
41+ ( url : string , options ?: { scroll ?: boolean } ) => {
42+ if ( pendingRouterPushTarget . current ) {
43+ console . error (
44+ "Already navigating to" ,
45+ pendingRouterPushTarget . current ,
46+ "can't navigate to" ,
47+ url
48+ ) ;
49+ return ;
50+ }
51+ pendingRouterPushTarget . current = url ;
52+ return new Promise < void > ( ( resolve ) => {
53+ pendingRouterPushResolver . current = resolve ;
54+ router . push ( url , options ) ;
55+ } ) ;
56+ } ,
57+ [ router ]
58+ ) ;
59+ useEffect ( ( ) => {
60+ if ( pendingRouterPushTarget . current === pathname ) {
61+ pendingRouterPushResolver . current ?.( ) ;
62+ pendingRouterPushTarget . current = null ;
63+ pendingRouterPushResolver . current = null ;
64+ }
65+ } , [ pathname ] ) ;
66+
3567 // const documentContentInView = sectionContent
3668 // .filter((s) => s.inView)
3769 // .map((s) => s.rawContent)
@@ -98,6 +130,7 @@ export function ChatForm({ path, sectionContent, close }: ChatFormProps) {
98130 const reader = response . body ! . getReader ( ) ;
99131 const decoder = new TextDecoder ( ) ;
100132 let buffer = "" ;
133+ let chatId : string | null = null ;
101134 let navigated = false ;
102135
103136 // ストリームを非同期で読み続ける(ナビゲーション後もバックグラウンドで継続)
@@ -118,11 +151,16 @@ export function ChatForm({ path, sectionContent, close }: ChatFormProps) {
118151 const event = JSON . parse ( line ) as ChatStreamEvent ;
119152
120153 if ( event . type === "chat" ) {
154+ // revalidateChatは/api/chatの中では呼ばず、別のServerActionとして呼び出す
155+ await revalidateChatAction ( event . chatId , path ) ;
156+ chatId = event . chatId ;
121157 streamingChatContext . startStreaming ( event . chatId ) ;
122158 document . getElementById ( event . sectionId ) ?. scrollIntoView ( {
123159 behavior : "smooth" ,
124160 } ) ;
125- router . push ( `/chat/${ event . chatId } ` , { scroll : false } ) ;
161+ await asyncRouterPush ( `/chat/${ event . chatId } ` , {
162+ scroll : false ,
163+ } ) ;
126164 router . refresh ( ) ;
127165 navigated = true ;
128166 setIsLoading ( false ) ;
@@ -131,14 +169,21 @@ export function ChatForm({ path, sectionContent, close }: ChatFormProps) {
131169 } else if ( event . type === "chunk" ) {
132170 streamingChatContext . appendChunk ( event . text ) ;
133171 } else if ( event . type === "done" ) {
172+ if ( chatId ) {
173+ await revalidateChatAction ( chatId , path ) ;
174+ }
134175 streamingChatContext . finishStreaming ( ) ;
135176 router . refresh ( ) ;
136177 } else if ( event . type === "error" ) {
137178 if ( ! navigated ) {
138179 setErrorMessage ( event . message ) ;
139180 setIsLoading ( false ) ;
140181 }
182+ if ( chatId ) {
183+ await revalidateChatAction ( chatId , path ) ;
184+ }
141185 streamingChatContext . finishStreaming ( ) ;
186+ router . refresh ( ) ;
142187 }
143188 } catch {
144189 // ignore JSON parse errors
0 commit comments