diff --git a/src/actions/admin.ts b/src/actions/admin.ts index 9923674d3..2383aec95 100644 --- a/src/actions/admin.ts +++ b/src/actions/admin.ts @@ -1,13 +1,10 @@ import { fetchRelationships } from 'soapbox/actions/accounts.ts'; import { importFetchedAccount, importFetchedAccounts, importFetchedStatuses } from 'soapbox/actions/importer/index.ts'; -import { DittoInstanceCredentials } from 'soapbox/features/admin/manage-ditto-server.tsx'; import { accountIdsToAccts } from 'soapbox/selectors/index.ts'; import { filterBadges, getTagDiff } from 'soapbox/utils/badges.ts'; import api, { getLinks } from '../api/index.ts'; -import { fetchInstance } from './instance.ts'; - import type { AxiosResponse } from 'axios'; import type { AppDispatch, RootState } from 'soapbox/store.ts'; import type { APIEntity } from 'soapbox/types/entities.ts'; @@ -109,13 +106,6 @@ const updateSoapboxConfig = (data: Record) => return dispatch(updateConfig(params)); }; -function putDittoInstance(data: DittoInstanceCredentials) { - return async (dispatch: AppDispatch, getState: () => RootState) => { - await api(getState).put('/api/v1/admin/ditto/instance', data); - await dispatch(fetchInstance()); - }; -} - function fetchReports(params: Record = {}) { return async (dispatch: AppDispatch, getState: () => RootState): Promise => { dispatch({ type: ADMIN_REPORTS_FETCH_REQUEST, params }); @@ -452,5 +442,4 @@ export { promoteToModerator, demoteToUser, setRole, - putDittoInstance, }; diff --git a/src/features/admin/hooks/useManageDittoServer.ts b/src/features/admin/hooks/useManageDittoServer.ts new file mode 100644 index 000000000..75f6d50aa --- /dev/null +++ b/src/features/admin/hooks/useManageDittoServer.ts @@ -0,0 +1,44 @@ +import { useMutation, useQuery } from '@tanstack/react-query'; + +import { DittoInstanceCredentials } from 'soapbox/features/admin/manage-ditto-server.tsx'; +import { useApi } from 'soapbox/hooks/useApi.ts'; +import { queryClient } from 'soapbox/queries/client.ts'; +import { instanceV2Schema } from 'soapbox/schemas/instance.ts'; + +function useManageDittoServer() { + const api = useApi(); + + const getDittoInstance = async () => { + const response = await api.get('/api/v2/instance'); + const data: DittoInstanceCredentials = await response.json(); + + const instance = instanceV2Schema.parse(data); + return { + title: instance.title, + description: instance.description, + short_description: instance.short_description, + screenshots: instance.screenshots, + thumbnail: instance.thumbnail, + }; + }; + + const result = useQuery>({ + queryKey: ['DittoInstance'], + queryFn: getDittoInstance, + }); + + + const { mutate: updateDittoInstance } = useMutation({ + mutationFn: (data: DittoInstanceCredentials) => api.put('/api/v1/admin/ditto/instance', data), + onSuccess: () => { + queryClient.refetchQueries({ queryKey: ['DittoInstance'] }); + }, + }); + + return { + ...result, + updateDittoInstance, + }; +} + +export { useManageDittoServer }; \ No newline at end of file diff --git a/src/features/admin/manage-ditto-server.tsx b/src/features/admin/manage-ditto-server.tsx index ce7c88858..6e457108f 100644 --- a/src/features/admin/manage-ditto-server.tsx +++ b/src/features/admin/manage-ditto-server.tsx @@ -1,8 +1,7 @@ import { AxiosError } from 'axios'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; -import { putDittoInstance } from 'soapbox/actions/admin.ts'; import { uploadMedia } from 'soapbox/actions/media.ts'; import StillImage from 'soapbox/components/still-image.tsx'; import { Button } from 'soapbox/components/ui/button.tsx'; @@ -15,8 +14,8 @@ import Input from 'soapbox/components/ui/input.tsx'; import Spinner from 'soapbox/components/ui/spinner.tsx'; import Stack from 'soapbox/components/ui/stack.tsx'; import Streamfield from 'soapbox/components/ui/streamfield.tsx'; +import { useManageDittoServer } from 'soapbox/features/admin/hooks/useManageDittoServer.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; -import { useInstance } from 'soapbox/hooks/useInstance.ts'; import { normalizeAttachment } from 'soapbox/normalizers/index.ts'; import { thumbnailSchema } from 'soapbox/schemas/instance.ts'; import { Screenshots } from 'soapbox/schemas/manifest.ts'; @@ -63,30 +62,40 @@ export interface DittoInstanceCredentials { const ManageDittoServer: React.FC = () => { const intl = useIntl(); const dispatch = useAppDispatch(); - const { instance } = useInstance(); + const { updateDittoInstance, data: dittoInstanceData } = useManageDittoServer(); const [data, setData] = useState({ - title: instance.title, - description: instance.description, - short_description: instance.short_description, - screenshots: instance.screenshots, - thumbnail: instance.thumbnail, + title: dittoInstanceData?.title ?? '', + description: dittoInstanceData?.description ?? '', + short_description: dittoInstanceData?.short_description ?? '', + screenshots: dittoInstanceData?.screenshots ?? [], + thumbnail: dittoInstanceData?.thumbnail ?? { url: '', versions: {} }, }); const [isThumbnailLoading, setThumbnailLoading] = useState(false); + useEffect(() => { + if (dittoInstanceData) { + setData({ + title: dittoInstanceData.title, + description: dittoInstanceData.description, + short_description: dittoInstanceData.short_description, + screenshots: dittoInstanceData.screenshots, + thumbnail: dittoInstanceData.thumbnail, + }); + } + }, [dittoInstanceData]); + const handleSubmit: React.FormEventHandler = async (event) => { event.preventDefault(); - try { - await dispatch(putDittoInstance(data)); - toast.success(messages.submit_success); - } catch (err) { - if (err instanceof AxiosError) { - toast.error(err.response?.data?.error || 'An error occurred'); - return; - } - toast.error((err as Error)?.message || 'An error occurred'); - } + updateDittoInstance(data, { + onSuccess: async () => { + toast.success(messages.submit_success); + }, + onError: async (err) => { + toast.error(err.message); // generic error message, not the one returned by the backend + }, + }); }; /** Set a single key in the request data. */