Files
TriggerFrontend/src/pages/settings/components/Messages/Messages.tsx
2025-06-18 18:10:11 -05:00

157 lines
4.4 KiB
TypeScript

import { Button, Divider, Grid, GridCol, Group, Stack, TextInput } from '@mantine/core';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react';
import { textInputClasses } from 'styles';
import type { Message } from 'types';
import AddItemModal from '../Shared/AddItemModal';
import NoItemsFound from '../Shared/NoItemsFound';
import SettingsHeader from '../Shared/SettingsHeader';
import DebouncedMessage from './DebouncedMessage';
const MessageSettings = () => {
const endpoint = 'api/messages';
const { data: messageData, isFetched: isMessagesFetched } = useQueryAPI({
endpoint: endpoint,
});
const { isMobile } = 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);
const [isLoading, setIsLoading] = useState(false);
const handleClose = () => {
setNewMessage('');
setNewMessageError('');
closeModal();
};
useEffect(() => {
if (messageData && isMessagesFetched) {
setMessages(
messageData.filter((m: Message) =>
m.message.toLowerCase().includes(debouncedSearch.toLowerCase()),
),
);
}
if (debouncedSearch === searchValue) {
setIsLoading(false);
}
}, [messageData, isMessagesFetched, debouncedSearch]);
useEffect(() => {
if (Object.keys(debounced).length) {
mutateAsync({ method: 'PATCH', endpoint: endpoint, body: debounced });
}
}, [debounced]);
return (
<Stack w={'100%'}>
<SettingsHeader
setDragging={undefined}
openModal={openModal}
title={'Messages'}
tooltip={{
title: 'These custom messages will be displayed in the header on the homepage.',
highlightList: [
'$firstName',
'$lastName',
'$^firstName',
'$^lastName',
'messages',
],
description:
'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.',
}}
searchValue={searchValue}
setSearchValue={setSearchValue}
searchPlaceholder={'Search Message content...'}
isLoading={isLoading}
setIsLoading={setIsLoading}
/>
<AddItemModal
modalOpened={modalOpened}
handleClose={handleClose}
title={'Add a new message'}
body={
<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 },
}).then(handleClose);
} else {
setNewMessageError('Please enter a message');
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={handleClose}
>
Cancel
</Button>
</Group>
</Stack>
}
/>
<Stack
mt={isMobile ? '10rem' : '6rem'}
mb={isMobile ? '6rem' : '1rem'}
w={'100%'}
align='center'
>
<Grid w={'75%'}>
{messages.length > 0 ? (
messages?.map((message: Message) => (
<GridCol span={isMobile ? 12 : 6} key={message.id}>
<DebouncedMessage
label={`ID# ${message.id}`}
message={message}
setMessage={setMessage}
/>
</GridCol>
))
) : (
<GridCol
w={'100%'}
span={12}
style={{ display: 'flex', justifyContent: 'center' }}
>
<NoItemsFound />
</GridCol>
)}
</Grid>
</Stack>
</Stack>
);
};
export default MessageSettings;