global changes and test
This commit is contained in:
parent
44cdba6b7d
commit
b75f2e3b49
3
public/robots.txt
Normal file
3
public/robots.txt
Normal file
@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
25
src/components/ModalEditor.jsx
Normal file
25
src/components/ModalEditor.jsx
Normal file
@ -0,0 +1,25 @@
|
||||
import { Modal, Text } from '@mantine/core';
|
||||
|
||||
const ModalEditor = ({ title, opened, handlerClose }) => {
|
||||
|
||||
return (
|
||||
<Modal.Root opened={opened} onClose={handlerClose}>
|
||||
<Modal.Overlay />
|
||||
<Modal.Content>
|
||||
<Modal.Header>
|
||||
<Modal.Title>
|
||||
<Text fw={700} fz="lg">
|
||||
{title}
|
||||
</Text>
|
||||
</Modal.Title>
|
||||
<Modal.CloseButton />
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
{content}
|
||||
</Modal.Body>
|
||||
</Modal.Content>
|
||||
</Modal.Root>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModalEditor;
|
@ -1,8 +1,8 @@
|
||||
import { Image } from '@mantine/core';
|
||||
import { isImage } from '../tools/fileUtil';
|
||||
|
||||
const MediaPlayer = ({ file, fileId, shouldContain }) => {
|
||||
const isImage = () => file.type.split('/')[0] === 'image';
|
||||
return isImage() ? (
|
||||
return isImage(file.type) ? (
|
||||
<Image
|
||||
src={'/api/files/' + (fileId ?? file.id)}
|
||||
alt={file?.name ?? ''}
|
||||
|
@ -25,7 +25,6 @@ const ModalAddFile = ({ opened, handler, addFiles }) => {
|
||||
const handleSubmit = () => {
|
||||
setIsLoading(true);
|
||||
const formData = new FormData();
|
||||
const CHUNK_SIZE = 1 * 1024 * 1024; // 1MB chunks
|
||||
|
||||
files.forEach((file) => formData.append(`${file.name}`, file, file.name));
|
||||
|
||||
|
@ -12,6 +12,9 @@ import { Perm, checkPerm } from '../../tools/grant-access';
|
||||
import { useAuth } from '../../tools/auth-provider';
|
||||
import { parseTime } from '../../tools/timeUtil';
|
||||
import MediaPlayer from '../../components/media-player';
|
||||
import { isVideo } from '../../tools/fileUtil';
|
||||
|
||||
const DEFAULT_FILE_TIME = 2;
|
||||
|
||||
const Content = ({ form, playlistId, playlist }) => {
|
||||
const [fileSelector, setFileSelector] = useState(false);
|
||||
@ -36,7 +39,7 @@ const Content = ({ form, playlistId, playlist }) => {
|
||||
max_position++;
|
||||
|
||||
file.position = max_position;
|
||||
file.seconds = 10;
|
||||
file.seconds = DEFAULT_FILE_TIME;
|
||||
const index = form.values.files.length;
|
||||
form.insertListItem('files', file);
|
||||
API.playlists
|
||||
@ -154,10 +157,18 @@ const Content = ({ form, playlistId, playlist }) => {
|
||||
<MediaPlayer file={form.getInputProps(`files.${index}`).value} />
|
||||
<NumberInput
|
||||
required
|
||||
{...(isVideo(form.getInputProps(`files.${index}.type`).value)
|
||||
? {
|
||||
disabled: true,
|
||||
value: 0,
|
||||
description: 'Default to video duration',
|
||||
}
|
||||
: {
|
||||
value: form.getInputProps(`files.${index}.seconds`).value,
|
||||
onChange: (secs) => handleChangeSeconds(secs, index),
|
||||
})}
|
||||
hideControls
|
||||
description="Seconds to display"
|
||||
value={form.getInputProps(`files.${index}.seconds`).value}
|
||||
onChange={(secs) => handleChangeSeconds(secs, index)}
|
||||
label="Seconds to display"
|
||||
error={
|
||||
form.getInputProps(`files.${index}.seconds`).errors && 'This field is required'
|
||||
}
|
||||
|
38
src/pages/roles/create.jsx
Normal file
38
src/pages/roles/create.jsx
Normal file
@ -0,0 +1,38 @@
|
||||
import { Modal, Text } from '@mantine/core';
|
||||
import API from '../../services/api';
|
||||
import RoleViewEditor from './role-view-editor';
|
||||
|
||||
const ModalCreateRole = ({ opened, handler, addRole, item }) => {
|
||||
const validate = (role) => {
|
||||
if (role) {
|
||||
addRole(role);
|
||||
}
|
||||
handler();
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal.Root opened={opened} onClose={handler}>
|
||||
<Modal.Overlay />
|
||||
<Modal.Content>
|
||||
<Modal.Header>
|
||||
<Modal.Title>
|
||||
<Text fw={700} fz="lg">
|
||||
Create Role
|
||||
</Text>
|
||||
</Modal.Title>
|
||||
<Modal.CloseButton />
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<RoleViewEditor
|
||||
buttonText="Create"
|
||||
item={item}
|
||||
APICall={API.roles.create}
|
||||
handler={(role) => validate(role)}
|
||||
/>
|
||||
</Modal.Body>
|
||||
</Modal.Content>
|
||||
</Modal.Root>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModalCreateRole;
|
82
src/pages/roles/role-selector.jsx
Normal file
82
src/pages/roles/role-selector.jsx
Normal file
@ -0,0 +1,82 @@
|
||||
import { MultiSelect } from '@mantine/core';
|
||||
import { useEffect, useState } from 'react';
|
||||
import setNotification from '../errors/error-notification';
|
||||
import API from '../../services/api';
|
||||
import { Perm, checkPerm } from '../../tools/grant-access';
|
||||
import { useAuth } from '../../tools/auth-provider';
|
||||
import ModalCreateRole from './create';
|
||||
|
||||
const RoleSelector = ({ defaultRoles, label, value, setValue }) => {
|
||||
const [data, setData] = useState([]);
|
||||
const [search, setSearch] = useState();
|
||||
const [showCreateRole, setShowCreateRole] = useState(false);
|
||||
const toggleCreateRole = () => setShowCreateRole(!showCreateRole);
|
||||
const [query, setQuery] = useState('');
|
||||
|
||||
const { user } = useAuth();
|
||||
const canCreateRole = checkPerm(Perm.CREATE_ROLE, user);
|
||||
|
||||
const addRoles = (roles) => {
|
||||
if (!roles) return;
|
||||
for (let i = 0; i < roles.length; i++) {
|
||||
const role = roles[i];
|
||||
if (!data.find((r) => r.id === role.id)) {
|
||||
role.label = role.name;
|
||||
role.value = role.id.toString();
|
||||
setData((prev) => [...prev, role]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
API.roles
|
||||
.search(search)
|
||||
.then((res) => {
|
||||
if (res.status === 200) {
|
||||
addRoles(res.data);
|
||||
} else {
|
||||
setNotification(true, res);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
setNotification(true, err);
|
||||
});
|
||||
// eslint-disable-next-line
|
||||
}, [search]);
|
||||
|
||||
useEffect(() => {
|
||||
addRoles(defaultRoles);
|
||||
// eslint-disable-next-line
|
||||
}, [defaultRoles]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<MultiSelect
|
||||
label={label}
|
||||
data={data}
|
||||
searchable
|
||||
searchValue={search}
|
||||
onSearchChange={setSearch}
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
maxDropdownHeight={160}
|
||||
creatable={canCreateRole}
|
||||
getCreateLabel={(query) => `+ Create ${query}`}
|
||||
onCreate={(query) => {
|
||||
setQuery(query);
|
||||
setShowCreateRole(true);
|
||||
}}
|
||||
/>
|
||||
{canCreateRole && (
|
||||
<ModalCreateRole
|
||||
opened={showCreateRole}
|
||||
item={{ name: query }}
|
||||
addRole={(role) => addRoles([role])}
|
||||
handler={toggleCreateRole}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default RoleSelector;
|
64
src/pages/roles/role-view-editor.jsx
Normal file
64
src/pages/roles/role-view-editor.jsx
Normal file
@ -0,0 +1,64 @@
|
||||
import { Button, TextInput, Group, Stack } from '@mantine/core';
|
||||
import { useForm, isNotEmpty } from '@mantine/form';
|
||||
import { useEffect, useState } from 'react';
|
||||
import setNotification from '../errors/error-notification';
|
||||
|
||||
const RoleViewEditor = ({ item, handler, buttonText, APICall }) => {
|
||||
const handleClose = (role) => {
|
||||
form.reset();
|
||||
handler(role);
|
||||
};
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const form = useForm({
|
||||
initialValues: {
|
||||
name: item?.name ?? '',
|
||||
},
|
||||
validate: {
|
||||
name: isNotEmpty('Name is required'),
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldValue('name', item?.name);
|
||||
return () => {};
|
||||
}, [item]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
if (form.validate().hasErrors) return;
|
||||
try {
|
||||
setIsLoading(true);
|
||||
if (item?.id) {
|
||||
const res = await APICall(item?.id, { name: form.values.name });
|
||||
handleClose(res.data);
|
||||
} else {
|
||||
const res = await APICall({ name: form.values.name });
|
||||
handleClose(res.data);
|
||||
}
|
||||
setIsLoading(false);
|
||||
} catch (err) {
|
||||
setIsLoading(false);
|
||||
setNotification(true, err);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextInput label="Name" placeholder="Name" withAsterisk {...form.getInputProps('name')} mb="sm" />
|
||||
todo parent id
|
||||
users
|
||||
<Group position="right" mt="md">
|
||||
<Button variant="light" color="red" onClick={() => handler()}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit" variant="light" color="green" loading={isLoading}>
|
||||
{buttonText}
|
||||
</Button>
|
||||
</Group>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default RoleViewEditor;
|
10
src/tools/fileUtil.js
Normal file
10
src/tools/fileUtil.js
Normal file
@ -0,0 +1,10 @@
|
||||
export const isImage = (type) => {
|
||||
if (!type) return false;
|
||||
return type.split('/')[0] === 'image';
|
||||
};
|
||||
|
||||
export const isVideo = (type) => {
|
||||
if (!type) return false;
|
||||
return type.split('/')[0] === 'video';
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user