satistics done

This commit is contained in:
keyan 2021-12-16 14:02:17 -06:00
parent d92f58aaf4
commit bbc34edf51
8 changed files with 119 additions and 22 deletions

View File

@ -3,6 +3,7 @@ import { UserInputError, AuthenticationError } from 'apollo-server-micro'
import serialize from './serial'
import { decodeCursor, LIMIT, nextCursorEncoded } from '../../lib/cursor'
import lnpr from 'bolt11'
import { SELECT } from './item'
export default {
Query: {
@ -86,9 +87,29 @@ export default {
AND created_at <= $2)`)
}
// TODO
// 1. union invoices and withdrawals (check)
// 2. add to union spending and receiving
if (include.has('stacked')) {
queries.push(
`(SELECT ('stacked' || "Item".id) as id, "Item".id as "factId", NULL as bolt11,
MAX("ItemAct".created_at) as "createdAt", sum("ItemAct".sats) * 1000 as msats,
0 as "msatsFee", NULL as status, 'stacked' as type
FROM "ItemAct"
JOIN "Item" on "ItemAct"."itemId" = "Item".id
WHERE "ItemAct"."userId" <> $1 AND "ItemAct".act <> 'BOOST'
AND "Item"."userId" = $1 AND "ItemAct".created_at <= $2
GROUP BY "Item".id)`)
}
if (include.has('spent')) {
queries.push(
`(SELECT ('spent' || "Item".id) as id, "Item".id as "factId", NULL as bolt11,
MAX("ItemAct".created_at) as "createdAt", sum("ItemAct".sats) * 1000 as msats,
0 as "msatsFee", NULL as status, 'spent' as type
FROM "ItemAct"
JOIN "Item" on "ItemAct"."itemId" = "Item".id
WHERE "ItemAct"."userId" = $1
AND "ItemAct".created_at <= $2
GROUP BY "Item".id)`)
}
if (queries.length === 0) {
return {
@ -103,8 +124,6 @@ export default {
OFFSET $3
LIMIT ${LIMIT}`, me.id, decodedCursor.time, decodedCursor.offset)
console.log(history)
history = history.map(f => {
if (f.bolt11) {
const inv = lnpr.decode(f.bolt11)
@ -120,6 +139,9 @@ export default {
}
switch (f.type) {
case 'withdrawal':
f.msats = (-1 * f.msats) - f.msatsFee
break
case 'spent':
f.msats *= -1
break
default:
@ -129,8 +151,6 @@ export default {
return f
})
console.log(history)
return {
cursor: history.length === LIMIT ? nextCursorEncoded(decodedCursor) : null,
facts: history
@ -251,5 +271,19 @@ export default {
satsPaid: w => Math.floor(w.msatsPaid / 1000),
satsFeePaying: w => Math.floor(w.msatsFeePaying / 1000),
satsFeePaid: w => Math.floor(w.msatsFeePaid / 1000)
},
Fact: {
item: async (fact, args, { models }) => {
if (fact.type !== 'spent' && fact.type !== 'stacked') {
return null
}
const [item] = await models.$queryRaw(`
${SELECT}
FROM "Item"
WHERE id = $1`, Number(fact.factId))
return item
}
}
}

View File

@ -46,9 +46,10 @@ export default gql`
createdAt: String!
msats: Int!
msatsFee: Int
status: String!
status: String
type: String!
description: String
item: Item
}
type History {

View File

@ -38,9 +38,14 @@ function Parent ({ item, rootText }) {
)
}
const truncateString = (string = '', maxLength = 140) =>
string.length > maxLength
? `${string.substring(0, maxLength)} […]`
: string
export default function Comment ({
item, children, replyOpen, includeParent,
rootText, noComments, noReply
rootText, noComments, noReply, truncate
}) {
const [edit, setEdit] = useState()
const [collapse, setCollapse] = useState(false)
@ -129,7 +134,9 @@ export default function Comment ({
)
: (
<div className={styles.text}>
<Text nofollow={item.sats + item.boost < NOFOLLOW_LIMIT}>{item.text}</Text>
<Text nofollow={item.sats + item.boost < NOFOLLOW_LIMIT}>
{truncate ? truncateString(item.text) : item.text}
</Text>
</div>
)}
</div>

View File

@ -132,7 +132,7 @@ export default function UserHeader ({ user }) {
</Nav.Item>
{isMe &&
<Nav.Item>
<Link href='/satistics?inc=invoice,withdrawal,stacked,spent' passHref>
<Link href='/satistics?inc=invoice,withdrawal' passHref>
<Nav.Link eventKey='/satistics'>satistics</Nav.Link>
</Link>
</Nav.Item>}

View File

@ -1,4 +1,5 @@
import { gql } from '@apollo/client'
import { ITEM_FIELDS } from './items'
export const INVOICE = gql`
query Invoice($id: ID!) {
@ -25,6 +26,8 @@ export const WITHDRAWL = gql`
}`
export const WALLET_HISTORY = gql`
${ITEM_FIELDS}
query WalletHistory($cursor: String, $inc: String) {
walletHistory(cursor: $cursor, inc: $inc) {
facts {
@ -37,6 +40,10 @@ export const WALLET_HISTORY = gql`
status
type
description
item {
...ItemFields
text
}
}
cursor
}

View File

@ -1,7 +1,6 @@
import { useQuery } from '@apollo/client'
import Link from 'next/link'
import { Table } from 'react-bootstrap'
import useDarkMode from 'use-dark-mode'
import { getGetServerSideProps } from '../api/ssrApollo'
import Layout from '../components/layout'
import { useMe } from '../components/me'
@ -14,10 +13,16 @@ import Check from '../svgs/check-double-line.svg'
import ThumbDown from '../svgs/thumb-down-fill.svg'
import { Checkbox, Form } from '../components/form'
import { useRouter } from 'next/router'
import Item from '../components/item'
import Comment from '../components/comment'
export const getServerSideProps = getGetServerSideProps(WALLET_HISTORY)
function satusClass (status) {
if (!status) {
return ''
}
switch (status) {
case 'CONFIRMED':
return ''
@ -82,14 +87,30 @@ function Satus ({ status }) {
)
}
function Detail ({ fact }) {
if (!fact.item) {
return (
<>
<div className={satusClass(fact.status)}>
{fact.description || 'no description'}
</div>
<Satus status={fact.status} />
</>
)
}
if (fact.item.title) {
return <div className={styles.itemWrapper}><Item item={fact.item} /></div>
}
return <div className={styles.commentWrapper}><Comment item={fact.item} includeParent noReply truncate /></div>
}
export default function Satistics ({ data: { walletHistory: { facts, cursor } } }) {
const me = useMe()
const { value: darkMode } = useDarkMode()
const router = useRouter()
const { data, fetchMore } = useQuery(WALLET_HISTORY, { variables: { inc: router.query.inc } })
console.log(router.query.inc, data)
function filterRoutePush (filter, add) {
const inc = new Set(router.query.inc.split(','))
inc.delete('')
@ -109,6 +130,16 @@ export default function Satistics ({ data: { walletHistory: { facts, cursor } }
return inc.has(filter)
}
function href (fact) {
switch (fact.type) {
case 'withdrawal':
case 'invoice':
return `/${fact.type}s/${fact.factId}`
default:
return `/items/${fact.factId}`
}
}
if (data) {
({ walletHistory: { facts, cursor } } = data)
}
@ -149,7 +180,7 @@ export default function Satistics ({ data: { walletHistory: { facts, cursor } }
/>
</div>
</Form>
<Table className='mt-3 mb-0' bordered hover size='sm' variant={darkMode ? 'dark' : undefined}>
<Table className='mt-3 mb-0' bordered hover size='sm'>
<thead>
<tr>
<th className={styles.type}>type</th>
@ -159,14 +190,11 @@ export default function Satistics ({ data: { walletHistory: { facts, cursor } }
</thead>
<tbody>
{facts.map((f, i) => (
<Link href={`${f.type}s/${f.factId}`} key={f.id}>
<Link href={href(f)} key={f.id}>
<tr className={styles.row}>
<td className={`${styles.type} ${satusClass(f.status)}`}>{f.type}</td>
<td className={styles.description}>
<div className={satusClass(f.status)}>
{f.description || 'no description'}
</div>
<Satus status={f.status} />
<Detail fact={f} />
</td>
<td className={`${styles.sats} ${satusClass(f.status)}`}>{f.msats / 1000}</td>
</tr>

View File

@ -59,8 +59,13 @@ $tooltip-bg: #5c8001;
src: url(/Lightningvolt-xoqm.ttf);
}
@media screen and (min-width: 767px) {
.table-sm th, .table-sm td {
padding: .3rem .75rem;
}
}
.table-sm th, .table-sm td {
padding: .3rem .75rem;
line-height: 1.2rem;
}
@ -77,6 +82,11 @@ $tooltip-bg: #5c8001;
border-color: var(--theme-borderColor);
}
.table-hover tbody tr:hover {
color: var(--theme-color);
background-color: var(--theme-clickToContextColor);
}
body {
background: var(--theme-body);
color: var(--theme-color);

View File

@ -15,4 +15,14 @@
.row {
cursor: pointer;
}
.itemWrapper {
padding-top: .25rem;
margin-bottom: -.25rem;
}
.commentWrapper {
padding-top: .2rem;
padding-bottom: .4rem;
}