Files
TriggerFrontend/src/pages/settings/components/Messages/Messages.tsx
2025-03-28 14:25:33 -05:00

216 lines
6.0 KiB
TypeScript

import {
ActionIcon,
Button,
Card,
Divider,
Grid,
GridCol,
Group,
Highlight,
Modal,
Popover,
Stack,
Text,
TextInput,
} from '@mantine/core';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import DebouncedMessage from 'pages/settings/components/Messages/DebouncedMessage';
import { useEffect, useState } from 'react';
import { FiHelpCircle, FiPlus } from 'react-icons/fi';
import {
actionIconClasses,
buttonClasses,
cardClasses,
modalClasses,
textClasses,
textInputClasses,
} from 'styles';
import type { Message } from 'types';
const MessageSettings = () => {
const endpoint = 'api/messages';
const { data: messageData, isFetched: isMessagesFetched } = useQueryAPI({
endpoint: endpoint,
});
const { theme, isMobile, modalStyle } = useCommonHooks();
const { mutateAsync } = useMutationAPI();
const [messages, setMessages] = useState<Message[]>([]);
const [newMessage, setNewMessage] = useState('');
const [newMessageError, setNewMessageError] = useState<string>('');
const [message, setMessage] = useState({});
const [debounced] = useDebouncedValue(message, 1000);
const [searchValue, setSearchValue] = useState('');
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
useEffect(() => {
if (messageData && isMessagesFetched) {
setMessages(
messageData.filter((m: Message) =>
m.message.toLowerCase().includes(debouncedSearch.toLowerCase()),
),
);
}
}, [messageData, isMessagesFetched, debouncedSearch]);
useEffect(() => {
if (Object.keys(debounced).length) {
mutateAsync({ method: 'PATCH', endpoint: endpoint, body: debounced });
}
}, [debounced]);
return (
<Stack w={'100%'}>
<Modal.Root
size={'60%'}
className={modalClasses.helpModal}
classNames={modalClasses}
opened={modalOpened}
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'>
<TextInput
label='Message text'
autoFocus={!isMobile}
w={'75%'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
onChange={(event) => {
setNewMessage(event.target.value);
}}
error={newMessageError}
/>
<Divider color='black' my='lg' />
<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>
</Card>
</Modal.Body>
</Modal.Content>
</Modal.Root>
<Group align='center' justify='center' mt={'1rem'}>
<Group w={isMobile ? undefined : '100%'}>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
Messages
</Text>
<Popover withArrow withOverlay withinPortal={false}>
<Popover.Target>
<ActionIcon
className={actionIconClasses.settingsTooltip}
classNames={actionIconClasses}
>
<FiHelpCircle />
</ActionIcon>
</Popover.Target>
<Popover.Dropdown
style={{
color: theme.primaryColor,
backgroundColor: theme.backgroundColor,
width: '500px',
}}
>
<Stack>
<Text className={textClasses.settingsTooltip} classNames={textClasses}>
{
'These custom messages will be displayed in the header on the homepage.'
}
</Text>
<Highlight
highlight={['$firstName', '$lastName', '$^firstName', '$^lastName']}
className={textClasses.settingsTooltip}
classNames={textClasses}
highlightStyles={{
backgroundImage:
'linear-gradient(45deg, var(--color-text-acc), var(--color-text-pri))',
fontWeight: 700,
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
}}
>
{
'Built-in variables include $firstName and $lastName. To force the text to upper case, use a carat (^), ie, $^firstName. Messages may contain any unicode text.'
}
</Highlight>
</Stack>
</Popover.Dropdown>
</Popover>
<Button
className={buttonClasses.tableButton}
classNames={buttonClasses}
onClick={openModal}
>
<FiPlus />
</Button>
</Group>
<TextInput
w={isMobile ? undefined : '35%'}
pos={isMobile ? undefined : 'absolute'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
autoFocus={!isMobile}
placeholder='Search...'
value={searchValue}
onInput={(event: any) => {
setSearchValue(event.target.value);
}}
/>
</Group>
<Stack w={'100%'} align='center'>
<Grid w={'75%'}>
{messages?.map((message: Message) => (
<GridCol span={isMobile ? 12 : 6} key={message.id}>
<DebouncedMessage
label={`ID# ${message.id}`}
message={message}
setMessage={setMessage}
/>
</GridCol>
))}
</Grid>
</Stack>
</Stack>
);
};
export default MessageSettings;