New settings pages
This commit is contained in:
@@ -1,61 +0,0 @@
|
||||
import type { MRT_ColumnDef } from 'mantine-react-table';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export function PersonalizationColumns() {
|
||||
const columns = useMemo<MRT_ColumnDef<any>[]>(
|
||||
() => [
|
||||
{
|
||||
accessorFn: (row: any) => {
|
||||
if (row.firstName) {
|
||||
return `${row.firstName}`;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
id: 'firstName',
|
||||
header: 'First Name',
|
||||
size: 50,
|
||||
Cell: ({ renderedCellValue }) => renderedCellValue,
|
||||
Header: ({ column }) => column.columnDef.header,
|
||||
},
|
||||
{
|
||||
accessorFn: (row: any) => {
|
||||
if (row.lastName) {
|
||||
return `${row.lastName}`;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
id: 'lastName',
|
||||
header: 'Last Name',
|
||||
Cell: ({ renderedCellValue }) => renderedCellValue,
|
||||
Header: ({ column }) => column.columnDef.header,
|
||||
},
|
||||
{
|
||||
accessorFn: (row: any) => {
|
||||
if (row.email) {
|
||||
return `${row.email}`;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
id: 'email',
|
||||
header: 'Email',
|
||||
Cell: ({ renderedCellValue }) => renderedCellValue,
|
||||
Header: ({ column }) => column.columnDef.header,
|
||||
},
|
||||
{
|
||||
accessorFn: (row: any) => {
|
||||
if (row.physicalAddress) {
|
||||
return `${row.physicalAddress}`;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
id: 'physicalAddress',
|
||||
header: 'Address',
|
||||
Cell: ({ renderedCellValue }) => renderedCellValue,
|
||||
Header: ({ column }) => column.columnDef.header,
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
|
||||
return columns;
|
||||
}
|
||||
@@ -1,15 +1,18 @@
|
||||
import { Divider, Group, Modal, Stack } from '@mantine/core';
|
||||
import { Divider, Modal, Stack } from '@mantine/core';
|
||||
import { useCommonHooks } from 'hooks';
|
||||
import { modalClasses } from 'styles';
|
||||
import HintItem from './HintItem';
|
||||
import HelpSection from './HelpSection';
|
||||
|
||||
export function HelpModal({
|
||||
setSearchValue,
|
||||
setProviderLabel,
|
||||
setProviderURL,
|
||||
providerModalOpened,
|
||||
closeProviderModal,
|
||||
applicationData,
|
||||
providerData,
|
||||
}: any) {
|
||||
const { theme, setSearchValue, setProviderLabel, setProviderURL } = useCommonHooks();
|
||||
const { theme } = useCommonHooks();
|
||||
return (
|
||||
<Modal.Root
|
||||
size={'60%'}
|
||||
@@ -17,10 +20,10 @@ export function HelpModal({
|
||||
classNames={modalClasses}
|
||||
opened={providerModalOpened}
|
||||
onClose={() => {
|
||||
closeProviderModal();
|
||||
setSearchValue('');
|
||||
setProviderLabel('Google Search');
|
||||
setProviderURL('https://www.google.com/search?q=');
|
||||
closeProviderModal();
|
||||
}}
|
||||
style={{
|
||||
'--color-text-pri': theme.primaryColor,
|
||||
@@ -41,67 +44,25 @@ export function HelpModal({
|
||||
</Modal.Header>
|
||||
<Modal.Body pb={'2rem'}>
|
||||
<Stack gap={0} w={'100%'} align='center'>
|
||||
<h3
|
||||
style={{
|
||||
zIndex: 0,
|
||||
padding: '8px',
|
||||
marginTop: 0,
|
||||
marginBottom: -32,
|
||||
borderRadius: '8px',
|
||||
color: theme.backgroundColor,
|
||||
backgroundColor: theme.borderColor,
|
||||
}}
|
||||
>
|
||||
Search Providers
|
||||
</h3>
|
||||
<Divider py={8} color={theme.accentColor} />
|
||||
<Group
|
||||
style={{
|
||||
width: '100%',
|
||||
backgroundColor: theme.searchColor,
|
||||
borderRadius: '8px',
|
||||
padding: '24px',
|
||||
justifyItems: 'center',
|
||||
}}
|
||||
>
|
||||
{providerData?.map((provider: any) => (
|
||||
<HintItem
|
||||
key={provider.prefix}
|
||||
command={provider.prefix}
|
||||
item={provider.name}
|
||||
<HelpSection
|
||||
name={'Search Providers'}
|
||||
items={providerData.map((provider: any) => {
|
||||
return {
|
||||
name: provider.name,
|
||||
command: provider.prefix,
|
||||
};
|
||||
})}
|
||||
/>
|
||||
))}
|
||||
</Group>
|
||||
<h3
|
||||
style={{
|
||||
zIndex: 0,
|
||||
padding: '8px',
|
||||
marginBottom: -32,
|
||||
borderRadius: '8px',
|
||||
color: theme.backgroundColor,
|
||||
backgroundColor: theme.borderColor,
|
||||
}}
|
||||
>
|
||||
Available Applications
|
||||
</h3>
|
||||
<Divider py={8} color={theme.accentColor} />
|
||||
<Group
|
||||
style={{
|
||||
width: '100%',
|
||||
backgroundColor: theme.searchColor,
|
||||
borderRadius: '8px',
|
||||
padding: '32px',
|
||||
justifyItems: 'center',
|
||||
}}
|
||||
>
|
||||
{applicationData?.map((application: any) => (
|
||||
<HintItem
|
||||
key={application.id}
|
||||
command={`!${application.baseUrl.substr(1).toLowerCase()}`}
|
||||
item={application.url}
|
||||
<Divider my={8} color={theme.accentColor} />
|
||||
<HelpSection
|
||||
name={'Available Applications'}
|
||||
items={applicationData.map((application: any) => {
|
||||
return {
|
||||
name: application.url,
|
||||
command: `!${application.baseUrl.substring(1).toLowerCase()}`,
|
||||
};
|
||||
})}
|
||||
/>
|
||||
))}
|
||||
</Group>
|
||||
</Stack>
|
||||
</Modal.Body>
|
||||
</Modal.Content>
|
||||
|
||||
42
src/components/HelpModal/HelpSection.tsx
Normal file
42
src/components/HelpModal/HelpSection.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { Divider, Group } from '@mantine/core';
|
||||
import { useCommonHooks } from 'hooks';
|
||||
import HintItem from './HintItem';
|
||||
|
||||
function HelpSection({ name, items }: any) {
|
||||
const { theme } = useCommonHooks();
|
||||
return (
|
||||
<>
|
||||
<h3
|
||||
style={{
|
||||
zIndex: 0,
|
||||
padding: '8px',
|
||||
marginTop: 0,
|
||||
marginBottom: -32,
|
||||
borderRadius: '8px',
|
||||
color: theme.backgroundColor,
|
||||
backgroundColor: theme.borderColor,
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</h3>
|
||||
<Divider py={8} color={theme.accentColor} />
|
||||
<Group
|
||||
style={{
|
||||
width: '100%',
|
||||
backgroundColor: theme.searchColor,
|
||||
borderRadius: '8px',
|
||||
padding: '24px',
|
||||
justifyItems: 'center',
|
||||
}}
|
||||
>
|
||||
{items
|
||||
?.sort((a: any, b: any) => (a.command > b.command ? 1 : -1))
|
||||
.map((item: any) => (
|
||||
<HintItem key={item.command} command={item.command} name={item.name} />
|
||||
))}
|
||||
</Group>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default HelpSection;
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Group, Text } from '@mantine/core';
|
||||
|
||||
function HintItem({ command, item }: any) {
|
||||
function HintItem({ command, name }: any) {
|
||||
return (
|
||||
<Group
|
||||
gap={0}
|
||||
@@ -31,7 +31,7 @@ function HintItem({ command, item }: any) {
|
||||
borderRadius: '10px',
|
||||
}}
|
||||
>
|
||||
{item}
|
||||
{name}
|
||||
</Text>
|
||||
</Group>
|
||||
);
|
||||
|
||||
120
src/components/Shared/DebouncedMessage.tsx
Normal file
120
src/components/Shared/DebouncedMessage.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import {
|
||||
ActionIcon,
|
||||
Button,
|
||||
Card,
|
||||
Group,
|
||||
Modal,
|
||||
Stack,
|
||||
Text,
|
||||
TextInput,
|
||||
Tooltip,
|
||||
} from '@mantine/core';
|
||||
import { useDisclosure } from '@mantine/hooks';
|
||||
import { IconTrash } from '@tabler/icons-react';
|
||||
import { useCommonHooks } from 'hooks';
|
||||
import { cardClasses, modalClasses, textInputClasses } from 'styles';
|
||||
|
||||
function DebouncedMessage({ label, message, setMessage, handleDelete }: any) {
|
||||
const { theme } = useCommonHooks();
|
||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||
return (
|
||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
||||
<Modal.Root
|
||||
size={'60%'}
|
||||
className={modalClasses.helpModal}
|
||||
classNames={modalClasses}
|
||||
opened={modalOpened}
|
||||
onClose={() => {
|
||||
closeModal();
|
||||
}}
|
||||
style={{
|
||||
'--color-text-pri': theme.primaryColor,
|
||||
'--color-text-acc': theme.accentColor,
|
||||
'--color-background': theme.backgroundColor,
|
||||
'--color-border': theme.borderColor,
|
||||
'--color-search-background': theme.searchColor,
|
||||
'--image-background': `url(${theme.backgroundImage})`,
|
||||
}}
|
||||
closeOnEscape
|
||||
closeOnClickOutside
|
||||
>
|
||||
<Modal.Overlay />
|
||||
<Modal.Content>
|
||||
<Modal.Header>
|
||||
<Modal.Title>Add a new message</Modal.Title>
|
||||
<Modal.CloseButton />
|
||||
</Modal.Header>
|
||||
<Modal.Body pb={'2rem'}>
|
||||
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
|
||||
<Text>Are you sure you want to delete this message?</Text>
|
||||
<Text
|
||||
style={{
|
||||
fontWeight: 'bold',
|
||||
fontSize: '20px',
|
||||
padding: '8px',
|
||||
margin: '8px',
|
||||
borderRadius: '10px',
|
||||
backgroundColor: 'var(--color-text-acc)',
|
||||
color: 'var(--color-background)',
|
||||
}}
|
||||
>{`"${message.message}"`}</Text>
|
||||
<Text c='red'>This action cannot be undone!</Text>
|
||||
<Group pos={'absolute'} bottom={8}>
|
||||
<Button
|
||||
color={'red'}
|
||||
styles={{ label: { color: 'black' } }}
|
||||
onClick={() => {
|
||||
handleDelete(message);
|
||||
closeModal();
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
<Button
|
||||
color={'grey'}
|
||||
styles={{ label: { color: 'black' } }}
|
||||
onClick={() => {
|
||||
closeModal();
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Modal.Body>
|
||||
</Modal.Content>
|
||||
</Modal.Root>
|
||||
<Tooltip
|
||||
color={theme.primaryColor}
|
||||
bd={`solid 1px ${theme.borderColor}`}
|
||||
label={'Delete'}
|
||||
>
|
||||
<ActionIcon
|
||||
pos={'absolute'}
|
||||
right={16}
|
||||
color='red'
|
||||
onClick={() => {
|
||||
openModal();
|
||||
}}
|
||||
>
|
||||
<IconTrash />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
<TextInput
|
||||
label={label}
|
||||
className={textInputClasses.settingsItem}
|
||||
pt={16}
|
||||
classNames={textInputClasses}
|
||||
defaultValue={message.message}
|
||||
onChange={(event) => {
|
||||
setMessage({
|
||||
...message,
|
||||
message: event.target.value,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default DebouncedMessage;
|
||||
@@ -7,6 +7,5 @@ export { ApplicationColumns } from './DataTable/columns/ApplicationColumns';
|
||||
export { BookmarkColumns } from './DataTable/columns/BookmarkColumns';
|
||||
export { CategoryColumns } from './DataTable/columns/CategoryColumns';
|
||||
export { MessagesColumns } from './DataTable/columns/MessagesColumns';
|
||||
export { PersonalizationColumns } from './DataTable/columns/PersonalizationColumns';
|
||||
export { SearchProviderColumns } from './DataTable/columns/SearchProviderColumns';
|
||||
export { WolClientColumns } from './DataTable/columns/WolClientColumns';
|
||||
|
||||
@@ -240,8 +240,12 @@ export default function Search({
|
||||
|
||||
const optionsFilter: OptionsFilter = ({ options, search }) => {
|
||||
const splittedSearch = search.toLowerCase().trim().split(' ');
|
||||
if (splittedSearch[0] === '!') {
|
||||
return apps.map((app: any) => {
|
||||
if (splittedSearch[0].startsWith('!')) {
|
||||
return apps
|
||||
.filter((app: any) =>
|
||||
app.name.toLowerCase().includes(splittedSearch[0].substring(1).toLowerCase()),
|
||||
)
|
||||
.map((app: any) => {
|
||||
return {
|
||||
label: app.name,
|
||||
value: app.baseUrl,
|
||||
@@ -469,6 +473,9 @@ export default function Search({
|
||||
onKeyUp={handleKeyUp}
|
||||
/>
|
||||
<HelpModal
|
||||
setSearchValue={setSearchValue}
|
||||
setProviderLabel={setProviderLabel}
|
||||
setProviderURL={setProviderURL}
|
||||
providerModalOpened={providerModalOpened}
|
||||
applicationData={applicationData}
|
||||
providerData={providerData}
|
||||
|
||||
@@ -13,15 +13,15 @@ import {
|
||||
} from 'react-icons/fi';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { actionIconClasses, tabClasses, textClasses } from 'styles';
|
||||
import Applications from './components/Applications';
|
||||
import Bookmarks from './components/Bookmarks';
|
||||
import Categories from './components/Categories';
|
||||
import Messages from './components/Messages';
|
||||
import Personalization from './components/Personalization';
|
||||
import SearchProviders from './components/SearchProviders';
|
||||
import ThemePlaylists from './components/ThemePlaylists';
|
||||
import Themes from './components/Themes';
|
||||
import WolClients from './components/WolClients';
|
||||
import Applications from './components/Applications/Applications';
|
||||
import Bookmarks from './components/Bookmarks/Bookmarks';
|
||||
import Categories from './components/Categories/Categories';
|
||||
import Messages from './components/Messages/Messages';
|
||||
import Personalization from './components/Personalization/Personalization';
|
||||
import SearchProviders from './components/Search/SearchProviders';
|
||||
import ThemePlaylists from './components/Theming/ThemePlaylists';
|
||||
import Themes from './components/Theming/Themes';
|
||||
import WolClients from './components/WoL/WolClients';
|
||||
|
||||
export function Settings() {
|
||||
const { isMobile } = useCommonHooks();
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Stack, Text } from '@mantine/core';
|
||||
import { CategoryColumns, DataTable } from 'components';
|
||||
import { useQueryAPI } from 'hooks';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { textClasses } from '../../../styles';
|
||||
import { textClasses } from '../../../../styles';
|
||||
const CategorySettings = () => {
|
||||
const endpoint = 'api/categories';
|
||||
const {
|
||||
@@ -1,40 +0,0 @@
|
||||
import { Stack, Text } from '@mantine/core';
|
||||
import { DataTable, MessagesColumns } from 'components';
|
||||
import { useQueryAPI } from 'hooks';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { textClasses } from 'styles';
|
||||
const MessageSettings = () => {
|
||||
const endpoint = 'api/messages';
|
||||
const {
|
||||
data: messageData,
|
||||
isFetching: isMessagesFetching,
|
||||
isFetched: isMessagesFetched,
|
||||
isLoading: isMessagesLoading,
|
||||
} = useQueryAPI({
|
||||
endpoint: 'api/messages',
|
||||
});
|
||||
const [messages, setMessages] = useState<any>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (messageData && isMessagesFetched) {
|
||||
setMessages(messageData);
|
||||
}
|
||||
}, [messageData, isMessagesFetched]);
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
|
||||
Messages
|
||||
</Text>
|
||||
<DataTable
|
||||
tableName='Messages'
|
||||
columns={MessagesColumns()}
|
||||
tableData={messages}
|
||||
isFetching={isMessagesFetching}
|
||||
isLoading={isMessagesLoading}
|
||||
endpoint={endpoint}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
export default MessageSettings;
|
||||
154
src/pages/settings/components/Messages/Messages.tsx
Normal file
154
src/pages/settings/components/Messages/Messages.tsx
Normal file
@@ -0,0 +1,154 @@
|
||||
import {
|
||||
Button,
|
||||
Divider,
|
||||
Grid,
|
||||
GridCol,
|
||||
Group,
|
||||
Modal,
|
||||
Stack,
|
||||
Text,
|
||||
TextInput,
|
||||
} from '@mantine/core';
|
||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||
import DebouncedMessage from 'components/Shared/DebouncedMessage';
|
||||
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FiPlus } from 'react-icons/fi';
|
||||
import { buttonClasses, modalClasses, textClasses, textInputClasses } from 'styles';
|
||||
const MessageSettings = () => {
|
||||
const endpoint = 'api/messages';
|
||||
const {
|
||||
data: messageData,
|
||||
isFetching: isMessagesFetching,
|
||||
isFetched: isMessagesFetched,
|
||||
isLoading: isMessagesLoading,
|
||||
} = useQueryAPI({
|
||||
endpoint: 'api/messages',
|
||||
});
|
||||
const { theme } = useCommonHooks();
|
||||
const { mutateAsync } = useMutationAPI();
|
||||
const [messages, setMessages] = useState<any>([]);
|
||||
const [newMessage, setNewMessage] = useState('');
|
||||
const [newMessageError, setNewMessageError] = useState<string>('');
|
||||
const [message, setMessage] = useState({});
|
||||
const [debounced] = useDebouncedValue(message, 1000);
|
||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||
|
||||
const handleDelete = (message: any) => {
|
||||
mutateAsync({ method: 'DELETE', endpoint: endpoint, body: message });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (messageData && isMessagesFetched) {
|
||||
setMessages(messageData);
|
||||
}
|
||||
}, [messageData, isMessagesFetched]);
|
||||
|
||||
useEffect(() => {
|
||||
if (Object.keys(debounced).length) {
|
||||
mutateAsync({ method: 'PATCH', endpoint: endpoint, body: debounced });
|
||||
}
|
||||
}, [debounced]);
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Modal.Root
|
||||
size={'60%'}
|
||||
className={modalClasses.helpModal}
|
||||
classNames={modalClasses}
|
||||
opened={modalOpened}
|
||||
onClose={() => {
|
||||
closeModal();
|
||||
}}
|
||||
style={{
|
||||
'--color-text-pri': theme.primaryColor,
|
||||
'--color-text-acc': theme.accentColor,
|
||||
'--color-background': theme.backgroundColor,
|
||||
'--color-border': theme.borderColor,
|
||||
'--color-search-background': theme.searchColor,
|
||||
'--image-background': `url(${theme.backgroundImage})`,
|
||||
}}
|
||||
closeOnEscape
|
||||
closeOnClickOutside
|
||||
>
|
||||
<Modal.Overlay />
|
||||
<Modal.Content>
|
||||
<Modal.Header>
|
||||
<Modal.Title>Add a new message</Modal.Title>
|
||||
<Modal.CloseButton />
|
||||
</Modal.Header>
|
||||
<Modal.Body pb={'2rem'}>
|
||||
<Stack gap={0} w={'100%'} align='center'>
|
||||
<TextInput
|
||||
autoFocus
|
||||
w={'75%'}
|
||||
className={textInputClasses.settingsItem}
|
||||
classNames={textInputClasses}
|
||||
onChange={(event) => {
|
||||
setNewMessage(event.target.value);
|
||||
}}
|
||||
error={newMessageError}
|
||||
/>
|
||||
<Divider color='black' my='sm' />
|
||||
<Group pos={'absolute'} bottom={8}>
|
||||
<Button
|
||||
color={'green'}
|
||||
styles={{ label: { color: 'black' } }}
|
||||
onClick={() => {
|
||||
if (newMessage) {
|
||||
mutateAsync({
|
||||
method: 'POST',
|
||||
endpoint: endpoint,
|
||||
body: { message: newMessage },
|
||||
});
|
||||
closeModal();
|
||||
} else {
|
||||
setNewMessageError('Please enter a message');
|
||||
}
|
||||
}}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
<Button
|
||||
color={'red'}
|
||||
styles={{ label: { color: 'black' } }}
|
||||
onClick={() => {
|
||||
closeModal();
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Modal.Body>
|
||||
</Modal.Content>
|
||||
</Modal.Root>
|
||||
<Group align='center'>
|
||||
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
|
||||
Messages
|
||||
</Text>
|
||||
<Button
|
||||
mt={'1.5rem'}
|
||||
className={buttonClasses.tableButton}
|
||||
classNames={buttonClasses}
|
||||
onClick={openModal}
|
||||
>
|
||||
<FiPlus />
|
||||
</Button>
|
||||
</Group>
|
||||
<Grid>
|
||||
{messages?.map((message: any) => (
|
||||
<GridCol span={6} key={message.id}>
|
||||
<DebouncedMessage
|
||||
label={`ID# ${message.id}`}
|
||||
message={message}
|
||||
setMessage={setMessage}
|
||||
handleDelete={handleDelete}
|
||||
/>
|
||||
</GridCol>
|
||||
))}
|
||||
</Grid>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
export default MessageSettings;
|
||||
@@ -1,40 +0,0 @@
|
||||
import { Text } from '@mantine/core';
|
||||
import { DataTable, PersonalizationColumns } from 'components';
|
||||
import { useQueryAPI } from 'hooks';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { textClasses } from 'styles';
|
||||
const PersonalizationSettings = () => {
|
||||
const endpoint = 'api/personalData';
|
||||
const {
|
||||
data: personalData,
|
||||
isFetched: personalIsFetched,
|
||||
isFetching: personalIsFetching,
|
||||
isLoading: personalIsLoading,
|
||||
} = useQueryAPI({
|
||||
endpoint: endpoint,
|
||||
});
|
||||
const [personal, setPersonal] = useState<any>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (personalData && personalIsFetched) {
|
||||
setPersonal(personalData);
|
||||
}
|
||||
}, [personalData, personalIsFetched]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
|
||||
Personalization
|
||||
</Text>
|
||||
<DataTable
|
||||
tableName='Personalization'
|
||||
columns={PersonalizationColumns()}
|
||||
tableData={personal}
|
||||
isFetching={personalIsFetching}
|
||||
isLoading={personalIsLoading}
|
||||
endpoint={endpoint}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default PersonalizationSettings;
|
||||
@@ -0,0 +1,128 @@
|
||||
import { Card, Grid, GridCol, Overlay, Stack, Text, TextInput } from '@mantine/core';
|
||||
import { useDebouncedValue } from '@mantine/hooks';
|
||||
import { useMutationAPI, useQueryAPI } from 'hooks';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { cardClasses, textClasses, textInputClasses } from 'styles';
|
||||
const PersonalizationSettings = () => {
|
||||
const endpoint = 'api/personalData';
|
||||
const {
|
||||
data: personalData,
|
||||
isFetched: personalIsFetched,
|
||||
isFetching: personalIsFetching,
|
||||
} = useQueryAPI({
|
||||
endpoint: endpoint,
|
||||
});
|
||||
const [personal, setPersonal] = useState<any>({});
|
||||
const [update, setUpdate] = useState({});
|
||||
const [debounced] = useDebouncedValue(update, 1000);
|
||||
const { mutateAsync: editRow } = useMutationAPI();
|
||||
useEffect(() => {
|
||||
if (personalData && personalIsFetched) {
|
||||
setPersonal(personalData[0]);
|
||||
}
|
||||
}, [personalData, personalIsFetched]);
|
||||
|
||||
useEffect(() => {
|
||||
if (Object.keys(debounced).length) {
|
||||
setPersonal(update);
|
||||
editRow({ method: 'PATCH', endpoint: endpoint, body: debounced });
|
||||
setUpdate({});
|
||||
}
|
||||
}, [debounced]);
|
||||
|
||||
useEffect(() => {
|
||||
if (update !== personal && Object.keys(update).length) {
|
||||
setPersonal(update);
|
||||
}
|
||||
}, [update]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
|
||||
Personalization
|
||||
</Text>
|
||||
<Stack w={'100%'} align='center'>
|
||||
<Grid w={'75%'} pos={'relative'}>
|
||||
{personalIsFetching && (
|
||||
<Overlay
|
||||
style={{
|
||||
borderRadius: '10px',
|
||||
margin: '-8px',
|
||||
backdropFilter: 'blur(10px) brightness(1.2)',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<GridCol span={4}>
|
||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
||||
<TextInput
|
||||
label={'First Name'}
|
||||
className={textInputClasses.settingsItem}
|
||||
classNames={textInputClasses}
|
||||
defaultValue={personal?.firstName}
|
||||
onChange={(event) => {
|
||||
const updatedPersonal = {
|
||||
...personal,
|
||||
firstName: event.currentTarget.value,
|
||||
};
|
||||
setUpdate(updatedPersonal);
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
</GridCol>
|
||||
<GridCol span={4}>
|
||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
||||
<TextInput
|
||||
label={'Last Name'}
|
||||
className={textInputClasses.settingsItem}
|
||||
classNames={textInputClasses}
|
||||
defaultValue={personal?.lastName}
|
||||
onChange={(event) => {
|
||||
const updatedPersonal = {
|
||||
...personal,
|
||||
lastName: event.currentTarget.value,
|
||||
};
|
||||
setUpdate(updatedPersonal);
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
</GridCol>
|
||||
<GridCol span={4}>
|
||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
||||
<TextInput
|
||||
label={'Email'}
|
||||
className={textInputClasses.settingsItem}
|
||||
classNames={textInputClasses}
|
||||
defaultValue={personal?.email}
|
||||
onChange={(event) => {
|
||||
const updatedPersonal = {
|
||||
...personal,
|
||||
email: event.currentTarget.value,
|
||||
};
|
||||
setUpdate(updatedPersonal);
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
</GridCol>
|
||||
<GridCol span={12}>
|
||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
||||
<TextInput
|
||||
label={'Physical Address'}
|
||||
className={textInputClasses.settingsItem}
|
||||
classNames={textInputClasses}
|
||||
defaultValue={personal?.physicalAddress}
|
||||
onChange={(event) => {
|
||||
const updatedPersonal = {
|
||||
...personal,
|
||||
physicalAddress: event.currentTarget.value,
|
||||
};
|
||||
setUpdate(updatedPersonal);
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
</GridCol>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default PersonalizationSettings;
|
||||
@@ -11,7 +11,7 @@ function ThemeCard({
|
||||
createTheme,
|
||||
allThemes,
|
||||
}: any) {
|
||||
const { data: themePlaylists, isFetched: isThemePlaylistsFetched } = useQueryAPI({
|
||||
const { data: themePlaylists } = useQueryAPI({
|
||||
endpoint: 'api/themePlaylists',
|
||||
});
|
||||
const [hover, setHover] = useState(false);
|
||||
7
src/styles/Card.module.css
Normal file
7
src/styles/Card.module.css
Normal file
@@ -0,0 +1,7 @@
|
||||
.settingsItem {
|
||||
&.root {
|
||||
color: var(--color-text-pri);
|
||||
background-color: transparent;
|
||||
backdrop-filter: blur(10px) brightness(.75) !important;
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
.settingsItem {
|
||||
&.root {
|
||||
.wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
.input {
|
||||
width: 100%;
|
||||
border: none;
|
||||
background-color: var(--color-search-background);
|
||||
color: var(--color-text-pri);
|
||||
font-size: 18px;
|
||||
}
|
||||
.section {
|
||||
color: var(--color-border);
|
||||
width: auto;
|
||||
padding-left: .5rem;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search {
|
||||
&.root {
|
||||
.wrapper {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import actionIconClasses from './ActionIcon.module.css';
|
||||
import buttonClasses from './Button.module.css';
|
||||
import cardClasses from './Card.module.css';
|
||||
import menuClasses from './Menu.module.css';
|
||||
import modalClasses from './Modal.module.css';
|
||||
import multiSelectClasses from './MultiSelect.module.css';
|
||||
@@ -13,6 +14,7 @@ import textInputClasses from './TextInput.module.css';
|
||||
|
||||
export {
|
||||
actionIconClasses,
|
||||
cardClasses,
|
||||
buttonClasses,
|
||||
menuClasses,
|
||||
modalClasses,
|
||||
|
||||
Reference in New Issue
Block a user