From 9aebed7ddcd8e13c9a35a60cbab1c01ee78958a9 Mon Sep 17 00:00:00 2001 From: miko Date: Sun, 27 Aug 2023 13:18:52 +0400 Subject: [PATCH] Save --- src/components/ActivityIcon.js | 90 +++++---- src/components/ActivityStreamItem.js | 138 +++++-------- src/components/ActivityStreamItemAvatar.js | 22 ++- src/components/ActivityStreamWithTabs.js | 67 +++---- src/components/NewsFeed.js | 215 --------------------- src/components/TabNavigationAction.js | 1 - src/store/activity/actions.js | 9 + src/store/activity/reducers.js | 3 +- 8 files changed, 145 insertions(+), 400 deletions(-) delete mode 100644 src/components/NewsFeed.js diff --git a/src/components/ActivityIcon.js b/src/components/ActivityIcon.js index 108a18ae..c08bbec5 100644 --- a/src/components/ActivityIcon.js +++ b/src/components/ActivityIcon.js @@ -3,61 +3,57 @@ import React from 'react'; import { useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; -import core from '~/services/core'; import { CATEGORIES } from '~/store/activity/reducers'; import { IconNotification } from '~/styles/icons'; -const newsItems = core.news; const DashboardActivityIcon = () => { - // const { categories, lastSeenAt } = useSelector((state) => { - // return state.activity; - // }); + const { categories, lastSeenAt, news } = useSelector((state) => { + return state.activity; + }); - // const NEWS = Symbol.for('NEWS'); - // const categoriesWithNews = { ...categories, ...{ [NEWS]: newsItems } }; - // let CATEGORIES_WITH_NEWS = [...CATEGORIES]; - // CATEGORIES_WITH_NEWS.push(NEWS); + // Is there any pending transactions? + const isPending = CATEGORIES.find((category) => { + return !!categories[category].activities.find((activity) => { + return activity.isPending; + }); + }); - // // Is there any pending transactions? - // const isPending = CATEGORIES_WITH_NEWS.find((category) => { - // return !!categoriesWithNews[category].activities.find((activity) => { - // return activity.isPending; - // }); - // }); + // Count how many activities we haven't seen yet + const count = CATEGORIES.reduce((acc, category) => { + return ( + acc + + categories[category].activities.reduce((itemAcc, activity) => { + return activity.createdAt > lastSeenAt ? itemAcc + 1 : itemAcc; + }, 0) + ); + }, 0); - // // Count how many activities we haven't seen yet - // const count = CATEGORIES_WITH_NEWS.reduce((acc, category) => { - // return ( - // acc + - // categoriesWithNews[category].activities.reduce((itemAcc, activity) => { - // return activity.createdAt > lastSeenAt ? itemAcc + 1 : itemAcc; - // }, 0) - // ); - // }, 0); + const countNews = news.activities.reduce((itemAcc, activity) => { + return activity.createdAt > lastSeenAt ? itemAcc + 1 : itemAcc; + }, 0); - // return ( - // - // {isPending ? ( - // - // ) : ( - // - // - // - // )} - // - // ); - return <>; + return ( + + {isPending ? ( + + ) : ( + + + + )} + + ); }; export default DashboardActivityIcon; diff --git a/src/components/ActivityStreamItem.js b/src/components/ActivityStreamItem.js index 5e66fc85..a33945f6 100644 --- a/src/components/ActivityStreamItem.js +++ b/src/components/ActivityStreamItem.js @@ -1,27 +1,22 @@ import { - Badge, Box, Card, CardContent, CardHeader, - CircularProgress, Collapse, Divider, IconButton, - Avatar as MuiAvatar, Typography, Zoom, } from '@mui/material'; import makeStyles from '@mui/styles/makeStyles'; import clsx from 'clsx'; +import { DateTime } from 'luxon'; import PropTypes from 'prop-types'; import React, { Fragment, useMemo, useState } from 'react'; -import { Link } from 'react-router-dom'; import ActivityStreamItemAvatar from '~/components/ActivityStreamItemAvatar'; -import Avatar from '~/components/Avatar'; import ExternalLink from '~/components/ExternalLink'; -import Logo from '~/components/Logo'; import { usePaymentNote } from '~/hooks/transfer'; import { useRelativeProfileLink } from '~/hooks/url'; import { useUserdata } from '~/hooks/username'; @@ -34,18 +29,19 @@ import { FAQ_URL, ISSUANCE_RATE_MONTH, ZERO_ADDRESS } from '~/utils/constants'; const { ActivityTypes } = core.activity; const useStyles = makeStyles((theme) => ({ - // avatarTransparent: { - // width: theme.custom.components.avatarSize, - // height: theme.custom.components.avatarSize, - // backgroundColor: 'transparent', - // }, - cardHeader: { - cursor: 'pointer', - background: theme.custom.colors.whiteAlmost, + cardContainer: { '&:hover': { background: theme.custom.colors.blackSqueeze, + + '& .MuiCardHeader-root': { + background: theme.custom.colors.blackSqueeze, + }, }, }, + cardHeader: { + cursor: 'pointer', + background: theme.custom.colors.whiteAlmost, + }, cardHeaderUnseen: { position: 'relative', '&::after': { @@ -55,8 +51,8 @@ const useStyles = makeStyles((theme) => ({ display: 'block', content: '""', borderRadius: '50%', - width: 7, - height: 7, + width: '13px', + height: '13px', background: theme.custom.gradients.purple, }, }, @@ -66,7 +62,9 @@ const useStyles = makeStyles((theme) => ({ alignSelf: 'center', }, cardContent: { - paddingTop: 0, + padding: '15px 0 15px', + margin: '5px 15px 0 15px', + borderTop: `1px solid ${theme.custom.colors.oldLavender}`, ' &.MuiCardContent-root': { paddingBottom: `${theme.spacing(1.5)}`, }, @@ -88,29 +86,6 @@ const useStyles = makeStyles((theme) => ({ }, })); -// const ActivityStreamItemAvatar = (props) => { -// return ( -// -// {props.isPending ? ( -// -// -// -// ) : isUBIPayout ? ( -// -// -// -// ) : ( -// -// -// -// )} -// -// ); -// }; - const ActivityStreamItem = (props) => { const classes = useStyles(); const [isExpanded, setIsExanded] = useState(false); @@ -120,7 +95,7 @@ const ActivityStreamItem = (props) => { }; // Reformat the message for the user - const { + let { addressActor, addressOrigin, addressTarget, @@ -129,6 +104,13 @@ const ActivityStreamItem = (props) => { messageId, } = props.type !== 'NEWS' ? formatMessage(props) : props; + if (!formattedDate) { + // // TODO which one? data.createdAt || data.date + formattedDate = DateTime.fromISO( + props.data.createdAt || props.data.date, + ).toFormat('dd.LL.yyyy'); + } + const actor = useUserdata(addressActor).username; const profilePath = useRelativeProfileLink( addressActor ? addressActor : props.safeAddress, @@ -160,11 +142,12 @@ const ActivityStreamItem = (props) => { ...data, actor, }) - : data.message.en; + : // TODO remove || 'This is test title' + data.title?.en || 'This is test title'; }, [actor, data, messageId]); return ( - + { profilePath={profilePath} type={props.type} /> - // - // {props.isPending ? ( - // - // - // - // ) : isUBIPayout ? ( - // - // - // - // ) : ( - // - // - // - // )} - // } classes={{ root: clsx(classes.cardHeader, { @@ -216,6 +181,7 @@ const ActivityStreamItem = (props) => { { const classes = useStyles(); @@ -260,20 +228,28 @@ const ActivityStreamExplained = ({ {type === ActivityTypes.HUB_TRANSFER && isExpanded && ( )} + {messageId && ( + + {text} + + )} - {text} - - - {translate('ActivityStream.bodyExplainSecondary')}{' '} - + {' '} + {translate('ActivityStream.linkLearnMore')} @@ -304,21 +280,6 @@ const ActivityStreamPaymentNote = ({ txHash }) => { ); }; -// const ActivityStreamAvatars = ({ addressOrigin, addressTarget }) => { -// return ( -// } -// overlap="circular" -// > -// -// -// ); -// }; - ActivityStreamItem.propTypes = { createdAt: PropTypes.string, data: PropTypes.object.isRequired, @@ -337,19 +298,16 @@ ActivityStreamItem.propTypes = { ActivityStreamExplained.propTypes = { actor: PropTypes.string.isRequired, data: PropTypes.object.isRequired, + extendedMsg: PropTypes.string, isExpanded: PropTypes.bool.isRequired, messageId: PropTypes.string, txHash: PropTypes.string, type: PropTypes.oneOfType([PropTypes.symbol, PropTypes.string]), + url: PropTypes.string, }; ActivityStreamPaymentNote.propTypes = { txHash: PropTypes.string.isRequired, }; -// ActivityStreamAvatars.propTypes = { -// addressOrigin: PropTypes.string.isRequired, -// addressTarget: PropTypes.string.isRequired, -// }; - export default ActivityStreamItem; diff --git a/src/components/ActivityStreamItemAvatar.js b/src/components/ActivityStreamItemAvatar.js index b5e36f6f..5b73e1be 100644 --- a/src/components/ActivityStreamItemAvatar.js +++ b/src/components/ActivityStreamItemAvatar.js @@ -16,7 +16,6 @@ import { IconExclamationAndQuestionMark, IconHeartWithExclamationMark, } from '~/styles/icons'; -import { IconCloseOutline } from '~/styles/icons'; const useStyles = makeStyles((theme) => ({ avatarTransparent: { @@ -24,18 +23,23 @@ const useStyles = makeStyles((theme) => ({ height: theme.custom.components.avatarSize, backgroundColor: 'transparent', }, + iconContainer: { + '& svg': { + fontSize: '32px', + }, + }, })); const iconSelector = (icon) => { switch (icon) { - case 'IconHeartWithExclamationMark': - return IconExclamationAndQuestionMark; - case 'IconCirclesLogoLight': + case 1: return IconCirclesLogoLight; - case 'IconExclamationAndQuestionMark': + case 2: + return IconExclamationAndQuestionMark; + case 3: return IconHeartWithExclamationMark; default: - return IconExclamationAndQuestionMark; + return IconCirclesLogoLight; } }; @@ -61,7 +65,6 @@ const ActivityStreamItemAvatar = ({ }) => { const classes = useStyles(); - console.log('props2', type); if (type === 'NEWS') { return ; } @@ -106,12 +109,17 @@ const ActivityStreamAvatars = ({ addressOrigin, addressTarget }) => { ActivityStreamItemAvatar.propTypes = { addressOrigin: PropTypes.string, addressTarget: PropTypes.string, + iconId: PropTypes.number, isPending: PropTypes.bool, isUBIPayout: PropTypes.bool, profilePath: PropTypes.string, type: PropTypes.oneOfType([PropTypes.symbol, PropTypes.string]), }; +ActivityStreamItemAvatarNews.propTypes = { + iconId: PropTypes.number, +}; + ActivityStreamAvatars.propTypes = { addressOrigin: PropTypes.string, addressTarget: PropTypes.string, diff --git a/src/components/ActivityStreamWithTabs.js b/src/components/ActivityStreamWithTabs.js index 2c97dab0..cb2361df 100644 --- a/src/components/ActivityStreamWithTabs.js +++ b/src/components/ActivityStreamWithTabs.js @@ -7,24 +7,25 @@ import React, { Fragment, useCallback, useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { generatePath, useHistory } from 'react-router-dom'; -import { IconMegaphone } from '../styles/icons'; import { ACTIVITIES_PATH } from '~/routes'; import ActivityStream from '~/components/ActivityStream'; import BadgeTab from '~/components/BadgeTab'; import ButtonIcon from '~/components/ButtonIcon'; import DialogExportStatement from '~/components/DialogExportStatement'; -import NewsFeed from '~/components/NewsFeed'; import Popover from '~/components/Popover'; import TabNavigation from '~/components/TabNavigation'; import TabNavigationAction from '~/components/TabNavigationAction'; -import { useQuery } from '~/hooks/url'; import { useIsOrganization } from '~/hooks/username'; import core from '~/services/core'; import translate from '~/services/locale'; import { loadMoreActivities, updateLastSeen } from '~/store/activity/actions'; import { CATEGORIES } from '~/store/activity/reducers'; -import { IconConnections, IconTransactions } from '~/styles/icons'; +import { + IconConnections, + IconMegaphone, + IconTransactions, +} from '~/styles/icons'; import { FILTER_TRANSACTION_ALL, FILTER_TRANSACTION_RECEIVED, @@ -32,7 +33,6 @@ import { } from '~/utils/constants'; const { ActivityFilterTypes } = core.activity; -const { activities: newsActivities } = core.news; const DEFAULT_CATEGORY = ActivityFilterTypes.CONNECTIONS; @@ -46,6 +46,9 @@ const useStyles = makeStyles(() => ({ display: 'flex', justifyContent: 'flex-start', }, + isHidden: { + visibility: 'hidden', + }, actionsContainer: { display: 'flex', flexDirection: 'row', @@ -74,7 +77,7 @@ const useStyles = makeStyles(() => ({ const QUERY_FILTER_MAP = { transfers: ActivityFilterTypes.TRANSFERS, connections: ActivityFilterTypes.CONNECTIONS, - news: 'News', + news: Symbol('NEWS'), }; const filterToQuery = (filterName) => { @@ -89,12 +92,6 @@ const ActivityStreamWithTabs = ({ basePath = ACTIVITIES_PATH }) => { const history = useHistory(); const [dialogOpen, setDialogOpen] = useState(false); - const { category } = useQuery(); - const preselectedCategory = - category in QUERY_FILTER_MAP - ? QUERY_FILTER_MAP[category] - : DEFAULT_CATEGORY; - const [categorySetByUser, setCategorySetByUser] = useState(false); const [filterTransactionsIndex, setFilterTransactionIndex] = useState(0); const [filterTransactionsType, setFilterTransactionType] = useState( @@ -122,7 +119,7 @@ const ActivityStreamWithTabs = ({ basePath = ACTIVITIES_PATH }) => { const { isOrganization } = useIsOrganization(safeAddress); // Get only new Activities and segregate them by category - const newActivities = CATEGORIES.reduceRight((newActivities, category) => { + let newActivities = CATEGORIES.reduceRight((newActivities, category) => { const newActivitiesInCategoryCounter = categories[ category ].activities.reduce((itemAcc, activity) => { @@ -134,6 +131,11 @@ const ActivityStreamWithTabs = ({ basePath = ACTIVITIES_PATH }) => { return newActivities; }, {}); + const newNews = news.activities.reduce((itemAcc, activity) => { + return activity.createdAt > lastSeenAt ? itemAcc + 1 : itemAcc; + }, 0); + newActivities = { ...newActivities, [QUERY_FILTER_MAP.news]: newNews }; + // Get the highest activity tab from all new activities const symbols = Object.getOwnPropertySymbols(newActivities); const newActivitiesHighestItem = symbols.reduce( @@ -205,13 +207,6 @@ const ActivityStreamWithTabs = ({ basePath = ACTIVITIES_PATH }) => { handleFilterSelection(null, category); } }, [handleFilterSelection]); - // const handleLoadMoreNews = () => {}; - // const isLoadingMoreNews = false; - // const isMoreAvailableNews = false; - - // const newNewsActivities = newsActivities.reduceRight((acc, activity) => { - // return activity.createdAt > lastSeenAt ? acc + 1 : acc; - // }, 0); const filterBtnHandler = (event) => { setAnchorEl(event.currentTarget); @@ -259,18 +254,24 @@ const ActivityStreamWithTabs = ({ basePath = ACTIVITIES_PATH }) => { value={ActivityFilterTypes.CONNECTIONS} /> } - // itemsCounter={ - // preselectedCategory !== 'News' && newNewsActivities - // ? newNewsActivities - // : null - // } + icon={ + + } label={translate('ActivityStreamWithTabs.bodyFilterNews')} - value={'News'} + value={QUERY_FILTER_MAP.news} /> - + { onLoadMore={handleLoadMore} /> )} - {/* TODO merge(?) NewsFeed with ActivityStream depending on API */} - {/* {preselectedCategory === 'News' && ( - - )} */} ); }; diff --git a/src/components/NewsFeed.js b/src/components/NewsFeed.js deleted file mode 100644 index 80006f38..00000000 --- a/src/components/NewsFeed.js +++ /dev/null @@ -1,215 +0,0 @@ -import { - Box, - Card, - CircularProgress, - Collapse, - Divider, - IconButton, - Zoom, -} from '@mui/material'; -import makeStyles from '@mui/styles/makeStyles'; -import PropTypes from 'prop-types'; -import React, { useState } from 'react'; - -import Button from '~/components/Button'; -import translate from '~/services/locale'; -import { - IconCirclesLogoLight, - IconExclamationAndQuestionMark, - IconHeartWithExclamationMark, -} from '~/styles/icons'; -import { IconCloseOutline } from '~/styles/icons'; - -const useStyles = makeStyles((theme) => ({ - newsItemContainer: { - boxShadow: theme.custom.shadows.grayAround, - borderRadius: '5px', - background: theme.custom.colors.whiteAlmost, - padding: '16px', - gap: '18px', - marginBottom: '12px', - cursor: 'pointer', - - '&:hover': { - background: theme.custom.colors.blackSqueeze, - }, - }, - newsItemHeader: { - display: 'flex', - flexDirection: 'row', - alignItems: 'center', - }, - newsItemContentContainer: { - paddingTop: '16px', - }, - divider: { backgroundColor: theme.custom.colors.oldLavender }, - content: { - paddingTop: '16px', - color: theme.custom.colors.violet, - '& p:last-of-type': { - display: 'inline', - }, - '& a': { - color: theme.custom.colors.purple, - textDecoration: 'none', - }, - }, - iconContainer: { - width: '33px', - height: '33px', - display: 'flex', - marginRight: '18px', - alignItems: 'center', - justifyContent: 'center', - - '& .MuiSvgIcon-root': { - width: '100%', - height: '100%', - }, - }, - title: { - color: theme.custom.colors.violet, - display: 'block', - fontWeight: '500', - }, - date: { - color: theme.custom.colors.oldLavender, - fontSize: '12px', - }, - cardContentCloseIcon: { - color: theme.custom.colors.oldLavender, - - '&:hover': { - color: theme.custom.colors.mountbattenPink, - backgroundColor: 'transparent', - }, - }, -})); - -const iconSelector = (icon) => { - switch (icon) { - case 'IconHeartWithExclamationMark': - return IconExclamationAndQuestionMark; - case 'IconCirclesLogoLight': - return IconCirclesLogoLight; - case 'IconExclamationAndQuestionMark': - return IconHeartWithExclamationMark; - default: - return IconExclamationAndQuestionMark; - } -}; - -const NewsFeed = ({ - news, - isLoading, - isMoreAvailable, - onLoadMore, - lastSeenAt, -}) => { - return ( - - - {isLoading && ( - - - - )} - {isMoreAvailable && onLoadMore && ( - - - - )} - - ); -}; - -const NewsList = ({ news, lastSeenAt }) => { - const newsListElement = news.map((item) => { - return ; - }); - - return {newsListElement}; -}; - -const NewsItem = ({ newsItem, lastSeenAt }) => { - const classes = useStyles(); - - const [isExpanded, setIsExpanded] = useState(newsItem.createdAt > lastSeenAt); - - const handleBtnContent = () => { - setIsExpanded(!isExpanded); - }; - const Icon = iconSelector(newsItem.icon); - - return ( - - - - - - - {newsItem.title} - {newsItem.date} - - - - - - ${translate( - 'ActivityStream.linkLearnMore', - )}`, - }} - /> - - - - - - - - - - - ); -}; - -NewsFeed.propTypes = { - isLoading: PropTypes.bool.isRequired, - isMoreAvailable: PropTypes.bool.isRequired, - lastSeenAt: PropTypes.string, - news: PropTypes.array.isRequired, - onLoadMore: PropTypes.func, -}; - -NewsList.propTypes = { - lastSeenAt: PropTypes.string, - news: PropTypes.array.isRequired, -}; - -NewsItem.propTypes = { - lastSeenAt: PropTypes.string, - newsItem: PropTypes.shape({ - createdAt: PropTypes.string, - id: PropTypes.string, - title: PropTypes.string, - text: PropTypes.string, - url: PropTypes.string, - date: PropTypes.string, - icon: PropTypes.string, - }), -}; - -export default NewsFeed; diff --git a/src/components/TabNavigationAction.js b/src/components/TabNavigationAction.js index 1518bb34..e3b9f88c 100644 --- a/src/components/TabNavigationAction.js +++ b/src/components/TabNavigationAction.js @@ -40,7 +40,6 @@ const useStyles = makeStyles((theme) => ({ }, }, '&.MuiTab-labelIcon': { - // minHeight: 'auto', paddingBottom: '3px', '& .MuiTab-wrapper > *:first-child': { diff --git a/src/store/activity/actions.js b/src/store/activity/actions.js index 11e69e84..57ed1e4f 100644 --- a/src/store/activity/actions.js +++ b/src/store/activity/actions.js @@ -366,6 +366,7 @@ export function loadMoreActivitiesNews(options = {}) { const offset = fromOffsetZero ? 0 : activity.news.offset; try { + // TODO - we could use const { data } = await core.news.getLatestNews... but it's undefined here const { data } = await core.utils.requestAPI({ path: ['news'], method: 'GET', @@ -376,6 +377,14 @@ export function loadMoreActivitiesNews(options = {}) { // offset, }, }); + // const { data } = await core.news.getLatestNews({ + // // afterDate, + // // isActive, + // // limit, + // // offset, + // }); + + console.log('data', data); dispatch({ type: ActionTypes.ACTIVITIES_NEWS_LOAD_MORE_SUCCESS, diff --git a/src/store/activity/reducers.js b/src/store/activity/reducers.js index 04e6b39c..62e5fd69 100644 --- a/src/store/activity/reducers.js +++ b/src/store/activity/reducers.js @@ -272,8 +272,7 @@ const activityReducer = (state = initialState, action) => { }); case ActionTypes.ACTIVITIES_NEWS_LOAD_MORE_SUCCESS: { // Nothing more to add .. - console.log('action.meta', action.meta); - if (action.meta.activities.length === 0) { + if (action.meta.activities.lengthx === 0) { return update(state, { news: { isLoadingMore: { $set: false },