Skip to content

Commit bc2df1a

Browse files
committed
languages api and default english selection
1. Adding the default language logic for the LanguageSelection 2. Implementing the Language REST API endpoint for WordPress languages 3. Adding Redux store caching to prevent redundant API calls for fetching languages 4. Fixing the timing issues with setting English as the default language
1 parent 48d2ed6 commit bc2df1a

File tree

7 files changed

+124
-13
lines changed

7 files changed

+124
-13
lines changed

src/OnboardingSPA/steps/SiteGen/SiteDetails/contents.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,7 @@ const getContents = () => {
2121
),
2222
walkThroughlink: __( 'click here', 'wp-module-onboarding' ),
2323
languageList: [
24-
[ __( 'English (US)', 'wp-module-onboarding' ), 'en-US' ],
25-
[ __( 'English (UK)', 'wp-module-onboarding' ), 'en-UK' ],
26-
[ __( 'Spanish', 'wp-module-onboarding' ), 'es-ES' ],
27-
[ __( 'French', 'wp-module-onboarding' ), 'fr-FR' ],
28-
[ __( 'Hindi', 'wp-module-onboarding' ), 'hi-IN' ],
24+
[ __( 'English (United States)', 'wp-module-onboarding' ), 'en_US' ],
2925
],
3026
languageSelectionLabel: __(
3127
'Choose your preferred site language:',

src/OnboardingSPA/steps/SiteGen/SiteDetails/index.js

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
trackOnboardingEvent,
1010
} from '../../../utils/analytics/hiive';
1111
import getContents from './contents';
12+
import { fetchLanguages, formatLanguagesForSelection } from '../../../utils/api/languages';
1213

1314
// Components
1415
import Animate from '../../../components/Animate';
@@ -29,11 +30,12 @@ const SiteGenSiteDetails = () => {
2930
const [ customerInput, setCustomerInput ] = useState( '' );
3031
const [ customerInputStrength, setCustomerInputStrength ] = useState( 0 );
3132
const [ isValidInput, setIsValidInput ] = useState( false );
33+
const [ languages, setLanguages ] = useState( [] );
3234

33-
const { currentData } = useSelect( ( select ) => {
35+
const { currentData, storedLanguages } = useSelect( ( select ) => {
3436
return {
35-
currentData:
36-
select( nfdOnboardingStore ).getCurrentOnboardingData(),
37+
currentData: select( nfdOnboardingStore ).getCurrentOnboardingData(),
38+
storedLanguages: select( nfdOnboardingStore ).getLanguages(),
3739
};
3840
} );
3941

@@ -50,22 +52,51 @@ const SiteGenSiteDetails = () => {
5052
setHideFooterNav,
5153
setCurrentOnboardingData,
5254
setIsHeaderNavigationEnabled,
55+
setStoreLanguages,
5356
} = useDispatch( nfdOnboardingStore );
5457

5558
const isLargeViewport = useViewportMatch( 'small' );
5659
const content = getContents();
5760

61+
// Fetch languages from API only if they don't exist in the store
62+
useEffect( () => {
63+
const getLanguages = async () => {
64+
// Check if languages already exist in the store
65+
if ( storedLanguages?.length > 0 ) {
66+
// Use languages from the store
67+
setLanguages( formatLanguagesForSelection( storedLanguages ) );
68+
} else {
69+
// Fetch languages if not in store
70+
const languageData = await fetchLanguages();
71+
if ( languageData?.length > 0 ) {
72+
const formattedLanguages = formatLanguagesForSelection( languageData );
73+
setLanguages( formattedLanguages );
74+
75+
// Save languages to the store for future use
76+
setStoreLanguages( languageData );
77+
}
78+
}
79+
};
80+
81+
getLanguages();
82+
}, [ storedLanguages, setStoreLanguages ] );
83+
5884
// Function to find English in language list or default to first language
5985
const getDefaultLocale = () => {
60-
const englishOption = content.languageList.find( ( [ language ] ) =>
86+
const languageList = languages.length > 0 ? languages : content.languageList;
87+
const englishOption = languageList.find( ( [ language ] ) =>
6188
language.toLowerCase().includes( 'english' ) );
62-
const defaultOption = content.languageList[ 0 ] ? content.languageList[ 0 ][ 1 ] : '';
89+
const defaultOption = languageList[ 0 ] ? languageList[ 0 ][ 1 ] : '';
6390
return englishOption ? englishOption[ 1 ] : defaultOption;
6491
};
6592

6693
// Set English as default if no locale is selected
6794
useEffect( () => {
68-
if ( ! selectedLocale && content.languageList && content.languageList.length > 0 ) {
95+
// Only run this if languages have loaded or we have content.languageList
96+
const languageList = languages?.length > 0 ? languages : content.languageList;
97+
98+
// initialize default locale when the user visits the first time
99+
if ( languageList?.length > 0 && ! selectedLocale ) {
69100
const defaultLocale = getDefaultLocale();
70101
setSelectedLocale( defaultLocale );
71102

@@ -75,7 +106,7 @@ const SiteGenSiteDetails = () => {
75106
setCurrentOnboardingData( currentData );
76107
}
77108
}
78-
}, [ content.languageList ] );
109+
}, [ languages, selectedLocale ] );
79110

80111
useEffect( () => {
81112
setHideFooterNav( false );
@@ -183,7 +214,7 @@ const SiteGenSiteDetails = () => {
183214
>
184215
<LanguageSelection
185216
languageSelectionLabel={ content.languageSelectionLabel }
186-
languageList={ content.languageList }
217+
languageList={ languages.length > 0 ? languages : content.languageList }
187218
selectedLocale={ selectedLocale }
188219
setSelectedLocale={ setSelectedLocale }
189220
/>

src/OnboardingSPA/store/actions.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,3 +331,10 @@ export function setContinueWithoutAi( continueWithoutAi ) {
331331
continueWithoutAi,
332332
};
333333
}
334+
335+
export function setStoreLanguages( languages ) {
336+
return {
337+
type: 'SET_LANGUAGES',
338+
languages,
339+
};
340+
}

src/OnboardingSPA/store/reducer.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,11 @@ export function data( state = {}, action ) {
179179
...action.socialData,
180180
},
181181
};
182+
case 'SET_LANGUAGES':
183+
return {
184+
...state,
185+
languages: action.languages,
186+
};
182187

183188
case 'SET_SITEGEN_AI_ERROR_STATUS':
184189
// Only update if the prev value was false and now there is an error else don't

src/OnboardingSPA/store/selectors.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,3 +471,7 @@ export function getInteractionDisabled( state ) {
471471
export function getIsFreshInstallation( state ) {
472472
return state.runtime.isFreshInstallation;
473473
}
474+
475+
export function getLanguages( state ) {
476+
return state.data.languages;
477+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Build a request URL for the Newfold Onboarding API.
3+
*
4+
* @param {string} endpoint - The API endpoint.
5+
* @return {string} The fully-qualified API URL.
6+
*/
7+
const buildRequestUrl = ( endpoint ) => {
8+
// Remove leading slash if it exists
9+
if ( endpoint.startsWith( '/' ) ) {
10+
endpoint = endpoint.substring( 1 );
11+
}
12+
13+
// Get the WordPress site URL
14+
const wpApiSettings = window.wpApiSettings || {};
15+
const apiRoot = wpApiSettings.root || '/wp-json/';
16+
17+
// Build the full API URL
18+
return `${apiRoot}newfold-onboarding/v1/${endpoint}`;
19+
};
20+
21+
export default buildRequestUrl;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import apiFetch from '@wordpress/api-fetch';
2+
import buildRequestUrl from './buildRequestUrl';
3+
4+
/*
5+
* Fetches the available languages from the WordPress installation.
6+
*
7+
* @return {Promise<Array>} Promise that resolves to an array of language data
8+
*/
9+
export const fetchLanguages = async () => {
10+
const requestUrl = buildRequestUrl( 'languages' );
11+
try {
12+
const response = await apiFetch( { url: requestUrl } );
13+
14+
// Validate response format
15+
if ( response?.languages?.length ) {
16+
return response.languages;
17+
}
18+
19+
// invalid response format
20+
return [];
21+
} catch ( error ) {
22+
// Return a basic fallback with English
23+
return [
24+
{
25+
code: 'en_US',
26+
name: 'English (United States)',
27+
native_name: 'English (United States)',
28+
},
29+
];
30+
}
31+
};
32+
33+
/*
34+
* Formats language data for the language selection component.
35+
* Returns array of [language_name, language_code] pairs.
36+
*
37+
* @param {Array} languages Array of language objects
38+
* @return {Array} Array formatted for the LanguageSelection component
39+
*/
40+
export const formatLanguagesForSelection = ( languages ) => {
41+
if ( ! languages?.length ) {
42+
// Return basic English if input isn't valid
43+
return [ [ 'English (United States)', 'en_US' ] ];
44+
}
45+
46+
return languages.map( ( language ) => [ language.name, language.code ] );
47+
};

0 commit comments

Comments
 (0)