inv & with satistics + filtering
This commit is contained in:
parent
06f5ed731e
commit
d92f58aaf4
@ -49,18 +49,18 @@ export default {
|
|||||||
connectAddress: async (parent, args, { lnd }) => {
|
connectAddress: async (parent, args, { lnd }) => {
|
||||||
return process.env.LND_CONNECT_ADDRESS
|
return process.env.LND_CONNECT_ADDRESS
|
||||||
},
|
},
|
||||||
walletHistory: async (parent, { cursor }, { me, models, lnd }) => {
|
walletHistory: async (parent, { cursor, inc }, { me, models, lnd }) => {
|
||||||
const decodedCursor = decodeCursor(cursor)
|
const decodedCursor = decodeCursor(cursor)
|
||||||
if (!me) {
|
if (!me) {
|
||||||
throw new AuthenticationError('you must be logged in')
|
throw new AuthenticationError('you must be logged in')
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
const include = new Set(inc.split(','))
|
||||||
// 1. union invoices and withdrawals (check)
|
const queries = []
|
||||||
// 2. add to union spending and receiving
|
|
||||||
|
|
||||||
let history = await models.$queryRaw(`
|
if (include.has('invoice')) {
|
||||||
(SELECT id, bolt11, created_at as "createdAt",
|
queries.push(
|
||||||
|
`(SELECT ('invoice' || id) as id, id as "factId", bolt11, created_at as "createdAt",
|
||||||
COALESCE("msatsReceived", "msatsRequested") as msats, NULL as "msatsFee",
|
COALESCE("msatsReceived", "msatsRequested") as msats, NULL as "msatsFee",
|
||||||
CASE WHEN "confirmedAt" IS NOT NULL THEN 'CONFIRMED'
|
CASE WHEN "confirmedAt" IS NOT NULL THEN 'CONFIRMED'
|
||||||
WHEN "expiresAt" <= $2 THEN 'EXPIRED'
|
WHEN "expiresAt" <= $2 THEN 'EXPIRED'
|
||||||
@ -69,11 +69,12 @@ export default {
|
|||||||
'invoice' as type
|
'invoice' as type
|
||||||
FROM "Invoice"
|
FROM "Invoice"
|
||||||
WHERE "userId" = $1
|
WHERE "userId" = $1
|
||||||
AND created_at <= $2
|
AND created_at <= $2)`)
|
||||||
ORDER BY created_at desc
|
}
|
||||||
LIMIT ${LIMIT}+$3)
|
|
||||||
UNION ALL
|
if (include.has('withdrawal')) {
|
||||||
(SELECT id, bolt11, created_at as "createdAt",
|
queries.push(
|
||||||
|
`(SELECT ('withdrawal' || id) as id, id as "factId", bolt11, created_at as "createdAt",
|
||||||
CASE WHEN status = 'CONFIRMED' THEN "msatsPaid"
|
CASE WHEN status = 'CONFIRMED' THEN "msatsPaid"
|
||||||
ELSE "msatsPaying" END as msats,
|
ELSE "msatsPaying" END as msats,
|
||||||
CASE WHEN status = 'CONFIRMED' THEN "msatsFeePaid"
|
CASE WHEN status = 'CONFIRMED' THEN "msatsFeePaid"
|
||||||
@ -82,13 +83,28 @@ export default {
|
|||||||
'withdrawal' as type
|
'withdrawal' as type
|
||||||
FROM "Withdrawl"
|
FROM "Withdrawl"
|
||||||
WHERE "userId" = $1
|
WHERE "userId" = $1
|
||||||
AND created_at <= $2
|
AND created_at <= $2)`)
|
||||||
ORDER BY created_at desc
|
}
|
||||||
LIMIT ${LIMIT}+$3)
|
|
||||||
|
// TODO
|
||||||
|
// 1. union invoices and withdrawals (check)
|
||||||
|
// 2. add to union spending and receiving
|
||||||
|
|
||||||
|
if (queries.length === 0) {
|
||||||
|
return {
|
||||||
|
cursor: null,
|
||||||
|
facts: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let history = await models.$queryRaw(`
|
||||||
|
${queries.join(' UNION ALL ')}
|
||||||
ORDER BY "createdAt" DESC
|
ORDER BY "createdAt" DESC
|
||||||
OFFSET $3
|
OFFSET $3
|
||||||
LIMIT ${LIMIT}`, me.id, decodedCursor.time, decodedCursor.offset)
|
LIMIT ${LIMIT}`, me.id, decodedCursor.time, decodedCursor.offset)
|
||||||
|
|
||||||
|
console.log(history)
|
||||||
|
|
||||||
history = history.map(f => {
|
history = history.map(f => {
|
||||||
if (f.bolt11) {
|
if (f.bolt11) {
|
||||||
const inv = lnpr.decode(f.bolt11)
|
const inv = lnpr.decode(f.bolt11)
|
||||||
@ -113,6 +129,8 @@ export default {
|
|||||||
return f
|
return f
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log(history)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cursor: history.length === LIMIT ? nextCursorEncoded(decodedCursor) : null,
|
cursor: history.length === LIMIT ? nextCursorEncoded(decodedCursor) : null,
|
||||||
facts: history
|
facts: history
|
||||||
|
@ -30,7 +30,7 @@ export default async function getSSRApolloClient (req, me = null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getGetServerSideProps (query, variables = null, foundField) {
|
export function getGetServerSideProps (query, variables = null, foundField) {
|
||||||
return async function ({ req, params }) {
|
return async function ({ req, query: params }) {
|
||||||
const client = await getSSRApolloClient(req)
|
const client = await getSSRApolloClient(req)
|
||||||
const { error, data } = await client.query({
|
const { error, data } = await client.query({
|
||||||
query,
|
query,
|
||||||
|
@ -5,7 +5,7 @@ export default gql`
|
|||||||
invoice(id: ID!): Invoice!
|
invoice(id: ID!): Invoice!
|
||||||
withdrawl(id: ID!): Withdrawl!
|
withdrawl(id: ID!): Withdrawl!
|
||||||
connectAddress: String!
|
connectAddress: String!
|
||||||
walletHistory(cursor: String): History
|
walletHistory(cursor: String, inc: String): History
|
||||||
}
|
}
|
||||||
|
|
||||||
extend type Mutation {
|
extend type Mutation {
|
||||||
@ -41,6 +41,7 @@ export default gql`
|
|||||||
|
|
||||||
type Fact {
|
type Fact {
|
||||||
id: ID!
|
id: ID!
|
||||||
|
factId: ID!
|
||||||
bolt11: String
|
bolt11: String
|
||||||
createdAt: String!
|
createdAt: String!
|
||||||
msats: Int!
|
msats: Int!
|
||||||
|
@ -175,16 +175,16 @@ export function Input ({ label, groupClassName, ...props }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Checkbox ({ children, label, extra, handleChange, ...props }) {
|
export function Checkbox ({ children, label, extra, handleChange, inline, ...props }) {
|
||||||
// React treats radios and checkbox inputs differently other input types, select, and textarea.
|
// React treats radios and checkbox inputs differently other input types, select, and textarea.
|
||||||
// Formik does this too! When you specify `type` to useField(), it will
|
// Formik does this too! When you specify `type` to useField(), it will
|
||||||
// return the correct bag of props for you
|
// return the correct bag of props for you
|
||||||
const [field, { value }] = useField({ ...props, type: 'checkbox' })
|
const [field] = useField({ ...props, type: 'checkbox' })
|
||||||
return (
|
return (
|
||||||
<div className={value ? styles.checkboxChecked : styles.checkboxUnchecked}>
|
|
||||||
<BootstrapForm.Check
|
<BootstrapForm.Check
|
||||||
custom
|
custom
|
||||||
id={props.id || props.name}
|
id={props.id || props.name}
|
||||||
|
inline={inline}
|
||||||
>
|
>
|
||||||
<BootstrapForm.Check.Input
|
<BootstrapForm.Check.Input
|
||||||
{...field} {...props} type='checkbox' onChange={(e) => {
|
{...field} {...props} type='checkbox' onChange={(e) => {
|
||||||
@ -200,8 +200,6 @@ export function Checkbox ({ children, label, extra, handleChange, ...props }) {
|
|||||||
</div>}
|
</div>}
|
||||||
</BootstrapForm.Check.Label>
|
</BootstrapForm.Check.Label>
|
||||||
</BootstrapForm.Check>
|
</BootstrapForm.Check>
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ export default function UserHeader ({ user }) {
|
|||||||
</div>
|
</div>
|
||||||
<Nav
|
<Nav
|
||||||
className={styles.nav}
|
className={styles.nav}
|
||||||
activeKey={router.asPath}
|
activeKey={router.asPath.split('?')[0]}
|
||||||
>
|
>
|
||||||
<Nav.Item>
|
<Nav.Item>
|
||||||
<Link href={'/' + user.name} passHref>
|
<Link href={'/' + user.name} passHref>
|
||||||
@ -132,8 +132,8 @@ export default function UserHeader ({ user }) {
|
|||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
{isMe &&
|
{isMe &&
|
||||||
<Nav.Item>
|
<Nav.Item>
|
||||||
<Link href='/satistics' passHref>
|
<Link href='/satistics?inc=invoice,withdrawal,stacked,spent' passHref>
|
||||||
<Nav.Link>satistics</Nav.Link>
|
<Nav.Link eventKey='/satistics'>satistics</Nav.Link>
|
||||||
</Link>
|
</Link>
|
||||||
</Nav.Item>}
|
</Nav.Item>}
|
||||||
</Nav>
|
</Nav>
|
||||||
|
@ -25,10 +25,11 @@ export const WITHDRAWL = gql`
|
|||||||
}`
|
}`
|
||||||
|
|
||||||
export const WALLET_HISTORY = gql`
|
export const WALLET_HISTORY = gql`
|
||||||
query WalletHistory($cursor: String) {
|
query WalletHistory($cursor: String, $inc: String) {
|
||||||
walletHistory(cursor: $cursor) {
|
walletHistory(cursor: $cursor, inc: $inc) {
|
||||||
facts {
|
facts {
|
||||||
id
|
id
|
||||||
|
factId
|
||||||
type
|
type
|
||||||
createdAt
|
createdAt
|
||||||
msats
|
msats
|
||||||
|
@ -66,7 +66,7 @@ export default function getApolloClient () {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
walletHistory: {
|
walletHistory: {
|
||||||
keyArgs: false,
|
keyArgs: ['inc'],
|
||||||
merge (existing, incoming) {
|
merge (existing, incoming) {
|
||||||
if (isFirstPage(incoming.cursor, existing?.facts)) {
|
if (isFirstPage(incoming.cursor, existing?.facts)) {
|
||||||
return incoming
|
return incoming
|
||||||
|
@ -12,6 +12,8 @@ import styles from '../styles/satistics.module.css'
|
|||||||
import Moon from '../svgs/moon-fill.svg'
|
import Moon from '../svgs/moon-fill.svg'
|
||||||
import Check from '../svgs/check-double-line.svg'
|
import Check from '../svgs/check-double-line.svg'
|
||||||
import ThumbDown from '../svgs/thumb-down-fill.svg'
|
import ThumbDown from '../svgs/thumb-down-fill.svg'
|
||||||
|
import { Checkbox, Form } from '../components/form'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
export const getServerSideProps = getGetServerSideProps(WALLET_HISTORY)
|
export const getServerSideProps = getGetServerSideProps(WALLET_HISTORY)
|
||||||
|
|
||||||
@ -83,7 +85,29 @@ function Satus ({ status }) {
|
|||||||
export default function Satistics ({ data: { walletHistory: { facts, cursor } } }) {
|
export default function Satistics ({ data: { walletHistory: { facts, cursor } } }) {
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
const { value: darkMode } = useDarkMode()
|
const { value: darkMode } = useDarkMode()
|
||||||
const { data, fetchMore } = useQuery(WALLET_HISTORY)
|
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('')
|
||||||
|
// depending on addrem, add or remove filter
|
||||||
|
if (add) {
|
||||||
|
inc.add(filter)
|
||||||
|
} else {
|
||||||
|
inc.delete(filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
const incstr = [...inc].join(',')
|
||||||
|
router.push(`/satistics?inc=${incstr}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function included (filter) {
|
||||||
|
const inc = new Set(router.query.inc.split(','))
|
||||||
|
return inc.has(filter)
|
||||||
|
}
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
({ walletHistory: { facts, cursor } } = data)
|
({ walletHistory: { facts, cursor } } = data)
|
||||||
@ -97,6 +121,34 @@ export default function Satistics ({ data: { walletHistory: { facts, cursor } }
|
|||||||
return (
|
return (
|
||||||
<Layout noSeo>
|
<Layout noSeo>
|
||||||
<UserHeader user={me} />
|
<UserHeader user={me} />
|
||||||
|
<div className='mt-3'>
|
||||||
|
<Form
|
||||||
|
initial={{
|
||||||
|
invoice: included('invoice'),
|
||||||
|
withdrawal: included('withdrawal'),
|
||||||
|
stacked: included('stacked'),
|
||||||
|
spent: included('spent')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className='d-flex justify-content-around flex-wrap'>
|
||||||
|
<Checkbox
|
||||||
|
label='invoice' name='invoice' inline
|
||||||
|
handleChange={c => filterRoutePush('invoice', c)}
|
||||||
|
/>
|
||||||
|
<Checkbox
|
||||||
|
label='withdrawal' name='withdrawal' inline
|
||||||
|
handleChange={c => filterRoutePush('withdrawal', c)}
|
||||||
|
/>
|
||||||
|
<Checkbox
|
||||||
|
label='stacked' name='stacked' inline
|
||||||
|
handleChange={c => filterRoutePush('stacked', c)}
|
||||||
|
/>
|
||||||
|
<Checkbox
|
||||||
|
label='spent' name='spent' inline
|
||||||
|
handleChange={c => filterRoutePush('spent', c)}
|
||||||
|
/>
|
||||||
|
</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' variant={darkMode ? 'dark' : undefined}>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -107,7 +159,7 @@ export default function Satistics ({ data: { walletHistory: { facts, cursor } }
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{facts.map((f, i) => (
|
{facts.map((f, i) => (
|
||||||
<Link href={`${f.type}s/${f.id}`} key={`${f.type}-${f.id}`}>
|
<Link href={`${f.type}s/${f.factId}`} key={f.id}>
|
||||||
<tr className={styles.row}>
|
<tr className={styles.row}>
|
||||||
<td className={`${styles.type} ${satusClass(f.status)}`}>{f.type}</td>
|
<td className={`${styles.type} ${satusClass(f.status)}`}>{f.type}</td>
|
||||||
<td className={styles.description}>
|
<td className={styles.description}>
|
||||||
@ -123,6 +175,7 @@ export default function Satistics ({ data: { walletHistory: { facts, cursor } }
|
|||||||
</tbody>
|
</tbody>
|
||||||
</Table>
|
</Table>
|
||||||
<MoreFooter cursor={cursor} fetchMore={fetchMore} Skeleton={SatisticsSkeleton} />
|
<MoreFooter cursor={cursor} fetchMore={fetchMore} Skeleton={SatisticsSkeleton} />
|
||||||
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,10 @@ $tooltip-bg: #5c8001;
|
|||||||
line-height: 1.2rem;
|
line-height: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.custom-checkbox.custom-control-inline {
|
||||||
|
margin-right: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.table {
|
.table {
|
||||||
color: var(--theme-color);
|
color: var(--theme-color);
|
||||||
background-color: var(--theme-body);
|
background-color: var(--theme-body);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user