2022-03-27 15:10:47 +02:00
import * as React from 'react' ;
2022-03-30 20:11:18 +02:00
import { useEffect , useRef , useState } from 'react' ;
2022-03-27 15:10:47 +02:00
import { NotificationItem } from "./Notifications" ;
import theme from "./theme" ;
2022-04-01 17:34:53 +02:00
import { Checkbox , Chip , FormControl , FormControlLabel , InputLabel , Link , Select , useMediaQuery } from "@mui/material" ;
2022-03-27 15:10:47 +02:00
import TextField from "@mui/material/TextField" ;
import priority1 from "../img/priority-1.svg" ;
import priority2 from "../img/priority-2.svg" ;
import priority3 from "../img/priority-3.svg" ;
import priority4 from "../img/priority-4.svg" ;
import priority5 from "../img/priority-5.svg" ;
import Dialog from "@mui/material/Dialog" ;
import DialogTitle from "@mui/material/DialogTitle" ;
import DialogContent from "@mui/material/DialogContent" ;
import Button from "@mui/material/Button" ;
import Typography from "@mui/material/Typography" ;
2022-03-29 04:54:27 +02:00
import IconButton from "@mui/material/IconButton" ;
import InsertEmoticonIcon from '@mui/icons-material/InsertEmoticon' ;
import { Close } from "@mui/icons-material" ;
import MenuItem from "@mui/material/MenuItem" ;
2022-04-01 17:34:53 +02:00
import { basicAuth , formatBytes , shortUrl , splitTopicUrl , validTopicUrl } from "../app/utils" ;
2022-03-29 21:22:26 +02:00
import Box from "@mui/material/Box" ;
2022-04-04 14:40:54 +02:00
import AttachmentIcon from "./AttachmentIcon" ;
2022-03-29 21:22:26 +02:00
import DialogFooter from "./DialogFooter" ;
import api from "../app/Api" ;
2022-04-01 14:41:45 +02:00
import userManager from "../app/UserManager" ;
2022-04-04 16:04:01 +02:00
import EmojiPicker from "./EmojiPicker" ;
2022-03-27 15:10:47 +02:00
const SendDialog = ( props ) => {
2022-04-03 18:39:52 +02:00
const [ topicUrl , setTopicUrl ] = useState ( "" ) ;
2022-04-04 01:51:32 +02:00
const [ message , setMessage ] = useState ( "" ) ;
2022-03-27 15:10:47 +02:00
const [ title , setTitle ] = useState ( "" ) ;
const [ tags , setTags ] = useState ( "" ) ;
2022-03-29 04:54:27 +02:00
const [ priority , setPriority ] = useState ( 3 ) ;
const [ clickUrl , setClickUrl ] = useState ( "" ) ;
const [ attachUrl , setAttachUrl ] = useState ( "" ) ;
2022-03-29 21:22:26 +02:00
const [ attachFile , setAttachFile ] = useState ( null ) ;
2022-03-29 04:54:27 +02:00
const [ filename , setFilename ] = useState ( "" ) ;
2022-03-31 18:03:36 +02:00
const [ filenameEdited , setFilenameEdited ] = useState ( false ) ;
2022-03-27 15:10:47 +02:00
const [ email , setEmail ] = useState ( "" ) ;
2022-03-29 04:54:27 +02:00
const [ delay , setDelay ] = useState ( "" ) ;
2022-04-01 17:34:53 +02:00
const [ publishAnother , setPublishAnother ] = useState ( false ) ;
2022-03-29 04:54:27 +02:00
2022-04-03 18:39:52 +02:00
const [ showTopicUrl , setShowTopicUrl ] = useState ( "" ) ;
2022-03-29 04:54:27 +02:00
const [ showClickUrl , setShowClickUrl ] = useState ( false ) ;
const [ showAttachUrl , setShowAttachUrl ] = useState ( false ) ;
const [ showEmail , setShowEmail ] = useState ( false ) ;
const [ showDelay , setShowDelay ] = useState ( false ) ;
2022-03-30 15:57:22 +02:00
const showAttachFile = ! ! attachFile && ! showAttachUrl ;
2022-03-29 21:22:26 +02:00
const attachFileInput = useRef ( ) ;
2022-04-03 18:39:52 +02:00
const [ attachFileError , setAttachFileError ] = useState ( "" ) ;
2022-03-30 15:57:22 +02:00
2022-04-02 23:06:26 +02:00
const [ activeRequest , setActiveRequest ] = useState ( null ) ;
2022-04-04 01:51:32 +02:00
const [ status , setStatus ] = useState ( "" ) ;
2022-04-02 23:06:26 +02:00
const disabled = ! ! activeRequest ;
2022-04-04 16:04:01 +02:00
const [ emojiPickerAnchorEl , setEmojiPickerAnchorEl ] = useState ( null ) ;
2022-04-04 04:42:56 +02:00
const [ dropZone , setDropZone ] = useState ( false ) ;
2022-04-03 18:39:52 +02:00
const [ sendButtonEnabled , setSendButtonEnabled ] = useState ( true ) ;
2022-03-29 21:22:26 +02:00
2022-04-04 04:42:56 +02:00
const open = ! ! props . openMode ;
2022-03-27 15:10:47 +02:00
const fullScreen = useMediaQuery ( theme . breakpoints . down ( 'sm' ) ) ;
2022-04-02 23:06:26 +02:00
2022-04-04 04:42:56 +02:00
useEffect ( ( ) => {
window . addEventListener ( 'dragenter' , ( ) => {
props . onDragEnter ( ) ;
setDropZone ( true ) ;
} ) ;
} , [ ] ) ;
2022-04-03 18:39:52 +02:00
useEffect ( ( ) => {
setTopicUrl ( props . topicUrl ) ;
setShowTopicUrl ( props . topicUrl === "" )
} , [ props . topicUrl ] ) ;
useEffect ( ( ) => {
2022-04-04 01:51:32 +02:00
const valid = validTopicUrl ( topicUrl ) && ! attachFileError ;
setSendButtonEnabled ( valid ) ;
2022-04-03 18:39:52 +02:00
} , [ topicUrl , attachFileError ] ) ;
2022-04-02 23:06:26 +02:00
2022-04-04 01:51:32 +02:00
useEffect ( ( ) => {
setMessage ( props . message ) ;
} , [ props . message ] ) ;
2022-03-27 15:10:47 +02:00
const handleSubmit = async ( ) => {
2022-03-29 21:22:26 +02:00
const { baseUrl , topic } = splitTopicUrl ( topicUrl ) ;
2022-04-01 14:41:45 +02:00
const headers = { } ;
2022-03-29 21:22:26 +02:00
if ( title . trim ( ) ) {
2022-04-01 14:41:45 +02:00
headers [ "X-Title" ] = title . trim ( ) ;
2022-03-29 21:22:26 +02:00
}
if ( tags . trim ( ) ) {
2022-04-01 14:41:45 +02:00
headers [ "X-Tags" ] = tags . trim ( ) ;
2022-03-29 21:22:26 +02:00
}
if ( priority && priority !== 3 ) {
2022-04-01 14:41:45 +02:00
headers [ "X-Priority" ] = priority . toString ( ) ;
2022-03-29 21:22:26 +02:00
}
if ( clickUrl . trim ( ) ) {
2022-04-01 14:41:45 +02:00
headers [ "X-Click" ] = clickUrl . trim ( ) ;
2022-03-29 21:22:26 +02:00
}
if ( attachUrl . trim ( ) ) {
2022-04-01 14:41:45 +02:00
headers [ "X-Attach" ] = attachUrl . trim ( ) ;
2022-03-29 21:22:26 +02:00
}
if ( filename . trim ( ) ) {
2022-04-01 14:41:45 +02:00
headers [ "X-Filename" ] = filename . trim ( ) ;
2022-03-29 21:22:26 +02:00
}
if ( email . trim ( ) ) {
2022-04-01 14:41:45 +02:00
headers [ "X-Email" ] = email . trim ( ) ;
2022-03-29 21:22:26 +02:00
}
if ( delay . trim ( ) ) {
2022-04-01 14:41:45 +02:00
headers [ "X-Delay" ] = delay . trim ( ) ;
2022-03-29 21:22:26 +02:00
}
2022-04-01 14:41:45 +02:00
if ( attachFile && message . trim ( ) ) {
headers [ "X-Message" ] = message . replaceAll ( "\n" , "\\n" ) . trim ( ) ;
}
const body = ( attachFile ) ? attachFile : message ;
2022-03-29 21:22:26 +02:00
try {
2022-04-01 14:41:45 +02:00
const user = await userManager . get ( baseUrl ) ;
if ( user ) {
headers [ "Authorization" ] = basicAuth ( user . username , user . password ) ;
}
const progressFn = ( ev ) => {
if ( ev . loaded > 0 && ev . total > 0 ) {
const percent = Math . round ( ev . loaded * 100.0 / ev . total ) ;
2022-04-04 01:51:32 +02:00
setStatus ( ` Uploading ${ formatBytes ( ev . loaded ) } / ${ formatBytes ( ev . total ) } ( ${ percent } %) ... ` ) ;
2022-04-01 14:41:45 +02:00
} else {
2022-04-04 01:51:32 +02:00
setStatus ( ` Uploading ... ` ) ;
2022-04-01 14:41:45 +02:00
}
} ;
const request = api . publishXHR ( baseUrl , topic , body , headers , progressFn ) ;
2022-04-02 23:06:26 +02:00
setActiveRequest ( request ) ;
2022-04-01 14:41:45 +02:00
await request ;
2022-04-01 17:34:53 +02:00
if ( ! publishAnother ) {
props . onClose ( ) ;
} else {
2022-04-04 01:51:32 +02:00
setStatus ( "Message published" ) ;
setActiveRequest ( null ) ;
2022-04-01 17:34:53 +02:00
}
2022-03-29 21:22:26 +02:00
} catch ( e ) {
2022-04-04 01:51:32 +02:00
setStatus ( < Typography sx = { { color : 'error.main' , maxWidth : "400px" } } > { e } < / T y p o g r a p h y > ) ;
setActiveRequest ( null ) ;
2022-03-29 21:22:26 +02:00
}
} ;
2022-04-02 23:06:26 +02:00
2022-04-03 18:39:52 +02:00
const checkAttachmentLimits = async ( file ) => {
try {
const { baseUrl } = splitTopicUrl ( topicUrl ) ;
const stats = await api . userStats ( baseUrl ) ;
console . log ( ` [SendDialog] Visitor attachment limits ` , stats ) ;
const fileSizeLimit = stats . attachmentFileSizeLimit ? ? 0 ;
const remainingBytes = stats . visitorAttachmentBytesRemaining ? ? 0 ;
2022-04-04 01:51:32 +02:00
const fileSizeLimitReached = fileSizeLimit > 0 && file . size > fileSizeLimit ;
const quotaReached = remainingBytes > 0 && file . size > remainingBytes ;
if ( fileSizeLimitReached && quotaReached ) {
2022-04-04 04:58:44 +02:00
return setAttachFileError ( ` exceeds ${ formatBytes ( fileSizeLimit ) } file limit, and quota reached, ${ formatBytes ( remainingBytes ) } remaining ` ) ;
2022-04-04 01:51:32 +02:00
} else if ( fileSizeLimitReached ) {
return setAttachFileError ( ` exceeds ${ formatBytes ( fileSizeLimit ) } file limit ` ) ;
} else if ( quotaReached ) {
2022-04-04 04:58:44 +02:00
return setAttachFileError ( ` quota reached, ${ formatBytes ( remainingBytes ) } remaining ` ) ;
2022-04-03 18:39:52 +02:00
}
setAttachFileError ( "" ) ;
} catch ( e ) {
console . log ( ` [SendDialog] Retrieving attachment limits failed ` , e ) ;
setAttachFileError ( "" ) ; // Reset error (rely on server-side checking)
}
} ;
2022-03-29 21:22:26 +02:00
const handleAttachFileClick = ( ) => {
attachFileInput . current . click ( ) ;
} ;
2022-04-02 23:06:26 +02:00
2022-04-03 18:39:52 +02:00
const handleAttachFileChanged = async ( ev ) => {
await updateAttachFile ( ev . target . files [ 0 ] ) ;
2022-03-27 15:10:47 +02:00
} ;
2022-04-02 23:06:26 +02:00
2022-04-03 18:39:52 +02:00
const handleAttachFileDrop = async ( ev ) => {
2022-04-02 23:06:26 +02:00
ev . preventDefault ( ) ;
2022-04-04 04:42:56 +02:00
setDropZone ( false ) ;
2022-04-03 18:39:52 +02:00
await updateAttachFile ( ev . dataTransfer . files [ 0 ] ) ;
} ;
const updateAttachFile = async ( file ) => {
2022-04-02 23:06:26 +02:00
setAttachFile ( file ) ;
setFilename ( file . name ) ;
2022-04-04 01:51:32 +02:00
props . onResetOpenMode ( ) ;
2022-04-03 18:39:52 +02:00
await checkAttachmentLimits ( file ) ;
2022-04-02 23:06:26 +02:00
} ;
2022-04-04 01:51:32 +02:00
const handleAttachFileDragLeave = ( ) => {
2022-04-04 04:42:56 +02:00
setDropZone ( false ) ;
2022-04-04 01:51:32 +02:00
if ( props . openMode === SendDialog . OPEN _MODE _DRAG ) {
2022-04-04 04:42:56 +02:00
props . onClose ( ) ; // Only close dialog if it was not open before dragging file in
2022-04-02 23:06:26 +02:00
}
} ;
2022-04-04 16:04:01 +02:00
const handleEmojiClick = ( ev ) => {
setEmojiPickerAnchorEl ( ev . currentTarget ) ;
} ;
const handleEmojiPick = ( emoji ) => {
setTags ( tags => ( tags . trim ( ) ) ? ` ${ tags . trim ( ) } , ${ emoji } ` : emoji ) ;
} ;
const handleEmojiClose = ( ) => {
setEmojiPickerAnchorEl ( null ) ;
} ;
2022-03-27 15:10:47 +02:00
return (
2022-04-04 01:51:32 +02:00
< >
{ dropZone && < DropArea
onDrop = { handleAttachFileDrop }
onDragLeave = { handleAttachFileDragLeave } / >
}
2022-04-04 04:42:56 +02:00
< Dialog maxWidth = "md" open = { open } onClose = { props . onCancel } fullScreen = { fullScreen } >
2022-04-05 01:56:21 +02:00
< DialogTitle > { topicUrl ? ` Publish to ${ shortUrl ( topicUrl ) } ` : "Publish message" } < / D i a l o g T i t l e >
2022-04-04 01:51:32 +02:00
< DialogContent >
{ dropZone && < DropBox / > }
{ showTopicUrl &&
2022-04-05 01:56:21 +02:00
< ClosableRow closable = { ! ! props . topicUrl } disabled = { disabled } onClose = { ( ) => {
2022-04-04 01:51:32 +02:00
setTopicUrl ( props . topicUrl ) ;
setShowTopicUrl ( false ) ;
} } >
< TextField
margin = "dense"
label = "Topic URL"
value = { topicUrl }
onChange = { ev => setTopicUrl ( ev . target . value ) }
disabled = { disabled }
type = "text"
variant = "standard"
fullWidth
required
/ >
< / C l o s a b l e R o w >
}
2022-03-29 04:54:27 +02:00
< TextField
margin = "dense"
2022-04-04 01:51:32 +02:00
label = "Title"
value = { title }
onChange = { ev => setTitle ( ev . target . value ) }
2022-04-01 14:41:45 +02:00
disabled = { disabled }
2022-03-29 04:54:27 +02:00
type = "text"
2022-04-04 01:51:32 +02:00
fullWidth
2022-03-29 04:54:27 +02:00
variant = "standard"
2022-04-04 01:51:32 +02:00
placeholder = "Notification title, e.g. Disk space alert"
2022-03-29 04:54:27 +02:00
/ >
2022-04-04 01:51:32 +02:00
< TextField
2022-03-29 04:54:27 +02:00
margin = "dense"
2022-04-04 01:51:32 +02:00
label = "Message"
placeholder = "Type the main message body here."
value = { message }
onChange = { ev => setMessage ( ev . target . value ) }
disabled = { disabled }
type = "text"
variant = "standard"
rows = { 5 }
fullWidth
autoFocus
multiline
/ >
< div style = { { display : 'flex' } } >
2022-04-04 16:04:01 +02:00
< EmojiPicker
anchorEl = { emojiPickerAnchorEl }
onEmojiPick = { handleEmojiPick }
onClose = { handleEmojiClose }
/ >
< DialogIconButton disabled = { disabled } onClick = { handleEmojiClick } >
< InsertEmoticonIcon / >
< / D i a l o g I c o n B u t t o n >
2022-03-29 04:54:27 +02:00
< TextField
margin = "dense"
2022-04-04 01:51:32 +02:00
label = "Tags"
placeholder = "Comma-separated list of tags, e.g. warning, srv1-backup"
value = { tags }
onChange = { ev => setTags ( ev . target . value ) }
2022-04-01 14:41:45 +02:00
disabled = { disabled }
2022-04-04 01:51:32 +02:00
type = "text"
2022-03-29 04:54:27 +02:00
variant = "standard"
2022-04-04 01:51:32 +02:00
sx = { { flexGrow : 1 , marginRight : 1 } }
2022-03-29 04:54:27 +02:00
/ >
2022-04-04 01:51:32 +02:00
< FormControl
2022-03-31 18:03:36 +02:00
variant = "standard"
2022-03-29 21:22:26 +02:00
margin = "dense"
2022-04-04 01:51:32 +02:00
sx = { { minWidth : 120 , maxWidth : 200 , flexGrow : 1 } }
>
< InputLabel / >
< Select
label = "Priority"
margin = "dense"
value = { priority }
onChange = { ( ev ) => setPriority ( ev . target . value ) }
disabled = { disabled }
>
{ [ 5 , 4 , 3 , 2 , 1 ] . map ( priority =>
< MenuItem key = { ` priorityMenuItem ${ priority } ` } value = { priority } >
< div style = { { display : 'flex' , alignItems : 'center' } } >
< img src = { priorities [ priority ] . file } style = { { marginRight : "8px" } } / >
< div > { priorities [ priority ] . label } < / d i v >
< / d i v >
< / M e n u I t e m >
) }
< / S e l e c t >
< / F o r m C o n t r o l >
< / d i v >
{ showClickUrl &&
< ClosableRow disabled = { disabled } onClose = { ( ) => {
setClickUrl ( "" ) ;
setShowClickUrl ( false ) ;
} } >
< TextField
margin = "dense"
label = "Click URL"
placeholder = "URL that is opened when notification is clicked"
value = { clickUrl }
onChange = { ev => setClickUrl ( ev . target . value ) }
disabled = { disabled }
type = "url"
fullWidth
variant = "standard"
/ >
< / C l o s a b l e R o w >
}
{ showEmail &&
< ClosableRow disabled = { disabled } onClose = { ( ) => {
setEmail ( "" ) ;
setShowEmail ( false ) ;
} } >
< TextField
margin = "dense"
label = "Email"
placeholder = "Address to forward the message to, e.g. phil@example.com"
value = { email }
onChange = { ev => setEmail ( ev . target . value ) }
disabled = { disabled }
type = "email"
variant = "standard"
fullWidth
/ >
< / C l o s a b l e R o w >
}
{ showAttachUrl &&
< ClosableRow disabled = { disabled } onClose = { ( ) => {
setAttachUrl ( "" ) ;
setFilename ( "" ) ;
setFilenameEdited ( false ) ;
setShowAttachUrl ( false ) ;
} } >
< TextField
margin = "dense"
label = "Attachment URL"
placeholder = "Attach file by URL, e.g. https://f-droid.org/F-Droid.apk"
value = { attachUrl }
onChange = { ev => {
const url = ev . target . value ;
setAttachUrl ( url ) ;
if ( ! filenameEdited ) {
try {
const u = new URL ( url ) ;
const parts = u . pathname . split ( "/" ) ;
if ( parts . length > 0 ) {
setFilename ( parts [ parts . length - 1 ] ) ;
}
} catch ( e ) {
// Do nothing
2022-03-31 18:03:36 +02:00
}
}
2022-04-04 01:51:32 +02:00
} }
disabled = { disabled }
type = "url"
variant = "standard"
sx = { { flexGrow : 5 , marginRight : 1 } }
/ >
< TextField
margin = "dense"
label = "Filename"
placeholder = "Attachment filename"
value = { filename }
onChange = { ev => {
setFilename ( ev . target . value ) ;
setFilenameEdited ( true ) ;
} }
disabled = { disabled }
type = "text"
variant = "standard"
sx = { { flexGrow : 1 } }
/ >
< / C l o s a b l e R o w >
}
< input
type = "file"
ref = { attachFileInput }
onChange = { handleAttachFileChanged }
style = { { display : 'none' } }
/ >
{ showAttachFile && < AttachmentBox
file = { attachFile }
filename = { filename }
disabled = { disabled }
error = { attachFileError }
onChangeFilename = { ( f ) => setFilename ( f ) }
onClose = { ( ) => {
setAttachFile ( null ) ;
setAttachFileError ( "" ) ;
setFilename ( "" ) ;
} }
/ > }
{ showDelay &&
< ClosableRow disabled = { disabled } onClose = { ( ) => {
setDelay ( "" ) ;
setShowDelay ( false ) ;
} } >
< TextField
margin = "dense"
label = "Delay"
placeholder = "Delay delivery, e.g. 1649029748, 30m, or tomorrow, 9am"
value = { delay }
onChange = { ev => setDelay ( ev . target . value ) }
disabled = { disabled }
type = "text"
variant = "standard"
fullWidth
/ >
< / C l o s a b l e R o w >
}
< Typography variant = "body1" sx = { { marginTop : 2 , marginBottom : 1 } } >
Other features :
< / T y p o g r a p h y >
< div >
{ ! showClickUrl && < Chip clickable disabled = { disabled } label = "Click URL" onClick = { ( ) => setShowClickUrl ( true ) } sx = { { marginRight : 1 , marginBottom : 1 } } / > }
{ ! showEmail && < Chip clickable disabled = { disabled } label = "Forward to email" onClick = { ( ) => setShowEmail ( true ) } sx = { { marginRight : 1 , marginBottom : 1 } } / > }
{ ! showAttachUrl && ! showAttachFile && < Chip clickable disabled = { disabled } label = "Attach file by URL" onClick = { ( ) => setShowAttachUrl ( true ) } sx = { { marginRight : 1 , marginBottom : 1 } } / > }
{ ! showAttachFile && ! showAttachUrl && < Chip clickable disabled = { disabled } label = "Attach local file" onClick = { ( ) => handleAttachFileClick ( ) } sx = { { marginRight : 1 , marginBottom : 1 } } / > }
{ ! showDelay && < Chip clickable disabled = { disabled } label = "Delay delivery" onClick = { ( ) => setShowDelay ( true ) } sx = { { marginRight : 1 , marginBottom : 1 } } / > }
{ ! showTopicUrl && < Chip clickable disabled = { disabled } label = "Change topic" onClick = { ( ) => setShowTopicUrl ( true ) } sx = { { marginRight : 1 , marginBottom : 1 } } / > }
< / d i v >
< Typography variant = "body1" sx = { { marginTop : 1 , marginBottom : 1 } } >
For examples and a detailed description of all send features , please
refer to the < Link href = "/docs" target = "_blank" > documentation < / L i n k > .
< / T y p o g r a p h y >
< / D i a l o g C o n t e n t >
< DialogFooter status = { status } >
{ activeRequest && < Button onClick = { ( ) => activeRequest . abort ( ) } > Cancel sending < / B u t t o n > }
{ ! activeRequest &&
< >
< FormControlLabel
label = "Publish another"
sx = { { marginRight : 2 } }
control = {
< Checkbox size = "small" checked = { publishAnother } onChange = { ( ev ) => setPublishAnother ( ev . target . checked ) } / >
} / >
< Button onClick = { props . onClose } > Cancel < / B u t t o n >
< Button onClick = { handleSubmit } disabled = { ! sendButtonEnabled } > Send < / B u t t o n >
< / >
}
< / D i a l o g F o o t e r >
< / D i a l o g >
< / >
2022-03-27 15:10:47 +02:00
) ;
} ;
2022-03-29 04:54:27 +02:00
const Row = ( props ) => {
return (
< div style = { { display : 'flex' } } >
{ props . children }
< / d i v >
) ;
} ;
const ClosableRow = ( props ) => {
2022-04-05 01:56:21 +02:00
const closable = ( props . hasOwnProperty ( "closable" ) ) ? props . closable : true ;
2022-03-29 04:54:27 +02:00
return (
< Row >
{ props . children }
2022-04-05 01:56:21 +02:00
{ closable && < DialogIconButton disabled = { props . disabled } onClick = { props . onClose } sx = { { marginLeft : "6px" } } > < Close / > < / D i a l o g I c o n B u t t o n > }
2022-03-29 04:54:27 +02:00
< / R o w >
) ;
} ;
const DialogIconButton = ( props ) => {
2022-03-29 21:22:26 +02:00
const sx = props . sx || { } ;
2022-03-29 04:54:27 +02:00
return (
< IconButton
color = "inherit"
size = "large"
edge = "start"
2022-03-29 21:22:26 +02:00
sx = { { height : "45px" , marginTop : "17px" , ... sx } }
2022-03-29 04:54:27 +02:00
onClick = { props . onClick }
2022-04-01 14:41:45 +02:00
disabled = { props . disabled }
2022-03-29 04:54:27 +02:00
>
{ props . children }
< / I c o n B u t t o n >
) ;
} ;
2022-03-29 21:22:26 +02:00
const AttachmentBox = ( props ) => {
const file = props . file ;
return (
2022-03-30 15:57:22 +02:00
< >
< Typography variant = "body1" sx = { { marginTop : 2 } } >
Attached file :
2022-03-29 21:22:26 +02:00
< / T y p o g r a p h y >
2022-03-30 15:57:22 +02:00
< Box sx = { {
display : 'flex' ,
alignItems : 'center' ,
2022-03-30 20:11:18 +02:00
padding : 0.5 ,
2022-03-30 15:57:22 +02:00
borderRadius : '4px' ,
} } >
2022-04-04 14:40:54 +02:00
< AttachmentIcon type = { file . type } / >
2022-04-03 18:39:52 +02:00
< Box sx = { { marginLeft : 1 , textAlign : 'left' } } >
2022-03-31 18:03:36 +02:00
< ExpandingTextField
minWidth = { 140 }
variant = "body2"
2022-03-30 20:11:18 +02:00
value = { props . filename }
2022-03-31 18:03:36 +02:00
onChange = { ( ev ) => props . onChangeFilename ( ev . target . value ) }
2022-04-01 14:41:45 +02:00
disabled = { props . disabled }
2022-03-30 20:11:18 +02:00
/ >
2022-03-30 15:57:22 +02:00
< br / >
2022-04-03 18:39:52 +02:00
< Typography variant = "body2" sx = { { color : 'text.primary' } } >
{ formatBytes ( file . size ) }
{ props . error &&
< Typography component = "span" sx = { { color : 'error.main' } } >
{ " " } ( { props . error } )
< / T y p o g r a p h y >
}
< / T y p o g r a p h y >
< / B o x >
2022-04-01 14:41:45 +02:00
< DialogIconButton disabled = { props . disabled } onClick = { props . onClose } sx = { { marginLeft : "6px" } } > < Close / > < / D i a l o g I c o n B u t t o n >
2022-03-30 15:57:22 +02:00
< / B o x >
< / >
2022-03-29 21:22:26 +02:00
) ;
} ;
2022-03-31 18:03:36 +02:00
const ExpandingTextField = ( props ) => {
const invisibleFieldRef = useRef ( ) ;
const [ textWidth , setTextWidth ] = useState ( props . minWidth ) ;
const determineTextWidth = ( ) => {
const boundingRect = invisibleFieldRef ? . current ? . getBoundingClientRect ( ) ;
if ( ! boundingRect ) {
return props . minWidth ;
}
return ( boundingRect . width >= props . minWidth ) ? Math . round ( boundingRect . width ) : props . minWidth ;
} ;
useEffect ( ( ) => {
setTextWidth ( determineTextWidth ( ) + 5 ) ;
} , [ props . value ] ) ;
return (
< >
< Typography
ref = { invisibleFieldRef }
component = "span"
variant = { props . variant }
2022-04-04 01:51:32 +02:00
sx = { { position : "absolute" , left : "-200%" } }
2022-03-31 18:03:36 +02:00
>
{ props . value }
< / T y p o g r a p h y >
< TextField
margin = "dense"
placeholder = "Attachment filename"
value = { props . value }
onChange = { props . onChange }
type = "text"
variant = "standard"
sx = { { width : ` ${ textWidth } px ` , borderBottom : "none" } }
InputProps = { { style : { fontSize : theme . typography [ props . variant ] . fontSize } } }
inputProps = { { style : { paddingBottom : 0 , paddingTop : 0 } } }
2022-04-01 14:41:45 +02:00
disabled = { props . disabled }
2022-03-31 18:03:36 +02:00
/ >
< / >
)
} ;
2022-04-04 01:51:32 +02:00
const DropArea = ( props ) => {
const allowDrag = ( ev ) => {
// This is where we could disallow certain files to be dragged in.
// For now we allow all files.
ev . dataTransfer . dropEffect = 'copy' ;
ev . preventDefault ( ) ;
} ;
return (
< Box
sx = { {
position : 'absolute' ,
left : 0 ,
top : 0 ,
right : 0 ,
bottom : 0 ,
zIndex : 10002 ,
} }
onDrop = { props . onDrop }
onDragEnter = { allowDrag }
onDragOver = { allowDrag }
onDragLeave = { props . onDragLeave }
/ >
) ;
} ;
const DropBox = ( ) => {
return (
< Box sx = { {
position : 'absolute' ,
left : 0 ,
top : 0 ,
right : 0 ,
bottom : 0 ,
zIndex : 10000 ,
backgroundColor : "#ffffffbb"
} } >
< Box
sx = { {
position : 'absolute' ,
border : '3px dashed #ccc' ,
borderRadius : '5px' ,
left : "40px" ,
top : "40px" ,
right : "40px" ,
bottom : "40px" ,
zIndex : 10001 ,
display : 'flex' ,
justifyContent : "center" ,
alignItems : "center" ,
} }
>
< Typography variant = "h5" > Drop file here < / T y p o g r a p h y >
< / B o x >
< / B o x >
) ;
}
2022-03-29 04:54:27 +02:00
const priorities = {
2022-04-04 01:51:32 +02:00
1 : { label : "Min. priority" , file : priority1 } ,
2022-03-29 04:54:27 +02:00
2 : { label : "Low priority" , file : priority2 } ,
3 : { label : "Default priority" , file : priority3 } ,
4 : { label : "High priority" , file : priority4 } ,
2022-04-04 01:51:32 +02:00
5 : { label : "Max. priority" , file : priority5 }
2022-03-29 04:54:27 +02:00
} ;
2022-04-04 01:51:32 +02:00
SendDialog . OPEN _MODE _DEFAULT = "default" ;
SendDialog . OPEN _MODE _DRAG = "drag" ;
2022-03-27 15:10:47 +02:00
export default SendDialog ;