Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
89c5f74
fix: harden settings and type contracts
justlevine Nov 10, 2025
7fd66e4
Update inc/Modules/Settings/Settings.php
justlevine Nov 10, 2025
930c65e
Update inc/classes/rest/class-basic-options.php
justlevine Nov 10, 2025
6fd29ff
Update inc/Modules/Settings/Settings.php
justlevine Nov 10, 2025
babeea1
chore: cleanup
justlevine Nov 10, 2025
29c6a55
chore: cleanup
justlevine Nov 10, 2025
e9d0ce0
chore: cleanup
justlevine Nov 11, 2025
f8bed3c
Update inc/classes/rest/class-basic-options.php
justlevine Nov 11, 2025
eab4c82
chore: cleanup and punt
justlevine Nov 11, 2025
c258203
fix: remove unused method after cleanup
justlevine Nov 11, 2025
e60b6c2
fix: safe token
justlevine Nov 11, 2025
8b167d1
Update inc/classes/algolia/class-algolia-index.php
justlevine Nov 11, 2025
8bb2a66
fix: update and replace onboarding modal
justlevine Nov 11, 2025
829f28b
Update assets/src/css/admin.scss
justlevine Nov 11, 2025
e852c6b
Update assets/src/admin/onboarding/page.tsx
justlevine Nov 11, 2025
a219c64
Update inc/Modules/Settings/Admin.php
justlevine Nov 11, 2025
7a65512
Update assets/src/admin/onboarding/index.tsx
justlevine Nov 11, 2025
a02be00
fix: move apiFetch.use into `useEffect()`
justlevine Nov 11, 2025
68ef11e
Update assets/src/admin/onboarding/page.tsx
justlevine Nov 11, 2025
013f04f
Merge branch 'develop' into fix/onboarding-modal
justlevine Nov 11, 2025
a66d487
chore: post merge cleanup
justlevine Nov 11, 2025
a6c9839
fix: remove unnecessary asset stubs
justlevine Nov 11, 2025
15da457
Update assets/src/admin/onboarding/page.tsx
justlevine Nov 11, 2025
b390075
Update assets/src/admin/onboarding/page.tsx
justlevine Nov 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 0 additions & 15 deletions .eslintrc

This file was deleted.

75 changes: 75 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{
"root": true,
"extends": [
"plugin:@wordpress/eslint-plugin/recommended-with-formatting",
"plugin:import/recommended",
"plugin:import/typescript",
"plugin:eslint-comments/recommended"
],
"plugins": [],
"env": {
"browser": true
},
"settings": {
"import/resolver": {
"node": {
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
}
},
"globals": {
"_": true,
"patternSyncData": true
},
"rules": {
"jsdoc/check-indentation": "error",
"no-shadow": "warn",
/* WordPress surfaces snake_case keys and globals; allow them */
"camelcase": "off",
"import/no-unresolved": "off",
"import/extensions": "off",
"import/no-extraneous-dependencies": "off",
"import/default": "off",
"import/namespace": "off",
"import/no-named-as-default": "off",
"import/no-named-as-default-member": "off",
"eslint-comments/disable-enable-pair": "off",
"eslint-comments/no-unlimited-disable": "error",
"jsx-a11y/label-has-associated-control": "off",
"no-unused-vars": "off" // TODO: Fix this for flagging the types from functions.
},
"overrides": [
{
"files": ["**/*.{ts,tsx}"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": { "jsx": true },
"sourceType": "module"
},
"rules": {
"no-undef": "off"
}
},
{
"files": ["**/*.d.ts"],
"parser": "@typescript-eslint/parser",
"rules": {
"no-undef": "off",
"import/no-unresolved": "off",
"@typescript-eslint/triple-slash-reference": "off"
}
},
{
"files": [
"**/__tests__/**/*.js",
"**/test/*.js",
"**/?(*.)test.js",
"tests/js/**/*.js"
],
"extends": ["plugin:jest/all"],
"rules": {
// Add Rules for Jest here
}
}
]
}
21 changes: 21 additions & 0 deletions assets/src/admin/onboarding/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createRoot } from 'react-dom/client';
import OnboardingScreen, { type SiteType } from './page';

interface OneSearchPluginGlobal {
nonce: string;
site_type: SiteType | '';
setup_url: string;
}

declare global {
interface Window {
OneSearchPluginGlobal: OneSearchPluginGlobal;
}
}

// Render to the target element.
const target = document.getElementById( 'onesearch-site-selection-modal' );
if ( target ) {
const root = createRoot( target );
root.render( <OnboardingScreen /> );
}
136 changes: 136 additions & 0 deletions assets/src/admin/onboarding/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { useState, useEffect } from 'react';
import apiFetch from '@wordpress/api-fetch';
import { __ } from '@wordpress/i18n';
import {
Card,
CardHeader,
CardBody,
Notice,
Button,
SelectControl,
} from '@wordpress/components';

const BRAND_SITE = 'brand-site';
const GOVERNING_SITE = 'governing-site';

export type SiteType = typeof BRAND_SITE | typeof GOVERNING_SITE;

interface NoticeState {
type: 'success' | 'error' | 'warning' | 'info';
message: string;
}

const SiteTypeSelector = ( { value, setSiteType }: {
value: SiteType | '';
setSiteType: ( v: SiteType | '' ) => void;
} ) => (
<SelectControl
label={ __( 'Site Type', 'onesearch' ) }
value={ value }
help={ __(
"Choose your site's primary purpose. This setting cannot be changed later and affects available features and configurations.",
'onesearch',
) }
onChange={ ( v ) => {
setSiteType( v );
} }
options={ [
{ label: __( 'Select…', 'onesearch' ), value: '' },
{ label: __( 'Brand Site', 'onesearch' ), value: BRAND_SITE },
{ label: __( 'Governing site', 'onesearch' ), value: GOVERNING_SITE },
] }
/>
);

const OnboardingScreen = () => {
// WordPress provides snake_case keys here. Using them intentionally. eslint-disable-next-line camelcase
const { nonce, setup_url, site_type } = window.OneSearchPluginGlobal;

const [ siteType, setSiteType ] = useState<SiteType | ''>( site_type || '' );
const [ notice, setNotice ] = useState<NoticeState | null>( null );
const [ isSaving, setIsSaving ] = useState<boolean>( false );

useEffect( () => {
apiFetch.use( apiFetch.createNonceMiddleware( nonce ) );
apiFetch<{ onesearch_site_type?: SiteType }>( { path: '/wp/v2/settings' } )
.then( ( settings ) => {
if ( settings?.onesearch_site_type ) {
setSiteType( settings.onesearch_site_type );
}
} )
.catch( () => {
setNotice( {
type: 'error',
message: __( 'Error fetching site type.', 'onesearch' ),
} );
} );
}, [ nonce ] );

const handleSiteTypeChange = async ( value: SiteType | '' ) => {
// Optimistically set site type.
setSiteType( value );
setIsSaving( true );

try {
await apiFetch<{ onesearch_site_type?: SiteType }>( {
path: '/wp/v2/settings',
method: 'POST',
data: { onesearch_site_type: value },
} ).then( ( settings ) => {
if ( ! settings?.onesearch_site_type ) {
throw new Error( 'No site type in response' );
}

setSiteType( settings.onesearch_site_type );

// Redirect user to setup page.
if ( setup_url ) {
window.location.href = setup_url;
}
} );
} catch {
setNotice( {
type: 'error',
message: __( 'Error setting site type.', 'onesearch' ),
} );
} finally {
setIsSaving( false );
}
};

return (
<Card>
{ !! notice?.message && (
<Notice
status={ notice?.type ?? 'success' }
isDismissible={ true }
onRemove={ () => setNotice( null ) }
>
{ notice?.message }
</Notice>
) }

<CardHeader>
<h2>{ __( 'OneSearch', 'onesearch' ) }</h2>
</CardHeader>

<CardBody className="onesearch-onboarding-page">
<SiteTypeSelector
value={ siteType }
setSiteType={ setSiteType }
/>
<Button
variant="primary"
onClick={ () => handleSiteTypeChange( siteType ) }
disabled={ isSaving || ! siteType }
style={ { marginTop: '1.5rem' } }
className={ isSaving ? 'is-busy' : '' }
>
{ __( 'Select Current Site Type', 'onesearch' ) }
</Button>
</CardBody>
</Card>
);
};

export default OnboardingScreen;
140 changes: 0 additions & 140 deletions assets/src/admin/plugin/index.js

This file was deleted.

Loading
Loading