diff --git a/ghost/admin-x-settings/src/admin-x-ds/global/FileUpload.stories.tsx b/ghost/admin-x-settings/src/admin-x-ds/global/FileUpload.stories.tsx new file mode 100644 index 0000000000..81e7e34f41 --- /dev/null +++ b/ghost/admin-x-settings/src/admin-x-ds/global/FileUpload.stories.tsx @@ -0,0 +1,16 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import FileUpload from './FileUpload'; + +const meta = { + title: 'Global / Basic File Upload', + component: FileUpload, + tags: ['autodocs'] +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {} +}; diff --git a/ghost/admin-x-settings/src/admin-x-ds/global/FileUpload.tsx b/ghost/admin-x-settings/src/admin-x-ds/global/FileUpload.tsx new file mode 100644 index 0000000000..230f667b58 --- /dev/null +++ b/ghost/admin-x-settings/src/admin-x-ds/global/FileUpload.tsx @@ -0,0 +1,37 @@ +import Button from './Button'; +import React from 'react'; +import {ChangeEvent, useState} from 'react'; + +export interface FileUploadProps { + onUpload: (file: File) => void; +} + +const FileUpload: React.FC = ({onUpload}) => { + const [selectedFile, setSelectedFile] = useState(null); + + const handleFileChange = (event: ChangeEvent) => { + if (event.target.files && event.target.files.length > 0) { + setSelectedFile(event.target.files[0]); + } + }; + + const handleFileUpload = () => { + if (selectedFile) { + onUpload?.(selectedFile); + } + }; + + return ( +
+ +
+ ); +}; + +export default FileUpload; \ No newline at end of file diff --git a/ghost/admin-x-settings/src/utils/api.ts b/ghost/admin-x-settings/src/utils/api.ts index 9db6c8097a..5f4595365a 100644 --- a/ghost/admin-x-settings/src/utils/api.ts +++ b/ghost/admin-x-settings/src/utils/api.ts @@ -29,18 +29,25 @@ export interface RolesResponseType { interface RequestOptions { method?: string; - body?: string; + body?: string | FormData; + headers?: { + 'Content-Type'?: string; + }; } const {apiRoot} = getGhostPaths(); function fetcher(url: string, options: RequestOptions) { const endpoint = `${apiRoot}${url}`; + // By default, we set the Content-Type header to application/json + const headers = options?.headers || { + 'Content-Type': 'application/json' + }; return fetch(endpoint, { headers: { 'app-pragma': 'no-cache', 'x-ghost-version': '5.49', - 'Content-Type': 'application/json' + ...headers }, method: 'GET', mode: 'cors', @@ -107,4 +114,28 @@ const rolesApi = { } }; -export {settingsApi, usersApi, rolesApi}; +const siteApi = { + browse: async () => { + const response = await fetcher(`/site/`, {}); + const data: any = await response.json(); + return data; + } +}; + +const imagesApi = { + upload: async ({file}: {file: File}) => { + const formData = new FormData(); + formData.append('file', file); + formData.append('purpose', 'image'); + + const response = await fetcher(`/images/upload/`, { + method: 'POST', + body: formData, + headers: {} + }); + const data: any = await response.json(); + return data; + } +}; + +export {settingsApi, usersApi, rolesApi, siteApi, imagesApi};