Skip to content

Commit

Permalink
Merge a96c757 into 5aa57f9
Browse files Browse the repository at this point in the history
  • Loading branch information
fzavalia committed Oct 4, 2023
2 parents 5aa57f9 + a96c757 commit 37d2c5c
Show file tree
Hide file tree
Showing 9 changed files with 233 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@
color: #cfcdd4;
}

.WorldListPage .TableRow .world-status.warning {
color: var(--danger);
}

.WorldListPage .TableRow .world-status.blocked {
color: var(--error);
}

.WorldListPage .ui.pagination {
width: 100%;
display: flex;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useState } from 'react'
import React, { ReactNode, useCallback, useEffect, useState } from 'react'
import { t } from 'decentraland-dapps/dist/modules/translation/utils'
import {
Button,
Expand All @@ -12,12 +12,15 @@ import {
Dropdown,
Empty,
Icon as DCLIcon,
Popup
Popup,
Message,
MessageContent
} from 'decentraland-ui'
import { config } from 'config'
import { isDevelopment } from 'lib/environment'
import { WorldsWalletStats } from 'lib/api/worlds'
import { ENS } from 'modules/ens/types'
import { isExternalName } from 'modules/ens/utils'
import { locations } from 'routing/locations'
import CopyToClipboard from 'components/CopyToClipboard/CopyToClipboard'
import Icon from 'components/Icon'
Expand All @@ -27,7 +30,7 @@ import { Props, SortBy } from './WorldListPage.types'
import NameTabs from './NameTabs'
import WorldsStorage from './WorldsStorage'
import { TabType, useCurrentlySelectedTab } from './hooks'
import { fromBytesToMegabytes } from './utils'
import { DCLWorldsStatus, fromBytesToMegabytes, getDCLWorldsStatus } from './utils'
import './WorldListPage.css'

const EXPLORER_URL = config.get('EXPLORER_URL', '')
Expand Down Expand Up @@ -124,7 +127,22 @@ const WorldListPage: React.FC<Props> = props => {
}

const renderWorldStatus = (ens: ENS) => {
const status = isWorldDeployed(ens) ? 'active' : 'inactive'
let status = isWorldDeployed(ens) ? 'active' : 'inactive'

if (status === 'active' && worldsWalletStats && !isExternalName(ens.subdomain)) {
const worldsStatus = getDCLWorldsStatus(worldsWalletStats)

switch (worldsStatus.status) {
case DCLWorldsStatus.BLOCKED: {
status = 'blocked'
break
}
case DCLWorldsStatus.TO_BE_BLOCKED: {
status = 'warning'
}
}
}

return <span className={`world-status ${status}`}>{t(`worlds_list_page.table.status_${status}`)}</span>
}

Expand Down Expand Up @@ -253,6 +271,42 @@ const WorldListPage: React.FC<Props> = props => {
)
}

const renderDCLNamesBlockedWorldsStatusMessage = () => {
if (!worldsWalletStats) {
return null
}

const dclWorldsStatus = getDCLWorldsStatus(worldsWalletStats)

if (dclWorldsStatus.status === DCLWorldsStatus.OK) {
return null
}

let warning = false
let error = false
let messageContent: ReactNode

if (dclWorldsStatus.status === DCLWorldsStatus.TO_BE_BLOCKED) {
warning = true
messageContent = t('worlds_list_page.worlds_warning_message.to_be_blocked', {
toBeBlockedAt: dclWorldsStatus.toBeBlockedAt.toLocaleDateString(),
b: (text: string) => <b>{text}</b>
})
} else {
error = true
messageContent = t('worlds_list_page.worlds_warning_message.blocked', {
blockedAt: dclWorldsStatus.blockedAt.toLocaleDateString(),
b: (text: string) => <b>{text}</b>
})
}

return (
<Message warning={warning} error={error}>
<MessageContent>{messageContent}</MessageContent>
</Message>
)
}

const renderDCLNamesView = () => {
return (
<div>
Expand All @@ -263,6 +317,7 @@ const WorldListPage: React.FC<Props> = props => {
className="worlds-storage"
/>
) : null}
{renderDCLNamesBlockedWorldsStatusMessage()}
{ensList.length > 0 ? renderList() : renderEmptyPage()}
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ describe('when rendering the worlds storage component', () => {
render(<WorldsStorage currentBytes={currentBytes} maxBytes={maxBytes} />)
})

it('should render 50.55/100.00mb', () => {
expect(screen.getByTestId(CURRENT_MBS_TEST_ID).textContent).toEqual('50.55 / 100.00 Mb')
it('should render 48.21 / 95.37 Mb', () => {
expect(screen.getByTestId(CURRENT_MBS_TEST_ID).textContent).toEqual('48.21 / 95.37 Mb')
})

it('should render the storage front bar with 50%', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { WorldsWalletStats } from 'lib/api/worlds'
import { BLOCK_DELAY_IN_MILLISECONDS, DCLWorldsStatus, fromBytesToMegabytes, getDCLWorldsStatus } from './utils'

describe('when converting from bytes to megabytes', () => {
describe('when the number is 10000000', () => {
it('should return 9.5367431640625', () => {
expect(fromBytesToMegabytes(10000000)).toBe(9.5367431640625)
})
})
})

describe('when getting the dcl worlds status', () => {
let stats: WorldsWalletStats

beforeEach(() => {
stats = {
usedSpace: '0',
maxAllowedSpace: '0'
} as WorldsWalletStats
})

describe('when the used space is lower than the max allowed space', () => {
beforeEach(() => {
stats.usedSpace = '100'
stats.maxAllowedSpace = '101'
})

it('should return status ok', () => {
expect(getDCLWorldsStatus(stats)).toEqual({ status: DCLWorldsStatus.OK })
})
})

describe('when the used space is equal to the max allowed space', () => {
beforeEach(() => {
stats.usedSpace = '100'
stats.maxAllowedSpace = '100'
})

it('should return status ok', () => {
expect(getDCLWorldsStatus(stats)).toEqual({ status: DCLWorldsStatus.OK })
})
})

describe('when the used space is greater to the max allowed space', () => {
beforeEach(() => {
stats.usedSpace = '101'
stats.maxAllowedSpace = '100'
})

describe('and blocked since is not defined', () => {
beforeEach(() => {
stats.blockedSince = undefined
})

it('should return status ok', () => {
expect(getDCLWorldsStatus(stats)).toEqual({ status: DCLWorldsStatus.OK })
})
})

describe('and blocked since is defined as 1 day later than now', () => {
beforeEach(() => {
stats.blockedSince = new Date(Date.now() + 24 * 60 * 60 * 1000 /* 1 day */).toISOString()
})

it('should return status ok', () => {
expect(getDCLWorldsStatus(stats)).toEqual({ status: DCLWorldsStatus.OK })
})
})

describe('and blocked since is defined as 1 day earlier than now', () => {
beforeEach(() => {
stats.blockedSince = new Date(Date.now() - 24 * 60 * 60 * 1000 /* 1 day */).toISOString()
})

it('should return status to be blocked with the to be blocked date', () => {
expect(getDCLWorldsStatus(stats)).toEqual({
status: DCLWorldsStatus.TO_BE_BLOCKED,
toBeBlockedAt: new Date(new Date(stats.blockedSince!).getTime() + BLOCK_DELAY_IN_MILLISECONDS)
})
})
})

describe('and blocked since is defined as 3 days earlier than now', () => {
beforeEach(() => {
stats.blockedSince = new Date(Date.now() - 72 * 60 * 60 * 1000 /* 3 days */).toISOString()
})

it('should return status to be blocked with the to be blocked date', () => {
expect(getDCLWorldsStatus(stats)).toEqual({
status: DCLWorldsStatus.BLOCKED,
blockedAt: new Date(new Date(stats.blockedSince!).getTime() + BLOCK_DELAY_IN_MILLISECONDS)
})
})
})
})
})
50 changes: 49 additions & 1 deletion src/components/WorldListPage_WorldsForEnsOwnersFeature/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,51 @@
import { WorldsWalletStats } from 'lib/api/worlds'

export const fromBytesToMegabytes = (bytes: number) => {
return bytes / 1000000
return bytes / 1024 / 1024
}

export const BLOCK_DELAY_IN_MILLISECONDS = 48 * 60 * 60 * 1000 // 48 hours

export enum DCLWorldsStatus {
OK = 'ok',
BLOCKED = 'blocked',
TO_BE_BLOCKED = 'to-be-blocked'
}

export type GetDCLWorldsStatusResult =
| {
status: DCLWorldsStatus.OK
}
| {
status: DCLWorldsStatus.TO_BE_BLOCKED
toBeBlockedAt: Date
}
| {
status: DCLWorldsStatus.BLOCKED
blockedAt: Date
}

export const getDCLWorldsStatus = (stats: WorldsWalletStats): GetDCLWorldsStatusResult => {
const now = new Date().getTime()
const blockedSince = stats.blockedSince ? new Date(stats.blockedSince).getTime() : null

if (stats.usedSpace <= stats.maxAllowedSpace || !blockedSince || now < blockedSince) {
return {
status: DCLWorldsStatus.OK
}
}

const blockedAt = new Date(blockedSince + BLOCK_DELAY_IN_MILLISECONDS)

if (now - blockedSince > BLOCK_DELAY_IN_MILLISECONDS) {
return {
status: DCLWorldsStatus.BLOCKED,
blockedAt: blockedAt
}
}

return {
status: DCLWorldsStatus.TO_BE_BLOCKED,
toBeBlockedAt: blockedAt
}
}
1 change: 1 addition & 0 deletions src/lib/api/worlds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export type WorldsWalletStats = {
}[]
usedSpace: string
maxAllowedSpace: string
blockedSince?: string
}

export class WorldsAPI extends BaseAPI {
Expand Down
6 changes: 6 additions & 0 deletions src/modules/translation/languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,8 @@
"status": "Status",
"status_active": "Active",
"status_inactive": "Inactive",
"status_warning": "Warning",
"status_blocked": "Blocked",
"actions": "Actions",
"empty_url": "To activate this world you need to publish a scene",
"size": "Size Mb"
Expand All @@ -617,6 +619,10 @@
"worlds_storage": {
"space_used": "Space used",
"view_details": "view details"
},
"worlds_warning_message": {
"to_be_blocked": "You are using more storage than you are allowed. Unpublish some scenes to free some space or increase you maximum storage before <b>{toBeBlockedAt}</b> to avoid losing access to your scenes.",
"blocked": "Access to your scenes has been blocked since <b>{blockedAt}</b> because you don't have enough storage to maintain your currently published worlds. Unpublish some scenes to free some space or increase your maximum storage to regain access."
}
},
"error_page": {
Expand Down
6 changes: 6 additions & 0 deletions src/modules/translation/languages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,8 @@
"status": "Estado",
"status_active": "Activo",
"status_inactive": "Inactivo",
"status_warning": "Atención",
"status_blocked": "Bloqueado",
"actions": "Acciones",
"empty_url": "Para activar este mundo, necesitas publicar una escena",
"size": "Peso Mb"
Expand All @@ -619,6 +621,10 @@
"worlds_storage": {
"space_used": "Espacio utilizado",
"view_details": "ver detalles"
},
"worlds_warning_message": {
"to_be_blocked": "Está utilizando más almacenamiento del permitido. Cancele la publicación de algunas escenas para liberar espacio o aumentar su almacenamiento máximo antes de <b>{toBeBlockedAt}</b> para evitar perder el acceso a sus escenas.",
"blocked": "El acceso a tus escenas ha sido bloqueado desde <b>{blockedAt}</b> porque no tienes suficiente almacenamiento para mantener tus mundos publicados actualmente. Cancele la publicación de algunas escenas para liberar espacio o aumente su almacenamiento máximo para recuperar el acceso."
}
},
"error_page": {
Expand Down
6 changes: 6 additions & 0 deletions src/modules/translation/languages/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,8 @@
"status": "地位",
"status_active": "积极的",
"status_inactive": "不活动",
"status_warning": "注意力",
"status_blocked": "锁定",
"actions": "动作",
"empty_url": "要激活这个世界,您需要发布一个场景",
"size": "重量 Mb"
Expand All @@ -621,6 +623,10 @@
"worlds_storage": {
"space_used": "使用空间",
"view_details": "查看详情"
},
"worlds_warning_message": {
"to_be_blocked": "您使用的存储空间超出了允许的范围。 在<b>{toBeBlockedAt}</b>之前取消发布某些场景以释放空间或增加最大存储空间,以避免失去对场景的访问权限。",
"blocked": "自 <b>{blockedAt}</b> 起,对您的场景的访问已被阻止,因为您没有足够的存储空间来维护当前发布的世界。 取消发布某些场景以释放空间或增加最大存储空间以重新获得访问权限。"
}
},
"estate_editor": {
Expand Down

0 comments on commit 37d2c5c

Please sign in to comment.