mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-06 22:40:14 -05:00
Added new provider to manage settings for admin-x
refs https://github.com/TryGhost/Team/issues/3151 - adds new settings provider that fetches settings for a site and allows saving them - adds new helpers for making admin api calls and fetching setting values
This commit is contained in:
parent
cfbcd6fc1a
commit
5b0eba9b1f
5 changed files with 172 additions and 3 deletions
|
@ -1,6 +1,7 @@
|
||||||
import Heading from './admin-x-ds/global/Heading';
|
import Heading from './admin-x-ds/global/Heading';
|
||||||
import Settings from './components/Settings';
|
import Settings from './components/Settings';
|
||||||
import Sidebar from './components/Sidebar';
|
import Sidebar from './components/Sidebar';
|
||||||
|
import {SettingsProvider} from './components/SettingsProvider';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
|
@ -22,7 +23,9 @@ function App() {
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-auto pt-[3vmin] md:pt-[72px]">
|
<div className="flex-auto pt-[3vmin] md:pt-[72px]">
|
||||||
<Settings />
|
<SettingsProvider>
|
||||||
|
<Settings />
|
||||||
|
</SettingsProvider>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,8 +1,20 @@
|
||||||
import React from 'react';
|
import React, {useContext} from 'react';
|
||||||
|
|
||||||
import GeneralSettings from './settings/general/GeneralSettings';
|
import GeneralSettings from './settings/general/GeneralSettings';
|
||||||
|
import {SettingsContext} from './SettingsProvider';
|
||||||
|
|
||||||
const Settings: React.FC = () => {
|
const Settings: React.FC = () => {
|
||||||
|
const {settings} = useContext(SettingsContext) || {};
|
||||||
|
|
||||||
|
// Show loader while settings is first fetched
|
||||||
|
if (!settings) {
|
||||||
|
return (
|
||||||
|
<div className="flex h-full flex-col items-center justify-center">
|
||||||
|
<div className="text-center text-2xl font-bold">Loading...</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<GeneralSettings />
|
<GeneralSettings />
|
||||||
|
@ -10,4 +22,4 @@ const Settings: React.FC = () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Settings;
|
export default Settings;
|
||||||
|
|
62
ghost/admin-x-settings/src/components/SettingsProvider.tsx
Normal file
62
ghost/admin-x-settings/src/components/SettingsProvider.tsx
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
import React, {createContext, useEffect, useState} from 'react';
|
||||||
|
import {getSettings, updateSettings} from '../utils/api';
|
||||||
|
|
||||||
|
// Define the Setting type
|
||||||
|
export interface ISetting {
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the Settings Context
|
||||||
|
interface SettingsContextProps {
|
||||||
|
settings: ISetting[] | null;
|
||||||
|
saveSettings: (updatedSettings: ISetting[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SettingsProviderProps {
|
||||||
|
children?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SettingsContext = createContext < SettingsContextProps | undefined > (undefined);
|
||||||
|
|
||||||
|
// Create a Settings Provider component
|
||||||
|
const SettingsProvider: React.FC<SettingsProviderProps> = ({children}) => {
|
||||||
|
const [settings, setSettings] = useState <ISetting[] | null> (null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchSettings = async (): Promise<void> => {
|
||||||
|
try {
|
||||||
|
// Make an API call to fetch the settings
|
||||||
|
const data = await getSettings();
|
||||||
|
setSettings(data.settings);
|
||||||
|
} catch (error) {
|
||||||
|
// Log error in settings API
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch the initial settings from the API
|
||||||
|
fetchSettings();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const saveSettings = async (updatedSettings: ISetting[]): Promise<void> => {
|
||||||
|
try {
|
||||||
|
// Make an API call to save the updated settings
|
||||||
|
const data = await updateSettings(updatedSettings);
|
||||||
|
|
||||||
|
// Update the local state with the new settings
|
||||||
|
setSettings(data.settings);
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Error', error);
|
||||||
|
// Log error in settings API
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Provide the settings and the saveSettings function to the children components
|
||||||
|
return (
|
||||||
|
<SettingsContext.Provider value={{settings, saveSettings}}>
|
||||||
|
{children}
|
||||||
|
</SettingsContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export {SettingsContext, SettingsProvider};
|
61
ghost/admin-x-settings/src/utils/api.tsx
Normal file
61
ghost/admin-x-settings/src/utils/api.tsx
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import {getGhostPaths} from './helpers';
|
||||||
|
|
||||||
|
interface IQueryParams {
|
||||||
|
group: string;
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the Setting type
|
||||||
|
export interface ISetting {
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the SettingsResponse type
|
||||||
|
export interface ISettingsResponse {
|
||||||
|
meta: any;
|
||||||
|
settings: ISetting[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSettings() {
|
||||||
|
const {apiRoot} = getGhostPaths();
|
||||||
|
const queryParams: IQueryParams = {group: 'site,theme,private,members,portal,newsletter,email,amp,labs,slack,unsplash,views,firstpromoter,editor,comments,analytics,announcement,pintura'};
|
||||||
|
const queryString = Object.keys(queryParams).map((key) => {
|
||||||
|
return `${key}=${queryParams[key] || ''}`;
|
||||||
|
}).join('&');
|
||||||
|
|
||||||
|
const response = await fetch(`${apiRoot}/settings/?${queryString}`, {
|
||||||
|
headers: {
|
||||||
|
'app-pragma': 'no-cache',
|
||||||
|
'x-ghost-version': '5.47'
|
||||||
|
},
|
||||||
|
method: 'GET',
|
||||||
|
mode: 'cors',
|
||||||
|
credentials: 'include'
|
||||||
|
});
|
||||||
|
const data: ISettingsResponse = await response.json();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateSettings(newSettings: ISetting[]) {
|
||||||
|
const {apiRoot} = getGhostPaths();
|
||||||
|
|
||||||
|
const payload = JSON.stringify({
|
||||||
|
settings: newSettings
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await fetch(`${apiRoot}/settings/`, {
|
||||||
|
headers: {
|
||||||
|
'app-pragma': 'no-cache',
|
||||||
|
'x-ghost-version': '5.47',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: payload,
|
||||||
|
method: 'PUT',
|
||||||
|
mode: 'cors',
|
||||||
|
credentials: 'include'
|
||||||
|
});
|
||||||
|
|
||||||
|
const data: ISettingsResponse = await response.json();
|
||||||
|
return data;
|
||||||
|
}
|
31
ghost/admin-x-settings/src/utils/helpers.tsx
Normal file
31
ghost/admin-x-settings/src/utils/helpers.tsx
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import {ISetting} from '../components/SettingsProvider';
|
||||||
|
|
||||||
|
export interface IGhostPaths {
|
||||||
|
adminRoot: string;
|
||||||
|
assetRoot: string;
|
||||||
|
apiRoot: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSettingValue(settings: ISetting[] | null | undefined, key: string): string {
|
||||||
|
if (!settings) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const setting = settings.find(d => d.key === key);
|
||||||
|
return setting ? setting.value : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getGhostPaths(): IGhostPaths {
|
||||||
|
let path = window.location.pathname;
|
||||||
|
let subdir = path.substr(0, path.search('/ghost/'));
|
||||||
|
let adminRoot = `${subdir}/ghost/`;
|
||||||
|
let assetRoot = `${subdir}/ghost/assets/`;
|
||||||
|
let apiRoot = `${subdir}/ghost/api/admin`;
|
||||||
|
return {adminRoot, assetRoot, apiRoot};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLocalTime({timeZone}) {
|
||||||
|
const date = new Date();
|
||||||
|
const options = {timeZone: timeZone, hour12: false, hour: 'numeric', minute: 'numeric', second: 'numeric'};
|
||||||
|
const localTime = date.toLocaleString('en-US', options);
|
||||||
|
return localTime;
|
||||||
|
}
|
Loading…
Reference in a new issue