ENH - complete Mail and Radio Sky UI

This commit is contained in:
DerEchteAlec
2026-08-16 22:53:20 +02:00
parent c5c9c33c2e
commit 0d351f9743
18 changed files with 2547 additions and 465 deletions
+112 -5
View File
@@ -85,6 +85,10 @@ function memoWaveform(phase = 0) {
let authenticated = true
let draft = null
let mockMailboxes = [
{ count: 0, id: 7, name: 'Projects', sort_order: 0 },
]
let nextMockMailboxId = 8
const radioData = {
badge: '231',
badgeEnabled: true,
@@ -3339,17 +3343,33 @@ function counts() {
return {
drafts: draft ? 1 : 0,
inbox: messages.filter(
(item) => item.folder === 'inbox' && !item.trashed_at,
(item) =>
item.folder === 'inbox' && !item.mailbox_id && !item.trashed_at,
).length,
sent: messages.filter(
(item) => item.folder === 'sent' && !item.mailbox_id && !item.trashed_at,
).length,
sent: messages.filter((item) => item.folder === 'sent' && !item.trashed_at)
.length,
trash: messages.filter((item) => item.trashed_at).length,
unread: messages.filter(
(item) => item.folder === 'inbox' && !item.trashed_at && !item.is_read,
(item) =>
item.folder === 'inbox' &&
!item.mailbox_id &&
!item.trashed_at &&
!item.is_read,
).length,
}
}
function mailboxViews() {
return mockMailboxes.map((mailbox) => ({
...mailbox,
count: messages.filter(
(message) =>
message.mailbox_id === mailbox.id && !message.trashed_at,
).length,
}))
}
let flareProfile = {
id: 1,
name: 'Alex',
@@ -9998,17 +10018,104 @@ app.post('/api/:endpoint', (request, response) => {
response.json({ success: true, data: counts() })
return
}
if (endpoint === 'mail:mailboxes') {
response.json({ success: true, data: { mailboxes: mailboxViews() } })
return
}
if (endpoint === 'mail:create-mailbox') {
const name = String(request.body.name ?? '').trim()
if (!name || name.length > 50) {
response.json({ success: false, error: 'invalid_mailbox' })
return
}
if (
mockMailboxes.some(
(mailbox) => mailbox.name.toLowerCase() === name.toLowerCase(),
)
) {
response.json({ success: false, error: 'mailbox_exists' })
return
}
if (mockMailboxes.length >= 20) {
response.json({ success: false, error: 'mailbox_limit' })
return
}
const mailbox = {
count: 0,
id: nextMockMailboxId,
name,
sort_order: mockMailboxes.length,
}
nextMockMailboxId += 1
mockMailboxes.push(mailbox)
response.json({ success: true, data: mailbox })
return
}
if (endpoint === 'mail:delete-mailbox') {
const mailboxId = Number(request.body.id)
const mailboxIndex = mockMailboxes.findIndex(
(mailbox) => mailbox.id === mailboxId,
)
if (mailboxIndex < 0) {
response.json({ success: false, error: 'mailbox_not_found' })
return
}
mockMailboxes.splice(mailboxIndex, 1)
for (const message of messages) {
if (message.mailbox_id === mailboxId) message.mailbox_id = null
}
response.json({ success: true })
return
}
if (endpoint === 'mail:move') {
const message = messages.find(
(item) => item.id === Number(request.body.id) && !item.trashed_at,
)
const mailboxId = Number(request.body.mailboxId)
const mailboxExists = mockMailboxes.some(
(mailbox) => mailbox.id === mailboxId,
)
if (!message) {
response.json({ success: false, error: 'message_not_found' })
return
}
if (mailboxId !== 0 && !mailboxExists) {
response.json({ success: false, error: 'mailbox_not_found' })
return
}
message.mailbox_id = mailboxId || null
response.json({ success: true })
return
}
if (endpoint === 'mail:list') {
const { folder, search = '' } = request.body
const mailboxMatch = /^mailbox:(\d+)$/.exec(String(folder))
const mailboxId = mailboxMatch ? Number(mailboxMatch[1]) : null
if (
mailboxId &&
!mockMailboxes.some((mailbox) => mailbox.id === mailboxId)
) {
response.json({ success: false, error: 'mailbox_not_found' })
return
}
let items =
folder === 'drafts'
? draft
? [{ ...draft, created_at: draft.updated_at, preview: draft.body }]
: []
: mailboxId
? messages.filter(
(item) => item.mailbox_id === mailboxId && !item.trashed_at,
)
: messages.filter((item) =>
folder === 'trash'
? item.trashed_at
: item.folder === folder && !item.trashed_at,
: item.folder === folder &&
!item.mailbox_id &&
!item.trashed_at,
)
const query = String(search).toLowerCase()
if (query) {
+38
View File
@@ -39,6 +39,7 @@ const browserDataRequests = [
['housing:key-candidates', { action: 'give' }],
['mail:counts', {}],
['mail:list', { folder: 'inbox' }],
['mail:mailboxes', {}],
['map:getPlayerCoords', {}],
['map:markers', {}],
['marketplace:counts', {}],
@@ -147,6 +148,10 @@ function verifyBrowserTestData(dataByEndpoint) {
5,
)
expectItems(dataByEndpoint.get('mail:list').items, 'inbox mail', 2)
expectItems(
dataByEndpoint.get('mail:mailboxes').mailboxes,
'custom mailboxes',
)
expectItems(dataByEndpoint.get('map:markers'), 'map markers')
expectItems(
dataByEndpoint.get('marketplace:list').items,
@@ -597,6 +602,39 @@ async function verifyStatefulActions(baseUrl) {
assert.equal(payphoneCall.state, 'connected')
await expectSuccess(baseUrl, 'payphone:hangup')
const mailbox = await expectSuccess(
baseUrl,
'mail:create-mailbox',
{ name: 'Browser Test' },
true,
)
const mailboxes = await expectSuccess(
baseUrl,
'mail:mailboxes',
{},
true,
)
assert(
mailboxes.mailboxes.some((item) => item.id === mailbox.id),
'mail:create-mailbox did not update the mock mailbox list',
)
await expectSuccess(baseUrl, 'mail:move', {
id: 2,
mailboxId: mailbox.id,
})
const mailboxItems = await expectSuccess(
baseUrl,
'mail:list',
{ folder: `mailbox:${mailbox.id}` },
true,
)
assert(
mailboxItems.items.some((message) => message.id === 2),
'mail:move did not add the message to the custom mailbox',
)
await expectSuccess(baseUrl, 'mail:move', { id: 2, mailboxId: 0 })
await expectSuccess(baseUrl, 'mail:delete-mailbox', { id: mailbox.id })
const draft = await expectSuccess(
baseUrl,
'mail:save-draft',