Skip to content

Commit 38d8ae4

Browse files
committed
Move SyncModalMode piece of state to Redux
1 parent bb66758 commit 38d8ae4

File tree

3 files changed

+35
-39
lines changed

3 files changed

+35
-39
lines changed

src/modules/sync/index.tsx

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -127,18 +127,13 @@ export function ContentTabSync( { selectedSite }: { selectedSite: SiteDetails }
127127
const { __ } = useI18n();
128128
const dispatch = useAppDispatch();
129129
const isModalOpen = useRootSelector( connectedSitesSelectors.selectIsModalOpen );
130+
const reduxModalMode = useRootSelector( connectedSitesSelectors.selectModalMode );
130131
const { connectedSites } = useConnectedSitesData();
131132
const { syncSites, isFetching, refetchSites } = useSyncSitesData();
132133
const { connectSite, disconnectSite } = useConnectedSitesOperations();
133134
const { pushSite, pullSite } = useSyncSites();
134135

135-
const [ modalState, setModalState ] = useState< {
136-
mode: SyncModalMode | null;
137-
selectedRemoteSite: SyncSite | null;
138-
} >( {
139-
mode: null,
140-
selectedRemoteSite: null,
141-
} );
136+
const [ selectedRemoteSite, setSelectedRemoteSite ] = useState< SyncSite | null >( null );
142137

143138
const { isAuthenticated } = useAuth();
144139

@@ -164,13 +159,11 @@ export function ContentTabSync( { selectedSite }: { selectedSite: SiteDetails }
164159
};
165160

166161
const handleLaunchSite = () => {
167-
setModalState( ( prev ) => ( { ...prev, mode: 'push' } ) );
168-
dispatch( connectedSitesActions.openModal() );
162+
dispatch( connectedSitesActions.openModal( 'push' ) );
169163
};
170164

171165
const handleImportSite = () => {
172-
setModalState( ( prev ) => ( { ...prev, mode: 'pull' } ) );
173-
dispatch( connectedSitesActions.openModal() );
166+
dispatch( connectedSitesActions.openModal( 'pull' ) );
174167
};
175168

176169
const handleSiteSelection = async ( siteId: number, mode: SyncModalMode | null ) => {
@@ -193,19 +186,13 @@ export function ContentTabSync( { selectedSite }: { selectedSite: SiteDetails }
193186
await handleConnect( selectedSiteFromList );
194187

195188
if ( mode === 'push' || mode === 'pull' ) {
196-
setModalState( ( prev ) => ( {
197-
...prev,
198-
mode: mode,
199-
selectedRemoteSite: selectedSiteFromList,
200-
} ) );
189+
dispatch( connectedSitesActions.setModalMode( mode ) );
190+
setSelectedRemoteSite( selectedSiteFromList );
201191
} else {
202-
setModalState( ( prev ) => ( { ...prev, mode: null } ) );
192+
dispatch( connectedSitesActions.setModalMode( null ) );
203193
}
204194
};
205195

206-
// Using a local variable to avoid non-null assertion operator in pushSite and pullSite
207-
const selectedRemoteSite = modalState.selectedRemoteSite;
208-
209196
return (
210197
<div className="flex flex-col h-full overflow-y-auto">
211198
{ connectedSites.length > 0 ? (
@@ -218,7 +205,7 @@ export function ContentTabSync( { selectedSite }: { selectedSite: SiteDetails }
218205
<div className="sticky bottom-0 bg-white/[0.8] backdrop-blur-sm w-full px-8 py-6 mt-auto">
219206
<ConnectButton
220207
variant="primary"
221-
connectSite={ () => dispatch( connectedSitesActions.openModal() ) }
208+
connectSite={ () => dispatch( connectedSitesActions.openModal( 'connect' ) ) }
222209
disableConnectButtonStyle={ true }
223210
>
224211
{ __( 'Connect another site' ) }
@@ -250,47 +237,37 @@ export function ContentTabSync( { selectedSite }: { selectedSite: SiteDetails }
250237

251238
{ isModalOpen && (
252239
<SyncSitesModalSelector
253-
mode={ modalState.mode || 'connect' }
240+
mode={ reduxModalMode || 'connect' }
254241
isLoading={ isFetching }
255242
onRequestClose={ () => {
256243
dispatch( connectedSitesActions.closeModal() );
257-
setModalState( ( prev ) => ( { ...prev, mode: null } ) );
258244
} }
259245
syncSites={ syncSites }
260246
onInitialRender={ refetchSites }
261247
onConnect={ async ( siteId: number ) => {
262-
await handleSiteSelection( siteId, modalState.mode );
248+
await handleSiteSelection( siteId, reduxModalMode );
263249
} }
264250
selectedSite={ selectedSite }
265251
/>
266252
) }
267253

268-
{ modalState.mode && modalState.mode !== 'connect' && selectedRemoteSite && (
254+
{ reduxModalMode && reduxModalMode !== 'connect' && selectedRemoteSite && (
269255
<SyncDialog
270-
type={ modalState.mode }
256+
type={ reduxModalMode }
271257
localSite={ selectedSite }
272258
remoteSite={ selectedRemoteSite }
273259
onPush={ ( tree ) => {
274260
const pushOptions = convertTreeToPushOptions( tree );
275261
void pushSite( selectedRemoteSite, selectedSite, pushOptions );
276-
setModalState( {
277-
mode: null,
278-
selectedRemoteSite: null,
279-
} );
262+
setSelectedRemoteSite( null );
280263
} }
281264
onPull={ ( tree ) => {
282265
const pullOptions = convertTreeToPullOptions( tree );
283266
void pullSite( selectedRemoteSite, selectedSite, pullOptions );
284-
setModalState( {
285-
mode: null,
286-
selectedRemoteSite: null,
287-
} );
267+
setSelectedRemoteSite( null );
288268
} }
289269
onRequestClose={ () => {
290-
setModalState( {
291-
mode: null,
292-
selectedRemoteSite: null,
293-
} );
270+
setSelectedRemoteSite( null );
294271
} }
295272
/>
296273
) }

src/modules/sync/tests/index.test.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,15 @@ jest.mock( 'src/stores/sync', () => ( {
4545
useConnectedSitesOperations: jest.fn(),
4646
connectedSitesSelectors: {
4747
selectIsModalOpen: jest.fn(),
48+
selectModalMode: jest.fn(),
4849
},
4950
connectedSitesActions: {
5051
openModal: jest.fn().mockImplementation( () => {
5152
return { type: 'connectedSites/openModal' };
5253
} ),
54+
setModalMode: jest.fn().mockImplementation( () => {
55+
return { type: 'connectedSites/setModalMode' };
56+
} ),
5357
closeModal: jest.fn().mockImplementation( () => {
5458
return { type: 'connectedSites/closeModal' };
5559
} ),
@@ -190,6 +194,7 @@ describe( 'ContentTabSync', () => {
190194
useAppDispatch.mockReturnValue( jest.fn() );
191195

192196
( connectedSitesSelectors.selectIsModalOpen as jest.Mock ).mockReturnValue( false );
197+
( connectedSitesSelectors.selectModalMode as jest.Mock ).mockReturnValue( null );
193198
( useRemoteFileTree as jest.Mock ).mockReturnValue( {
194199
fetchChildren: jest.fn().mockResolvedValue( [
195200
{
@@ -280,6 +285,7 @@ describe( 'ContentTabSync', () => {
280285
fireEvent.click( importButton );
281286

282287
( connectedSitesSelectors.selectIsModalOpen as jest.Mock ).mockReturnValue( true );
288+
( connectedSitesSelectors.selectModalMode as jest.Mock ).mockReturnValue( null );
283289

284290
renderWithProvider( <ContentTabSync selectedSite={ selectedSite } /> );
285291
expect( screen.getByTestId( 'sync-sites-modal-selector' ) ).toBeInTheDocument();
@@ -362,6 +368,7 @@ describe( 'ContentTabSync', () => {
362368
expect( importButton ).toBeInTheDocument();
363369
fireEvent.click( importButton );
364370
( connectedSitesSelectors.selectIsModalOpen as jest.Mock ).mockReturnValue( true );
371+
( connectedSitesSelectors.selectModalMode as jest.Mock ).mockReturnValue( null );
365372
renderWithProvider( <ContentTabSync selectedSite={ selectedSite } /> );
366373
const createNewSiteButton = screen.getByRole( 'button', {
367374
name: /Create a new WordPress.com site /i,

src/stores/sync/connected-sites-slice.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ import { createAsyncThunk, createSelector, createSlice, PayloadAction } from '@r
22
import { getIpcApi } from 'src/lib/get-ipc-api';
33
import { RootState } from 'src/stores';
44
import type { SyncSite } from 'src/hooks/use-fetch-wpcom-sites/types';
5+
import type { SyncModalMode } from 'src/modules/sync/types';
56

67
type ConnectedSites = SyncSite[];
78
type ModalState = false | true | { disconnectSiteId?: number };
89

910
interface ConnectedSitesState {
1011
sites: Record< string, ConnectedSites >; // Keyed by localSiteId for efficient lookups
1112
isModalOpen: ModalState;
13+
modalMode: SyncModalMode | null;
1214
}
1315

1416
interface ConnectSiteParams {
@@ -24,6 +26,7 @@ interface DisconnectSiteParams {
2426
const initialState: ConnectedSitesState = {
2527
sites: {},
2628
isModalOpen: false,
29+
modalMode: null,
2730
};
2831

2932
export const loadAllConnectedSites = createAsyncThunk( 'connectedSites/loadAll', async () => {
@@ -96,12 +99,20 @@ const connectedSitesSlice = createSlice( {
9699
delete state.sites[ action.payload ];
97100
},
98101

99-
openModal: ( state ) => {
102+
openModal: ( state, action: PayloadAction< SyncModalMode | undefined > ) => {
100103
state.isModalOpen = true;
104+
if ( action.payload ) {
105+
state.modalMode = action.payload;
106+
}
107+
},
108+
109+
setModalMode: ( state, action: PayloadAction< SyncModalMode | null > ) => {
110+
state.modalMode = action.payload;
101111
},
102112

103113
closeModal: ( state ) => {
104114
state.isModalOpen = false;
115+
state.modalMode = null;
105116
},
106117
},
107118
extraReducers: ( builder ) => {
@@ -125,6 +136,7 @@ export const connectedSitesReducer = connectedSitesSlice.reducer;
125136

126137
export const connectedSitesSelectors = {
127138
selectIsModalOpen: ( state: RootState ) => state.connectedSites.isModalOpen,
139+
selectModalMode: ( state: RootState ) => state.connectedSites.modalMode,
128140
selectSitesByLocalSiteId: createSelector(
129141
[
130142
( state: RootState ) => state.connectedSites,

0 commit comments

Comments
 (0)