From 5eefb265e50419c3db7f2bfe828b195e3440432e Mon Sep 17 00:00:00 2001 From: Deluan Date: Tue, 24 Jan 2023 20:58:20 -0500 Subject: [PATCH] Simplify radio CRUD code --- ui/src/i18n/en.json | 7 -- ui/src/radio/DeleteRadioButton.js | 76 ------------ ui/src/radio/RadioCreate.js | 55 +++------ ui/src/radio/RadioEdit.js | 148 +++++------------------- ui/src/transcoding/TranscodingCreate.js | 2 +- ui/src/utils/validations.js | 12 ++ 6 files changed, 59 insertions(+), 241 deletions(-) delete mode 100644 ui/src/radio/DeleteRadioButton.js create mode 100644 ui/src/utils/validations.js diff --git a/ui/src/i18n/en.json b/ui/src/i18n/en.json index 74d344376..a57cc81b5 100644 --- a/ui/src/i18n/en.json +++ b/ui/src/i18n/en.json @@ -174,11 +174,6 @@ "updatedAt": "Updated at", "createdAt": "Created at" }, - "notifications": { - "created": "Radio created", - "updated": "Radio updated", - "deleted": "Radio deleted" - }, "actions": { "playNow": "Play Now" } @@ -356,8 +351,6 @@ "noPlaylistsAvailable": "None available", "delete_user_title": "Delete user '%{name}'", "delete_user_content": "Are you sure you want to delete this user and all their data (including playlists and preferences)?", - "delete_radio_title": "Delete radio '%{name}'", - "delete_radio_content": "Are you sure you want to remove this radio?", "notifications_blocked": "You have blocked Notifications for this site in your browser's settings", "notifications_not_available": "This browser does not support desktop notifications or you are not accessing Navidrome over https", "lastfmLinkSuccess": "Last.fm successfully linked and scrobbling enabled", diff --git a/ui/src/radio/DeleteRadioButton.js b/ui/src/radio/DeleteRadioButton.js deleted file mode 100644 index 75257a584..000000000 --- a/ui/src/radio/DeleteRadioButton.js +++ /dev/null @@ -1,76 +0,0 @@ -import { fade, makeStyles } from '@material-ui/core' -import DeleteIcon from '@material-ui/icons/Delete' -import clsx from 'clsx' -import React from 'react' -import { - Button, - Confirm, - useDeleteWithConfirmController, - useNotify, - useRedirect, -} from 'react-admin' - -const useStyles = makeStyles( - (theme) => ({ - deleteButton: { - color: theme.palette.error.main, - '&:hover': { - backgroundColor: fade(theme.palette.error.main, 0.12), - // Reset on mouse devices - '@media (hover: none)': { - backgroundColor: 'transparent', - }, - }, - }, - }), - { name: 'RaDeleteWithConfirmButton' } -) - -const DeleteRadioButton = (props) => { - const { resource, record, basePath, className, onClick, ...rest } = props - - const notify = useNotify() - const redirect = useRedirect() - - const onSuccess = () => { - notify('resources.radio.notifications.deleted') - redirect('/radio') - } - - const { open, loading, handleDialogOpen, handleDialogClose, handleDelete } = - useDeleteWithConfirmController({ - resource, - record, - basePath, - onClick, - onSuccess, - }) - - const classes = useStyles(props) - return ( - <> - - - - ) -} - -export default DeleteRadioButton diff --git a/ui/src/radio/RadioCreate.js b/ui/src/radio/RadioCreate.js index 2d1bfe0a5..bbd4b4aaa 100644 --- a/ui/src/radio/RadioCreate.js +++ b/ui/src/radio/RadioCreate.js @@ -1,62 +1,41 @@ -import React, { useCallback } from 'react' import { Create, required, SimpleForm, TextInput, - useMutation, - useNotify, - useRedirect, useTranslate, } from 'react-admin' import { Title } from '../common' +import { urlValidate } from '../utils/validations' -const RadioCreate = (props) => { +const RadioTitle = () => { const translate = useTranslate() - const [mutate] = useMutation() - const notify = useNotify() - const redirect = useRedirect() - - const resourceName = translate('resources.radio.name', { smart_count: 1 }) + const resourceName = translate('resources.radio.name', { + smart_count: 1, + }) const title = translate('ra.page.create', { name: `${resourceName}`, }) + return +} - const save = useCallback( - async (values) => { - try { - await mutate( - { - type: 'create', - resource: 'radio', - payload: { data: values }, - }, - { returnPromise: true } - ) - notify('resources.radio.notifications.created', 'info', { - smart_count: 1, - }) - redirect('/radio') - } catch (error) { - if (error.body.errors) { - return error.body.errors - } - } - }, - [mutate, notify, redirect] - ) - +const RadioCreate = (props) => { return ( - <Create title={<Title subTitle={title} />} {...props}> - <SimpleForm save={save} variant={'outlined'}> + <Create title={<RadioTitle />} {...props}> + <SimpleForm redirect="list" variant={'outlined'}> <TextInput source="name" validate={[required()]} /> <TextInput type="url" source="streamUrl" fullWidth - validate={[required()]} + validate={[required(), urlValidate]} + /> + <TextInput + type="url" + source="homepageUrl" + fullWidth + validate={[urlValidate]} /> - <TextInput type="url" source="homepageUrl" fullWidth /> </SimpleForm> </Create> ) diff --git a/ui/src/radio/RadioEdit.js b/ui/src/radio/RadioEdit.js index 6e9e87145..f00f889f3 100644 --- a/ui/src/radio/RadioEdit.js +++ b/ui/src/radio/RadioEdit.js @@ -1,133 +1,43 @@ -import { Card, makeStyles } from '@material-ui/core' -import React, { useCallback } from 'react' import { DateField, - EditContextProvider, + Edit, required, - SaveButton, SimpleForm, TextInput, - Toolbar, - useEditController, - useMutation, - useNotify, - useRedirect, + useTranslate, } from 'react-admin' -import DeleteRadioButton from './DeleteRadioButton' +import { urlValidate } from '../utils/validations' +import { Title } from '../common' -const useStyles = makeStyles({ - toolbar: { - display: 'flex', - justifyContent: 'space-between', - }, -}) - -function urlValidate(value) { - if (!value) { - return undefined - } - - try { - new URL(value) - return undefined - } catch (_) { - return 'ra.validation.url' - } -} - -const RadioToolbar = (props) => ( - <Toolbar {...props} classes={useStyles()}> - <SaveButton disabled={props.pristine} /> - <DeleteRadioButton /> - </Toolbar> -) - -const RadioEditLayout = ({ - hasCreate, - hasShow, - hasEdit, - hasList, - ...props -}) => { - const [mutate] = useMutation() - const notify = useNotify() - const redirect = useRedirect() - - const { record } = props - - const save = useCallback( - async (values) => { - try { - await mutate( - { - type: 'update', - resource: 'radio', - payload: { - id: values.id, - data: { - name: values.name, - streamUrl: values.streamUrl, - homePageUrl: values.homePageUrl, - }, - }, - }, - { returnPromise: true } - ) - notify('resources.radio.notifications.updated', 'info', { - smart_count: 1, - }) - redirect('/radio') - } catch (error) { - if (error.body.errors) { - return error.body.errors - } - } - }, - [mutate, notify, redirect] - ) - - if (!record) { - return null - } - - return ( - <> - {record && ( - <Card> - <SimpleForm - variant="outlined" - save={save} - toolbar={<RadioToolbar />} - {...props} - > - <TextInput source="name" validate={[required()]} /> - <TextInput - type="url" - source="streamUrl" - fullWidth - validate={[required(), urlValidate]} - /> - <TextInput - type="url" - source="homePageUrl" - fullWidth - validate={[urlValidate]} - /> - <DateField variant="body1" source="updatedAt" showTime /> - <DateField variant="body1" source="createdAt" showTime /> - </SimpleForm> - </Card> - )} - </> - ) +const RadioTitle = ({ record }) => { + const translate = useTranslate() + const resourceName = translate('resources.radio.name', { + smart_count: 1, + }) + return <Title subTitle={`${resourceName} ${record ? record.name : ''}`} /> } const RadioEdit = (props) => { - const controllerProps = useEditController(props) return ( - <EditContextProvider value={controllerProps}> - <RadioEditLayout {...props} record={controllerProps.record} /> - </EditContextProvider> + <Edit title={<RadioTitle />} {...props}> + <SimpleForm variant="outlined" {...props}> + <TextInput source="name" validate={[required()]} /> + <TextInput + type="url" + source="streamUrl" + fullWidth + validate={[required(), urlValidate]} + /> + <TextInput + type="url" + source="homePageUrl" + fullWidth + validate={[urlValidate]} + /> + <DateField variant="body1" source="updatedAt" showTime /> + <DateField variant="body1" source="createdAt" showTime /> + </SimpleForm> + </Edit> ) } diff --git a/ui/src/transcoding/TranscodingCreate.js b/ui/src/transcoding/TranscodingCreate.js index aebe422fa..aaf122665 100644 --- a/ui/src/transcoding/TranscodingCreate.js +++ b/ui/src/transcoding/TranscodingCreate.js @@ -23,7 +23,7 @@ const TranscodingTitle = () => { const TranscodingCreate = (props) => ( <Create title={<TranscodingTitle />} {...props}> - <SimpleForm variant={'outlined'}> + <SimpleForm redirect="list" variant={'outlined'}> <TextInput source="name" validate={[required()]} /> <TextInput source="targetFormat" validate={[required()]} /> <SelectInput diff --git a/ui/src/utils/validations.js b/ui/src/utils/validations.js new file mode 100644 index 000000000..8b163c156 --- /dev/null +++ b/ui/src/utils/validations.js @@ -0,0 +1,12 @@ +export const urlValidate = (value) => { + if (!value) { + return undefined + } + + try { + new URL(value) + return undefined + } catch (_) { + return 'ra.validation.url' + } +}