This commit is contained in:
2026-05-23 17:17:56 -07:00
commit 448f2e33ef
135 changed files with 11817 additions and 0 deletions
@@ -0,0 +1,88 @@
import { useEffect, useMemo, useState } from 'react'
import type { BackendArt } from '../../functions/BackendTypes'
import { KEY_PREFIX_UPLOAD, setTitle, stateRecover } from '../../functions/Route'
import { BackendFetch } from '../../functions/Backend'
import { wtEvent } from '../../functions/Watchtower'
import LayoutBrowser, { type RecoverForLayoutBrowser } from '../layout/LayoutBrowser'
import HeaderMessage from '../layout/HeaderMessage'
import HeaderLoading from '../layout/HeaderLoading'
import HeaderError from '../layout/HeaderError'
export default function ViewPersonal() {
const recovered = stateRecover<RecoverForLayoutBrowser>()
const [isLoading, setLoading] = useState(true)
const [items, setItems] = useState(recovered?.items ?? [])
const message = useMemo(() => `View: Personal <Count: ${items.length}>`, [items])
useEffect(() => {
Promise.allSettled(
Object.keys(localStorage)
.filter((key) => key.startsWith(KEY_PREFIX_UPLOAD))
.map((key) => key.slice(KEY_PREFIX_UPLOAD.length))
.sort((a, b) => Number(BigInt(b) - BigInt(a)))
.map(
(id) =>
new Promise<BackendArt>(async (resolve, reject) => {
// Check Caches
const item = recovered?.items.find((i) => i.id === id)
if (item) {
return resolve(item)
}
// Fetch from API
const resp = await BackendFetch<BackendArt>(`/art/${id}`)
if (!resp.success) {
if (resp.status === 404) {
// Was probably deleted, remove from storage so
// this client can stop spamming the backend.
localStorage.removeItem(KEY_PREFIX_UPLOAD + id)
}
console.error(`Request for Animation (${id}) failed:`, resp)
return reject()
}
resolve(resp.json)
}),
),
).then((p) => {
const items = p.filter((p) => p.status === 'fulfilled').map((p) => p.value)
setItems(items)
setLoading(false)
wtEvent('view_personal', {
ids: items.map((i) => i.id),
item_total: items.length,
item_error: p.filter((p) => p.status === 'rejected').length,
item_count: p.filter((p) => p.status === 'fulfilled').length,
nsfw_count: items.filter((i) => i.rating >= 0.8).length,
nsfw_rating: items.reduce((sum, i) => sum + i.rating, 0) / items.length || 0,
})
})
}, [])
if (isLoading) {
return (
<>
<HeaderMessage label="Retrieving Uploads" />
<HeaderLoading reason="" />
</>
)
}
if (!items.length) {
return (
<>
<HeaderMessage label={message} />
<HeaderError reason="No past uploads were found on this device. <br> Expecting something? Restore your lost data in Settings." />
</>
)
}
setTitle('Personal')
return (
<>
<HeaderMessage label={message} />
<LayoutBrowser items={items} position={recovered?.position ?? 0} />
</>
)
}