Skip to content

Commit

Permalink
Merge pull request #711 from systemli/Disable-Message-Form-when-Ticke…
Browse files Browse the repository at this point in the history
…r-is-not-active

💄 Disable Message Form when Ticker is not active
  • Loading branch information
0x46616c6b authored Feb 2, 2025
2 parents 93c1228 + 0526a88 commit 59c52d0
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 44 deletions.
17 changes: 10 additions & 7 deletions src/components/message/EmojiPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import React, { FC } from 'react'
import data from '@emoji-mart/data'
import Picker from '@emoji-mart/react'
import { Emoji } from './Emoji'
import { Box, IconButton, Popper } from '@mui/material'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faSmile } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { Box, IconButton, Popper } from '@mui/material'
import React, { FC } from 'react'
import palette from '../../theme/palette'
import { Emoji } from './Emoji'

interface Props {
color?: string
disabled: boolean
onChange: (emoji: Emoji) => void
}

const EmojiPicker: FC<Props> = ({ onChange }) => {
const EmojiPicker: FC<Props> = ({ color, disabled, onChange }) => {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null)

const handleChange = (emoji: Emoji) => {
Expand All @@ -25,12 +27,13 @@ const EmojiPicker: FC<Props> = ({ onChange }) => {
}

const open = Boolean(anchorEl)
color = color ?? palette.primary['main']
const id = open ? 'simple-popper' : undefined

return (
<Box>
<IconButton component="span" onClick={handleClick} style={{ marginRight: '8px' }}>
<FontAwesomeIcon color={palette.primary['main']} icon={faSmile} size="xs" />
<IconButton component="span" onClick={handleClick} style={{ marginRight: '8px' }} disabled={disabled}>
<FontAwesomeIcon color={color} icon={faSmile} size="xs" />
</IconButton>
<Popper anchorEl={anchorEl} id={id} open={open}>
<Picker data={data} onClickOutside={() => setAnchorEl(null)} onEmojiSelect={handleChange} theme="light" />
Expand Down
16 changes: 16 additions & 0 deletions src/components/message/MessageForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ describe('MessageForm', () => {
setup({
id: 1,
title: 'ticker',
active: true,
bluesky: { active: false },
mastodon: { active: false },
telegram: { active: false },
Expand All @@ -54,4 +55,19 @@ describe('MessageForm', () => {
expect(api.postMessageApi).toHaveBeenCalledTimes(1)
expect(api.postMessageApi).toHaveBeenCalledWith('', '1', 'Hello, World!', { features: [], type: 'FeatureCollection' }, [])
})

it('should render the component when ticker is inactive', async () => {
setup({
id: 1,
title: 'ticker',
active: false,
bluesky: { active: false },
mastodon: { active: false },
telegram: { active: false },
location: { lat: 0, lon: 0 },
} as Ticker)

expect(screen.getByRole('textbox')).toBeDisabled()
expect(screen.getByRole('button', { name: 'Send' })).toBeDisabled()
})
})
74 changes: 40 additions & 34 deletions src/components/message/MessageForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,43 +115,49 @@ const MessageForm: FC<Props> = ({ ticker }) => {
}, [isSubmitSuccessful, reset])

const message = watch('message')
const disabled = !ticker.active || isSubmitting
const color = disabled ? palette.action.disabled : palette.primary['main']
const placeholder = ticker.active ? 'Write a message' : "You can't post messages to inactive tickers."

return (
<form id="sendMessage" onSubmit={handleSubmit(onSubmit)}>
<FormGroup sx={{ mb: 1 }}>
<TextField
{...register('message', {
required: true,
maxLength: maxLength,
})}
color={errors.message ? 'error' : 'primary'}
error={!!errors.message}
helperText={
errors.message?.type === 'maxLength' ? 'The message is too long.' : errors.message?.type === 'required' ? 'The message is required.' : null
}
multiline
placeholder="Write a message"
rows="3"
/>
</FormGroup>
<Stack alignItems="center" direction="row" justifyContent="space-between">
<Box display="flex">
<Button disabled={isSubmitting} startIcon={<FontAwesomeIcon icon={faPaperPlane} />} sx={{ mr: 1 }} type="submit" variant="outlined">
Send
</Button>
<EmojiPicker onChange={onSelectEmoji} />
<UploadButton onUpload={onUpload} ticker={ticker} />
<IconButton component="span" onClick={() => setMapDialogOpen(true)}>
<FontAwesomeIcon color={palette.primary['main']} icon={faMapLocationDot} size="xs" />
</IconButton>
<MessageMapModal map={map} onChange={onMapUpdate} onClose={() => setMapDialogOpen(false)} open={mapDialogOpen} ticker={ticker} />
<Box>
<form id="sendMessage" onSubmit={handleSubmit(onSubmit)}>
<FormGroup sx={{ mb: 1 }}>
<TextField
{...register('message', {
required: true,
maxLength: maxLength,
})}
color={errors.message ? 'error' : 'primary'}
error={!!errors.message}
helperText={
errors.message?.type === 'maxLength' ? 'The message is too long.' : errors.message?.type === 'required' ? 'The message is required.' : null
}
multiline
placeholder={placeholder}
rows="3"
disabled={!ticker.active}
/>
</FormGroup>
<Stack alignItems="center" direction="row" justifyContent="space-between">
<Box display="flex">
<Button disabled={disabled} startIcon={<FontAwesomeIcon icon={faPaperPlane} />} sx={{ mr: 1 }} type="submit" variant="outlined">
Send
</Button>
<EmojiPicker color={color} disabled={disabled} onChange={onSelectEmoji} />
<UploadButton color={color} disabled={disabled} onUpload={onUpload} ticker={ticker} />
<IconButton disabled={disabled} component="span" onClick={() => setMapDialogOpen(true)}>
<FontAwesomeIcon color={color} icon={faMapLocationDot} size="xs" />
</IconButton>
<MessageMapModal map={map} onChange={onMapUpdate} onClose={() => setMapDialogOpen(false)} open={mapDialogOpen} ticker={ticker} />
</Box>
<MessageFormCounter letterCount={message?.length || 0} maxLength={maxLength} />
</Stack>
<Box>
<AttachmentsPreview attachments={attachments} onDelete={onUploadDelete} />
</Box>
<MessageFormCounter letterCount={message?.length || 0} maxLength={maxLength} />
</Stack>
<Box>
<AttachmentsPreview attachments={attachments} onDelete={onUploadDelete} />
</Box>
</form>
</form>
</Box>
)
}

Expand Down
10 changes: 7 additions & 3 deletions src/components/message/UploadButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import useAuth from '../../contexts/useAuth'
import palette from '../../theme/palette'

interface Props {
color?: string
disabled: boolean
ticker: Ticker
onUpload: (uploads: Upload[]) => void
}

const UploadButton: FC<Props> = ({ onUpload, ticker }) => {
const UploadButton: FC<Props> = ({ color, disabled, onUpload, ticker }) => {
const ref = createRef<HTMLInputElement>()
const { token } = useAuth()

Expand All @@ -39,10 +41,12 @@ const UploadButton: FC<Props> = ({ onUpload, ticker }) => {
})
}

color = color ?? palette.primary['main']

return (
<>
<IconButton onClick={refClick} sx={{ mr: 1 }}>
<FontAwesomeIcon color={palette.primary['main']} icon={faImages} size="xs" />
<IconButton onClick={refClick} sx={{ mr: 1 }} disabled={disabled}>
<FontAwesomeIcon color={color} icon={faImages} size="xs" />
</IconButton>
<input ref={ref} hidden multiple onChange={handleUpload} type="file" />
</>
Expand Down

0 comments on commit 59c52d0

Please sign in to comment.