Skip to content

Commit

Permalink
Merge pull request #403 from skalenetwork/develop
Browse files Browse the repository at this point in the history
Portal 3.1 Hotfixes to Beta
  • Loading branch information
dmytrotkk authored Oct 29, 2024
2 parents 3ae6bfa + 2db8bee commit 1a5bfbb
Show file tree
Hide file tree
Showing 16 changed files with 411 additions and 106 deletions.
2 changes: 1 addition & 1 deletion src/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -276,4 +276,4 @@ export const useAuth = () => {
throw new Error('useAuth must be used within an AuthProvider')
}
return context
}
}
9 changes: 5 additions & 4 deletions src/components/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ import { cmn, cls } from '@skalenetwork/metaport'
interface CarouselProps {
children: ReactNode[]
showArrows?: boolean
className?: string
}

const Carousel: React.FC<CarouselProps> = ({ children, showArrows = true }) => {
const Carousel: React.FC<CarouselProps> = ({ children, showArrows = true, className }) => {
const [startIndex, setStartIndex] = useState(0)
const theme = useTheme()
const isXs = useMediaQuery(theme.breakpoints.only('xs'))
Expand All @@ -61,7 +62,7 @@ const Carousel: React.FC<CarouselProps> = ({ children, showArrows = true }) => {
const visibleChildren = children.slice(startIndex, startIndex + itemsToShow)

return (
<Box sx={{ position: 'relative' }}>
<Box sx={{ position: 'relative' }} className={className}>
<Box
sx={{
display: 'flex',
Expand Down Expand Up @@ -92,15 +93,15 @@ const Carousel: React.FC<CarouselProps> = ({ children, showArrows = true }) => {
onClick={handlePrev}
disabled={startIndex === 0}
size="small"
className={cls('outlined', cmn.mri5)}
className={cls('filled', cmn.mri5)}
>
<ArrowBackIosRoundedIcon />
</IconButton>
<IconButton
onClick={handleNext}
disabled={startIndex >= children.length - itemsToShow}
size="small"
className={cls(cmn.pSec, 'outlined', cmn.mleft5)}
className={cls(cmn.pSec, 'filled', cmn.mleft5)}
>
<ArrowForwardIosRoundedIcon />
</IconButton>
Expand Down
3 changes: 1 addition & 2 deletions src/components/MetricsWarning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ import { timestampToDate } from '../core/helper'
const MAX_DELAY_SECONDS = 48 * 60 * 60

export default function MetricsWarning(props: { metrics: types.IMetrics | null }) {
if (!props.metrics || Date.now() / 1000 - props.metrics.last_updated < MAX_DELAY_SECONDS)
return
if (!props.metrics || Date.now() / 1000 - props.metrics.last_updated < MAX_DELAY_SECONDS) return
return (
<Container maxWidth="md">
<Message
Expand Down
5 changes: 4 additions & 1 deletion src/components/ecosystem/AppCardV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,20 @@ export default function AppCard(props: {
isNew?: boolean
mostLiked?: number
trending?: boolean
gray?: boolean
}) {
const shortAlias = getChainShortAlias(props.chainsMeta, props.schainName)
const url = `/ecosystem/${shortAlias}/${props.appName}`
const appMeta = props.chainsMeta[props.schainName]?.apps?.[props.appName]

const gray = props.gray ?? true

if (!appMeta) return

const appDescription = appMeta.description ?? 'No description'

return (
<SkPaper gray fullHeight className="sk-app-card">
<SkPaper gray={gray} fullHeight className="sk-app-card">
<Link to={url}>
<div className={cls(cmn.flex)}>
<div className="sk-app-logo sk-logo-sm br__tile">
Expand Down
102 changes: 102 additions & 0 deletions src/components/ecosystem/RecommendedApps.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* @license
* SKALE portal
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

/**
* @file RecommendedApps.tsx
* @copyright SKALE Labs 2024-Present
*/

import React, { useMemo } from 'react'
import { Grid, Box } from '@mui/material'
import { cls } from '@skalenetwork/metaport'

import { type types } from '@/core'

import { isNewApp, isTrending } from '../../core/ecosystem/utils'
import { findSimilarApps, type SimilarApp } from '../../core/ecosystem/similarApps'

import AppCardV2 from './AppCardV2'
import Carousel from '../Carousel'
import { useLikedApps } from '../../LikedAppsContext'

interface RecommendedAppsProps {
skaleNetwork: types.SkaleNetwork
chainsMeta: types.ChainsMetadataMap
allApps: types.AppWithChainAndName[]
currentApp?: types.AppWithChainAndName
favoriteApps?: types.AppWithChainAndName[]
newApps: types.AppWithChainAndName[]
trendingApps: types.AppWithChainAndName[]
useCarousel?: boolean
className?: string
gray?: boolean
}

const RecommendedApps: React.FC<RecommendedAppsProps> = ({
skaleNetwork,
chainsMeta,
allApps,
currentApp,
favoriteApps,
newApps,
trendingApps,
useCarousel = false,
className,
gray = false
}) => {
const { getMostLikedApps, getAppId, getMostLikedRank } = useLikedApps()
const mostLikedAppIds = useMemo(() => getMostLikedApps(), [getMostLikedApps])

const similarApps = useMemo(() => {
return findSimilarApps(currentApp, allApps, favoriteApps)
}, [currentApp, allApps, favoriteApps])

if (similarApps.length === 0) return null

const renderAppCard = (app: SimilarApp) => {
const appId = getAppId(app.chain, app.appName)
return (
<Box key={`${app.chain}-${app.appName}`} className={cls('fl-centered dappCard')}>
<AppCardV2
skaleNetwork={skaleNetwork}
schainName={app.chain}
appName={app.appName}
chainsMeta={chainsMeta}
isNew={isNewApp({ chain: app.chain, app: app.appName }, newApps)}
mostLiked={getMostLikedRank(mostLikedAppIds, appId)}
trending={isTrending(trendingApps, app.chain, app.appName)}
gray={gray}
/>
</Box>
)
}
if (useCarousel) {
return <Carousel className={className}>{similarApps.map(renderAppCard)}</Carousel>
}
return (
<Grid container spacing={2} className={className}>
{similarApps.map((app) => (
<Grid key={`${app.chain}-${app.appName}`} item xs={12} sm={6} md={4} lg={4}>
{renderAppCard(app)}
</Grid>
))}
</Grid>
)
}

export default React.memo(RecommendedApps)
67 changes: 67 additions & 0 deletions src/components/ecosystem/UserRecommendations.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* @license
* SKALE portal
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

/**
* @file UserRecommendations.tsx
* @copyright SKALE Labs 2024-Present
*/

import React from 'react'
import { cmn, cls } from '@skalenetwork/metaport'
import AutoAwesomeRoundedIcon from '@mui/icons-material/AutoAwesomeRounded'

import { type types } from '@/core'

import RecommendedApps from '../ecosystem/RecommendedApps'
import { useAuth } from '../../AuthContext'
import { useApps } from '../../useApps'
import Headline from '../Headline'

const UserRecommendations: React.FC<{
skaleNetwork: types.SkaleNetwork
chainsMeta: types.ChainsMetadataMap
metrics: types.IMetrics | null
}> = ({ skaleNetwork, chainsMeta, metrics }) => {
const { isSignedIn } = useAuth()
const { allApps, favoriteApps, newApps, trendingApps } = useApps(chainsMeta, metrics)

const showRecommendations = isSignedIn && favoriteApps.length > 0
if (!showRecommendations) return null

return (
<div className={cls(cmn.mbott10, cmn.mtop20, cmn.ptop20)}>
<Headline
className={cls(cmn.mbott10)}
text="Recommended for you"
icon={<AutoAwesomeRoundedIcon color="primary" />}
/>
<RecommendedApps
skaleNetwork={skaleNetwork}
chainsMeta={chainsMeta}
allApps={allApps}
favoriteApps={favoriteApps}
newApps={newApps}
trendingApps={trendingApps}
useCarousel={true}
gray
/>
</div>
)
}

export default UserRecommendations
6 changes: 4 additions & 2 deletions src/components/profile/EmailSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ interface EmailSectionProps {
handleStartEditing: () => void
handleUpdateEmail: () => void
handleCancelEditing: () => void
className?: string
}

const EmailSection: React.FC<EmailSectionProps> = ({
Expand All @@ -48,7 +49,8 @@ const EmailSection: React.FC<EmailSectionProps> = ({
setNewEmail,
handleStartEditing,
handleUpdateEmail,
handleCancelEditing
handleCancelEditing,
className
}) => {
const inputRef = useRef<HTMLInputElement>(null)

Expand All @@ -61,7 +63,7 @@ const EmailSection: React.FC<EmailSectionProps> = ({
return (
<Tile
text="Email Address"
className={cls(styles.inputAmount)}
className={cls(styles.inputAmount, className)}
icon={<EmailRoundedIcon />}
value={!isEditing ? email ?? 'Not set' : undefined}
children={
Expand Down
104 changes: 52 additions & 52 deletions src/components/profile/ProfileModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
*/

import React, { useState, useCallback } from 'react'
import { Modal, Box, Grid, useTheme, useMediaQuery } from '@mui/material'
import { SkPaper, useWagmiAccount } from '@skalenetwork/metaport'
import { Modal, Box, useTheme, useMediaQuery } from '@mui/material'
import { cls, cmn, SkPaper, useWagmiAccount } from '@skalenetwork/metaport'
import { useAuth } from '../../AuthContext'
import Tile from '../Tile'
import Message from '../Message'
Expand Down Expand Up @@ -77,61 +77,61 @@ const ProfileModal: React.FC = () => {
<Box className="profileModal">
<SkPaper gray>
<ProfileModalHeader address={address} isSignedIn={isSignedIn} />

{!address || !isSignedIn ? (
<ConnectWallet customText="Connect your wallet and sign-in to use your profile" />
) : (
<Grid container spacing={2}>
<Grid item xs={12}>
<Tile
text="Wallet Address"
value={address}
icon={<Jazzicon diameter={20} seed={jsNumberForAddress(address)} />}
copy={address}
/>
</Grid>
<Grid item xs={12}>
<EmailSection
email={email}
isEditing={isEditing}
isEmailLoading={isEmailLoading}
isEmailUpdating={isEmailUpdating}
newEmail={newEmail}
setNewEmail={setNewEmail}
handleStartEditing={handleStartEditing}
handleUpdateEmail={handleUpdateEmail}
handleCancelEditing={handleCancelEditing}
/>
</Grid>
<div></div>
)}
{address && isSignedIn ? (
<div>
<Tile
text="Wallet Address"
value={address}
icon={<Jazzicon diameter={20} seed={jsNumberForAddress(address)} />}
copy={address}
className={cls(cmn.mbott10)}
/>
<EmailSection
email={email}
isEditing={isEditing}
isEmailLoading={isEmailLoading}
isEmailUpdating={isEmailUpdating}
newEmail={newEmail}
setNewEmail={setNewEmail}
handleStartEditing={handleStartEditing}
handleUpdateEmail={handleUpdateEmail}
handleCancelEditing={handleCancelEditing}
className={cls(cmn.mbott10)}
/>
{emailError && (
<Grid item xs={12}>
<Message
text={emailError}
type="error"
icon={<EmailRoundedIcon />}
closable={false}
/>
</Grid>
)}

<Grid item xs={12}>
<SwellMessage
email={email}
isEditing={isEditing}
handleStartEditing={handleStartEditing}
<Message
text={emailError}
type="error"
icon={<EmailRoundedIcon />}
closable={false}
className={cls(cmn.mbott10)}
/>
</Grid>

<Grid item xs={12}>
<ProfileModalActions
address={address}
isSignedIn={isSignedIn}
isMobile={isMobile}
handleSignIn={handleSignIn}
handleSignOut={handleSignOut}
/>
</Grid>
</Grid>
)}
<SwellMessage
email={email}
isEditing={isEditing}
handleStartEditing={handleStartEditing}
/>
</div>
) : (
<div></div>
)}
{address ? (
<ProfileModalActions
className={cls(cmn.mtop20)}
address={address}
isSignedIn={isSignedIn}
isMobile={isMobile}
handleSignIn={handleSignIn}
handleSignOut={handleSignOut}
/>
) : (
<div></div>
)}
</SkPaper>
</Box>
Expand Down
Loading

0 comments on commit 1a5bfbb

Please sign in to comment.