3
0
mirror of https://github.com/Qortal/q-mail.git synced 2025-02-11 17:55:56 +00:00

mobile friendly

This commit is contained in:
PhilReact 2025-01-06 20:03:11 +02:00
parent 604e5ee096
commit 96b165d452
6 changed files with 505 additions and 147 deletions

View File

@ -10,7 +10,7 @@ import { useNavigate } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { RootState } from "../../state/store";
import EditIcon from "@mui/icons-material/Edit";
import { Box, Button, Input, Typography, formLabelClasses, useTheme } from "@mui/material";
import { Box, Button, Input, Typography, formLabelClasses, useMediaQuery, useTheme } from "@mui/material";
import { useFetchPosts } from "../../hooks/useFetchPosts";
import LazyLoad from "../../components/common/LazyLoad";
import { removePrefix } from "../../utils/blogIdformats";
@ -59,6 +59,7 @@ export const GroupMail = ({ groupInfo, setCurrentThread, currentThread, filterMo
const [replyTo, setReplyTo] = useState<any>(null);
const [valueTab, setValueTab] = React.useState(0);
const [viewedThreads, setViewedThreads] = React.useState<any>({});
const isMobile = useMediaQuery("(max-width:950px)");
const [aliasValue, setAliasValue] = useState("");
const [alias, setAlias] = useState<string[]>([]);
@ -452,6 +453,60 @@ export const GroupMail = ({ groupInfo, setCurrentThread, currentThread, filterMo
{listOfThreadsToDisplay.map(thread => {
const hasViewedRecent = viewedThreads[`qmail_threads_${thread?.threadData?.groupId}_${thread?.threadId}`]
const shouldAppearLighter = hasViewedRecent && filterMode === 'Recently active' && thread?.threadData?.createdAt < hasViewedRecent?.timestamp
if(isMobile){
return (
<SingleThreadParent
onClick={() => {
setCurrentThread(thread);
}}
sx={{
flexDirection: 'column',
alignItems: 'flex-start',
height: 'auto'
}}
>
<Box sx={{
display: 'flex',
gap: '10px',
}}>
<AvatarWrapper isAlias={false} height="50px" user={thread?.threadData?.name} fallback={thread?.threadData?.name}></AvatarWrapper>
<ThreadInfoColumn>
<ThreadInfoColumnNameP><ThreadInfoColumnbyP>by </ThreadInfoColumnbyP>{thread?.threadData?.name}</ThreadInfoColumnNameP>
<ThreadInfoColumnTime>{formatTimestamp(thread?.threadData?.createdAt)}</ThreadInfoColumnTime>
</ThreadInfoColumn>
</Box>
<div
style={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
}}
>
<ThreadSingleTitle sx={{
fontWeight: shouldAppearLighter && 300
}}>{thread?.threadData?.title}</ThreadSingleTitle>
{filterMode === 'Recently active' && (
<div
style={{
display: "flex",
alignItems: "center",
}}
>
<ThreadSingleLastMessageP
>
<ThreadSingleLastMessageSpanP>last message: </ThreadSingleLastMessageSpanP>
{formatDate(thread?.created)}
</ThreadSingleLastMessageP>
</div>
)}
</div>
</SingleThreadParent>
)
}
return (
<SingleThreadParent
onClick={() => {

View File

@ -30,6 +30,7 @@ export const MailBody = styled(Box)(({ theme }) => ({
flexDirection: "row",
width: "100%",
height: "calc(100% - 59px)",
position: 'relative'
// overflow: 'auto !important'
}));
export const MailBodyInner = styled(Box)(({ theme }) => ({
@ -249,7 +250,7 @@ export const InstanceListParent = styled(Box)`
width: 100%;
min-height: 246px;
max-height: 325px;
width: 425px;
max-width: 425px;
padding: 10px 0px 7px 0px;
background-color: var(--color-instance-popover-bg);
border: 1px solid rgba(0, 0, 0, 0.1);
@ -334,7 +335,6 @@ export const InstanceListContainerRowMain = styled(Box)(({ theme }) => ({
justifyContent: "space-between",
width: "100%",
alignItems: "center",
paddingRight: "30px",
overflow: "hidden",
}));
export const CloseParent = styled(Box)(({ theme }) => ({

View File

@ -37,6 +37,8 @@ import {
CircularProgress,
Popover,
TextField,
useMediaQuery,
ButtonBase,
} from "@mui/material";
import LazyLoad from "../../components/common/LazyLoad";
import { NewMessage } from "./NewMessage";
@ -92,6 +94,7 @@ import { CloseSVG } from "../../assets/svgs/CloseSVG";
import { objectToBase64 } from "../../utils/toBase64";
import { ShowMessageV2 } from "./ShowMessageV2";
import { executeEvent } from "../../utils/events";
import { Spacer } from "../../components/common/Spacer";
const filterOptions = ["Recently active", "Newest", "Oldest"];
@ -134,7 +137,7 @@ const steps: Step[] = [
fontFamily: "Arial",
}}
>
Toggle between your main inbox, alias' and private groups.
Toggle between your main inbox, alias' and private groups.
</p>
</div>
),
@ -199,7 +202,8 @@ const steps: Step[] = [
fontFamily: "Arial",
}}
>
To access messages sent to that alias, simply add the alias as an instance.
To access messages sent to that alias, simply add the alias as an
instance.
</p>
</div>
),
@ -245,6 +249,8 @@ export const Mail = ({ isFromTo }: MailProps) => {
(state: RootState) => state.global.privateGroups
);
const [mailInfo, setMailInfo] = useState<any>(null);
const isMobile = useMediaQuery("(max-width:950px)");
const [mobileMode, setMobileMode] = useState("inbox");
const hasFetchedPrivateGroups = useSelector(
(state: RootState) => state.global.hasFetchedPrivateGroups
);
@ -523,9 +529,19 @@ export const Mail = ({ isFromTo }: MailProps) => {
return (
<MailContainer>
<InstanceContainer>
<InstanceContainer sx={{
flexDirection: isMobile ? 'column' : 'row',
padding: isMobile ? '10px' : '0px',
height: 'auto',
minHeight: '59px'
}}>
{selectedGroup ? (
<ComposeContainer onClick={openNewThread}>
<ComposeContainer onClick={openNewThread} sx={
{
marginBottom: '10px',
padding: '10px'
}
}>
<ComposeIcon src={ComposeIconSVG} />
<ComposeP>{currentThread ? "New Post" : "New Thread"}</ComposeP>
</ComposeContainer>
@ -749,7 +765,7 @@ export const Mail = ({ isFromTo }: MailProps) => {
sx={{
minHeight: "unset",
width: "auto",
padding: '0px'
padding: "0px",
}}
>
<InstanceListHeader></InstanceListHeader>
@ -813,95 +829,17 @@ export const Mail = ({ isFromTo }: MailProps) => {
setFilterMode={setFilterMode}
/>
) : (
<MailBody>
<MailBodyInner>
<MailBodyInnerHeader>
<MailIconImg src={MailSVG} />
<ComposeP>Inbox</ComposeP>
</MailBodyInnerHeader>
<MailBodyInnerScroll
sx={{
borderRight: "1px solid rgba(85, 84, 84, 0.4)",
}}
>
<Box
className="step-1"
sx={{
display: "flex",
width: "100%",
flexDirection: "column",
alignItems: "center",
}}
>
{!selectedAlias && (
<MessagesContainer>
{fullMailMessages.map(item => {
return (
<MailMessageRow
messageData={item}
openMessage={openMessage}
isOpen={message?.id === item?.id}
/>
);
})}
<LazyLoad onLoadMore={getMessages}></LazyLoad>
{isLoading && (
<Box
sx={{
display: "flex",
width: "100%",
justifyContent: "center",
}}
>
<CircularProgress />
</Box>
)}
</MessagesContainer>
)}
{selectedAlias && (
<AliasMail
value={selectedAlias}
onOpen={openMessage}
messageOpenedId={message?.id}
/>
)}
<Joyride
steps={steps}
run={run}
callback={handleJoyrideCallback}
continuous={true}
scrollToFirstStep={true}
showProgress={true}
showSkipButton={true}
/>
{mailInfo && isShow && (
<OpenMail
open={isShow}
handleClose={onOk}
fileInfo={mailInfo}
/>
)}
</Box>
</MailBodyInnerScroll>
</MailBodyInner>
<MailBodyInner>
{isOpen && message && (
<>
<>
{!isMobile && (
<MailBody>
<MailBodyInner>
<MailBodyInnerHeader>
<ShowMessageReturnButton
onClick={() => {
setIsOpen(false);
setMessage(null);
}}
>
<MailIconImg src={ReturnSVG} />
<ComposeP>Return to Sent</ComposeP>
</ShowMessageReturnButton>
<MailIconImg src={MailSVG} />
<ComposeP>Inbox</ComposeP>
</MailBodyInnerHeader>
<MailBodyInnerScroll
sx={{
direction: "rtl",
borderRight: "1px solid rgba(85, 84, 84, 0.4)",
}}
>
<Box
@ -911,52 +849,396 @@ export const Mail = ({ isFromTo }: MailProps) => {
width: "100%",
flexDirection: "column",
alignItems: "center",
direction: "ltr",
}}
>
<ShowMessageV2
isOpen={isOpen}
setIsOpen={setIsOpen}
message={message}
setReplyTo={setReplyTo}
setForwardInfo={setForwardInfo}
alias={selectedAlias}
{!selectedAlias && (
<MessagesContainer>
{fullMailMessages.map(item => {
return (
<MailMessageRow
messageData={item}
openMessage={openMessage}
isOpen={message?.id === item?.id}
/>
);
})}
<LazyLoad onLoadMore={getMessages}></LazyLoad>
{isLoading && (
<Box
sx={{
display: "flex",
width: "100%",
justifyContent: "center",
}}
>
<CircularProgress />
</Box>
)}
</MessagesContainer>
)}
{selectedAlias && (
<AliasMail
value={selectedAlias}
onOpen={openMessage}
messageOpenedId={message?.id}
/>
)}
<Joyride
steps={steps}
run={run}
callback={handleJoyrideCallback}
continuous={true}
scrollToFirstStep={true}
showProgress={true}
showSkipButton={true}
/>
{mailInfo && isShow && (
<OpenMail
open={isShow}
handleClose={onOk}
fileInfo={mailInfo}
/>
)}
</Box>
</MailBodyInnerScroll>
</>
)}
<>
<MailBodyInnerHeader
sx={{
display: isOpen && message ? "none" : "flex",
}}
>
<MailIconImg src={SendSVG} />
<ComposeP>Sent</ComposeP>
</MailBodyInnerHeader>
<MailBodyInnerScroll
sx={{
direction: "rtl",
display: isOpen && message ? "none" : "flex",
}}
>
</MailBodyInner>
<MailBodyInner>
{isOpen && message && (
<>
<MailBodyInnerHeader>
<ShowMessageReturnButton
onClick={() => {
setIsOpen(false);
setMessage(null);
}}
>
<MailIconImg src={ReturnSVG} />
<ComposeP>Return to Sent</ComposeP>
</ShowMessageReturnButton>
</MailBodyInnerHeader>
<MailBodyInnerScroll
sx={{
direction: "rtl",
}}
>
<Box
className="step-1"
sx={{
display: "flex",
width: "100%",
flexDirection: "column",
alignItems: "center",
direction: "ltr",
}}
>
<ShowMessageV2
isOpen={isOpen}
setIsOpen={setIsOpen}
message={message}
setReplyTo={setReplyTo}
setForwardInfo={setForwardInfo}
alias={selectedAlias}
/>
</Box>
</MailBodyInnerScroll>
</>
)}
<>
<MailBodyInnerHeader
sx={{
display: isOpen && message ? "none" : "flex",
}}
>
<MailIconImg src={SendSVG} />
<ComposeP>Sent</ComposeP>
</MailBodyInnerHeader>
<MailBodyInnerScroll
sx={{
direction: "rtl",
display: isOpen && message ? "none" : "flex",
}}
>
<Box
className="step-1"
sx={{
display: "flex",
width: "100%",
flexDirection: "column",
alignItems: "center",
direction: "ltr",
}}
>
<SentMail onOpen={openMessage} />
</Box>
</MailBodyInnerScroll>
</>
</MailBodyInner>
</MailBody>
)}
{isMobile && (
<MailBody sx={{
height: "calc(100% - 115px)"
}}>
{isOpen && message && (
<Box
className="step-1"
sx={{
display: "flex",
width: "100%",
flexDirection: "column",
alignItems: "center",
direction: "ltr",
position: "absolute",
top: 0,
bottom: 0,
left: 0,
right: 0,
zIndex: 5,
backgroundColor: "var(--Mail-Background)",
}}
>
<SentMail onOpen={openMessage} />
<MailBodyInnerHeader sx={{
marginTop: '25px',
marginBottom: '25px'
}}>
<ShowMessageReturnButton
onClick={() => {
setIsOpen(false);
setMessage(null);
}}
>
<MailIconImg src={ReturnSVG} />
<ComposeP>Return</ComposeP>
</ShowMessageReturnButton>
</MailBodyInnerHeader>
<MailBodyInnerScroll
sx={{
direction: "rtl",
height: 'calc(100% - 75px)'
}}
>
<Box
className="step-1"
sx={{
display: "flex",
width: "100%",
flexDirection: "column",
alignItems: "center",
direction: "ltr",
}}
>
<ShowMessageV2
isOpen={isOpen}
setIsOpen={setIsOpen}
message={message}
setReplyTo={setReplyTo}
setForwardInfo={setForwardInfo}
alias={selectedAlias}
/>
</Box>
</MailBodyInnerScroll>
</Box>
</MailBodyInnerScroll>
</>
</MailBodyInner>
</MailBody>
)}
{selectedAlias && (
<AliasMail
value={selectedAlias}
onOpen={openMessage}
messageOpenedId={message?.id}
/>
)}
{mailInfo && isShow && (
<OpenMail
open={isShow}
handleClose={onOk}
fileInfo={mailInfo}
/>
)}
{mobileMode === "inbox" && (
<MailBodyInner
sx={{
width: "100%",
}}
>
<Spacer height="15px" />
<Box
sx={{
display: "flex",
gap: "20px",
alignItems: "center",
justifyContent: "center",
}}
>
<ButtonBase
onClick={() => {
setMobileMode("inbox");
}}
sx={{
height: '40px'
}}
>
<MailBodyInnerHeader sx={{
marginTop: '0px',
marginBottom: '0px',
outline: '1px solid white',
padding: '4px 8px',
borderRadius: '5px',
height: '100%'
}}>
<MailIconImg src={MailSVG} />
<ComposeP>Inbox</ComposeP>
</MailBodyInnerHeader>
</ButtonBase>
<ButtonBase
onClick={() => {
setMobileMode("sent");
}}
sx={{
height: '40px'
}}
>
<MailBodyInnerHeader sx={{
marginTop: '0px',
marginBottom: '0px',
outline: 'none',
padding: '4px 8px',
borderRadius: '5px',
height: '100%'
}}>
<MailIconImg src={SendSVG} />
<ComposeP>Sent</ComposeP>
</MailBodyInnerHeader>
</ButtonBase>
</Box>
<Spacer height="15px" />
<MailBodyInnerScroll
sx={{
borderRight: "1px solid rgba(85, 84, 84, 0.4)",
height: 'calc(100% - 75px)'
}}
>
<Box
className="step-1"
sx={{
display: "flex",
width: "100%",
flexDirection: "column",
alignItems: "center",
}}
>
{!selectedAlias && (
<MessagesContainer>
{fullMailMessages.map(item => {
return (
<MailMessageRow
messageData={item}
openMessage={openMessage}
isOpen={message?.id === item?.id}
/>
);
})}
<LazyLoad onLoadMore={getMessages}></LazyLoad>
{isLoading && (
<Box
sx={{
display: "flex",
width: "100%",
justifyContent: "center",
}}
>
<CircularProgress />
</Box>
)}
</MessagesContainer>
)}
</Box>
</MailBodyInnerScroll>
</MailBodyInner>
)}
{mobileMode === "sent" && (
<MailBodyInner
sx={{
width: "100%",
}}
>
<>
<Spacer height="15px" />
<Box
sx={{
display: "flex",
gap: "20px",
alignItems: "center",
justifyContent: "center",
}}
>
<ButtonBase
onClick={() => {
setMobileMode("inbox");
}}
sx={{
height: '40px'
}}
>
<MailBodyInnerHeader sx={{
marginTop: '0px',
marginBottom: '0px',
outline: 'none',
padding: '4px 8px',
borderRadius: '5px',
height: '100%'
}}>
<MailIconImg src={MailSVG} />
<ComposeP>Inbox</ComposeP>
</MailBodyInnerHeader>
</ButtonBase>
<ButtonBase
onClick={() => {
setMobileMode("sent");
}}
sx={{
height: '40px'
}}
>
<MailBodyInnerHeader sx={{
marginTop: '0px',
marginBottom: '0px',
outline: '1px solid white',
padding: '4px 8px',
borderRadius: '5px',
height: '100%'
}}>
<MailIconImg src={SendSVG} />
<ComposeP>Sent</ComposeP>
</MailBodyInnerHeader>
</ButtonBase>
</Box>
<Spacer height="15px" />
<MailBodyInnerScroll
sx={{
direction: "rtl",
display: isOpen && message ? "none" : "flex",
height: 'calc(100% - 75px)'
}}
>
<Box
className="step-1"
sx={{
display: "flex",
width: "100%",
flexDirection: "column",
alignItems: "center",
direction: "ltr",
}}
>
<SentMail onOpen={openMessage} />
</Box>
</MailBodyInnerScroll>
</>
</MailBodyInner>
)}
</MailBody>
)}
</>
)}
</MailContainer>
);

View File

@ -17,6 +17,7 @@ import AttachmentSVG from '../../assets/svgs/Attachment.svg'
import { useSelector } from "react-redux";
import { RootState } from "../../state/store";
import { base64ToUint8Array, uint8ArrayToObject } from "../../utils/toBase64";
import { useMediaQuery } from "@mui/material";
function parseQuery(query: string) {
// Regular expression to match both possible formats
@ -49,6 +50,8 @@ export const MailMessageRow = ({
const [sentToNameInfo, setSentToNameInfo] = useState({
name: ""
})
const isMobile = useMediaQuery("(max-width:950px)");
const [alias, setAlias] = useState<null | string>(null)
const identifier = useMemo(()=> {
@ -149,7 +152,13 @@ const name = useMemo(()=> {
return (
<MailMessageRowContainer sx={{
background: isOpen ? '#434448' : 'unset'
background: isOpen ? '#434448' : 'unset',
flexDirection: isMobile ? 'column': 'row',
alignItems: isMobile ? 'flex-start' : 'center',
borderRadius: isMobile ? '10px' : "56px 5px 10px 56px",
padding: isMobile ? '5px' : 'center',
outline: isMobile ? '1px solid #434448' : 'none',
marginTop: isMobile ? '10px' : '0px'
}} onClick={()=> {
openMessage(messageData?.user, messageData?.id, messageData, isFromSent ? (alias || name) : username)
}}>

View File

@ -1,6 +1,6 @@
import React, { Dispatch, useEffect, useState } from 'react'
import { ReusableModal } from '../../components/modals/ReusableModal'
import { Box, Button, Input, Typography, useTheme } from '@mui/material'
import { Box, Button, Input, Typography, useMediaQuery, useTheme } from '@mui/material'
import { BuilderButton } from '../CreatePost/CreatePost-styles'
import BlogEditor from '../../components/editor/BlogEditor'
import EmailIcon from '@mui/icons-material/Email'
@ -85,6 +85,8 @@ export const NewMessage = ({
const [showAlias, setShowAlias] = useState<boolean>(false)
const [showBCC, setShowBCC] = useState<boolean>(false)
const [bccNames, setBccNames] = useState<NameChip[]>([])
const isMobile = useMediaQuery("(max-width:950px)");
const theme = useTheme()
const { Modal, showModal } = useConfirmationModal({
title: 'Important',
@ -436,7 +438,12 @@ export const NewMessage = ({
}}
>
{!hideButton && (
<ComposeContainer className='step-2' onClick={openModal}
<ComposeContainer className='step-2' onClick={openModal} sx={
{
marginBottom: '10px',
padding: '10px'
}
}
>
<ComposeIcon src={ComposeIconSVG} />
<ComposeP>Compose</ComposeP>
@ -448,17 +455,18 @@ export const NewMessage = ({
customStyles={{
maxHeight: '95vh',
maxWidth: '950px',
height: '700px',
height: isMobile ? '95vh' : '700px',
borderRadius: '12px 12px 0px 0px',
background: 'var(--Mail-Backgrund, #313338)',
padding: '0px',
gap: '0px'
gap: '0px',
width: isMobile ? '95%' : '75%'
}}
>
<InstanceListHeader sx={{
backgroundColor: 'unset',
height: '50px',
padding: '20px 42px',
padding: isMobile ? '10px' : '20px 42px',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center'
@ -470,7 +478,7 @@ export const NewMessage = ({
</InstanceListHeader>
<InstanceListContainer sx={{
backgroundColor: 'rgba(217, 217, 217, 1)',
padding: '20px 42px',
padding: isMobile ? '10px' : '20px 42px',
height: 'calc(100% - 150px)',
flexShrink: 0
}}>
@ -659,11 +667,13 @@ export const NewMessage = ({
</InstanceListContainer>
<InstanceFooter sx={{
backgroundColor: 'rgba(217, 217, 217, 1)',
padding: '20px 42px',
padding: isMobile ? '5px' : '20px 42px',
alignItems: 'center',
height: '90px'
height: isMobile ? '35px' : '90px'
}}>
<NewMessageSendButton onClick={sendMail}>
<NewMessageSendButton sx={{
padding: isMobile ? '0px' : '8px 16px 8px 12px'
}} onClick={sendMail}>
<NewMessageSendP>{replyTo ? 'Reply' : 'Send Message'}</NewMessageSendP>
<SendNewMessage color="red" opacity={1} height="25px" width="25px" />
</NewMessageSendButton>

View File

@ -1,6 +1,6 @@
import React, { Dispatch, useCallback, useEffect, useState } from "react";
import { ReusableModal } from "../../components/modals/ReusableModal";
import { Box, Button, Input, Typography, useTheme } from "@mui/material";
import { Box, Button, Input, Typography, useMediaQuery, useTheme } from "@mui/material";
import { BuilderButton } from "../CreatePost/CreatePost-styles";
import BlogEditor from "../../components/editor/BlogEditor";
import EmailIcon from "@mui/icons-material/Email";
@ -97,6 +97,7 @@ export const NewThread = ({
const [isOpenMultiplePublish, setIsOpenMultiplePublish] = useState(false);
const [publishes, setPublishes] = useState<any>(null);
const [callbackContent, setCallbackContent] = useState<any>(null);
const isMobile = useMediaQuery("(max-width:950px)");
const theme = useTheme();
@ -463,18 +464,19 @@ export const NewThread = ({
customStyles={{
maxHeight: "95vh",
maxWidth: "950px",
height: "700px",
height: isMobile ? '95vh' : '700px',
borderRadius: "12px 12px 0px 0px",
background: "var(--Mail-Backgrund, #313338)",
padding: "0px",
gap: "0px",
width: isMobile ? '95%' : '75%'
}}
>
<InstanceListHeader
sx={{
backgroundColor: "unset",
height: "50px",
padding: "20px 42px",
padding: isMobile ? '10px' : '20px 42px',
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
@ -490,7 +492,7 @@ export const NewThread = ({
<InstanceListContainer
sx={{
backgroundColor: "rgba(217, 217, 217, 1)",
padding: "20px 42px",
padding: isMobile ? '10px' : '20px 42px',
height: "calc(100% - 150px)",
flexShrink: 0,
}}
@ -618,9 +620,9 @@ export const NewThread = ({
<InstanceFooter
sx={{
backgroundColor: "rgba(217, 217, 217, 1)",
padding: "20px 42px",
padding: isMobile ? '5px' : '20px 42px',
alignItems: "center",
height: "90px",
height: isMobile ? '35px' : '90px'
}}
>
<NewMessageSendButton onClick={sendMail}>