mirror of
https://github.com/Permissionless-Software-Foundation/psf-memo-client.git
synced 2026-09-21 16:52:02 -07:00
Adding Posts page
This commit is contained in:
@@ -24,6 +24,7 @@ import SignMessage from './sign/index.js'
|
||||
import ServerSelectView from './configuration/select-server-view'
|
||||
import UserDataReview from './user-data-review'
|
||||
import RecentProfiles from './recent-profiles'
|
||||
import RecentPosts from './posts'
|
||||
|
||||
function AppBody (props) {
|
||||
// Dependency injection through props
|
||||
@@ -38,6 +39,7 @@ function AppBody (props) {
|
||||
<Route path='/wallet' element={<Wallet appData={appData} />} />
|
||||
<Route path='/slp-tokens' element={<SlpTokens appData={appData} />} />
|
||||
<Route path='/profile/recent' element={<RecentProfiles />} />
|
||||
<Route path='/posts/recent' element={<RecentPosts />} />
|
||||
<Route path='/placeholder2' element={<Placeholder2 />} />
|
||||
<Route path='/placeholder3' element={<Placeholder3 />} />
|
||||
<Route path='/servers' element={<ServerSelectView appData={appData} />} />
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
Display the most recent Memo posts from psf-memo-db.
|
||||
*/
|
||||
|
||||
// Global npm libraries
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { Container, Row, Col, Spinner, Table } from 'react-bootstrap'
|
||||
|
||||
// Local libraries
|
||||
import MemoDb from '../../../services/memo-db'
|
||||
import '../../../App.css'
|
||||
|
||||
function truncate (str, maxLen = 16) {
|
||||
if (!str || str.length <= maxLen) return str
|
||||
const half = Math.floor((maxLen - 3) / 2)
|
||||
return `${str.slice(0, half)}...${str.slice(-half)}`
|
||||
}
|
||||
|
||||
function formatSeen (seen) {
|
||||
if (!seen) return ''
|
||||
const ms = seen > 1e12 ? seen : seen * 1000
|
||||
return new Date(ms).toLocaleString()
|
||||
}
|
||||
|
||||
function RecentPosts () {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState(null)
|
||||
const [posts, setPosts] = useState([])
|
||||
const [pagination, setPagination] = useState(null)
|
||||
|
||||
useEffect(() => {
|
||||
const loadPosts = async () => {
|
||||
try {
|
||||
const memoDb = new MemoDb()
|
||||
const data = await memoDb.getRecentPosts({ limit: 100, offset: 0 })
|
||||
setPosts(data.posts || [])
|
||||
setPagination(data.pagination || null)
|
||||
} catch (err) {
|
||||
setError(err.message || 'Failed to load recent posts')
|
||||
}
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
loadPosts()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
<h1 className='mt-4'>Recent Posts</h1>
|
||||
{pagination && (
|
||||
<p className='text-muted'>
|
||||
Showing {posts.length} of {pagination.total} posts
|
||||
</p>
|
||||
)}
|
||||
|
||||
{error && <p className='text-danger'>{error}</p>}
|
||||
|
||||
{loading && (
|
||||
<div className='text-center my-5'>
|
||||
<Spinner animation='border' role='status' variant='primary'>
|
||||
<span className='visually-hidden'>Loading...</span>
|
||||
</Spinner>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!loading && !error && (
|
||||
<Table striped bordered hover responsive className='mt-3'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Address</th>
|
||||
<th>Post</th>
|
||||
<th>Block</th>
|
||||
<th>Seen</th>
|
||||
<th>TxID</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{posts.map((post) => (
|
||||
<tr key={post.txid}>
|
||||
<td>
|
||||
<span style={{ fontFamily: 'monospace' }} title={post.addr}>
|
||||
{truncate(post.addr, 24)}
|
||||
</span>
|
||||
</td>
|
||||
<td>{post.text}</td>
|
||||
<td>{post.blockHeight}</td>
|
||||
<td>{formatSeen(post.seen)}</td>
|
||||
<td>
|
||||
<span style={{ fontFamily: 'monospace' }} title={post.txid}>
|
||||
{truncate(post.txid, 20)}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</Table>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default RecentPosts
|
||||
@@ -62,6 +62,14 @@ function NavMenu (props) {
|
||||
Profiles
|
||||
</NavLink>
|
||||
|
||||
<NavLink
|
||||
className={currentPath === '/posts/recent' ? 'nav-link-active' : 'nav-link-inactive'}
|
||||
to='/posts/recent'
|
||||
onClick={handleClickEvent}
|
||||
>
|
||||
Posts
|
||||
</NavLink>
|
||||
|
||||
<NavLink
|
||||
className={currentPath === '/wallet' ? 'nav-link-active' : 'nav-link-inactive'}
|
||||
to='/wallet'
|
||||
|
||||
@@ -22,6 +22,19 @@ class MemoDb {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async getRecentPosts ({ limit = 100, offset = 0 } = {}) {
|
||||
try {
|
||||
const result = await this.axios.get(`${config.backend}/posts/recent`, {
|
||||
params: { limit, offset }
|
||||
})
|
||||
|
||||
return result.data
|
||||
} catch (err) {
|
||||
console.error('Error in getRecentPosts()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default MemoDb
|
||||
|
||||
Reference in New Issue
Block a user