@@ -911,6 +911,12 @@ export default function MapView({
911911 const [ visits , setVisits ] = useState < Visit [ ] > ( [ ] ) ;
912912 // 訪問予定リスト(絞り込みモーダルの「訪問予定リスト」セレクトで経路表示に使う)
913913 const [ planLists , setPlanLists ] = useState < VisitPlanList [ ] > ( [ ] ) ;
914+ // 経路表示するリストに、本体種別に無い(別スポット種別を重ねて追加した)スポットが
915+ // あるとき、その座標を api.spots.get で補完して経路に含める。resolvedRefで再取得を防ぐ
916+ const [ planListExtraSpots , setPlanListExtraSpots ] = useState < Map < string , Spot > > (
917+ new Map ( )
918+ ) ;
919+ const planListResolvedRef = useRef < Set < string > > ( new Set ( ) ) ;
914920 const visitedIds = useMemo (
915921 ( ) => new Set ( visits . map ( ( v ) => v . spot_id ) ) ,
916922 [ visits ]
@@ -920,6 +926,12 @@ export default function MapView({
920926 for ( const s of spots ) m . set ( s . id , s ) ;
921927 return m ;
922928 } , [ spots ] ) ;
929+ // 訪問予定リストの経路を組むときのスポット解決用。本体スポットに、別種別スポットの
930+ // 補完(planListExtraSpots)を足す。補完が無いときは spotById をそのまま使う(参照維持)
931+ const planPathSpotById = useMemo ( ( ) => {
932+ if ( planListExtraSpots . size === 0 ) return spotById ;
933+ return new Map ( [ ...spotById , ...planListExtraSpots ] ) ;
934+ } , [ spotById , planListExtraSpots ] ) ;
923935 /**
924936 * 訪問順の経路の対象日を選ぶドロップダウン用に、この種別のスポットへ訪問した
925937 * 日の一覧(新しい順)。他の種別の訪問しかない日は経路が0件になるため除く。
@@ -1003,10 +1015,38 @@ export default function MapView({
10031015 const planListId = value || null ;
10041016 setFilters ( { ...filters , planListId } ) ;
10051017 if ( ! planListId ) return ;
1006- fitMapToSpots ( buildPlanListPath ( planLists , { ...filters , planListId } , spotById ) ) ;
1018+ fitMapToSpots (
1019+ buildPlanListPath ( planLists , { ...filters , planListId } , planPathSpotById )
1020+ ) ;
10071021 } ,
1008- [ filters , setFilters , planLists , spotById , fitMapToSpots ]
1022+ [ filters , setFilters , planLists , planPathSpotById , fitMapToSpots ]
10091023 ) ;
1024+
1025+ // 経路表示中のリストに本体種別で解決できないスポット(別種別を重ねて追加したもの)が
1026+ // あれば、api.spots.get で座標を補完する(経路線から抜けないように)
1027+ useEffect ( ( ) => {
1028+ const listId = filters . planListId ;
1029+ if ( ! listId ) return ;
1030+ const list = planLists . find ( ( l ) => l . id === listId ) ;
1031+ if ( ! list ) return ;
1032+ const missing = list . spot_ids . filter (
1033+ ( id ) => ! spotById . has ( id ) && ! planListResolvedRef . current . has ( id )
1034+ ) ;
1035+ if ( missing . length === 0 ) return ;
1036+ missing . forEach ( ( id ) => planListResolvedRef . current . add ( id ) ) ;
1037+ let cancelled = false ;
1038+ Promise . all ( missing . map ( ( id ) => api . spots . get ( id ) ) ) . then ( ( results ) => {
1039+ if ( cancelled ) return ;
1040+ setPlanListExtraSpots ( ( prev ) => {
1041+ const next = new Map ( prev ) ;
1042+ for ( const { data } of results ) if ( data ) next . set ( data . id , data ) ;
1043+ return next ;
1044+ } ) ;
1045+ } ) ;
1046+ return ( ) => {
1047+ cancelled = true ;
1048+ } ;
1049+ } , [ filters . planListId , planLists , spotById ] ) ;
10101050 // マウント時と、マウント中に種別が切り替わった場合に、その種別の保存済み条件を読む
10111051 useEffect ( ( ) => {
10121052 setFiltersState ( loadSavedFilters ( spotTypeKey ) ) ;
@@ -1779,7 +1819,7 @@ export default function MapView({
17791819 // 絞り込みで外れていても必ず表示する(経路を辿るための表示のため全条件を免除)
17801820 const pathIds = new Set ( [
17811821 ...buildVisitPath ( visits , filters , spotById ) . map ( ( s ) => s . id ) ,
1782- ...buildPlanListPath ( planLists , filters , spotById ) . map ( ( s ) => s . id ) ,
1822+ ...buildPlanListPath ( planLists , filters , planPathSpotById ) . map ( ( s ) => s . id ) ,
17831823 ] ) ;
17841824 const filteredSpots = spots . filter (
17851825 ( spot ) =>
@@ -1832,6 +1872,7 @@ export default function MapView({
18321872 } , [
18331873 spots ,
18341874 spotById ,
1875+ planPathSpotById ,
18351876 visits ,
18361877 planLists ,
18371878 visitedIds ,
@@ -1850,7 +1891,7 @@ export default function MapView({
18501891
18511892 const visibleRoutes = filterVisibleRoutes ( routes , filters , seriesStyles , spotById ) ;
18521893 const visitPath = buildVisitPath ( visits , filters , spotById ) ;
1853- const planListPath = buildPlanListPath ( planLists , filters , spotById ) ;
1894+ const planListPath = buildPlanListPath ( planLists , filters , planPathSpotById ) ;
18541895
18551896 runWhenMapReady ( ( ) => {
18561897 ensureRouteLayers ( map , setDetailRouteId ) ;
@@ -1864,7 +1905,16 @@ export default function MapView({
18641905 ] )
18651906 ) ;
18661907 } ) ;
1867- } , [ routes , filters , seriesStyles , runWhenMapReady , visits , planLists , spotById ] ) ;
1908+ } , [
1909+ routes ,
1910+ filters ,
1911+ seriesStyles ,
1912+ runWhenMapReady ,
1913+ visits ,
1914+ planLists ,
1915+ spotById ,
1916+ planPathSpotById ,
1917+ ] ) ;
18681918
18691919 // 別種別の重ね表示の描画。絞り込み・経由地ピンの免除は本体と同じロジックを、
18701920 // その種別の保存済み設定・シリーズ設定で適用する(訪問順の経路(緑)は
0 commit comments