Application adding bugfix; consolidated Settings headers
This commit is contained in:
25
package-lock.json
generated
25
package-lock.json
generated
@@ -12,7 +12,6 @@
|
|||||||
"@iconify/react": "^5.2.0",
|
"@iconify/react": "^5.2.0",
|
||||||
"@mantine/core": "^7.17.3",
|
"@mantine/core": "^7.17.3",
|
||||||
"@mantine/hooks": "^7.17.3",
|
"@mantine/hooks": "^7.17.3",
|
||||||
"@tabler/icons-react": "^3.31.0",
|
|
||||||
"@tanstack/react-query": "^5.69.3",
|
"@tanstack/react-query": "^5.69.3",
|
||||||
"@tanstack/react-query-devtools": "^5.69.3",
|
"@tanstack/react-query-devtools": "^5.69.3",
|
||||||
"@tanstack/react-query-persist-client": "^5.69.3",
|
"@tanstack/react-query-persist-client": "^5.69.3",
|
||||||
@@ -1588,30 +1587,6 @@
|
|||||||
"sprintf-js": "~1.0.2"
|
"sprintf-js": "~1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tabler/icons": {
|
|
||||||
"version": "3.31.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.31.0.tgz",
|
|
||||||
"integrity": "sha512-dblAdeKY3+GA1U+Q9eziZ0ooVlZMHsE8dqP0RkwvRtEsAULoKOYaCUOcJ4oW1DjWegdxk++UAt2SlQVnmeHv+g==",
|
|
||||||
"funding": {
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/codecalm"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@tabler/icons-react": {
|
|
||||||
"version": "3.31.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.31.0.tgz",
|
|
||||||
"integrity": "sha512-2rrCM5y/VnaVKnORpDdAua9SEGuJKVqPtWxeQ/vUVsgaUx30LDgBZph7/lterXxDY1IKR6NO//HDhWiifXTi3w==",
|
|
||||||
"dependencies": {
|
|
||||||
"@tabler/icons": "3.31.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/codecalm"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": ">= 16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@tanstack/query-core": {
|
"node_modules/@tanstack/query-core": {
|
||||||
"version": "5.69.2",
|
"version": "5.69.2",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.69.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.69.2.tgz",
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
"@iconify/react": "^5.2.0",
|
"@iconify/react": "^5.2.0",
|
||||||
"@mantine/core": "^7.17.3",
|
"@mantine/core": "^7.17.3",
|
||||||
"@mantine/hooks": "^7.17.3",
|
"@mantine/hooks": "^7.17.3",
|
||||||
"@tabler/icons-react": "^3.31.0",
|
|
||||||
"@tanstack/react-query": "^5.69.3",
|
"@tanstack/react-query": "^5.69.3",
|
||||||
"@tanstack/react-query-devtools": "^5.69.3",
|
"@tanstack/react-query-devtools": "^5.69.3",
|
||||||
"@tanstack/react-query-persist-client": "^5.69.3",
|
"@tanstack/react-query-persist-client": "^5.69.3",
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
Grid,
|
Grid,
|
||||||
GridCol,
|
GridCol,
|
||||||
Group,
|
Group,
|
||||||
Modal,
|
|
||||||
Popover,
|
Popover,
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
@@ -16,21 +15,15 @@ import {
|
|||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { cardClasses, modalClasses, textInputClasses } from 'styles';
|
import { textInputClasses } from 'styles';
|
||||||
import type { Application } from 'types';
|
import type { Application } from 'types';
|
||||||
|
import AddItemModal from '../Shared/AddItemModal';
|
||||||
import SettingsHeader from '../Shared/SettingsHeader';
|
import SettingsHeader from '../Shared/SettingsHeader';
|
||||||
import AppSettingsItem from './AppSettingsItem';
|
import AppSettingsItem from './AppSettingsItem';
|
||||||
import DebouncedApplication from './DebouncedApplication';
|
import DebouncedApplication from './DebouncedApplication';
|
||||||
|
|
||||||
const ApplicationSettings = () => {
|
const ApplicationSettings = () => {
|
||||||
const endpoint = 'api/apps';
|
const defaultApplication: Application = {
|
||||||
const { data: apps, isFetching: isAppsFetching } = useQueryAPI({
|
|
||||||
endpoint: endpoint,
|
|
||||||
});
|
|
||||||
const [applicationData, setApplicationData] = useState<Application[]>([]);
|
|
||||||
const [applicationList, setApplicationList] = useState<Application[]>([]);
|
|
||||||
const { theme, isMobile, modalStyle } = useCommonHooks();
|
|
||||||
const [newApplication, setNewApplication] = useState<Application>({
|
|
||||||
id: null,
|
id: null,
|
||||||
name: '',
|
name: '',
|
||||||
url: '',
|
url: '',
|
||||||
@@ -39,7 +32,16 @@ const ApplicationSettings = () => {
|
|||||||
filterName: '',
|
filterName: '',
|
||||||
index: 0,
|
index: 0,
|
||||||
enabled: 1,
|
enabled: 1,
|
||||||
|
};
|
||||||
|
const appsEndpoint = 'api/apps';
|
||||||
|
const appsOrderEndpoint = 'api/appsOrder';
|
||||||
|
const { data: apps, isFetching: isAppsFetching } = useQueryAPI({
|
||||||
|
endpoint: appsEndpoint,
|
||||||
});
|
});
|
||||||
|
const [applicationData, setApplicationData] = useState<Application[]>([]);
|
||||||
|
const [applicationList, setApplicationList] = useState<Application[]>([]);
|
||||||
|
const { theme, isMobile } = useCommonHooks();
|
||||||
|
const [newApplication, setNewApplication] = useState<Application>(defaultApplication);
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
||||||
@@ -74,6 +76,11 @@ const ApplicationSettings = () => {
|
|||||||
|
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
closeModal();
|
||||||
|
setNewApplication(defaultApplication);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (apps && !isAppsFetching) {
|
if (apps && !isAppsFetching) {
|
||||||
setApplicationData(
|
setApplicationData(
|
||||||
@@ -90,7 +97,7 @@ const ApplicationSettings = () => {
|
|||||||
if (applicationList.length > 0 && applicationList !== applicationData) {
|
if (applicationList.length > 0 && applicationList !== applicationData) {
|
||||||
mutateAsync({
|
mutateAsync({
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
endpoint: 'api/applicationOrder',
|
endpoint: appsOrderEndpoint,
|
||||||
body: applicationList,
|
body: applicationList,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -98,27 +105,11 @@ const ApplicationSettings = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack w={'100%'}>
|
<Stack w={'100%'}>
|
||||||
<Modal.Root
|
<AddItemModal
|
||||||
size={'60%'}
|
modalOpened={modalOpened}
|
||||||
className={modalClasses.helpModal}
|
handleClose={handleClose}
|
||||||
classNames={modalClasses}
|
title={'Add a new application'}
|
||||||
opened={modalOpened}
|
body={
|
||||||
fullScreen={isMobile}
|
|
||||||
onClose={() => {
|
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
style={modalStyle}
|
|
||||||
closeOnEscape
|
|
||||||
closeOnClickOutside
|
|
||||||
>
|
|
||||||
<Modal.Overlay />
|
|
||||||
<Modal.Content>
|
|
||||||
<Modal.Header>
|
|
||||||
<Modal.Title>Add a new application</Modal.Title>
|
|
||||||
<Modal.CloseButton />
|
|
||||||
</Modal.Header>
|
|
||||||
<Modal.Body pb={'2rem'}>
|
|
||||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
|
||||||
<Stack gap={0} align='center'>
|
<Stack gap={0} align='center'>
|
||||||
<Group justify='center'>
|
<Group justify='center'>
|
||||||
<TextInput
|
<TextInput
|
||||||
@@ -202,10 +193,12 @@ const ApplicationSettings = () => {
|
|||||||
if (newApplication) {
|
if (newApplication) {
|
||||||
mutateAsync({
|
mutateAsync({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
endpoint: endpoint,
|
endpoint: appsEndpoint,
|
||||||
body: newApplication,
|
body: {
|
||||||
});
|
...newApplication,
|
||||||
closeModal();
|
index: applicationData.length,
|
||||||
|
},
|
||||||
|
}).then(handleClose);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -214,18 +207,14 @@ const ApplicationSettings = () => {
|
|||||||
<Button
|
<Button
|
||||||
color={'red'}
|
color={'red'}
|
||||||
styles={{ label: { color: 'black' } }}
|
styles={{ label: { color: 'black' } }}
|
||||||
onClick={() => {
|
onClick={handleClose}
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Card>
|
}
|
||||||
</Modal.Body>
|
/>
|
||||||
</Modal.Content>
|
|
||||||
</Modal.Root>
|
|
||||||
<SettingsHeader
|
<SettingsHeader
|
||||||
setDragging={setDragging}
|
setDragging={setDragging}
|
||||||
openModal={openModal}
|
openModal={openModal}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Group,
|
Group,
|
||||||
Modal,
|
|
||||||
Stack,
|
Stack,
|
||||||
Switch,
|
Switch,
|
||||||
Text,
|
Text,
|
||||||
@@ -11,14 +10,15 @@ import {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { IconTrash } from '@tabler/icons-react';
|
|
||||||
import { useCommonHooks, useMutationAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { cardClasses, modalClasses, textInputClasses } from 'styles';
|
import { FiTrash } from 'react-icons/fi';
|
||||||
|
import { cardClasses, textInputClasses } from 'styles';
|
||||||
import type { Application } from 'types';
|
import type { Application } from 'types';
|
||||||
|
import DeleteItemModal from '../Shared/DeleteItemModal';
|
||||||
|
|
||||||
function DebouncedApplication({ application }: { application: Application }) {
|
function DebouncedApplication({ application }: { application: Application }) {
|
||||||
const { theme, isMobile, modalStyle, handleDelete } = useCommonHooks();
|
const { theme, handleDelete } = useCommonHooks();
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
|
|
||||||
@@ -39,26 +39,11 @@ function DebouncedApplication({ application }: { application: Application }) {
|
|||||||
}, [update]);
|
}, [update]);
|
||||||
return (
|
return (
|
||||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
||||||
<Modal.Root
|
<DeleteItemModal
|
||||||
size={'60%'}
|
modalOpened={modalOpened}
|
||||||
fullScreen={isMobile}
|
handleClose={closeModal}
|
||||||
className={modalClasses.helpModal}
|
title='Delete Application'
|
||||||
classNames={modalClasses}
|
body={
|
||||||
opened={modalOpened}
|
|
||||||
onClose={() => {
|
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
style={modalStyle}
|
|
||||||
closeOnEscape
|
|
||||||
closeOnClickOutside
|
|
||||||
>
|
|
||||||
<Modal.Overlay />
|
|
||||||
<Modal.Content>
|
|
||||||
<Modal.Header>
|
|
||||||
<Modal.Title>Delete Application</Modal.Title>
|
|
||||||
<Modal.CloseButton />
|
|
||||||
</Modal.Header>
|
|
||||||
<Modal.Body pb={'2rem'}>
|
|
||||||
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
||||||
<Text>Are you sure you want to delete this application?</Text>
|
<Text>Are you sure you want to delete this application?</Text>
|
||||||
<Text
|
<Text
|
||||||
@@ -95,9 +80,8 @@ function DebouncedApplication({ application }: { application: Application }) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal.Body>
|
}
|
||||||
</Modal.Content>
|
/>
|
||||||
</Modal.Root>
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
color={theme.primaryColor}
|
color={theme.primaryColor}
|
||||||
bd={`solid 1px ${theme.borderColor}`}
|
bd={`solid 1px ${theme.borderColor}`}
|
||||||
@@ -111,7 +95,7 @@ function DebouncedApplication({ application }: { application: Application }) {
|
|||||||
openModal();
|
openModal();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconTrash />
|
<FiTrash />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
|||||||
@@ -1,40 +1,34 @@
|
|||||||
import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd';
|
import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd';
|
||||||
import {
|
import { Box, Button, Card, Divider, Group, Stack, Text, TextInput } from '@mantine/core';
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Card,
|
|
||||||
Divider,
|
|
||||||
Group,
|
|
||||||
Modal,
|
|
||||||
Stack,
|
|
||||||
Text,
|
|
||||||
TextInput,
|
|
||||||
} from '@mantine/core';
|
|
||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { cardClasses, modalClasses, textInputClasses } from 'styles';
|
import { textInputClasses } from 'styles';
|
||||||
import type { Bookmark, BookmarkGroup } from 'types';
|
import type { Bookmark, BookmarkGroup } from 'types';
|
||||||
|
import AddItemModal from '../Shared/AddItemModal';
|
||||||
import SettingsHeader from '../Shared/SettingsHeader';
|
import SettingsHeader from '../Shared/SettingsHeader';
|
||||||
import DebouncedGroupSettingsItem from './DebouncedGroupSettingsItem';
|
import DebouncedGroupSettingsItem from './DebouncedGroupSettingsItem';
|
||||||
const BookmarkSettings = () => {
|
const BookmarkSettings = () => {
|
||||||
const { data: linkData, isFetched: linksIsFetched } = useQueryAPI({
|
const defaultGroup = {
|
||||||
endpoint: 'api/links',
|
|
||||||
});
|
|
||||||
const [bookmarks, setBookmarks] = useState<Bookmark[]>([]);
|
|
||||||
const { data: groupData, isFetched: groupsIsFetched } = useQueryAPI({
|
|
||||||
endpoint: 'api/categories',
|
|
||||||
});
|
|
||||||
const [dragging, setDragging] = useState(false);
|
|
||||||
const [groups, setGroups] = useState<BookmarkGroup[]>([]);
|
|
||||||
const [newGroup, setNewGroup] = useState<BookmarkGroup>({
|
|
||||||
id: undefined,
|
id: undefined,
|
||||||
categoryName: '',
|
categoryName: '',
|
||||||
categoryIndex: 0,
|
categoryIndex: 0,
|
||||||
filterName: '',
|
filterName: '',
|
||||||
|
};
|
||||||
|
const linksEndpoint = 'api/links';
|
||||||
|
const { data: linkData, isFetched: linksIsFetched } = useQueryAPI({
|
||||||
|
endpoint: linksEndpoint,
|
||||||
});
|
});
|
||||||
|
const [bookmarks, setBookmarks] = useState<Bookmark[]>([]);
|
||||||
|
const categoriesEndpoint = 'api/categories';
|
||||||
|
const { data: groupData, isFetched: groupsIsFetched } = useQueryAPI({
|
||||||
|
endpoint: categoriesEndpoint,
|
||||||
|
});
|
||||||
|
const [dragging, setDragging] = useState(false);
|
||||||
|
const [groups, setGroups] = useState<BookmarkGroup[]>([]);
|
||||||
|
const [newGroup, setNewGroup] = useState<BookmarkGroup>(defaultGroup);
|
||||||
const [groupList, setGroupList] = useState<BookmarkGroup[]>([]);
|
const [groupList, setGroupList] = useState<BookmarkGroup[]>([]);
|
||||||
const { theme, isMobile, modalStyle } = useCommonHooks();
|
const { theme, isMobile } = useCommonHooks();
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [debouncedGroupSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedGroupSearch] = useDebouncedValue(searchValue, 500);
|
||||||
@@ -47,6 +41,11 @@ const BookmarkSettings = () => {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setNewGroup(defaultGroup);
|
||||||
|
closeModal();
|
||||||
|
};
|
||||||
|
|
||||||
function onDragEnd(result: any) {
|
function onDragEnd(result: any) {
|
||||||
if (!result.destination) {
|
if (!result.destination) {
|
||||||
return;
|
return;
|
||||||
@@ -95,27 +94,11 @@ const BookmarkSettings = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
<Modal.Root
|
<AddItemModal
|
||||||
size={'60%'}
|
modalOpened={modalOpened}
|
||||||
className={modalClasses.helpModal}
|
handleClose={handleClose}
|
||||||
classNames={modalClasses}
|
title={'Add a new Bookmark Group'}
|
||||||
opened={modalOpened}
|
body={
|
||||||
fullScreen={isMobile}
|
|
||||||
onClose={() => {
|
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
style={modalStyle}
|
|
||||||
closeOnEscape
|
|
||||||
closeOnClickOutside
|
|
||||||
>
|
|
||||||
<Modal.Overlay />
|
|
||||||
<Modal.Content>
|
|
||||||
<Modal.Header>
|
|
||||||
<Modal.Title>Add a new Bookmark Group</Modal.Title>
|
|
||||||
<Modal.CloseButton />
|
|
||||||
</Modal.Header>
|
|
||||||
<Modal.Body pb={'2rem'}>
|
|
||||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
|
||||||
<Stack gap={0} w={'100%'} align='center'>
|
<Stack gap={0} w={'100%'} align='center'>
|
||||||
<Group w={'100%'} justify='center'>
|
<Group w={'100%'} justify='center'>
|
||||||
<TextInput
|
<TextInput
|
||||||
@@ -155,10 +138,10 @@ const BookmarkSettings = () => {
|
|||||||
if (newGroup) {
|
if (newGroup) {
|
||||||
mutateAsync({
|
mutateAsync({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
endpoint: 'api/categories',
|
endpoint: categoriesEndpoint,
|
||||||
body: { ...newGroup, categoryIndex: groups.length },
|
body: { ...newGroup, categoryIndex: groups.length },
|
||||||
});
|
});
|
||||||
closeModal();
|
handleClose();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -167,18 +150,14 @@ const BookmarkSettings = () => {
|
|||||||
<Button
|
<Button
|
||||||
color={'red'}
|
color={'red'}
|
||||||
styles={{ label: { color: 'black' } }}
|
styles={{ label: { color: 'black' } }}
|
||||||
onClick={() => {
|
onClick={handleClose}
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Card>
|
}
|
||||||
</Modal.Body>
|
/>
|
||||||
</Modal.Content>
|
|
||||||
</Modal.Root>
|
|
||||||
<SettingsHeader
|
<SettingsHeader
|
||||||
setDragging={setDragging}
|
setDragging={setDragging}
|
||||||
openModal={openModal}
|
openModal={openModal}
|
||||||
|
|||||||
@@ -3,21 +3,24 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Group,
|
Group,
|
||||||
Modal,
|
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { IconTrash } from '@tabler/icons-react';
|
|
||||||
import { useCommonHooks, useMutationAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { cardClasses, modalClasses, textInputClasses } from 'styles';
|
import { FiTrash } from 'react-icons/fi';
|
||||||
|
import { cardClasses, textInputClasses } from 'styles';
|
||||||
import type { Bookmark } from 'types';
|
import type { Bookmark } from 'types';
|
||||||
|
import DeleteItemModal from '../Shared/DeleteItemModal';
|
||||||
|
|
||||||
function DebouncedBookmarkItem({ bookmarkItem }: { bookmarkItem: Bookmark }) {
|
function DebouncedBookmarkItem({
|
||||||
const { theme, isMobile, modalStyle, handleDelete } = useCommonHooks();
|
bookmarkItem,
|
||||||
|
setIsOpen,
|
||||||
|
}: { bookmarkItem: Bookmark; setIsOpen: any }) {
|
||||||
|
const { theme, handleDelete } = useCommonHooks();
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
|
|
||||||
@@ -39,26 +42,10 @@ function DebouncedBookmarkItem({ bookmarkItem }: { bookmarkItem: Bookmark }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
||||||
<Modal.Root
|
<DeleteItemModal
|
||||||
size={'60%'}
|
modalOpened={modalOpened}
|
||||||
className={modalClasses.helpModal}
|
handleClose={closeModal}
|
||||||
classNames={modalClasses}
|
body={
|
||||||
opened={modalOpened}
|
|
||||||
fullScreen={isMobile}
|
|
||||||
onClose={() => {
|
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
style={modalStyle}
|
|
||||||
closeOnEscape
|
|
||||||
closeOnClickOutside
|
|
||||||
>
|
|
||||||
<Modal.Overlay style={{ zIndex: 999 }} />
|
|
||||||
<Modal.Content style={{ zIndex: 1000 }}>
|
|
||||||
<Modal.Header>
|
|
||||||
<Modal.Title>Delete Bookmark</Modal.Title>
|
|
||||||
<Modal.CloseButton />
|
|
||||||
</Modal.Header>
|
|
||||||
<Modal.Body pb={'2rem'}>
|
|
||||||
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
||||||
<Text>Are you sure you want to delete this bookmark?</Text>
|
<Text>Are you sure you want to delete this bookmark?</Text>
|
||||||
<Text
|
<Text
|
||||||
@@ -95,9 +82,9 @@ function DebouncedBookmarkItem({ bookmarkItem }: { bookmarkItem: Bookmark }) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal.Body>
|
}
|
||||||
</Modal.Content>
|
title='Delete Bookmark'
|
||||||
</Modal.Root>
|
/>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
color={theme.primaryColor}
|
color={theme.primaryColor}
|
||||||
bd={`solid 1px ${theme.borderColor}`}
|
bd={`solid 1px ${theme.borderColor}`}
|
||||||
@@ -108,10 +95,11 @@ function DebouncedBookmarkItem({ bookmarkItem }: { bookmarkItem: Bookmark }) {
|
|||||||
right={16}
|
right={16}
|
||||||
color='red'
|
color='red'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
setIsOpen(true);
|
||||||
openModal();
|
openModal();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconTrash />
|
<FiTrash />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Group w={'100%'} justify='center'>
|
<Group w={'100%'} justify='center'>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Group,
|
Group,
|
||||||
Modal,
|
|
||||||
Popover,
|
Popover,
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
@@ -13,12 +12,12 @@ import {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { IconTrash } from '@tabler/icons-react';
|
|
||||||
import { useCommonHooks, useMutationAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { FiPlus } from 'react-icons/fi';
|
import { FiPlus, FiTrash } from 'react-icons/fi';
|
||||||
import { buttonClasses, cardClasses, modalClasses, textInputClasses } from 'styles';
|
import { buttonClasses, cardClasses, textInputClasses } from 'styles';
|
||||||
import type { Bookmark, BookmarkGroup } from 'types';
|
import type { Bookmark, BookmarkGroup } from 'types';
|
||||||
|
import DeleteItemModal from '../Shared/DeleteItemModal';
|
||||||
import BookmarkSettingsItem from './BookmarkSettingsItem';
|
import BookmarkSettingsItem from './BookmarkSettingsItem';
|
||||||
import DebouncedBookmarkItem from './DebouncedBookmarkItem';
|
import DebouncedBookmarkItem from './DebouncedBookmarkItem';
|
||||||
|
|
||||||
@@ -26,7 +25,7 @@ function DebouncedGroupSettingsItem({
|
|||||||
bookmarkGroup,
|
bookmarkGroup,
|
||||||
bookmarks,
|
bookmarks,
|
||||||
}: { bookmarkGroup: BookmarkGroup; bookmarks: Bookmark[] }) {
|
}: { bookmarkGroup: BookmarkGroup; bookmarks: Bookmark[] }) {
|
||||||
const { theme, isMobile, modalStyle, handleDelete } = useCommonHooks();
|
const { theme, isMobile, handleDelete } = useCommonHooks();
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
const [popoverOpened, setPopoverOpened] = useState(false);
|
const [popoverOpened, setPopoverOpened] = useState(false);
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
@@ -41,6 +40,7 @@ function DebouncedGroupSettingsItem({
|
|||||||
index: 0,
|
index: 0,
|
||||||
});
|
});
|
||||||
const [bookmarkList, setBookmarkList] = useState<Bookmark[]>(bookmarks);
|
const [bookmarkList, setBookmarkList] = useState<Bookmark[]>(bookmarks);
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
const reorder = (list: any, startIndex: any, endIndex: any) => {
|
const reorder = (list: any, startIndex: any, endIndex: any) => {
|
||||||
const result = Array.from(list);
|
const result = Array.from(list);
|
||||||
@@ -90,26 +90,11 @@ function DebouncedGroupSettingsItem({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Card w={'400px'} className={cardClasses.settingsItem} classNames={cardClasses}>
|
<Card w={'400px'} className={cardClasses.settingsItem} classNames={cardClasses}>
|
||||||
<Modal.Root
|
<DeleteItemModal
|
||||||
size={'60%'}
|
modalOpened={modalOpened}
|
||||||
className={modalClasses.helpModal}
|
handleClose={closeModal}
|
||||||
classNames={modalClasses}
|
title='Delete message'
|
||||||
opened={modalOpened}
|
body={
|
||||||
fullScreen={isMobile}
|
|
||||||
onClose={() => {
|
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
style={modalStyle}
|
|
||||||
closeOnEscape
|
|
||||||
closeOnClickOutside
|
|
||||||
>
|
|
||||||
<Modal.Overlay />
|
|
||||||
<Modal.Content>
|
|
||||||
<Modal.Header>
|
|
||||||
<Modal.Title>Delete Group</Modal.Title>
|
|
||||||
<Modal.CloseButton />
|
|
||||||
</Modal.Header>
|
|
||||||
<Modal.Body pb={'2rem'}>
|
|
||||||
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
||||||
<Text>Are you sure you want to delete this bookmark group?</Text>
|
<Text>Are you sure you want to delete this bookmark group?</Text>
|
||||||
<Text
|
<Text
|
||||||
@@ -146,9 +131,8 @@ function DebouncedGroupSettingsItem({
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal.Body>
|
}
|
||||||
</Modal.Content>
|
/>
|
||||||
</Modal.Root>
|
|
||||||
<Card.Section p={16} bg={theme.searchColor} c={theme.backgroundColor}>
|
<Card.Section p={16} bg={theme.searchColor} c={theme.backgroundColor}>
|
||||||
<Stack gap={0}>
|
<Stack gap={0}>
|
||||||
<Group gap={0} align='center' justify='space-between'>
|
<Group gap={0} align='center' justify='space-between'>
|
||||||
@@ -201,7 +185,7 @@ function DebouncedGroupSettingsItem({
|
|||||||
openModal();
|
openModal();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconTrash />
|
<FiTrash />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Group>
|
</Group>
|
||||||
@@ -243,7 +227,7 @@ function DebouncedGroupSettingsItem({
|
|||||||
{...provided.draggableProps}
|
{...provided.draggableProps}
|
||||||
{...provided.dragHandleProps}
|
{...provided.dragHandleProps}
|
||||||
>
|
>
|
||||||
<Popover withArrow withOverlay>
|
<Popover withArrow withOverlay closeOnClickOutside={!isOpen}>
|
||||||
<Popover.Target>
|
<Popover.Target>
|
||||||
<Box>
|
<Box>
|
||||||
<BookmarkSettingsItem bookmark={bookmark} />
|
<BookmarkSettingsItem bookmark={bookmark} />
|
||||||
@@ -259,7 +243,10 @@ function DebouncedGroupSettingsItem({
|
|||||||
'--image-background': `url(${theme.backgroundImage})`,
|
'--image-background': `url(${theme.backgroundImage})`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DebouncedBookmarkItem bookmarkItem={bookmark} />
|
<DebouncedBookmarkItem
|
||||||
|
bookmarkItem={bookmark}
|
||||||
|
setIsOpen={setIsOpen}
|
||||||
|
/>
|
||||||
</Popover.Dropdown>
|
</Popover.Dropdown>
|
||||||
</Popover>
|
</Popover>
|
||||||
{provided.placeholder}
|
{provided.placeholder}
|
||||||
@@ -284,6 +271,7 @@ function DebouncedGroupSettingsItem({
|
|||||||
opened={popoverOpened}
|
opened={popoverOpened}
|
||||||
onChange={setPopoverOpened}
|
onChange={setPopoverOpened}
|
||||||
closeOnEscape
|
closeOnEscape
|
||||||
|
// closeOnClickOutside={}
|
||||||
>
|
>
|
||||||
<Popover.Target>
|
<Popover.Target>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -3,42 +3,27 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Group,
|
Group,
|
||||||
Modal,
|
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useDisclosure } from '@mantine/hooks';
|
import { useDisclosure } from '@mantine/hooks';
|
||||||
import { IconTrash } from '@tabler/icons-react';
|
|
||||||
import { useCommonHooks } from 'hooks';
|
import { useCommonHooks } from 'hooks';
|
||||||
import { cardClasses, modalClasses, textInputClasses } from 'styles';
|
import { FiTrash } from 'react-icons/fi';
|
||||||
|
import { cardClasses, textInputClasses } from 'styles';
|
||||||
|
import DeleteItemModal from '../Shared/DeleteItemModal';
|
||||||
|
|
||||||
function DebouncedMessage({ label, message, setMessage }: any) {
|
function DebouncedMessage({ label, message, setMessage }: any) {
|
||||||
const { theme, isMobile, modalStyle, handleDelete } = useCommonHooks();
|
const { theme, handleDelete } = useCommonHooks();
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
return (
|
return (
|
||||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
||||||
<Modal.Root
|
<DeleteItemModal
|
||||||
size={'60%'}
|
modalOpened={modalOpened}
|
||||||
className={modalClasses.helpModal}
|
handleClose={closeModal}
|
||||||
classNames={modalClasses}
|
title='Delete message'
|
||||||
opened={modalOpened}
|
body={
|
||||||
fullScreen={isMobile}
|
|
||||||
onClose={() => {
|
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
style={modalStyle}
|
|
||||||
closeOnEscape
|
|
||||||
closeOnClickOutside
|
|
||||||
>
|
|
||||||
<Modal.Overlay />
|
|
||||||
<Modal.Content>
|
|
||||||
<Modal.Header>
|
|
||||||
<Modal.Title>Delete message</Modal.Title>
|
|
||||||
<Modal.CloseButton />
|
|
||||||
</Modal.Header>
|
|
||||||
<Modal.Body pb={'2rem'}>
|
|
||||||
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
||||||
<Text>Are you sure you want to delete this message?</Text>
|
<Text>Are you sure you want to delete this message?</Text>
|
||||||
<Text
|
<Text
|
||||||
@@ -67,17 +52,14 @@ function DebouncedMessage({ label, message, setMessage }: any) {
|
|||||||
<Button
|
<Button
|
||||||
color={'grey'}
|
color={'grey'}
|
||||||
styles={{ label: { color: 'black' } }}
|
styles={{ label: { color: 'black' } }}
|
||||||
onClick={() => {
|
onClick={closeModal}
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal.Body>
|
}
|
||||||
</Modal.Content>
|
/>
|
||||||
</Modal.Root>
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
color={theme.primaryColor}
|
color={theme.primaryColor}
|
||||||
bd={`solid 1px ${theme.borderColor}`}
|
bd={`solid 1px ${theme.borderColor}`}
|
||||||
@@ -91,7 +73,7 @@ function DebouncedMessage({ label, message, setMessage }: any) {
|
|||||||
openModal();
|
openModal();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconTrash />
|
<FiTrash />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
|||||||
@@ -1,27 +1,18 @@
|
|||||||
import {
|
import { Button, Divider, Grid, GridCol, Group, Stack, TextInput } from '@mantine/core';
|
||||||
Button,
|
|
||||||
Card,
|
|
||||||
Divider,
|
|
||||||
Grid,
|
|
||||||
GridCol,
|
|
||||||
Group,
|
|
||||||
Modal,
|
|
||||||
Stack,
|
|
||||||
TextInput,
|
|
||||||
} from '@mantine/core';
|
|
||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
||||||
import DebouncedMessage from 'pages/settings/components/Messages/DebouncedMessage';
|
import DebouncedMessage from 'pages/settings/components/Messages/DebouncedMessage';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { cardClasses, modalClasses, textInputClasses } from 'styles';
|
import { textInputClasses } from 'styles';
|
||||||
import type { Message } from 'types';
|
import type { Message } from 'types';
|
||||||
|
import AddItemModal from '../Shared/AddItemModal';
|
||||||
import SettingsHeader from '../Shared/SettingsHeader';
|
import SettingsHeader from '../Shared/SettingsHeader';
|
||||||
const MessageSettings = () => {
|
const MessageSettings = () => {
|
||||||
const endpoint = 'api/messages';
|
const endpoint = 'api/messages';
|
||||||
const { data: messageData, isFetched: isMessagesFetched } = useQueryAPI({
|
const { data: messageData, isFetched: isMessagesFetched } = useQueryAPI({
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
});
|
});
|
||||||
const { isMobile, modalStyle } = useCommonHooks();
|
const { isMobile } = useCommonHooks();
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const [messages, setMessages] = useState<Message[]>([]);
|
const [messages, setMessages] = useState<Message[]>([]);
|
||||||
const [newMessage, setNewMessage] = useState('');
|
const [newMessage, setNewMessage] = useState('');
|
||||||
@@ -32,6 +23,12 @@ const MessageSettings = () => {
|
|||||||
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setNewMessage('');
|
||||||
|
setNewMessageError('');
|
||||||
|
closeModal();
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (messageData && isMessagesFetched) {
|
if (messageData && isMessagesFetched) {
|
||||||
setMessages(
|
setMessages(
|
||||||
@@ -50,27 +47,11 @@ const MessageSettings = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack w={'100%'}>
|
<Stack w={'100%'}>
|
||||||
<Modal.Root
|
<AddItemModal
|
||||||
size={'60%'}
|
modalOpened={modalOpened}
|
||||||
className={modalClasses.helpModal}
|
handleClose={handleClose}
|
||||||
classNames={modalClasses}
|
title={'Add a new message'}
|
||||||
opened={modalOpened}
|
body={
|
||||||
fullScreen={isMobile}
|
|
||||||
onClose={() => {
|
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
style={modalStyle}
|
|
||||||
closeOnEscape
|
|
||||||
closeOnClickOutside
|
|
||||||
>
|
|
||||||
<Modal.Overlay />
|
|
||||||
<Modal.Content>
|
|
||||||
<Modal.Header>
|
|
||||||
<Modal.Title>Add a new message</Modal.Title>
|
|
||||||
<Modal.CloseButton />
|
|
||||||
</Modal.Header>
|
|
||||||
<Modal.Body pb={'2rem'}>
|
|
||||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
|
||||||
<Stack gap={0} w={'100%'} align='center'>
|
<Stack gap={0} w={'100%'} align='center'>
|
||||||
<TextInput
|
<TextInput
|
||||||
label='Message text'
|
label='Message text'
|
||||||
@@ -94,8 +75,7 @@ const MessageSettings = () => {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
body: { message: newMessage },
|
body: { message: newMessage },
|
||||||
});
|
}).then(handleClose);
|
||||||
closeModal();
|
|
||||||
} else {
|
} else {
|
||||||
setNewMessageError('Please enter a message');
|
setNewMessageError('Please enter a message');
|
||||||
}
|
}
|
||||||
@@ -106,18 +86,14 @@ const MessageSettings = () => {
|
|||||||
<Button
|
<Button
|
||||||
color={'red'}
|
color={'red'}
|
||||||
styles={{ label: { color: 'black' } }}
|
styles={{ label: { color: 'black' } }}
|
||||||
onClick={() => {
|
onClick={handleClose}
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Card>
|
}
|
||||||
</Modal.Body>
|
/>
|
||||||
</Modal.Content>
|
|
||||||
</Modal.Root>
|
|
||||||
<SettingsHeader
|
<SettingsHeader
|
||||||
setDragging={undefined}
|
setDragging={undefined}
|
||||||
openModal={openModal}
|
openModal={openModal}
|
||||||
|
|||||||
@@ -3,21 +3,21 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Group,
|
Group,
|
||||||
Modal,
|
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { IconTrash } from '@tabler/icons-react';
|
|
||||||
import { useCommonHooks, useMutationAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { cardClasses, modalClasses, textInputClasses } from 'styles';
|
import { FiTrash } from 'react-icons/fi';
|
||||||
|
import { cardClasses, textInputClasses } from 'styles';
|
||||||
import type { Provider } from 'types';
|
import type { Provider } from 'types';
|
||||||
|
import DeleteItemModal from '../Shared/DeleteItemModal';
|
||||||
|
|
||||||
function DebouncedSearchProvider({ searchProvider }: any) {
|
function DebouncedSearchProvider({ searchProvider }: any) {
|
||||||
const { theme, isMobile, modalStyle, handleDelete } = useCommonHooks();
|
const { theme, handleDelete } = useCommonHooks();
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
|
|
||||||
@@ -39,26 +39,11 @@ function DebouncedSearchProvider({ searchProvider }: any) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
||||||
<Modal.Root
|
<DeleteItemModal
|
||||||
size={'60%'}
|
modalOpened={modalOpened}
|
||||||
className={modalClasses.helpModal}
|
handleClose={closeModal}
|
||||||
classNames={modalClasses}
|
title={'Delete Search Provider'}
|
||||||
opened={modalOpened}
|
body={
|
||||||
fullScreen={isMobile}
|
|
||||||
onClose={() => {
|
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
style={modalStyle}
|
|
||||||
closeOnEscape
|
|
||||||
closeOnClickOutside
|
|
||||||
>
|
|
||||||
<Modal.Overlay />
|
|
||||||
<Modal.Content>
|
|
||||||
<Modal.Header>
|
|
||||||
<Modal.Title>Delete Search Provider</Modal.Title>
|
|
||||||
<Modal.CloseButton />
|
|
||||||
</Modal.Header>
|
|
||||||
<Modal.Body pb={'2rem'}>
|
|
||||||
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
||||||
<Text>Are you sure you want to delete this Search Provider?</Text>
|
<Text>Are you sure you want to delete this Search Provider?</Text>
|
||||||
<Text
|
<Text
|
||||||
@@ -95,9 +80,8 @@ function DebouncedSearchProvider({ searchProvider }: any) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal.Body>
|
}
|
||||||
</Modal.Content>
|
/>
|
||||||
</Modal.Root>
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
color={theme.primaryColor}
|
color={theme.primaryColor}
|
||||||
bd={`solid 1px ${theme.borderColor}`}
|
bd={`solid 1px ${theme.borderColor}`}
|
||||||
@@ -111,7 +95,7 @@ function DebouncedSearchProvider({ searchProvider }: any) {
|
|||||||
openModal();
|
openModal();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconTrash />
|
<FiTrash />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Stack>
|
<Stack>
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Card,
|
|
||||||
Divider,
|
Divider,
|
||||||
Grid,
|
Grid,
|
||||||
GridCol,
|
GridCol,
|
||||||
Group,
|
Group,
|
||||||
Modal,
|
|
||||||
Popover,
|
Popover,
|
||||||
Stack,
|
Stack,
|
||||||
TextInput,
|
TextInput,
|
||||||
@@ -14,30 +12,37 @@ import {
|
|||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { cardClasses, modalClasses, textInputClasses } from 'styles';
|
import { textInputClasses } from 'styles';
|
||||||
import type { Provider } from 'types';
|
import type { Provider } from 'types';
|
||||||
|
import AddItemModal from '../Shared/AddItemModal';
|
||||||
import SettingsHeader from '../Shared/SettingsHeader';
|
import SettingsHeader from '../Shared/SettingsHeader';
|
||||||
import DebouncedSearchProvider from './DebouncedSearchProvider';
|
import DebouncedSearchProvider from './DebouncedSearchProvider';
|
||||||
import SearchProviderSettingsItem from './SearchProviderSettingsItem';
|
import SearchProviderSettingsItem from './SearchProviderSettingsItem';
|
||||||
|
|
||||||
const SearchProviderSettings = () => {
|
const SearchProviderSettings = () => {
|
||||||
|
const defaultProvider = {
|
||||||
|
id: undefined,
|
||||||
|
name: '',
|
||||||
|
url: '',
|
||||||
|
prefix: '',
|
||||||
|
};
|
||||||
const endpoint = 'api/providers';
|
const endpoint = 'api/providers';
|
||||||
const { data: providers, isFetched: providersIsFetched } = useQueryAPI({
|
const { data: providers, isFetched: providersIsFetched } = useQueryAPI({
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
});
|
});
|
||||||
const [providerData, setProviderData] = useState<Provider[]>([]);
|
const [providerData, setProviderData] = useState<Provider[]>([]);
|
||||||
const { isMobile, modalStyle } = useCommonHooks();
|
const { isMobile } = useCommonHooks();
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const [newProvider, setNewProvider] = useState<Provider>({
|
const [newProvider, setNewProvider] = useState<Provider>(defaultProvider);
|
||||||
id: undefined,
|
|
||||||
name: '',
|
|
||||||
url: '',
|
|
||||||
prefix: '',
|
|
||||||
});
|
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setNewProvider(defaultProvider);
|
||||||
|
closeModal();
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (providers && providersIsFetched) {
|
if (providers && providersIsFetched) {
|
||||||
setProviderData(
|
setProviderData(
|
||||||
@@ -52,27 +57,11 @@ const SearchProviderSettings = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
<Modal.Root
|
<AddItemModal
|
||||||
size={'60%'}
|
modalOpened={modalOpened}
|
||||||
className={modalClasses.helpModal}
|
handleClose={handleClose}
|
||||||
classNames={modalClasses}
|
title={'Add a new Search Provider'}
|
||||||
opened={modalOpened}
|
body={
|
||||||
fullScreen={isMobile}
|
|
||||||
onClose={() => {
|
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
style={modalStyle}
|
|
||||||
closeOnEscape
|
|
||||||
closeOnClickOutside
|
|
||||||
>
|
|
||||||
<Modal.Overlay />
|
|
||||||
<Modal.Content>
|
|
||||||
<Modal.Header>
|
|
||||||
<Modal.Title>Add a new Search Provider</Modal.Title>
|
|
||||||
<Modal.CloseButton />
|
|
||||||
</Modal.Header>
|
|
||||||
<Modal.Body pb={'2rem'}>
|
|
||||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
|
||||||
<Stack gap={0} w={'100%'} align='center'>
|
<Stack gap={0} w={'100%'} align='center'>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Group w={'100%'} justify='center'>
|
<Group w={'100%'} justify='center'>
|
||||||
@@ -128,8 +117,7 @@ const SearchProviderSettings = () => {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
body: newProvider,
|
body: newProvider,
|
||||||
});
|
}).then(handleClose);
|
||||||
closeModal();
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -138,18 +126,14 @@ const SearchProviderSettings = () => {
|
|||||||
<Button
|
<Button
|
||||||
color={'red'}
|
color={'red'}
|
||||||
styles={{ label: { color: 'black' } }}
|
styles={{ label: { color: 'black' } }}
|
||||||
onClick={() => {
|
onClick={handleClose}
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Card>
|
}
|
||||||
</Modal.Body>
|
/>
|
||||||
</Modal.Content>
|
|
||||||
</Modal.Root>
|
|
||||||
<SettingsHeader
|
<SettingsHeader
|
||||||
setDragging={undefined}
|
setDragging={undefined}
|
||||||
openModal={openModal}
|
openModal={openModal}
|
||||||
|
|||||||
35
src/pages/settings/components/Shared/AddItemModal.tsx
Normal file
35
src/pages/settings/components/Shared/AddItemModal.tsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { Card, Modal } from '@mantine/core';
|
||||||
|
import { useCommonHooks } from 'hooks';
|
||||||
|
import { cardClasses, modalClasses } from 'styles';
|
||||||
|
|
||||||
|
function AddItemModal({ modalOpened, handleClose, body, title }: any) {
|
||||||
|
const { isMobile, modalStyle } = useCommonHooks();
|
||||||
|
return (
|
||||||
|
<Modal.Root
|
||||||
|
size={'60%'}
|
||||||
|
className={modalClasses.helpModal}
|
||||||
|
classNames={modalClasses}
|
||||||
|
opened={modalOpened}
|
||||||
|
fullScreen={isMobile}
|
||||||
|
onClose={handleClose}
|
||||||
|
style={modalStyle}
|
||||||
|
closeOnEscape
|
||||||
|
closeOnClickOutside
|
||||||
|
>
|
||||||
|
<Modal.Overlay style={{ zIndex: 999 }} />
|
||||||
|
<Modal.Content style={{ zIndex: 1000 }}>
|
||||||
|
<Modal.Header>
|
||||||
|
<Modal.Title>{title}</Modal.Title>
|
||||||
|
<Modal.CloseButton />
|
||||||
|
</Modal.Header>
|
||||||
|
<Modal.Body pb={'2rem'}>
|
||||||
|
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
||||||
|
{body}
|
||||||
|
</Card>
|
||||||
|
</Modal.Body>
|
||||||
|
</Modal.Content>
|
||||||
|
</Modal.Root>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AddItemModal;
|
||||||
35
src/pages/settings/components/Shared/DeleteItemModal.tsx
Normal file
35
src/pages/settings/components/Shared/DeleteItemModal.tsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { Card, Modal } from '@mantine/core';
|
||||||
|
import { useCommonHooks } from 'hooks';
|
||||||
|
import { cardClasses, modalClasses } from 'styles';
|
||||||
|
|
||||||
|
function DeleteItemModal({ modalOpened, handleClose, body, title }: any) {
|
||||||
|
const { isMobile, modalStyle } = useCommonHooks();
|
||||||
|
return (
|
||||||
|
<Modal.Root
|
||||||
|
size={'60%'}
|
||||||
|
className={modalClasses.helpModal}
|
||||||
|
classNames={modalClasses}
|
||||||
|
opened={modalOpened}
|
||||||
|
fullScreen={isMobile}
|
||||||
|
onClose={handleClose}
|
||||||
|
style={modalStyle}
|
||||||
|
closeOnEscape
|
||||||
|
closeOnClickOutside
|
||||||
|
>
|
||||||
|
<Modal.Overlay style={{ zIndex: 999 }} />
|
||||||
|
<Modal.Content style={{ zIndex: 1000 }}>
|
||||||
|
<Modal.Header>
|
||||||
|
<Modal.Title>{title}</Modal.Title>
|
||||||
|
<Modal.CloseButton />
|
||||||
|
</Modal.Header>
|
||||||
|
<Modal.Body pb={'2rem'}>
|
||||||
|
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
||||||
|
{body}
|
||||||
|
</Card>
|
||||||
|
</Modal.Body>
|
||||||
|
</Modal.Content>
|
||||||
|
</Modal.Root>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DeleteItemModal;
|
||||||
@@ -1,19 +1,11 @@
|
|||||||
import {
|
import { ActionIcon, Box, Button, Group, Overlay, Stack, Text } from '@mantine/core';
|
||||||
ActionIcon,
|
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Group,
|
|
||||||
Modal,
|
|
||||||
Overlay,
|
|
||||||
Stack,
|
|
||||||
Text,
|
|
||||||
} from '@mantine/core';
|
|
||||||
import { useDisclosure } from '@mantine/hooks';
|
import { useDisclosure } from '@mantine/hooks';
|
||||||
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { FiEdit, FiShuffle, FiTrash, FiX } from 'react-icons/fi';
|
import { FiEdit, FiShuffle, FiTrash, FiX } from 'react-icons/fi';
|
||||||
import { actionIconClasses, modalClasses } from 'styles';
|
import { actionIconClasses } from 'styles';
|
||||||
import type { ThemePlaylist } from 'types';
|
import type { ThemePlaylist } from 'types';
|
||||||
|
import DeleteItemModal from '../Shared/DeleteItemModal';
|
||||||
|
|
||||||
function ThemeCard({ cardTheme, handleOpen, allThemes }: any) {
|
function ThemeCard({ cardTheme, handleOpen, allThemes }: any) {
|
||||||
const { data: themePlaylists } = useQueryAPI({
|
const { data: themePlaylists } = useQueryAPI({
|
||||||
@@ -29,10 +21,8 @@ function ThemeCard({ cardTheme, handleOpen, allThemes }: any) {
|
|||||||
currentTheme,
|
currentTheme,
|
||||||
setCurrentTheme,
|
setCurrentTheme,
|
||||||
theme,
|
theme,
|
||||||
isMobile,
|
|
||||||
currentThemePlaylist,
|
currentThemePlaylist,
|
||||||
setCurrentThemePlaylist,
|
setCurrentThemePlaylist,
|
||||||
modalStyle,
|
|
||||||
handleDelete,
|
handleDelete,
|
||||||
} = useCommonHooks();
|
} = useCommonHooks();
|
||||||
|
|
||||||
@@ -46,26 +36,11 @@ function ThemeCard({ cardTheme, handleOpen, allThemes }: any) {
|
|||||||
onMouseEnter={() => setHover(true)}
|
onMouseEnter={() => setHover(true)}
|
||||||
onMouseLeave={() => setHover(false)}
|
onMouseLeave={() => setHover(false)}
|
||||||
>
|
>
|
||||||
<Modal.Root
|
<DeleteItemModal
|
||||||
size={'60%'}
|
modalOpened={modalOpened}
|
||||||
fullScreen={isMobile}
|
handleClose={closeModal}
|
||||||
className={modalClasses.helpModal}
|
title={'Delete Theme'}
|
||||||
classNames={modalClasses}
|
body={
|
||||||
opened={modalOpened}
|
|
||||||
onClose={() => {
|
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
style={modalStyle}
|
|
||||||
closeOnEscape
|
|
||||||
closeOnClickOutside
|
|
||||||
>
|
|
||||||
<Modal.Overlay />
|
|
||||||
<Modal.Content>
|
|
||||||
<Modal.Header>
|
|
||||||
<Modal.Title>Delete Theme</Modal.Title>
|
|
||||||
<Modal.CloseButton />
|
|
||||||
</Modal.Header>
|
|
||||||
<Modal.Body pb={'2rem'}>
|
|
||||||
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
||||||
<Text>Are you sure you want to delete this theme?</Text>
|
<Text>Are you sure you want to delete this theme?</Text>
|
||||||
<Text
|
<Text
|
||||||
@@ -102,9 +77,8 @@ function ThemeCard({ cardTheme, handleOpen, allThemes }: any) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal.Body>
|
}
|
||||||
</Modal.Content>
|
/>
|
||||||
</Modal.Root>
|
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import {
|
|||||||
ActionIcon,
|
ActionIcon,
|
||||||
Button,
|
Button,
|
||||||
Group,
|
Group,
|
||||||
Modal,
|
|
||||||
Overlay,
|
Overlay,
|
||||||
ScrollArea,
|
ScrollArea,
|
||||||
Stack,
|
Stack,
|
||||||
@@ -12,19 +11,12 @@ import { useDisclosure } from '@mantine/hooks';
|
|||||||
import { useCommonHooks, useMutationAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI } from 'hooks';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { FiEdit, FiRefreshCcw, FiTrash } from 'react-icons/fi';
|
import { FiEdit, FiRefreshCcw, FiTrash } from 'react-icons/fi';
|
||||||
import { modalClasses } from 'styles';
|
import DeleteItemModal from '../Shared/DeleteItemModal';
|
||||||
import ThemeMiniCard from './ThemeMiniCard';
|
import ThemeMiniCard from './ThemeMiniCard';
|
||||||
|
|
||||||
function ThemePlaylistCard({ cardPlaylist, handleOpen, allThemes }: any) {
|
function ThemePlaylistCard({ cardPlaylist, handleOpen, allThemes }: any) {
|
||||||
const [hover, setHover] = useState(false);
|
const [hover, setHover] = useState(false);
|
||||||
const {
|
const { setThemeName, setCurrentThemePlaylist, theme, handleDelete } = useCommonHooks();
|
||||||
setThemeName,
|
|
||||||
setCurrentThemePlaylist,
|
|
||||||
theme,
|
|
||||||
isMobile,
|
|
||||||
modalStyle,
|
|
||||||
handleDelete,
|
|
||||||
} = useCommonHooks();
|
|
||||||
const syncableLists = ['All', 'Backgrounds', 'No Backgrounds'];
|
const syncableLists = ['All', 'Backgrounds', 'No Backgrounds'];
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
@@ -42,26 +34,11 @@ function ThemePlaylistCard({ cardPlaylist, handleOpen, allThemes }: any) {
|
|||||||
onMouseEnter={() => setHover(true)}
|
onMouseEnter={() => setHover(true)}
|
||||||
onMouseLeave={() => setHover(false)}
|
onMouseLeave={() => setHover(false)}
|
||||||
>
|
>
|
||||||
<Modal.Root
|
<DeleteItemModal
|
||||||
size={'60%'}
|
modalOpened={modalOpened}
|
||||||
fullScreen={isMobile}
|
closeModal={closeModal}
|
||||||
className={modalClasses.helpModal}
|
title='Delete Theme Playlist'
|
||||||
classNames={modalClasses}
|
body={
|
||||||
opened={modalOpened}
|
|
||||||
onClose={() => {
|
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
style={modalStyle}
|
|
||||||
closeOnEscape
|
|
||||||
closeOnClickOutside
|
|
||||||
>
|
|
||||||
<Modal.Overlay />
|
|
||||||
<Modal.Content>
|
|
||||||
<Modal.Header>
|
|
||||||
<Modal.Title>Delete Theme Playlist</Modal.Title>
|
|
||||||
<Modal.CloseButton />
|
|
||||||
</Modal.Header>
|
|
||||||
<Modal.Body pb={'2rem'}>
|
|
||||||
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
||||||
<Text>Are you sure you want to delete this Theme Playlist?</Text>
|
<Text>Are you sure you want to delete this Theme Playlist?</Text>
|
||||||
<Text
|
<Text
|
||||||
@@ -98,9 +75,8 @@ function ThemePlaylistCard({ cardPlaylist, handleOpen, allThemes }: any) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal.Body>
|
}
|
||||||
</Modal.Content>
|
/>
|
||||||
</Modal.Root>
|
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
|||||||
@@ -10,11 +10,13 @@ import ThemePlaylistCard from './ThemePlaylistCard';
|
|||||||
import ThemePlaylistModal from './ThemePlaylistModal';
|
import ThemePlaylistModal from './ThemePlaylistModal';
|
||||||
|
|
||||||
function ThemePlaylists() {
|
function ThemePlaylists() {
|
||||||
|
const themesEndpoint = 'api/themes';
|
||||||
const { data: allThemes } = useQueryAPI({
|
const { data: allThemes } = useQueryAPI({
|
||||||
endpoint: 'api/themes',
|
endpoint: themesEndpoint,
|
||||||
});
|
});
|
||||||
|
const themePlaylistsEndpoint = 'api/themePlaylists';
|
||||||
const { data: themePlaylists } = useQueryAPI({
|
const { data: themePlaylists } = useQueryAPI({
|
||||||
endpoint: 'api/themePlaylists',
|
endpoint: themePlaylistsEndpoint,
|
||||||
});
|
});
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const [opened, { open, close }] = useDisclosure(false);
|
const [opened, { open, close }] = useDisclosure(false);
|
||||||
@@ -36,7 +38,7 @@ function ThemePlaylists() {
|
|||||||
const handleSavePlaylist = () => {
|
const handleSavePlaylist = () => {
|
||||||
mutateAsync({
|
mutateAsync({
|
||||||
method: selectedPlaylist.id === undefined ? 'POST' : 'PATCH',
|
method: selectedPlaylist.id === undefined ? 'POST' : 'PATCH',
|
||||||
endpoint: 'api/themePlaylists',
|
endpoint: themePlaylistsEndpoint,
|
||||||
body: selectedPlaylist,
|
body: selectedPlaylist,
|
||||||
});
|
});
|
||||||
close();
|
close();
|
||||||
|
|||||||
@@ -2,20 +2,20 @@ import { Box, Group, Overlay, Stack, Switch, Text } from '@mantine/core';
|
|||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { FiChevronRight } from 'react-icons/fi';
|
|
||||||
import '@mantine/core/styles/ModalBase.css';
|
|
||||||
import '@mantine/core/styles/Modal.css';
|
|
||||||
import { FaDice } from 'react-icons/fa';
|
import { FaDice } from 'react-icons/fa';
|
||||||
|
import { FiChevronRight } from 'react-icons/fi';
|
||||||
import type { Theme } from 'types';
|
import type { Theme } from 'types';
|
||||||
import SettingsHeader from '../Shared/SettingsHeader';
|
import SettingsHeader from '../Shared/SettingsHeader';
|
||||||
import ThemeCard from './ThemeCard';
|
import ThemeCard from './ThemeCard';
|
||||||
import ThemeModal from './ThemeModal';
|
import ThemeModal from './ThemeModal';
|
||||||
function ThemesSettings() {
|
function ThemesSettings() {
|
||||||
|
const themesEndpoint = 'api/themes';
|
||||||
|
const backgroundsEndpoint = 'api/backgrounds';
|
||||||
const { data: allThemes } = useQueryAPI({
|
const { data: allThemes } = useQueryAPI({
|
||||||
endpoint: 'api/themes',
|
endpoint: 'api/themes',
|
||||||
});
|
});
|
||||||
const { data: backgroundData, isFetched: isBackgroundFetched } = useQueryAPI({
|
const { data: backgroundData, isFetched: isBackgroundFetched } = useQueryAPI({
|
||||||
endpoint: 'api/backgrounds',
|
endpoint: backgroundsEndpoint,
|
||||||
});
|
});
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const [opened, { open, close }] = useDisclosure(false);
|
const [opened, { open, close }] = useDisclosure(false);
|
||||||
@@ -43,7 +43,7 @@ function ThemesSettings() {
|
|||||||
const handleSaveTheme = () => {
|
const handleSaveTheme = () => {
|
||||||
mutateAsync({
|
mutateAsync({
|
||||||
method: selectedTheme.id === undefined ? 'POST' : 'PATCH',
|
method: selectedTheme.id === undefined ? 'POST' : 'PATCH',
|
||||||
endpoint: 'api/themes',
|
endpoint: themesEndpoint,
|
||||||
body: selectedTheme,
|
body: selectedTheme,
|
||||||
});
|
});
|
||||||
close();
|
close();
|
||||||
|
|||||||
@@ -3,20 +3,20 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Group,
|
Group,
|
||||||
Modal,
|
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { IconTrash } from '@tabler/icons-react';
|
|
||||||
import { useCommonHooks, useMutationAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { cardClasses, modalClasses, textInputClasses } from 'styles';
|
import { FiTrash } from 'react-icons/fi';
|
||||||
|
import { cardClasses, textInputClasses } from 'styles';
|
||||||
|
import DeleteItemModal from '../Shared/DeleteItemModal';
|
||||||
|
|
||||||
function DebouncedWolClient({ wolClient }: any) {
|
function DebouncedWolClient({ wolClient }: any) {
|
||||||
const { theme, isMobile, modalStyle, handleDelete } = useCommonHooks();
|
const { theme, handleDelete } = useCommonHooks();
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
|
|
||||||
@@ -38,26 +38,11 @@ function DebouncedWolClient({ wolClient }: any) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
||||||
<Modal.Root
|
<DeleteItemModal
|
||||||
size={'60%'}
|
modalOpened={modalOpened}
|
||||||
className={modalClasses.helpModal}
|
handleClose={closeModal}
|
||||||
classNames={modalClasses}
|
title={'Delete WoL Client'}
|
||||||
opened={modalOpened}
|
body={
|
||||||
fullScreen={isMobile}
|
|
||||||
onClose={() => {
|
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
style={modalStyle}
|
|
||||||
closeOnEscape
|
|
||||||
closeOnClickOutside
|
|
||||||
>
|
|
||||||
<Modal.Overlay />
|
|
||||||
<Modal.Content>
|
|
||||||
<Modal.Header>
|
|
||||||
<Modal.Title>Delete WoL Client</Modal.Title>
|
|
||||||
<Modal.CloseButton />
|
|
||||||
</Modal.Header>
|
|
||||||
<Modal.Body pb={'2rem'}>
|
|
||||||
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
||||||
<Text>Are you sure you want to delete this WoL Client?</Text>
|
<Text>Are you sure you want to delete this WoL Client?</Text>
|
||||||
<Text
|
<Text
|
||||||
@@ -94,9 +79,8 @@ function DebouncedWolClient({ wolClient }: any) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal.Body>
|
}
|
||||||
</Modal.Content>
|
/>
|
||||||
</Modal.Root>
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
color={theme.primaryColor}
|
color={theme.primaryColor}
|
||||||
bd={`solid 1px ${theme.borderColor}`}
|
bd={`solid 1px ${theme.borderColor}`}
|
||||||
@@ -110,7 +94,7 @@ function DebouncedWolClient({ wolClient }: any) {
|
|||||||
openModal();
|
openModal();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconTrash />
|
<FiTrash />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Group w={'100%'} justify='center'>
|
<Group w={'100%'} justify='center'>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Card,
|
|
||||||
Divider,
|
Divider,
|
||||||
Grid,
|
Grid,
|
||||||
GridCol,
|
GridCol,
|
||||||
Group,
|
Group,
|
||||||
Modal,
|
|
||||||
Popover,
|
Popover,
|
||||||
Stack,
|
Stack,
|
||||||
TextInput,
|
TextInput,
|
||||||
@@ -13,29 +11,36 @@ import {
|
|||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { cardClasses, modalClasses, textInputClasses } from 'styles';
|
import { textInputClasses } from 'styles';
|
||||||
import type { WolClient } from 'types';
|
import type { WolClient } from 'types';
|
||||||
|
import AddItemModal from '../Shared/AddItemModal';
|
||||||
import SettingsHeader from '../Shared/SettingsHeader';
|
import SettingsHeader from '../Shared/SettingsHeader';
|
||||||
import DebouncedWolClient from './DebouncedWolClient';
|
import DebouncedWolClient from './DebouncedWolClient';
|
||||||
import WolClientSettingsItem from './WolClientSettingsItem';
|
import WolClientSettingsItem from './WolClientSettingsItem';
|
||||||
|
|
||||||
const WolClientSettings = () => {
|
const WolClientSettings = () => {
|
||||||
|
const defaultWolClient: WolClient = {
|
||||||
|
id: undefined,
|
||||||
|
hostname: '',
|
||||||
|
macAddress: '',
|
||||||
|
};
|
||||||
const endpoint = 'api/wolClients';
|
const endpoint = 'api/wolClients';
|
||||||
const { data: wolClientsData, isFetched: wolClientsIsFetched } = useQueryAPI({
|
const { data: wolClientsData, isFetched: wolClientsIsFetched } = useQueryAPI({
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
});
|
});
|
||||||
const [wolClients, setWolClients] = useState<WolClient[]>([]);
|
const [wolClients, setWolClients] = useState<WolClient[]>([]);
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const { isMobile, modalStyle } = useCommonHooks();
|
const { isMobile } = useCommonHooks();
|
||||||
const [newWolClient, setNewWolClient] = useState<WolClient>({
|
const [newWolClient, setNewWolClient] = useState<WolClient>(defaultWolClient);
|
||||||
id: undefined,
|
|
||||||
hostname: '',
|
|
||||||
macAddress: '',
|
|
||||||
});
|
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setNewWolClient(defaultWolClient);
|
||||||
|
closeModal();
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (wolClientsData && wolClientsIsFetched) {
|
if (wolClientsData && wolClientsIsFetched) {
|
||||||
setWolClients(
|
setWolClients(
|
||||||
@@ -48,27 +53,11 @@ const WolClientSettings = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
<Modal.Root
|
<AddItemModal
|
||||||
size={'60%'}
|
modalOpened={modalOpened}
|
||||||
className={modalClasses.helpModal}
|
handleClose={handleClose}
|
||||||
classNames={modalClasses}
|
title={'Add a new WoL Client'}
|
||||||
opened={modalOpened}
|
body={
|
||||||
fullScreen={isMobile}
|
|
||||||
onClose={() => {
|
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
style={modalStyle}
|
|
||||||
closeOnEscape
|
|
||||||
closeOnClickOutside
|
|
||||||
>
|
|
||||||
<Modal.Overlay />
|
|
||||||
<Modal.Content>
|
|
||||||
<Modal.Header>
|
|
||||||
<Modal.Title>Add a new WoL Client</Modal.Title>
|
|
||||||
<Modal.CloseButton />
|
|
||||||
</Modal.Header>
|
|
||||||
<Modal.Body pb={'2rem'}>
|
|
||||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
|
||||||
<Stack gap={0} w={'100%'} align='center'>
|
<Stack gap={0} w={'100%'} align='center'>
|
||||||
<Group w={'100%'} justify='center'>
|
<Group w={'100%'} justify='center'>
|
||||||
<TextInput
|
<TextInput
|
||||||
@@ -127,14 +116,12 @@ const WolClientSettings = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Card>
|
}
|
||||||
</Modal.Body>
|
/>
|
||||||
</Modal.Content>
|
|
||||||
</Modal.Root>
|
|
||||||
<SettingsHeader
|
<SettingsHeader
|
||||||
setDragging={undefined}
|
setDragging={undefined}
|
||||||
openModal={openModal}
|
openModal={openModal}
|
||||||
title={'Search Providers'}
|
title={'WoL Clients'}
|
||||||
tooltip={{
|
tooltip={{
|
||||||
title: 'Wake on Lan clients can be configured here.',
|
title: 'Wake on Lan clients can be configured here.',
|
||||||
highlightList: ['Clients', 'homepage'],
|
highlightList: ['Clients', 'homepage'],
|
||||||
|
|||||||
Reference in New Issue
Block a user