Refactor sReturn icon and set theme styles

This commit is contained in:
Nicola Benaglia
2025-04-12 15:31:10 +02:00
parent c5cfaf3722
commit dcfa7b258e
13 changed files with 3712 additions and 3303 deletions

View File

@@ -1,4 +1,11 @@
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
import React, {
useCallback,
useContext,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import {
AppCircle,
AppCircleContainer,
@@ -16,84 +23,95 @@ import {
PublishQAppCTAParent,
PublishQAppCTARight,
PublishQAppDotsBG,
} from "./Apps-styles";
import { Avatar, Box, ButtonBase, InputBase, styled } from "@mui/material";
import { Add } from "@mui/icons-material";
import { MyContext, getBaseApiReact } from "../../App";
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
import IconSearch from "../../assets/svgs/Search.svg";
import IconClearInput from "../../assets/svgs/ClearInput.svg";
import qappDevelopText from "../../assets/svgs/qappDevelopText.svg";
import qappDots from "../../assets/svgs/qappDots.svg";
import ReturnSVG from '../../assets/svgs/Return.svg'
} from './Apps-styles';
import { Avatar, Box, ButtonBase, InputBase, styled } from '@mui/material';
import { Add } from '@mui/icons-material';
import { MyContext, getBaseApiReact } from '../../App';
import LogoSelected from '../../assets/svgs/LogoSelected.svg';
import IconSearch from '../../assets/svgs/Search.svg';
import IconClearInput from '../../assets/svgs/ClearInput.svg';
import qappDevelopText from '../../assets/svgs/qappDevelopText.svg';
import qappDots from '../../assets/svgs/qappDots.svg';
import ReturnSVG from '../../assets/svgs/Return.svg';
import { Spacer } from "../../common/Spacer";
import { AppInfoSnippet } from "./AppInfoSnippet";
import { Virtuoso } from "react-virtuoso";
import { executeEvent } from "../../utils/events";
import { ComposeP, MailIconImg, ShowMessageReturnButton } from "../Group/Forum/Mail-styles";
import { Spacer } from '../../common/Spacer';
import { AppInfoSnippet } from './AppInfoSnippet';
import { Virtuoso } from 'react-virtuoso';
import { executeEvent } from '../../utils/events';
import {
ComposeP,
MailIconImg,
ShowMessageReturnButton,
} from '../Group/Forum/Mail-styles';
const officialAppList = [
"q-tube",
"q-blog",
"q-share",
"q-support",
"q-mail",
"q-fund",
"q-shop",
"q-trade",
"q-support",
"q-manager",
"q-wallets",
"q-search"
'q-tube',
'q-blog',
'q-share',
'q-support',
'q-mail',
'q-fund',
'q-shop',
'q-trade',
'q-support',
'q-manager',
'q-wallets',
'q-search',
];
const ScrollerStyled = styled('div')({
// Hide scrollbar for WebKit browsers (Chrome, Safari)
"::-webkit-scrollbar": {
width: "0px",
height: "0px",
},
// Hide scrollbar for Firefox
scrollbarWidth: "none",
// Hide scrollbar for IE and older Edge
"-msOverflowStyle": "none",
});
const StyledVirtuosoContainer = styled('div')({
position: 'relative',
width: '100%',
display: 'flex',
flexDirection: 'column',
// Hide scrollbar for WebKit browsers (Chrome, Safari)
"::-webkit-scrollbar": {
width: "0px",
height: "0px",
},
// Hide scrollbar for Firefox
scrollbarWidth: "none",
// Hide scrollbar for IE and older Edge
"-msOverflowStyle": "none",
});
// Hide scrollbar for WebKit browsers (Chrome, Safari)
'::-webkit-scrollbar': {
width: '0px',
height: '0px',
},
export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, isShow, categories={categories} }) => {
const [searchValue, setSearchValue] = useState("");
// Hide scrollbar for Firefox
scrollbarWidth: 'none',
// Hide scrollbar for IE and older Edge
'-msOverflowStyle': 'none',
});
const StyledVirtuosoContainer = styled('div')({
position: 'relative',
width: '100%',
display: 'flex',
flexDirection: 'column',
// Hide scrollbar for WebKit browsers (Chrome, Safari)
'::-webkit-scrollbar': {
width: '0px',
height: '0px',
},
// Hide scrollbar for Firefox
scrollbarWidth: 'none',
// Hide scrollbar for IE and older Edge
'-msOverflowStyle': 'none',
});
export const AppsLibrary = ({
availableQapps,
setMode,
myName,
hasPublishApp,
isShow,
categories = { categories },
}) => {
const [searchValue, setSearchValue] = useState('');
const virtuosoRef = useRef();
const { rootHeight } = useContext(MyContext);
const officialApps = useMemo(() => {
return availableQapps.filter(
(app) =>
app.service === "APP" &&
app.service === 'APP' &&
officialAppList.includes(app?.name?.toLowerCase())
);
}, [availableQapps]);
const [debouncedValue, setDebouncedValue] = useState(""); // Debounced value
const [debouncedValue, setDebouncedValue] = useState(''); // Debounced value
// Debounce logic
useEffect(() => {
@@ -117,23 +135,28 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
}, [debouncedValue]);
const rowRenderer = (index) => {
let app = searchedList[index];
return <AppInfoSnippet key={`${app?.service}-${app?.name}`} app={app} myName={myName} />;
return (
<AppInfoSnippet
key={`${app?.service}-${app?.name}`}
app={app}
myName={myName}
/>
);
};
return (
<AppsLibraryContainer sx={{
display: !isShow && 'none'
}}>
<AppsWidthLimiter>
<AppsLibraryContainer
sx={{
display: !isShow && 'none',
}}
>
<AppsWidthLimiter>
<Box
sx={{
display: "flex",
width: "100%",
justifyContent: "center",
display: 'flex',
width: '100%',
justifyContent: 'center',
}}
>
<AppsSearchContainer>
@@ -145,8 +168,8 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
sx={{ ml: 1, flex: 1 }}
placeholder="Search for apps"
inputProps={{
"aria-label": "Search for apps",
fontSize: "16px",
'aria-label': 'Search for apps',
fontSize: '16px',
fontWeight: 400,
}}
/>
@@ -155,7 +178,7 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
{searchValue && (
<ButtonBase
onClick={() => {
setSearchValue("");
setSearchValue('');
}}
>
<img src={IconClearInput} />
@@ -164,23 +187,27 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
</AppsSearchRight>
</AppsSearchContainer>
</Box>
</AppsWidthLimiter>
<Spacer height="25px" />
<ShowMessageReturnButton sx={{
padding: '2px'
}} onClick={() => {
executeEvent("navigateBack", {});
}}>
<MailIconImg src={ReturnSVG} />
<ComposeP>Return to Apps Dashboard</ComposeP>
</ShowMessageReturnButton>
<Spacer height="25px" />
{searchedList?.length > 0 ? (
<AppsWidthLimiter>
<StyledVirtuosoContainer sx={{
height: rootHeight
}}>
</AppsWidthLimiter>
<Spacer height="25px" />
<ShowMessageReturnButton
sx={{
padding: '2px',
}}
onClick={() => {
executeEvent('navigateBack', {});
}}
>
<MailIconImg src={ReturnSVG} />
<ComposeP>Return to Apps Dashboard</ComposeP>
</ShowMessageReturnButton>
<Spacer height="25px" />
{searchedList?.length > 0 ? (
<AppsWidthLimiter>
<StyledVirtuosoContainer
sx={{
height: rootHeight,
}}
>
<Virtuoso
ref={virtuosoRef}
data={searchedList}
@@ -188,14 +215,14 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
atBottomThreshold={50}
followOutput="smooth"
components={{
Scroller: ScrollerStyled // Use the styled scroller component
Scroller: ScrollerStyled, // Use the styled scroller component
}}
/>
</StyledVirtuosoContainer>
</AppsWidthLimiter>
) : (
<>
<AppsWidthLimiter>
</AppsWidthLimiter>
) : (
<>
<AppsWidthLimiter>
<AppLibrarySubTitle>Official Apps</AppLibrarySubTitle>
<Spacer height="18px" />
<AppsContainer>
@@ -203,14 +230,14 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
return (
<ButtonBase
sx={{
height: "80px",
width: "60px",
height: '80px',
width: '60px',
}}
onClick={()=> {
onClick={() => {
// executeEvent("addTab", {
// data: qapp
// })
executeEvent("selectedAppInfo", {
executeEvent('selectedAppInfo', {
data: qapp,
});
}}
@@ -218,13 +245,13 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
<AppCircleContainer>
<AppCircle
sx={{
border: "none",
border: 'none',
}}
>
<Avatar
sx={{
height: "31px",
width: "31px",
height: '31px',
width: '31px',
}}
alt={qapp?.name}
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
@@ -233,8 +260,8 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
>
<img
style={{
width: "31px",
height: "auto",
width: '31px',
height: 'auto',
}}
src={LogoSelected}
alt="center-icon"
@@ -250,77 +277,87 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
})}
</AppsContainer>
<Spacer height="30px" />
<AppLibrarySubTitle>{hasPublishApp ? 'Update Apps!' : 'Create Apps!'}</AppLibrarySubTitle>
<AppLibrarySubTitle>
{hasPublishApp ? 'Update Apps!' : 'Create Apps!'}
</AppLibrarySubTitle>
<Spacer height="18px" />
</AppsWidthLimiter>
<PublishQAppCTAParent>
<PublishQAppCTALeft>
<PublishQAppDotsBG>
<img src={qappDots} />
</AppsWidthLimiter>
<PublishQAppCTAParent>
<PublishQAppCTALeft>
<PublishQAppDotsBG>
<img src={qappDots} />
</PublishQAppDotsBG>
<Spacer width="29px" />
<Spacer width="29px" />
<img src={qappDevelopText} />
</PublishQAppCTALeft>
<PublishQAppCTARight onClick={()=> {
setMode('publish')
}}>
<PublishQAppCTAButton>
{hasPublishApp ? 'Update' : 'Publish'}
</PublishQAppCTAButton>
<Spacer width="20px" />
</PublishQAppCTARight>
</PublishQAppCTAParent>
<AppsWidthLimiter>
</PublishQAppCTALeft>
<PublishQAppCTARight
onClick={() => {
setMode('publish');
}}
>
<PublishQAppCTAButton>
{hasPublishApp ? 'Update' : 'Publish'}
</PublishQAppCTAButton>
<Spacer width="20px" />
</PublishQAppCTARight>
</PublishQAppCTAParent>
<AppsWidthLimiter>
<Spacer height="18px" />
<AppLibrarySubTitle>Categories</AppLibrarySubTitle>
<Spacer height="18px" />
<AppsWidthLimiter sx={{
flexDirection: 'row',
overflowX: 'auto',
width: '100%',
gap: '5px',
"::-webkit-scrollbar": {
width: "0px",
height: "0px",
},
// Hide scrollbar for Firefox
scrollbarWidth: "none",
// Hide scrollbar for IE and older Edge
"-msOverflowStyle": "none",
}}>
{categories?.map((category)=> {
return (
<ButtonBase key={category?.id} onClick={()=> {
executeEvent('selectedCategory', {
data: category
})
}}>
<Box sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '110px',
width: '110px',
background: 'linear-gradient(163.47deg, #4BBCFE 27.55%, #1386C9 86.56%)',
color: '#1D1D1E',
fontWeight: 700,
fontSize: '16px',
flexShrink: 0,
borderRadius: '11px'
}}>
{category?.name}
</Box>
</ButtonBase>
)
})}
<AppsWidthLimiter
sx={{
flexDirection: 'row',
overflowX: 'auto',
width: '100%',
gap: '5px',
'::-webkit-scrollbar': {
width: '0px',
height: '0px',
},
// Hide scrollbar for Firefox
scrollbarWidth: 'none',
// Hide scrollbar for IE and older Edge
'-msOverflowStyle': 'none',
}}
>
{categories?.map((category) => {
return (
<ButtonBase
key={category?.id}
onClick={() => {
executeEvent('selectedCategory', {
data: category,
});
}}
>
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '110px',
width: '110px',
background:
'linear-gradient(163.47deg, #4BBCFE 27.55%, #1386C9 86.56%)',
color: '#1D1D1E',
fontWeight: 700,
fontSize: '16px',
flexShrink: 0,
borderRadius: '11px',
}}
>
{category?.name}
</Box>
</ButtonBase>
);
})}
</AppsWidthLimiter>
</AppsWidthLimiter>
</>
)}
</AppsLibraryContainer>
</AppsWidthLimiter>
</>
)}
</AppsLibraryContainer>
);
};

View File

@@ -5,7 +5,7 @@ import React, {
useMemo,
useRef,
useState,
} from "react";
} from 'react';
import {
AppCircle,
AppCircleContainer,
@@ -23,77 +23,87 @@ import {
PublishQAppCTAParent,
PublishQAppCTARight,
PublishQAppDotsBG,
} from "./Apps-styles";
import { Avatar, Box, ButtonBase, InputBase, Typography, styled } from "@mui/material";
import { Add } from "@mui/icons-material";
import { MyContext, getBaseApiReact } from "../../App";
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
import IconSearch from "../../assets/svgs/Search.svg";
import IconClearInput from "../../assets/svgs/ClearInput.svg";
import qappDevelopText from "../../assets/svgs/qappDevelopText.svg";
import qappLibraryText from "../../assets/svgs/qappLibraryText.svg";
import RefreshIcon from "@mui/icons-material/Refresh";
} from './Apps-styles';
import {
Avatar,
Box,
ButtonBase,
InputBase,
Typography,
styled,
} from '@mui/material';
import { Add } from '@mui/icons-material';
import { MyContext, getBaseApiReact } from '../../App';
import LogoSelected from '../../assets/svgs/LogoSelected.svg';
import IconSearch from '../../assets/svgs/Search.svg';
import IconClearInput from '../../assets/svgs/ClearInput.svg';
import qappDevelopText from '../../assets/svgs/qappDevelopText.svg';
import qappLibraryText from '../../assets/svgs/qappLibraryText.svg';
import RefreshIcon from '@mui/icons-material/Refresh';
import qappDots from "../../assets/svgs/qappDots.svg";
import qappDots from '../../assets/svgs/qappDots.svg';
import { Spacer } from "../../common/Spacer";
import { AppInfoSnippet } from "./AppInfoSnippet";
import { Virtuoso } from "react-virtuoso";
import { executeEvent } from "../../utils/events";
import { Spacer } from '../../common/Spacer';
import { AppInfoSnippet } from './AppInfoSnippet';
import { Virtuoso } from 'react-virtuoso';
import { executeEvent } from '../../utils/events';
import {
AppsDesktopLibraryBody,
AppsDesktopLibraryHeader,
} from "./AppsDesktop-styles";
import { AppsNavBarDesktop } from "./AppsNavBarDesktop";
import ReturnSVG from '../../assets/svgs/Return.svg'
import { ComposeP, MailIconImg, ShowMessageReturnButton } from "../Group/Forum/Mail-styles";
} from './AppsDesktop-styles';
import ReturnSVG from '../../assets/svgs/Return.svg';
import {
ComposeP,
MailIconImg,
ShowMessageReturnButton,
} from '../Group/Forum/Mail-styles';
const officialAppList = [
"q-tube",
"q-blog",
"q-share",
"q-support",
"q-mail",
"q-fund",
"q-shop",
"q-trade",
"q-support",
"q-manager",
"q-mintership",
"q-wallets",
"q-search"
'q-tube',
'q-blog',
'q-share',
'q-support',
'q-mail',
'q-fund',
'q-shop',
'q-trade',
'q-support',
'q-manager',
'q-mintership',
'q-wallets',
'q-search',
];
const ScrollerStyled = styled("div")({
const ScrollerStyled = styled('div')({
// Hide scrollbar for WebKit browsers (Chrome, Safari)
"::-webkit-scrollbar": {
width: "0px",
height: "0px",
'::-webkit-scrollbar': {
width: '0px',
height: '0px',
},
// Hide scrollbar for Firefox
scrollbarWidth: "none",
scrollbarWidth: 'none',
// Hide scrollbar for IE and older Edge
"-msOverflowStyle": "none",
'-msOverflowStyle': 'none',
});
const StyledVirtuosoContainer = styled("div")({
position: "relative",
width: "100%",
display: "flex",
flexDirection: "column",
const StyledVirtuosoContainer = styled('div')({
position: 'relative',
width: '100%',
display: 'flex',
flexDirection: 'column',
// Hide scrollbar for WebKit browsers (Chrome, Safari)
"::-webkit-scrollbar": {
width: "0px",
height: "0px",
'::-webkit-scrollbar': {
width: '0px',
height: '0px',
},
// Hide scrollbar for Firefox
scrollbarWidth: "none",
scrollbarWidth: 'none',
// Hide scrollbar for IE and older Edge
"-msOverflowStyle": "none",
'-msOverflowStyle': 'none',
});
export const AppsLibraryDesktop = ({
@@ -103,20 +113,20 @@ export const AppsLibraryDesktop = ({
hasPublishApp,
isShow,
categories,
getQapps
getQapps,
}) => {
const [searchValue, setSearchValue] = useState("");
const [searchValue, setSearchValue] = useState('');
const virtuosoRef = useRef();
const officialApps = useMemo(() => {
return availableQapps.filter(
(app) =>
app.service === "APP" &&
app.service === 'APP' &&
officialAppList.includes(app?.name?.toLowerCase())
);
}, [availableQapps]);
const [debouncedValue, setDebouncedValue] = useState(""); // Debounced value
const [debouncedValue, setDebouncedValue] = useState(''); // Debounced value
// Debounce logic
useEffect(() => {
@@ -125,7 +135,7 @@ export const AppsLibraryDesktop = ({
}, 350);
setTimeout(() => {
virtuosoRef.current.scrollToIndex({
index: 0
index: 0,
});
}, 500);
// Cleanup timeout if searchValue changes before the timeout completes
@@ -138,8 +148,13 @@ export const AppsLibraryDesktop = ({
const searchedList = useMemo(() => {
if (!debouncedValue) return [];
return availableQapps.filter((app) =>
app.name.toLowerCase().includes(debouncedValue.toLowerCase()) || (app?.metadata?.title && app?.metadata?.title?.toLowerCase().includes(debouncedValue.toLowerCase()))
return availableQapps.filter(
(app) =>
app.name.toLowerCase().includes(debouncedValue.toLowerCase()) ||
(app?.metadata?.title &&
app?.metadata?.title
?.toLowerCase()
.includes(debouncedValue.toLowerCase()))
);
}, [debouncedValue]);
@@ -151,7 +166,7 @@ export const AppsLibraryDesktop = ({
app={app}
myName={myName}
parentStyles={{
padding: '0px 10px'
padding: '0px 10px',
}}
/>
);
@@ -160,111 +175,112 @@ export const AppsLibraryDesktop = ({
return (
<AppsLibraryContainer
sx={{
display: !isShow && "none",
padding: "0px",
height: "100vh",
overflow: "hidden",
paddingTop: '30px'
display: !isShow && 'none',
padding: '0px',
height: '100vh',
overflow: 'hidden',
paddingTop: '30px',
}}
>
<AppsDesktopLibraryHeader
sx={{
maxWidth: "1500px",
width: "90%",
maxWidth: '1500px',
width: '90%',
}}
>
<AppsWidthLimiter>
<Box
sx={{
display: "flex",
width: "100%",
justifyContent: "space-between",
display: 'flex',
width: '100%',
justifyContent: 'space-between',
}}
>
<img src={qappLibraryText} />
<Box sx={{
display: 'flex',
gap: '20px',
alignItems: 'center'
}}>
<AppsSearchContainer
<Box
sx={{
width: "412px",
display: 'flex',
gap: '20px',
alignItems: 'center',
}}
>
<AppsSearchLeft>
<img src={IconSearch} />
<InputBase
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
sx={{ ml: 1, flex: 1 }}
placeholder="Search for apps"
inputProps={{
"aria-label": "Search for apps",
fontSize: "16px",
fontWeight: 400,
<AppsSearchContainer
sx={{
width: '412px',
}}
>
<AppsSearchLeft>
<img src={IconSearch} />
<InputBase
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
sx={{ ml: 1, flex: 1 }}
placeholder="Search for apps"
inputProps={{
'aria-label': 'Search for apps',
fontSize: '16px',
fontWeight: 400,
}}
/>
</AppsSearchLeft>
<AppsSearchRight>
{searchValue && (
<ButtonBase
onClick={() => {
setSearchValue('');
}}
>
<img src={IconClearInput} />
</ButtonBase>
)}
</AppsSearchRight>
</AppsSearchContainer>
<ButtonBase
onClick={(e) => {
getQapps();
}}
>
<RefreshIcon
sx={{
color: 'rgba(250, 250, 250, 0.5)',
width: '40px',
height: 'auto',
}}
/>
</AppsSearchLeft>
<AppsSearchRight>
{searchValue && (
<ButtonBase
onClick={() => {
setSearchValue("");
}}
>
<img src={IconClearInput} />
</ButtonBase>
)}
</AppsSearchRight>
</AppsSearchContainer>
<ButtonBase
onClick={(e) => {
getQapps()
}}
>
<RefreshIcon
sx={{
color: "rgba(250, 250, 250, 0.5)",
width: '40px',
height: 'auto'
}}
/>
</ButtonBase>
</ButtonBase>
</Box>
</Box>
</AppsWidthLimiter>
</AppsDesktopLibraryHeader>
<AppsDesktopLibraryBody
sx={{
height: `calc(100vh - 36px)`,
overflow: "auto",
padding: "0px",
alignItems: "center",
overflow: 'auto',
padding: '0px',
alignItems: 'center',
}}
>
<AppsDesktopLibraryBody
sx={{
height: `calc(100vh - 36px)`,
flexGrow: "unset",
maxWidth: "1500px",
width: "90%",
flexGrow: 'unset',
maxWidth: '1500px',
width: '90%',
}}
>
<Spacer height="70px" />
<ShowMessageReturnButton sx={{
padding: '2px'
}} onClick={() => {
executeEvent("navigateBack", {});
}}>
<MailIconImg src={ReturnSVG} />
<ComposeP>Return to Apps Dashboard</ComposeP>
</ShowMessageReturnButton>
<Spacer height="20px" />
<ShowMessageReturnButton
sx={{
padding: '2px',
}}
onClick={() => {
executeEvent('navigateBack', {});
}}
>
<MailIconImg src={ReturnSVG} />
<ComposeP>Return to Apps Dashboard</ComposeP>
</ShowMessageReturnButton>
<Spacer height="20px" />
{searchedList?.length > 0 ? (
<AppsWidthLimiter>
<StyledVirtuosoContainer
@@ -292,46 +308,48 @@ export const AppsLibraryDesktop = ({
<>
<AppLibrarySubTitle
sx={{
fontSize: "30px",
fontSize: '30px',
}}
>
Official Apps
</AppLibrarySubTitle>
<Spacer height="45px" />
<AppsContainer sx={{
gap: '50px',
justifyContent: 'flex-start'
}}>
<AppsContainer
sx={{
gap: '50px',
justifyContent: 'flex-start',
}}
>
{officialApps?.map((qapp) => {
return (
<ButtonBase
sx={{
// height: "80px",
width: "80px",
width: '80px',
}}
onClick={() => {
// executeEvent("addTab", {
// data: qapp
// })
executeEvent("selectedAppInfo", {
executeEvent('selectedAppInfo', {
data: qapp,
});
}}
>
<AppCircleContainer
sx={{
gap: "10px",
gap: '10px',
}}
>
<AppCircle
sx={{
border: "none",
border: 'none',
}}
>
<Avatar
sx={{
height: "42px",
width: "42px",
height: '42px',
width: '42px',
}}
alt={qapp?.name}
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
@@ -340,8 +358,8 @@ export const AppsLibraryDesktop = ({
>
<img
style={{
width: "31px",
height: "auto",
width: '31px',
height: 'auto',
}}
src={LogoSelected}
alt="center-icon"
@@ -359,30 +377,30 @@ export const AppsLibraryDesktop = ({
<Spacer height="80px" />
<Box
sx={{
width: "100%",
gap: "250px",
display: "flex",
width: '100%',
gap: '250px',
display: 'flex',
}}
>
<Box
sx={{
display: "flex",
flexDirection: "column",
display: 'flex',
flexDirection: 'column',
}}
>
<AppLibrarySubTitle
sx={{
fontSize: "30px",
width: "100%",
textAlign: "start",
fontSize: '30px',
width: '100%',
textAlign: 'start',
}}
>
{hasPublishApp ? "Update Apps!" : "Create Apps!"}
{hasPublishApp ? 'Update Apps!' : 'Create Apps!'}
</AppLibrarySubTitle>
<Spacer height="18px" />
<PublishQAppCTAParent
sx={{
gap: "25px",
gap: '25px',
}}
>
<PublishQAppCTALeft>
@@ -394,11 +412,11 @@ export const AppsLibraryDesktop = ({
</PublishQAppCTALeft>
<PublishQAppCTARight
onClick={() => {
setMode("publish");
setMode('publish');
}}
>
<PublishQAppCTAButton>
{hasPublishApp ? "Update" : "Publish"}
{hasPublishApp ? 'Update' : 'Publish'}
</PublishQAppCTAButton>
<Spacer width="20px" />
</PublishQAppCTARight>
@@ -406,13 +424,13 @@ export const AppsLibraryDesktop = ({
</Box>
<Box
sx={{
display: "flex",
flexDirection: "column",
display: 'flex',
flexDirection: 'column',
}}
>
<AppLibrarySubTitle
sx={{
fontSize: "30px",
fontSize: '30px',
}}
>
Categories
@@ -420,58 +438,57 @@ export const AppsLibraryDesktop = ({
<Spacer height="18px" />
<Box
sx={{
width: "100%",
display: "flex",
gap: "20px",
flexWrap: "wrap",
width: '100%',
display: 'flex',
gap: '20px',
flexWrap: 'wrap',
}}
>
<ButtonBase
onClick={() => {
executeEvent("selectedCategory", {
data: {
id: 'all',
name: 'All'
},
});
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "center",
height: "60px",
padding: "0px 24px",
border: "4px solid #10242F",
borderRadius: "6px",
boxShadow: "2px 4px 0px 0px #000000",
}}
>
All
</Box>
</ButtonBase>
<ButtonBase
onClick={() => {
executeEvent('selectedCategory', {
data: {
id: 'all',
name: 'All',
},
});
}}
>
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '60px',
padding: '0px 24px',
border: '4px solid #10242F',
borderRadius: '6px',
boxShadow: '2px 4px 0px 0px #000000',
}}
>
All
</Box>
</ButtonBase>
{categories?.map((category) => {
return (
<ButtonBase
key={category?.id}
onClick={() => {
executeEvent("selectedCategory", {
executeEvent('selectedCategory', {
data: category,
});
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "center",
height: "60px",
padding: "0px 24px",
border: "4px solid #10242F",
borderRadius: "6px",
boxShadow: "2px 4px 0px 0px #000000",
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '60px',
padding: '0px 24px',
border: '4px solid #10242F',
borderRadius: '6px',
boxShadow: '2px 4px 0px 0px #000000',
}}
>
{category?.name}

View File

@@ -1,13 +1,13 @@
import { ButtonBase, Typography, useTheme } from "@mui/material";
import Box from "@mui/material/Box";
import { HubsIcon } from "../../assets/Icons/HubsIcon";
import { MessagingIcon } from "../../assets/Icons/MessagingIcon";
import AppIcon from "../../assets/svgs/AppIcon.svg";
import { ButtonBase, Typography, useTheme } from '@mui/material';
import Box from '@mui/material/Box';
import { HubsIcon } from '../../assets/Icons/HubsIcon';
import { MessagingIcon } from '../../assets/Icons/MessagingIcon';
import AppIcon from '../../assets/svgs/AppIcon.svg';
import { HomeIcon } from "../../assets/Icons/HomeIcon";
import { Save } from "../Save/Save";
import { useRecoilState } from "recoil";
import { enabledDevModeAtom } from "../../atoms/global";
import { HomeIcon } from '../../assets/Icons/HomeIcon';
import { Save } from '../Save/Save';
import { useRecoilState } from 'recoil';
import { enabledDevModeAtom } from '../../atoms/global';
export const IconWrapper = ({
children,
@@ -22,25 +22,25 @@ export const IconWrapper = ({
return (
<Box
sx={{
display: "flex",
justifyContent: "center",
alignItems: "center",
gap: "5px",
flexDirection: "column",
height: customWidth ? customWidth : disableWidth ? "auto" : "89px",
width: customWidth ? customWidth : disableWidth ? "auto" : "89px",
borderRadius: "50%",
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
gap: '5px',
flexDirection: 'column',
height: customWidth ? customWidth : disableWidth ? 'auto' : '89px',
width: customWidth ? customWidth : disableWidth ? 'auto' : '89px',
borderRadius: '50%',
backgroundColor: selected
? theme.palette.background.default
: "transparent",
: 'transparent',
color: color ? color : theme.palette.text.primary,
}}
>
{children}
<Typography
sx={{
fontFamily: "Inter",
fontSize: "12px",
fontFamily: 'Inter',
fontSize: '12px',
fontWeight: 500,
color: theme.palette.text.primary,
}}
@@ -72,20 +72,20 @@ export const DesktopFooter = ({
return (
<Box
sx={{
width: "100%",
position: "absolute",
width: '100%',
position: 'absolute',
bottom: 0,
display: "flex",
alignItems: "center",
height: "100px", // Footer height
display: 'flex',
alignItems: 'center',
height: '100px', // Footer height
zIndex: 1,
justifyContent: "center",
justifyContent: 'center',
}}
>
<Box
sx={{
display: "flex",
gap: "20px",
display: 'flex',
gap: '20px',
}}
>
<ButtonBase
@@ -94,15 +94,13 @@ export const DesktopFooter = ({
}}
>
<IconWrapper label="Home" selected={isHome}>
<HomeIcon
height={30}
/>
<HomeIcon height={30} />
</IconWrapper>
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopViewMode("apps");
setDesktopViewMode('apps');
setIsOpenSideViewDirects(false);
setIsOpenSideViewGroups(false);
}}
@@ -114,7 +112,7 @@ export const DesktopFooter = ({
<ButtonBase
onClick={() => {
setDesktopSideView("groups");
setDesktopSideView('groups');
}}
>
<IconWrapper label="Groups" selected={isGroups}>
@@ -122,10 +120,10 @@ export const DesktopFooter = ({
height={30}
color={
hasUnreadGroups
? "var(--danger)"
? 'var(--danger)'
: isGroups
? "white"
: "rgba(250, 250, 250, 0.5)"
? 'white'
: 'rgba(250, 250, 250, 0.5)'
}
/>
</IconWrapper>
@@ -133,7 +131,7 @@ export const DesktopFooter = ({
<ButtonBase
onClick={() => {
setDesktopSideView("directs");
setDesktopSideView('directs');
}}
>
<IconWrapper label="Messaging" selected={isDirects}>
@@ -141,10 +139,10 @@ export const DesktopFooter = ({
height={30}
color={
hasUnreadDirects
? "var(--danger)"
? 'var(--danger)'
: isDirects
? "white"
: "rgba(250, 250, 250, 0.5)"
? 'white'
: 'rgba(250, 250, 250, 0.5)'
}
/>
</IconWrapper>
@@ -154,7 +152,7 @@ export const DesktopFooter = ({
{isEnabledDevMode && (
<ButtonBase
onClick={() => {
setDesktopViewMode("dev");
setDesktopViewMode('dev');
setIsOpenSideViewDirects(false);
setIsOpenSideViewGroups(false);
}}

View File

@@ -5,7 +5,7 @@ import React, {
useMemo,
useRef,
useState,
} from "react";
} from 'react';
import {
Avatar,
Box,
@@ -14,8 +14,8 @@ import {
IconButton,
Skeleton,
Typography,
} from "@mui/material";
import { ShowMessage } from "./ShowMessageWithoutModal";
} from '@mui/material';
import { ShowMessage } from './ShowMessageWithoutModal';
import {
ComposeP,
GroupContainer,
@@ -28,34 +28,33 @@ import {
ThreadInfoColumn,
ThreadInfoColumnNameP,
ThreadInfoColumnTime,
} from "./Mail-styles";
import { Spacer } from "../../../common/Spacer";
import { threadIdentifier } from "./GroupMail";
import LazyLoad from "../../../common/LazyLoad";
import ReturnSVG from "../../../assets/svgs/Return.svg";
import { NewThread } from "./NewThread";
} from './Mail-styles';
import { Spacer } from '../../../common/Spacer';
import { threadIdentifier } from './GroupMail';
import ReturnSVG from '../../../assets/svgs/Return.svg';
import { NewThread } from './NewThread';
import {
decryptPublishes,
getTempPublish,
handleUnencryptedPublishes,
} from "../../Chat/GroupAnnouncements";
import { LoadingSnackbar } from "../../Snackbar/LoadingSnackbar";
import { subscribeToEvent, unsubscribeFromEvent } from "../../../utils/events";
import RefreshIcon from "@mui/icons-material/Refresh";
} from '../../Chat/GroupAnnouncements';
import { LoadingSnackbar } from '../../Snackbar/LoadingSnackbar';
import { subscribeToEvent, unsubscribeFromEvent } from '../../../utils/events';
import RefreshIcon from '@mui/icons-material/Refresh';
import {
getArbitraryEndpointReact,
getBaseApiReact,
isMobile,
} from "../../../App";
} from '../../../App';
import {
ArrowDownward as ArrowDownwardIcon,
ArrowUpward as ArrowUpwardIcon,
} from "@mui/icons-material";
import { addDataPublishesFunc, getDataPublishesFunc } from "../Group";
import { RequestQueueWithPromise } from "../../../utils/queue/queue";
import { CustomLoader } from "../../../common/CustomLoader";
import { WrapperUserAction } from "../../WrapperUserAction";
import { formatTimestampForum } from "../../../utils/time";
} from '@mui/icons-material';
import { addDataPublishesFunc, getDataPublishesFunc } from '../Group';
import { RequestQueueWithPromise } from '../../../utils/queue/queue';
import { CustomLoader } from '../../../common/CustomLoader';
import { WrapperUserAction } from '../../WrapperUserAction';
import { formatTimestampForum } from '../../../utils/time';
const requestQueueSaveToLocal = new RequestQueueWithPromise(1);
const requestQueueDownloadPost = new RequestQueueWithPromise(3);
interface ThreadProps {
@@ -65,14 +64,10 @@ interface ThreadProps {
members: any;
}
const getEncryptedResource = async ({
name,
identifier,
secretKey,
resource,
groupId,
dataPublishes,
}, isPrivate) => {
const getEncryptedResource = async (
{ name, identifier, secretKey, resource, groupId, dataPublishes },
isPrivate
) => {
let data = dataPublishes[`${name}-${identifier}`];
if (
!data ||
@@ -92,15 +87,18 @@ const getEncryptedResource = async ({
};
}
data = await res.text();
if (data?.error || typeof data !== "string") return;
if (data?.error || typeof data !== 'string') return;
await requestQueueSaveToLocal.enqueue(() => {
return addDataPublishesFunc({ ...resource, data }, groupId, "thmsg");
return addDataPublishesFunc({ ...resource, data }, groupId, 'thmsg');
});
} else {
data = data.data;
}
const response = isPrivate === false ? handleUnencryptedPublishes([data]) : await decryptPublishes([{ data }], secretKey);
const response =
isPrivate === false
? handleUnencryptedPublishes([data])
: await decryptPublishes([{ data }], secretKey);
const messageData = response[0];
return messageData.decryptedData;
@@ -115,7 +113,7 @@ export const Thread = ({
secretKey,
getSecretKey,
updateThreadActivityCurrentThread,
isPrivate
isPrivate,
}: ThreadProps) => {
const [tempPublishedList, setTempPublishedList] = useState([]);
const [messages, setMessages] = useState<any[]>([]);
@@ -129,7 +127,7 @@ export const Thread = ({
// Update: Use a new ref for the scrollable container
const threadContainerRef = useRef(null);
const threadBeginningRef = useRef(null)
const threadBeginningRef = useRef(null);
// New state variables
const [showScrollButton, setShowScrollButton] = useState(false);
const [isAtBottom, setIsAtBottom] = useState(false);
@@ -140,7 +138,7 @@ export const Thread = ({
const dataPublishes = useRef({});
const getSavedData = useCallback(async (groupId) => {
const res = await getDataPublishesFunc(groupId, "thmsg");
const res = await getDataPublishesFunc(groupId, 'thmsg');
dataPublishes.current = res || {};
}, []);
@@ -159,14 +157,17 @@ export const Thread = ({
const getIndividualMsg = async (message: any) => {
try {
const responseDataMessage = await getEncryptedResource({
identifier: message.identifier,
name: message.name,
secretKey,
resource: message,
groupId: groupInfo?.groupId,
dataPublishes: dataPublishes.current,
}, isPrivate);
const responseDataMessage = await getEncryptedResource(
{
identifier: message.identifier,
name: message.name,
secretKey,
resource: message,
groupId: groupInfo?.groupId,
dataPublishes: dataPublishes.current,
},
isPrivate
);
if (responseDataMessage?.error) {
const fullObject = {
@@ -201,7 +202,7 @@ export const Thread = ({
try {
let threadId = currentThread.threadId;
const keyTemp = "thread-post";
const keyTemp = 'thread-post';
const getTempAnnouncements = await getTempPublish();
if (getTempAnnouncements?.[keyTemp]) {
@@ -232,10 +233,10 @@ export const Thread = ({
const identifier = `thmsg-${threadId}`;
let url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=${threadIdentifier}&identifier=${identifier}&limit=20&includemetadata=false&prefix=true`;
if (!isReverse) {
url = url + "&reverse=false";
url = url + '&reverse=false';
}
if (isReverse) {
url = url + "&reverse=true";
url = url + '&reverse=true';
}
if (after) {
url = url + `&after=${after}`;
@@ -245,9 +246,9 @@ export const Thread = ({
}
const response = await fetch(url, {
method: "GET",
method: 'GET',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json',
},
});
const responseData = await response.json();
@@ -263,14 +264,13 @@ export const Thread = ({
setMessages(fullArrayMsg);
if (before === null && after === null && isReverse) {
setTimeout(() => {
containerRef.current.scrollIntoView({ behavior: "smooth" });
containerRef.current.scrollIntoView({ behavior: 'smooth' });
}, 300);
}
if(after || before === null && after === null && !isReverse){
if (after || (before === null && after === null && !isReverse)) {
setTimeout(() => {
threadBeginningRef.current.scrollIntoView();
}, 100);
}
if (fullArrayMsg.length === 0) {
@@ -282,9 +282,9 @@ export const Thread = ({
fullArrayMsg[0].created
}`;
const responseNewer = await fetch(urlNewer, {
method: "GET",
method: 'GET',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json',
},
});
const responseDataNewer = await responseNewer.json();
@@ -300,9 +300,9 @@ export const Thread = ({
fullArrayMsg[fullArrayMsg.length - 1].created
}`;
const responseOlder = await fetch(urlOlder, {
method: "GET",
method: 'GET',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json',
},
});
const responseDataOlder = await responseOlder.json();
@@ -316,7 +316,7 @@ export const Thread = ({
updateThreadActivityCurrentThread();
}
} catch (error) {
console.log("error", error);
console.log('error', error);
} finally {
setIsLoading(false);
getSavedData(groupId);
@@ -325,9 +325,21 @@ export const Thread = ({
[messages, secretKey]
);
const getMessages = React.useCallback(async () => {
if (!currentThread || (!secretKey && isPrivate) || !groupInfo?.groupId || isPrivate === null) return;
if (
!currentThread ||
(!secretKey && isPrivate) ||
!groupInfo?.groupId ||
isPrivate === null
)
return;
await getMailMessages(currentThread, null, null, false, groupInfo?.groupId);
}, [getMailMessages, currentThread, secretKey, groupInfo?.groupId, isPrivate]);
}, [
getMailMessages,
currentThread,
secretKey,
groupInfo?.groupId,
isPrivate,
]);
const firstMount = useRef(false);
const saveTimestamp = useCallback((currentThread: any, username?: string) => {
@@ -339,7 +351,7 @@ export const Thread = ({
return;
const threadIdForLocalStorage = `qmail_threads_${currentThread?.threadData?.groupId}_${currentThread?.threadId}`;
const threads = JSON.parse(
localStorage.getItem(`qmail_threads_viewedtimestamp_${username}`) || "{}"
localStorage.getItem(`qmail_threads_viewedtimestamp_${username}`) || '{}'
);
// Convert to an array of objects with identifier and all fields
let dataArray = Object.entries(threads).map(([identifier, value]) => ({
@@ -382,8 +394,8 @@ export const Thread = ({
if (currentThreadRef.current?.threadId !== currentThread?.threadId) {
firstMount.current = false;
}
if(!secretKey && isPrivate) return
if (currentThread && !firstMount.current && isPrivate !== null) {
if (!secretKey && isPrivate) return;
if (currentThread && !firstMount.current && isPrivate !== null) {
getMessagesMiddleware();
}
}, [currentThread, secretKey, isPrivate]);
@@ -402,9 +414,9 @@ export const Thread = ({
const identifier = `thmsg-${threadId}`;
const url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=${threadIdentifier}&identifier=${identifier}&limit=20&includemetadata=false&offset=${0}&reverse=true&prefix=true`;
const response = await fetch(url, {
method: "GET",
method: 'GET',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json',
},
});
const responseData = await response.json();
@@ -469,17 +481,17 @@ export const Thread = ({
const threadFetchModeFunc = (e) => {
const mode = e.detail?.mode;
if (mode === "last-page") {
if (mode === 'last-page') {
getMailMessages(currentThread, null, null, true, groupInfo?.groupId);
}
firstMount.current = true;
};
React.useEffect(() => {
subscribeToEvent("threadFetchMode", threadFetchModeFunc);
subscribeToEvent('threadFetchMode', threadFetchModeFunc);
return () => {
unsubscribeFromEvent("threadFetchMode", threadFetchModeFunc);
unsubscribeFromEvent('threadFetchMode', threadFetchModeFunc);
};
}, []);
@@ -526,11 +538,11 @@ export const Thread = ({
handleScroll();
}, 400);
container.addEventListener("scroll", handleScroll);
container.addEventListener('scroll', handleScroll);
// Cleanup
return () => {
container.removeEventListener("scroll", handleScroll);
container.removeEventListener('scroll', handleScroll);
};
}, [messages]);
@@ -540,9 +552,9 @@ export const Thread = ({
if (!container) return;
if (isAtBottom) {
container.scrollTo({ top: 0, behavior: "smooth" }); // Scroll to top
container.scrollTo({ top: 0, behavior: 'smooth' }); // Scroll to top
} else {
container.scrollTo({ top: container.scrollHeight, behavior: "smooth" }); // Scroll to bottom
container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' }); // Scroll to bottom
}
};
@@ -550,19 +562,19 @@ export const Thread = ({
return (
<GroupContainer
sx={{
position: "relative",
width: "100%",
display: "flex",
flexDirection: "column",
overflow: "hidden",
position: 'relative',
width: '100%',
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
}}
// Removed the ref from here since the scrollable area has changed
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
flexShrink: 0, // Corrected property name
}}
>
@@ -583,16 +595,16 @@ export const Thread = ({
/>
<Box
sx={{
display: "flex",
gap: isMobile ? "45px" : "35px",
alignItems: "center",
padding: isMobile && "5px",
display: 'flex',
gap: isMobile ? '45px' : '35px',
alignItems: 'center',
padding: isMobile && '5px',
}}
>
<ShowMessageReturnButton
sx={{
padding: isMobile && "5px",
minWidth: isMobile && "50px",
padding: isMobile && '5px',
minWidth: isMobile && '50px',
}}
onClick={() => {
setMessages([]);
@@ -608,9 +620,9 @@ export const Thread = ({
<ButtonBase onClick={scrollToPosition}>
<ArrowUpwardIcon
sx={{
color: "white",
cursor: "pointer",
fontSize: isMobile ? "28px" : "36px",
color: 'white',
cursor: 'pointer',
fontSize: isMobile ? '28px' : '36px',
}}
/>
</ButtonBase>
@@ -618,9 +630,9 @@ export const Thread = ({
<ButtonBase onClick={scrollToPosition}>
<ArrowDownwardIcon
sx={{
color: "white",
cursor: "pointer",
fontSize: isMobile ? "28px" : "36px",
color: 'white',
cursor: 'pointer',
fontSize: isMobile ? '28px' : '36px',
}}
/>
</ButtonBase>
@@ -631,45 +643,45 @@ export const Thread = ({
<ThreadContainerFullWidth
sx={{
flexGrow: 1,
overflow: "auto",
overflow: 'auto',
}}
ref={threadContainerRef} // Updated ref attached here
>
<div ref={threadBeginningRef}/>
<div ref={threadBeginningRef} />
<ThreadContainer>
<Spacer height={isMobile ? "10px" : "30px"} />
<Spacer height={isMobile ? '10px' : '30px'} />
<Box
sx={{
width: "100%",
alignItems: "center",
display: "flex",
justifyContent: "space-between",
width: '100%',
alignItems: 'center',
display: 'flex',
justifyContent: 'space-between',
}}
>
<GroupNameP
sx={{
fontSize: isMobile && "18px",
fontSize: isMobile && '18px',
}}
>
{currentThread?.threadData?.title}
</GroupNameP>
</Box>
<Spacer height={"15px"} />
<Spacer height={'15px'} />
<Box
sx={{
width: "100%",
alignItems: "center",
display: "flex",
justifyContent: "center",
gap: "5px",
width: '100%',
alignItems: 'center',
display: 'flex',
justifyContent: 'center',
gap: '5px',
}}
>
<Button
sx={{
padding: isMobile && "5px",
fontSize: isMobile && "14px",
textTransformation: "capitalize",
padding: isMobile && '5px',
fontSize: isMobile && '14px',
textTransformation: 'capitalize',
}}
onClick={() => {
getMailMessages(
@@ -687,9 +699,9 @@ export const Thread = ({
</Button>
<Button
sx={{
padding: isMobile && "5px",
fontSize: isMobile && "14px",
textTransformation: "capitalize",
padding: isMobile && '5px',
fontSize: isMobile && '14px',
textTransformation: 'capitalize',
}}
onClick={() => {
getMailMessages(
@@ -707,9 +719,9 @@ export const Thread = ({
</Button>
<Button
sx={{
padding: isMobile && "5px",
fontSize: isMobile && "14px",
textTransformation: "capitalize",
padding: isMobile && '5px',
fontSize: isMobile && '14px',
textTransformation: 'capitalize',
}}
onClick={() => {
getMailMessages(
@@ -727,9 +739,9 @@ export const Thread = ({
</Button>
<Button
sx={{
padding: isMobile && "5px",
fontSize: isMobile && "14px",
textTransformation: "capitalize",
padding: isMobile && '5px',
fontSize: isMobile && '14px',
textTransformation: 'capitalize',
}}
onClick={() => {
getMailMessages(
@@ -746,35 +758,34 @@ export const Thread = ({
Last
</Button>
</Box>
<Spacer height={isMobile ? "10px" : "30px"} />
<Spacer height={isMobile ? '10px' : '30px'} />
{combinedListTempAndReal.map((message, index, list) => {
let fullMessage = message;
if (hashMapMailMessages[message?.identifier]) {
fullMessage = hashMapMailMessages[message.identifier];
if (fullMessage?.error) {
return (
<SingleThreadParent
sx={{
height: "auto",
height: 'auto',
}}
>
<Box
style={{
width: "100%",
borderRadius: "8px",
overflow: "hidden",
position: "relative",
flexDirection: "column",
width: '100%',
borderRadius: '8px',
overflow: 'hidden',
position: 'relative',
flexDirection: 'column',
}}
>
<Box
sx={{
display: "flex",
alignItems: "flex-start",
gap: "10px",
display: 'flex',
alignItems: 'flex-start',
gap: '10px',
}}
>
<WrapperUserAction
@@ -784,8 +795,8 @@ export const Thread = ({
>
<Avatar
sx={{
height: "50px",
width: "50px",
height: '50px',
width: '50px',
}}
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
message?.name
@@ -812,23 +823,22 @@ export const Thread = ({
</Box>
<Box
sx={{
width: "100%",
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
width: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'column',
}}
>
<Typography
sx={{
fontSize: "18px",
color: "white",
fontSize: '18px',
color: 'white',
}}
>
{fullMessage?.error}
</Typography>
</Box>
</Box>
</SingleThreadParent>
);
@@ -855,23 +865,23 @@ export const Thread = ({
return (
<SingleThreadParent
sx={{
height: "auto",
height: 'auto',
}}
>
<Box
style={{
width: "100%",
borderRadius: "8px",
overflow: "hidden",
position: "relative",
flexDirection: "column",
width: '100%',
borderRadius: '8px',
overflow: 'hidden',
position: 'relative',
flexDirection: 'column',
}}
>
<Box
sx={{
display: "flex",
alignItems: "flex-start",
gap: "10px",
display: 'flex',
alignItems: 'flex-start',
gap: '10px',
}}
>
<WrapperUserAction
@@ -881,8 +891,8 @@ export const Thread = ({
>
<Avatar
sx={{
height: "50px",
width: "50px",
height: '50px',
width: '50px',
}}
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
message?.name
@@ -909,37 +919,36 @@ export const Thread = ({
</Box>
<Box
sx={{
width: "100%",
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
width: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'column',
}}
>
<CustomLoader />
<Typography
sx={{
fontSize: "18px",
color: "white",
fontSize: '18px',
color: 'white',
}}
>
Downloading from QDN
</Typography>
</Box>
</Box>
</SingleThreadParent>
);
})}
{!hasLastPage && !isLoading && (
<>
<Spacer height="20px" />
<Box
sx={{
width: "100%",
display: "flex",
justifyContent: "flex-end",
width: '100%',
display: 'flex',
justifyContent: 'flex-end',
}}
>
<Button
@@ -955,7 +964,7 @@ export const Thread = ({
);
}}
sx={{
color: "white",
color: 'white',
}}
>
Refetch page
@@ -964,112 +973,113 @@ export const Thread = ({
</>
)}
<Box sx={{
<Box
sx={{
width: '100%',
visibility: messages?.length > 4 ? 'visible' : 'hidden'
}}>
<Spacer height="30px" />
<Box
visibility: messages?.length > 4 ? 'visible' : 'hidden',
}}
>
<Spacer height="30px" />
<Box
sx={{
width: '100%',
alignItems: 'center',
display: 'flex',
justifyContent: 'center',
gap: '5px',
}}
>
<Button
sx={{
width: "100%",
alignItems: "center",
display: "flex",
justifyContent: "center",
gap: "5px",
padding: isMobile && '5px',
fontSize: isMobile && '14px',
textTransformation: 'capitalize',
}}
onClick={() => {
getMailMessages(
currentThread,
null,
null,
false,
groupInfo?.groupId
);
}}
disabled={!hasFirstPage}
variant="contained"
>
<Button
sx={{
padding: isMobile && "5px",
fontSize: isMobile && "14px",
textTransformation: "capitalize",
}}
onClick={() => {
getMailMessages(
currentThread,
null,
null,
false,
groupInfo?.groupId
);
}}
disabled={!hasFirstPage}
variant="contained"
>
First
</Button>
<Button
sx={{
padding: isMobile && "5px",
fontSize: isMobile && "14px",
textTransformation: "capitalize",
}}
onClick={() => {
getMailMessages(
currentThread,
messages[0].created,
null,
false,
groupInfo?.groupId
);
}}
disabled={!hasPreviousPage}
variant="contained"
>
Previous
</Button>
<Button
sx={{
padding: isMobile && "5px",
fontSize: isMobile && "14px",
textTransformation: "capitalize",
}}
onClick={() => {
getMailMessages(
currentThread,
null,
messages[messages.length - 1].created,
false,
groupInfo?.groupId
);
}}
disabled={!hasNextPage}
variant="contained"
>
Next
</Button>
<Button
sx={{
padding: isMobile && "5px",
fontSize: isMobile && "14px",
textTransformation: "capitalize",
}}
onClick={() => {
getMailMessages(
currentThread,
null,
null,
true,
groupInfo?.groupId
);
}}
disabled={!hasLastPage}
variant="contained"
>
Last
</Button>
</Box>
<Spacer height="30px" />
First
</Button>
<Button
sx={{
padding: isMobile && '5px',
fontSize: isMobile && '14px',
textTransformation: 'capitalize',
}}
onClick={() => {
getMailMessages(
currentThread,
messages[0].created,
null,
false,
groupInfo?.groupId
);
}}
disabled={!hasPreviousPage}
variant="contained"
>
Previous
</Button>
<Button
sx={{
padding: isMobile && '5px',
fontSize: isMobile && '14px',
textTransformation: 'capitalize',
}}
onClick={() => {
getMailMessages(
currentThread,
null,
messages[messages.length - 1].created,
false,
groupInfo?.groupId
);
}}
disabled={!hasNextPage}
variant="contained"
>
Next
</Button>
<Button
sx={{
padding: isMobile && '5px',
fontSize: isMobile && '14px',
textTransformation: 'capitalize',
}}
onClick={() => {
getMailMessages(
currentThread,
null,
null,
true,
groupInfo?.groupId
);
}}
disabled={!hasLastPage}
variant="contained"
>
Last
</Button>
</Box>
<div ref={containerRef} />
<Spacer height="30px" />
</Box>
<div ref={containerRef} />
</ThreadContainer>
</ThreadContainerFullWidth>
<LoadingSnackbar
open={isLoading}
info={{
message: "Loading posts... please wait.",
message: 'Loading posts... please wait.',
}}
/>
</GroupContainer>

View File

@@ -4,56 +4,59 @@ import {
TextField,
TextFieldProps,
styled,
} from "@mui/material";
import { forwardRef, useState } from "react";
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
import VisibilityIcon from "@mui/icons-material/Visibility";
useTheme,
} from '@mui/material';
import { forwardRef, useState } from 'react';
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
import VisibilityIcon from '@mui/icons-material/Visibility';
export const CustomInput = styled(TextField)(({ theme }) => ({
width: "183px",
borderRadius: "5px",
backgroundColor: theme.palette.background.paper,
outline: "none",
input: {
fontSize: 10,
fontFamily: "Inter",
fontWeight: 400,
color: theme.palette.text.primary,
"&::placeholder": {
fontSize: 16,
color: theme.palette.text.disabled,
},
outline: "none",
padding: "10px",
width: '183px',
borderRadius: '5px',
backgroundColor: theme.palette.background.paper,
outline: 'none',
input: {
fontSize: 10,
fontFamily: 'Inter',
fontWeight: 400,
color: theme.palette.text.primary,
'&::placeholder': {
fontSize: 16,
color: theme.palette.text.disabled,
},
"& .MuiOutlinedInput-root": {
"& fieldset": {
border: `0.5px solid ${theme.palette.divider}`,
},
"&:hover fieldset": {
border: `0.5px solid ${theme.palette.divider}`,
},
"&.Mui-focused fieldset": {
border: `0.5px solid ${theme.palette.divider}`,
},
outline: 'none',
padding: '10px',
},
'& .MuiOutlinedInput-root': {
'& fieldset': {
border: `0.5px solid ${theme.palette.divider}`,
},
"& .MuiInput-underline:before": {
borderBottom: "none",
'&:hover fieldset': {
border: `0.5px solid ${theme.palette.divider}`,
},
"& .MuiInput-underline:hover:not(.Mui-disabled):before": {
borderBottom: "none",
'&.Mui-focused fieldset': {
border: `0.5px solid ${theme.palette.divider}`,
},
"& .MuiInput-underline:after": {
borderBottom: "none",
},
}));
},
'& .MuiInput-underline:before': {
borderBottom: 'none',
},
'& .MuiInput-underline:hover:not(.Mui-disabled):before': {
borderBottom: 'none',
},
'& .MuiInput-underline:after': {
borderBottom: 'none',
},
}));
export const PasswordField = forwardRef<HTMLInputElement, TextFieldProps>(
({ ...props }, ref) => {
const [canViewPassword, setCanViewPassword] = useState(false);
const theme = useTheme();
return (
<CustomInput
type={canViewPassword ? "text" : "password"}
type={canViewPassword ? 'text' : 'password'}
InputProps={{
endAdornment: (
<InputAdornment
@@ -70,7 +73,10 @@ export const PasswordField = forwardRef<HTMLInputElement, TextFieldProps>(
>
<VisibilityOffIcon
sx={{
color: "white",
color:
theme.palette.mode === 'dark'
? 'rgba(255, 255, 255, 0.5)'
: 'rgba(0, 0, 0, 0.3)',
}}
/>
</ButtonBase>
@@ -81,7 +87,10 @@ export const PasswordField = forwardRef<HTMLInputElement, TextFieldProps>(
>
<VisibilityIcon
sx={{
color: "white",
color:
theme.palette.mode === 'dark'
? 'rgba(255, 255, 255, 0.5)'
: 'rgba(0, 0, 0, 0.3)',
}}
/>
</ButtonBase>