Skip to content

Commit

Permalink
dev: source setting screens from global
Browse files Browse the repository at this point in the history
  • Loading branch information
justlevine committed Oct 26, 2024
1 parent a07dc26 commit 92eadc3
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 100 deletions.
4 changes: 2 additions & 2 deletions packages/admin/components/fields/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { AllowedSettingKeys, SettingSchema } from '@/admin/types';
import type { FieldSchema } from '@/admin/types';
import { Field } from './field';

export const Fields = ( {
Expand All @@ -9,7 +9,7 @@ export const Fields = ( {
}: {
excludedProperties?: string[];
values: Record< string, unknown > | undefined;
fields: SettingSchema[ AllowedSettingKeys ];
fields: Record< string, FieldSchema >;
setValue: ( values: Record< string, unknown > ) => void;
} ) => {
if ( ! values ) {
Expand Down
70 changes: 42 additions & 28 deletions packages/admin/components/layout/header/menu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Button, Icon, NavigableMenu } from '@wordpress/components';
import { link as LinkSVG } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';
import { useCurrentScreen } from '@/admin/components/screen/context';
import type { AllowedScreens } from '@/admin/components/screen/screen';
import { getScreenForSetting } from '@/admin/components/screen/utils';

import styles from './styles.module.scss';

Expand All @@ -13,43 +13,57 @@ const LinkIcon = () => {
return <Icon icon={ LinkSVG } className={ styles.linkIcon } size={ 16 } />;
};

const SCREEN_LABELS: Record< AllowedScreens, string > = {
providers: __( 'Login Providers', 'wp-graphql-headless-login' ),
'access-control': __( 'Access Control', 'wp-graphql-headless-login' ),
'plugin-settings': __( 'Misc', 'wp-graphql-headless-login' ),
/**
* Builds and returns the menu object from the wpGraphQLLogin.settings global.
*/
export const getMenuObject = (): Record< string, string > => {
const settings = wpGraphQLLogin.settings;

const menu: Record< string, string > = {
providers: '', // We want this as the first key.
};

for ( const key in settings ) {
// @todo get providers from global after the refactor.
const menuTitle =
settings[ key ].label ||
__( 'Providers', 'wp-graphql-headless-login' );
const screen = getScreenForSetting( key );

menu[ screen ] = menuTitle;
}

return menu;
};

export const Menu = () => {
const { currentScreen, setCurrentScreen } = useCurrentScreen();

// Build the menu object of screens and labels from the wpGraphQLLogin?.settings.
const menuItems = getMenuObject();

return (
<NavigableMenu orientation="horizontal">
<ul role="menubar" className={ styles.menu }>
{
// Loop through the screen titles and create a button for each one.
Object.entries( SCREEN_LABELS ).map(
( [ screen, title ] ) => (
<li key={ screen }>
<Button
key={ screen }
className={
currentScreen === screen
? styles.active
: ''
}
variant="tertiary"
onClick={ () =>
setCurrentScreen(
screen as AllowedScreens
)
}
role="menuitem"
>
{ title }
</Button>
</li>
)
)
Object.entries( menuItems ).map( ( [ screen, title ] ) => (
<li key={ screen }>
<Button
key={ screen }
className={
currentScreen === screen
? styles.active
: ''
}
variant="tertiary"
onClick={ () => setCurrentScreen( screen ) }
role="menuitem"
>
{ title }
</Button>
</li>
) )
}
<li>
<Button
Expand Down
13 changes: 7 additions & 6 deletions packages/admin/components/screen/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,29 @@ import {
useContext,
startTransition,
} from 'react';
import { SCREEN_MAP, type AllowedScreens } from './screen';
import { isAllowedScreen } from './utils';

const ScreenContext = createContext< {
currentScreen: AllowedScreens;
setCurrentScreen: ( screen: AllowedScreens ) => void;
currentScreen: string;
setCurrentScreen: ( screen: string ) => void;
} >( {
currentScreen: 'providers',
setCurrentScreen: () => {}, // eslint-disable-line @typescript-eslint/no-empty-function
} );

export const ScreenProvider = ( { children }: PropsWithChildren ) => {
const [ currentScreen, setCurrentScreen ] =
useState< AllowedScreens >( 'providers' );
useState< string >( 'providers' );

// The screen is set as a query parameter in the URL.
useEffect( () => {
startTransition( () => {
const url = new URL( window.location.href );
const screen = url.searchParams.get( 'screen' );

if ( screen && screen in SCREEN_MAP ) {
setCurrentScreen( screen as AllowedScreens );
// Allowed screens appear in the WPGraphQLLogin.settings global.
if ( screen && isAllowedScreen( screen ) ) {
setCurrentScreen( screen );
}
} );
}, [] );
Expand Down
58 changes: 15 additions & 43 deletions packages/admin/components/screen/screen.tsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,23 @@
import { __ } from '@wordpress/i18n';
import { Panel, PanelBody, PanelRow } from '@wordpress/components';
import clsx from 'clsx';
import { lazy, Suspense, type PropsWithChildren } from 'react';
import { Loading } from '@/admin/components/ui/loading';
import { useCurrentScreen } from './context';
import { SettingsScreen } from './setting-screen';
import type { AllowedSettingKeys } from '@/admin/types';

import styles from './styles.module.scss';
import { getSettingForScreen } from './utils';
import { __ } from '@wordpress/i18n';

const ClientSettingsScreen = lazy(
() => import( '../provider-config/ClientSettings' )
);

export type AllowedScreens = 'access-control' | 'providers' | 'plugin-settings';

export const SCREEN_MAP: Record< AllowedScreens, AllowedSettingKeys > = {
'access-control': 'wpgraphql_login_access_control',
'plugin-settings': 'wpgraphql_login_settings',
providers: 'providers',
};

/**
* The titles of the screens that are available in the admin.
*
* @todo get from the server.
*/
const SCREEN_TITLES: Record< AllowedScreens, string > = {
'access-control': __(
'Access Control Settings',
'wp-graphql-headless-login'
),
'plugin-settings': __( 'Plugin Settings', 'wp-graphql-headless-login' ),
providers: __( 'Login Providers', 'wp-graphql-headless-login' ),
};

/**
* The descriptions of the screens that are available in the admin.
*
* @todo get from the server.
*/
const SCREEN_DESCRIPTIONS: Record< AllowedScreens, string > = {
'access-control': __(
'Configure the Access Control headers for the plugin.',
'wp-graphql-headless-login'
),
'plugin-settings': __(
'Configure the plugin settings.',
'wp-graphql-headless-login'
),
providers: __(
'Configure the Authentication Providers that are available to users.',
'wp-graphql-headless-login'
),
};

const Wrapper = ( {
title,
Expand Down Expand Up @@ -85,18 +49,26 @@ const Wrapper = ( {
export const Screen = () => {
const { currentScreen } = useCurrentScreen();

const title = SCREEN_TITLES[ currentScreen ];
const description = SCREEN_DESCRIPTIONS[ currentScreen ];
const settingKey = getSettingForScreen( currentScreen );

// @todo get provider context from global.
const title =
wpGraphQLLogin?.settings[ settingKey ]?.title ||
__( 'Login Providers', 'wp-graphql-headless-login' );
const description =
wpGraphQLLogin?.settings[ settingKey ]?.description ||
__(
'Configure the Authentication Providers that are available to users.',
'wp-graphql-headless-login'
);

return (
<Suspense fallback={ <Loading /> }>
<Wrapper title={ title } description={ description }>
{ currentScreen === 'providers' ? (
<ClientSettingsScreen />
) : (
<SettingsScreen
settingKey={ SCREEN_MAP[ currentScreen ] }
/>
<SettingsScreen settingKey={ settingKey } />
) }
</Wrapper>
</Suspense>
Expand Down
10 changes: 3 additions & 7 deletions packages/admin/components/screen/setting-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,8 @@ import { useEffect } from 'react';
import { Button, PanelBody, Spinner } from '@wordpress/components';
import { Fields } from '@/admin/components/fields';
import { useSettings } from '@/admin/contexts/settings-context';
import type { AllowedSettingKeys } from '@/admin/types';

export const SettingsScreen = ( {
settingKey,
}: {
settingKey: AllowedSettingKeys;
} ) => {
export const SettingsScreen = ( { settingKey }: { settingKey: string } ) => {
const {
settings: allSettings,
updateSettings,
Expand All @@ -19,7 +14,8 @@ export const SettingsScreen = ( {
errorMessage,
} = useSettings();

const optionsSchema = wpGraphQLLogin?.settings?.[ settingKey ] || undefined;
const optionsSchema =
wpGraphQLLogin?.settings?.[ settingKey ]?.fields || undefined;

const settings = allSettings?.[ settingKey ] || undefined;

Expand Down
47 changes: 47 additions & 0 deletions packages/admin/components/screen/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Maps a plugin setting key to to its corresponding screen.
*
* @param {string} setting The setting to map to a screen. E.g. `wpgraphql_login_access_control`.
*/
export const getScreenForSetting = ( setting: string ): string => {
const settingPrefix = 'wpgraphql_login_';

// First, strip the prefix.
const settingWithoutPrefix = setting.replace( settingPrefix, '' );

// Then, convert to `kebab-case`.
return settingWithoutPrefix.replace( /_/g, '-' );
};

/**
* Maps a screen to it's corresponding plugin setting.
*
* @param {string} screen The screen to map to a setting. E.g. `access-control`.
*/
export const getSettingForScreen = ( screen: string ): string => {
const settingPrefix = 'wpgraphql_login_';

// First, convert to `snake_case`.
const snakeCaseScreen = screen.replace( /-/g, '_' );

// Then, add the prefix.
const setting = settingPrefix + snakeCaseScreen;

// Ensure lowercase
return setting.toLowerCase();
};

/**
* Checks whether a screen is allowed.
*
* Allowed screens are the keys defined in the `WPGraphQLLogin.settings` global.
*
* @param {string} screen The screen to check.
*/
export const isAllowedScreen = ( screen: string ): boolean => {
const allowedSettings = Object.keys( wpGraphQLLogin.settings );

const settingToCheck = getSettingForScreen( screen );

return allowedSettings.includes( settingToCheck );
};
3 changes: 1 addition & 2 deletions packages/admin/contexts/settings-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import {
useState,
} from 'react';
import apiFetch from '@wordpress/api-fetch';
import type { AllowedSettingKeys } from '@/admin/types';

const REST_ENDPOINT = 'wp-graphql-login/v1/settings';

type AllowedStatuses = 'saving' | 'complete' | undefined;

type SettingType = Record< AllowedSettingKeys, Record< string, unknown > >;
type SettingType = Record< string, Record< string, unknown > >;

const SettingsContext = createContext< {
settings: SettingType | undefined;
Expand Down
17 changes: 8 additions & 9 deletions packages/admin/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ declare global {
};
}

type AllowedSettingKeys =
| 'providers'
| 'wpgraphql_login_settings'
| 'wpgraphql_login_access_control';

type AllowedConditionalLogicOperators = '==' | '!=' | '>' | '<' | '>=' | '<=';

type FieldSchema = {
Expand All @@ -45,10 +40,14 @@ type FieldSchema = {
required?: boolean;
};

type SettingSchema = Record<
AllowedSettingKeys,
Record< string, FieldSchema >
>;
type SettingSchema = {
[ key: string ]: {
title: string;
description: string;
label: string;
fields: Record< string, FieldSchema >;
}
};

type ProviderSettingType = {
name: string;
Expand Down
Loading

0 comments on commit 92eadc3

Please sign in to comment.