Simplify radio CRUD code

This commit is contained in:
Deluan 2023-01-24 20:58:20 -05:00 committed by Deluan Quintão
parent 39161fdf47
commit 5eefb265e5
6 changed files with 59 additions and 241 deletions

View file

@ -174,11 +174,6 @@
"updatedAt": "Updated at", "updatedAt": "Updated at",
"createdAt": "Created at" "createdAt": "Created at"
}, },
"notifications": {
"created": "Radio created",
"updated": "Radio updated",
"deleted": "Radio deleted"
},
"actions": { "actions": {
"playNow": "Play Now" "playNow": "Play Now"
} }
@ -356,8 +351,6 @@
"noPlaylistsAvailable": "None available", "noPlaylistsAvailable": "None available",
"delete_user_title": "Delete user '%{name}'", "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_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_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", "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", "lastfmLinkSuccess": "Last.fm successfully linked and scrobbling enabled",

View file

@ -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 (
<>
<Button
onClick={handleDialogOpen}
label="ra.action.delete"
key="button"
className={clsx('ra-delete-button', classes.deleteButton, className)}
{...rest}
>
<DeleteIcon />
</Button>
<Confirm
isOpen={open}
loading={loading}
title="message.delete_radio_title"
content="message.delete_radio_content"
translateOptions={{
name: record.name,
}}
onConfirm={handleDelete}
onClose={handleDialogClose}
/>
</>
)
}
export default DeleteRadioButton

View file

@ -1,62 +1,41 @@
import React, { useCallback } from 'react'
import { import {
Create, Create,
required, required,
SimpleForm, SimpleForm,
TextInput, TextInput,
useMutation,
useNotify,
useRedirect,
useTranslate, useTranslate,
} from 'react-admin' } from 'react-admin'
import { Title } from '../common' import { Title } from '../common'
import { urlValidate } from '../utils/validations'
const RadioCreate = (props) => { const RadioTitle = () => {
const translate = useTranslate() const translate = useTranslate()
const [mutate] = useMutation() const resourceName = translate('resources.radio.name', {
const notify = useNotify() smart_count: 1,
const redirect = useRedirect() })
const resourceName = translate('resources.radio.name', { smart_count: 1 })
const title = translate('ra.page.create', { const title = translate('ra.page.create', {
name: `${resourceName}`, name: `${resourceName}`,
}) })
return <Title subTitle={title} />
}
const save = useCallback( const RadioCreate = (props) => {
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]
)
return ( return (
<Create title={<Title subTitle={title} />} {...props}> <Create title={<RadioTitle />} {...props}>
<SimpleForm save={save} variant={'outlined'}> <SimpleForm redirect="list" variant={'outlined'}>
<TextInput source="name" validate={[required()]} /> <TextInput source="name" validate={[required()]} />
<TextInput <TextInput
type="url" type="url"
source="streamUrl" source="streamUrl"
fullWidth fullWidth
validate={[required()]} validate={[required(), urlValidate]}
/>
<TextInput
type="url"
source="homepageUrl"
fullWidth
validate={[urlValidate]}
/> />
<TextInput type="url" source="homepageUrl" fullWidth />
</SimpleForm> </SimpleForm>
</Create> </Create>
) )

View file

@ -1,133 +1,43 @@
import { Card, makeStyles } from '@material-ui/core'
import React, { useCallback } from 'react'
import { import {
DateField, DateField,
EditContextProvider, Edit,
required, required,
SaveButton,
SimpleForm, SimpleForm,
TextInput, TextInput,
Toolbar, useTranslate,
useEditController,
useMutation,
useNotify,
useRedirect,
} from 'react-admin' } from 'react-admin'
import DeleteRadioButton from './DeleteRadioButton' import { urlValidate } from '../utils/validations'
import { Title } from '../common'
const useStyles = makeStyles({ const RadioTitle = ({ record }) => {
toolbar: { const translate = useTranslate()
display: 'flex', const resourceName = translate('resources.radio.name', {
justifyContent: 'space-between', smart_count: 1,
}, })
}) return <Title subTitle={`${resourceName} ${record ? record.name : ''}`} />
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 RadioEdit = (props) => { const RadioEdit = (props) => {
const controllerProps = useEditController(props)
return ( return (
<EditContextProvider value={controllerProps}> <Edit title={<RadioTitle />} {...props}>
<RadioEditLayout {...props} record={controllerProps.record} /> <SimpleForm variant="outlined" {...props}>
</EditContextProvider> <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>
) )
} }

View file

@ -23,7 +23,7 @@ const TranscodingTitle = () => {
const TranscodingCreate = (props) => ( const TranscodingCreate = (props) => (
<Create title={<TranscodingTitle />} {...props}> <Create title={<TranscodingTitle />} {...props}>
<SimpleForm variant={'outlined'}> <SimpleForm redirect="list" variant={'outlined'}>
<TextInput source="name" validate={[required()]} /> <TextInput source="name" validate={[required()]} />
<TextInput source="targetFormat" validate={[required()]} /> <TextInput source="targetFormat" validate={[required()]} />
<SelectInput <SelectInput

View file

@ -0,0 +1,12 @@
export const urlValidate = (value) => {
if (!value) {
return undefined
}
try {
new URL(value)
return undefined
} catch (_) {
return 'ra.validation.url'
}
}