complete tips
This commit is contained in:
parent
0a20f2ea23
commit
2dd49171e2
@ -219,8 +219,23 @@ export default {
|
|||||||
throw new UserInputError('sats must be positive', { argumentName: 'sats' })
|
throw new UserInputError('sats must be positive', { argumentName: 'sats' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we are tipping disallow self tips
|
||||||
|
if (act === 'TIP') {
|
||||||
|
const [item] = await models.$queryRaw(`
|
||||||
|
${SELECT}
|
||||||
|
FROM "Item"
|
||||||
|
WHERE id = $1 AND "userId" = $2`, Number(id), me.id)
|
||||||
|
if (item) {
|
||||||
|
throw new UserInputError('cannot tip your self')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await serialize(models, models.$queryRaw`SELECT item_act(${Number(id)}, ${me.id}, ${act}, ${Number(sats)})`)
|
await serialize(models, models.$queryRaw`SELECT item_act(${Number(id)}, ${me.id}, ${act}, ${Number(sats)})`)
|
||||||
return sats
|
|
||||||
|
return {
|
||||||
|
sats,
|
||||||
|
act
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -260,7 +275,20 @@ export default {
|
|||||||
|
|
||||||
return sats || 0
|
return sats || 0
|
||||||
},
|
},
|
||||||
meSats: async (item, args, { me, models }) => {
|
tips: async (item, args, { models }) => {
|
||||||
|
const { sum: { sats } } = await models.itemAct.aggregate({
|
||||||
|
sum: {
|
||||||
|
sats: true
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
itemId: item.id,
|
||||||
|
act: 'TIP'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return sats || 0
|
||||||
|
},
|
||||||
|
meVote: async (item, args, { me, models }) => {
|
||||||
if (!me) return 0
|
if (!me) return 0
|
||||||
|
|
||||||
const { sum: { sats } } = await models.itemAct.aggregate({
|
const { sum: { sats } } = await models.itemAct.aggregate({
|
||||||
@ -276,6 +304,38 @@ export default {
|
|||||||
|
|
||||||
return sats || 0
|
return sats || 0
|
||||||
},
|
},
|
||||||
|
meBoost: async (item, args, { me, models }) => {
|
||||||
|
if (!me) return 0
|
||||||
|
|
||||||
|
const { sum: { sats } } = await models.itemAct.aggregate({
|
||||||
|
sum: {
|
||||||
|
sats: true
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
itemId: item.id,
|
||||||
|
userId: me.id,
|
||||||
|
act: 'BOOST'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return sats || 0
|
||||||
|
},
|
||||||
|
meTip: async (item, args, { me, models }) => {
|
||||||
|
if (!me) return 0
|
||||||
|
|
||||||
|
const { sum: { sats } } = await models.itemAct.aggregate({
|
||||||
|
sum: {
|
||||||
|
sats: true
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
itemId: item.id,
|
||||||
|
userId: me.id,
|
||||||
|
act: 'TIP'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return sats || 0
|
||||||
|
},
|
||||||
root: async (item, args, { models }) => {
|
root: async (item, args, { models }) => {
|
||||||
if (!item.parentId) {
|
if (!item.parentId) {
|
||||||
return null
|
return null
|
||||||
|
@ -15,6 +15,11 @@ export default gql`
|
|||||||
TIP
|
TIP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ItemActResult {
|
||||||
|
sats: Int!
|
||||||
|
act: ItemAct!
|
||||||
|
}
|
||||||
|
|
||||||
extend type Mutation {
|
extend type Mutation {
|
||||||
createLink(title: String!, url: String): Item!
|
createLink(title: String!, url: String): Item!
|
||||||
updateLink(id: ID!, title: String!, url: String): Item!
|
updateLink(id: ID!, title: String!, url: String): Item!
|
||||||
@ -22,7 +27,7 @@ export default gql`
|
|||||||
updateDiscussion(id: ID!, title: String!, text: String): Item!
|
updateDiscussion(id: ID!, title: String!, text: String): Item!
|
||||||
createComment(text: String!, parentId: ID!): Item!
|
createComment(text: String!, parentId: ID!): Item!
|
||||||
updateComment(id: ID!, text: String!): Item!
|
updateComment(id: ID!, text: String!): Item!
|
||||||
act(id: ID!, act: ItemAct!, sats: Int): Int!
|
act(id: ID!, act: ItemAct!, sats: Int): ItemActResult!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Items {
|
type Items {
|
||||||
@ -48,7 +53,10 @@ export default gql`
|
|||||||
depth: Int!
|
depth: Int!
|
||||||
sats: Int!
|
sats: Int!
|
||||||
boost: Int!
|
boost: Int!
|
||||||
meSats: Int!
|
tips: Int!
|
||||||
|
meVote: Int!
|
||||||
|
meBoost: Int!
|
||||||
|
meTip: Int!
|
||||||
ncomments: Int!
|
ncomments: Int!
|
||||||
comments: [Item!]!
|
comments: [Item!]!
|
||||||
path: String
|
path: String
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useFormikContext } from 'formik'
|
import { useFormikContext } from 'formik'
|
||||||
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
|
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||||
|
|
||||||
export default function ActionTooltip ({ children, notForm }) {
|
export default function ActionTooltip ({ children, notForm, overlayText }) {
|
||||||
// if we're in a form, we want to hide tooltip on submit
|
// if we're in a form, we want to hide tooltip on submit
|
||||||
let formik
|
let formik
|
||||||
if (!notForm) {
|
if (!notForm) {
|
||||||
@ -12,7 +12,7 @@ export default function ActionTooltip ({ children, notForm }) {
|
|||||||
placement='bottom'
|
placement='bottom'
|
||||||
overlay={
|
overlay={
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
1 sat
|
{overlayText || '1 sat'}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
trigger={['hover', 'focus']}
|
trigger={['hover', 'focus']}
|
||||||
|
@ -63,14 +63,22 @@ export default function Comment ({ item, children, replyOpen, includeParent, roo
|
|||||||
ref={ref} className={includeParent ? '' : `${styles.comment} ${collapse ? styles.collapsed : ''}`}
|
ref={ref} className={includeParent ? '' : `${styles.comment} ${collapse ? styles.collapsed : ''}`}
|
||||||
>
|
>
|
||||||
<div className={`${itemStyles.item} ${styles.item}`}>
|
<div className={`${itemStyles.item} ${styles.item}`}>
|
||||||
<UpVote itemId={item.id} meSats={item.meSats} className={styles.upvote} />
|
<UpVote item={item} className={styles.upvote} />
|
||||||
<div className={`${itemStyles.hunk} ${styles.hunk}`}>
|
<div className={`${itemStyles.hunk} ${styles.hunk}`}>
|
||||||
<div className='d-flex align-items-center'>
|
<div className='d-flex align-items-center'>
|
||||||
<div className={`${itemStyles.other} ${styles.other}`}>
|
<div className={`${itemStyles.other} ${styles.other}`}>
|
||||||
<span>{item.sats} sats</span>
|
<span>{item.sats} sats</span>
|
||||||
<span> \ </span>
|
<span> \ </span>
|
||||||
<span>{item.boost} boost</span>
|
{item.boost > 0 &&
|
||||||
<span> \ </span>
|
<>
|
||||||
|
<span>{item.boost} boost</span>
|
||||||
|
<span> \ </span>
|
||||||
|
</>}
|
||||||
|
{item.tips > 0 &&
|
||||||
|
<>
|
||||||
|
<span>{item.tips} tipped</span>
|
||||||
|
<span> \ </span>
|
||||||
|
</>}
|
||||||
<Link href={`/items/${item.id}`} passHref>
|
<Link href={`/items/${item.id}`} passHref>
|
||||||
<a onClick={e => e.stopPropagation()} className='text-reset'>{item.ncomments} replies</a>
|
<a onClick={e => e.stopPropagation()} className='text-reset'>{item.ncomments} replies</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -22,7 +22,7 @@ export default function Item ({ item, rank, children }) {
|
|||||||
</div>)
|
</div>)
|
||||||
: <div />}
|
: <div />}
|
||||||
<div className={styles.item}>
|
<div className={styles.item}>
|
||||||
<UpVote itemId={item.id} meSats={item.meSats} className={styles.upvote} />
|
<UpVote item={item} className={styles.upvote} />
|
||||||
<div className={styles.hunk}>
|
<div className={styles.hunk}>
|
||||||
<div className={`${styles.main} flex-wrap`}>
|
<div className={`${styles.main} flex-wrap`}>
|
||||||
<Link href={`/items/${item.id}`} passHref>
|
<Link href={`/items/${item.id}`} passHref>
|
||||||
@ -44,6 +44,11 @@ export default function Item ({ item, rank, children }) {
|
|||||||
<span>{item.boost} boost</span>
|
<span>{item.boost} boost</span>
|
||||||
<span> \ </span>
|
<span> \ </span>
|
||||||
</>}
|
</>}
|
||||||
|
{item.tips > 0 &&
|
||||||
|
<>
|
||||||
|
<span>{item.tips} tipped</span>
|
||||||
|
<span> \ </span>
|
||||||
|
</>}
|
||||||
<Link href={`/items/${item.id}`} passHref>
|
<Link href={`/items/${item.id}`} passHref>
|
||||||
<a className='text-reset'>{item.ncomments} comments</a>
|
<a className='text-reset'>{item.ncomments} comments</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -20,9 +20,17 @@ export default function Seo ({ item, user }) {
|
|||||||
desc = desc.replace(/\s+/g, ' ')
|
desc = desc.replace(/\s+/g, ' ')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
desc = `@${item.user.name} stacked ${item.sats} sats ${item.url ? `posting ${item.url}` : ''}`
|
desc = `@${item.user.name} stacked ${(item.sats > 0 ? item.sats - 1 : 0) + item.tips} sats ${item.url ? `posting ${item.url}` : 'with this discussion'}`
|
||||||
|
}
|
||||||
|
if (item.ncomments) {
|
||||||
|
desc += ` [${item.ncomments} comments`
|
||||||
|
if (item.boost) {
|
||||||
|
desc += `, ${item.boost} boost`
|
||||||
|
}
|
||||||
|
desc += ']'
|
||||||
|
} else if (item.boost) {
|
||||||
|
desc += ` [${item.boost} boost]`
|
||||||
}
|
}
|
||||||
desc += ` [${item.ncomments} comments, ${item.boost} boost]`
|
|
||||||
}
|
}
|
||||||
if (user) {
|
if (user) {
|
||||||
desc = `@${user.name} has [${user.stacked} stacked, ${user.sats} sats, ${user.nitems} posts, ${user.ncomments} comments]`
|
desc = `@${user.name} has [${user.stacked} stacked, ${user.sats} sats, ${user.nitems} posts, ${user.ncomments} comments]`
|
||||||
|
@ -6,38 +6,61 @@ import { signIn, useSession } from 'next-auth/client'
|
|||||||
import { useFundError } from './fund-error'
|
import { useFundError } from './fund-error'
|
||||||
import ActionTooltip from './action-tooltip'
|
import ActionTooltip from './action-tooltip'
|
||||||
import { useItemAct } from './item-act'
|
import { useItemAct } from './item-act'
|
||||||
|
import Window from '../svgs/window-2-fill.svg'
|
||||||
|
|
||||||
export default function UpVote ({ itemId, meSats, className }) {
|
export default function UpVote ({ item, className }) {
|
||||||
const [session] = useSession()
|
const [session] = useSession()
|
||||||
const { setError } = useFundError()
|
const { setError } = useFundError()
|
||||||
const { setItem } = useItemAct()
|
const { setItem } = useItemAct()
|
||||||
const [act] = useMutation(
|
const [act] = useMutation(
|
||||||
gql`
|
gql`
|
||||||
mutation act($id: ID!, $act: ItemAct! $sats: Int!) {
|
mutation act($id: ID!, $act: ItemAct! $sats: Int!) {
|
||||||
act(id: $id, act: $act, sats: $sats)
|
act(id: $id, act: $act, sats: $sats) {
|
||||||
|
act,
|
||||||
|
sats
|
||||||
|
}
|
||||||
}`, {
|
}`, {
|
||||||
update (cache, { data: { act } }) {
|
update (cache, { data: { act: { act, sats } } }) {
|
||||||
// read in the cached object so we don't use meSats prop
|
// read in the cached object so we don't use meSats prop
|
||||||
// which can be stale
|
// which can be stale
|
||||||
const item = cache.readFragment({
|
|
||||||
id: `Item:${itemId}`,
|
|
||||||
fragment: gql`
|
|
||||||
fragment actedItem on Item {
|
|
||||||
meSats
|
|
||||||
}
|
|
||||||
`
|
|
||||||
})
|
|
||||||
cache.modify({
|
cache.modify({
|
||||||
id: `Item:${itemId}`,
|
id: `Item:${item.id}`,
|
||||||
fields: {
|
fields: {
|
||||||
meSats (existingMeSats = 0) {
|
meVote (existingMeVote = 0) {
|
||||||
return existingMeSats + act
|
if (act === 'VOTE') {
|
||||||
|
return existingMeVote + sats
|
||||||
|
}
|
||||||
|
return existingMeVote
|
||||||
|
},
|
||||||
|
meBoost (existingMeBoost = 0) {
|
||||||
|
if (act === 'BOOST') {
|
||||||
|
return existingMeBoost + sats
|
||||||
|
}
|
||||||
|
return existingMeBoost
|
||||||
|
},
|
||||||
|
meTip (existingMeTip = 0) {
|
||||||
|
if (act === 'TIP') {
|
||||||
|
return existingMeTip + sats
|
||||||
|
}
|
||||||
|
return existingMeTip
|
||||||
},
|
},
|
||||||
sats (existingSats = 0) {
|
sats (existingSats = 0) {
|
||||||
return item.meSats === 0 ? existingSats + act : existingSats
|
if (act === 'VOTE') {
|
||||||
|
return existingSats + sats
|
||||||
|
}
|
||||||
|
return existingSats
|
||||||
},
|
},
|
||||||
boost (existingBoost = 0) {
|
boost (existingBoost = 0) {
|
||||||
return item.meSats >= 1 ? existingBoost + act : existingBoost
|
if (act === 'BOOST') {
|
||||||
|
return existingBoost + sats
|
||||||
|
}
|
||||||
|
return existingBoost
|
||||||
|
},
|
||||||
|
tips (existingTips = 0) {
|
||||||
|
if (act === 'TIP') {
|
||||||
|
return existingTips + sats
|
||||||
|
}
|
||||||
|
return existingTips
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -48,29 +71,29 @@ export default function UpVote ({ itemId, meSats, className }) {
|
|||||||
return (
|
return (
|
||||||
<LightningConsumer>
|
<LightningConsumer>
|
||||||
{({ strike }) =>
|
{({ strike }) =>
|
||||||
<ActionTooltip notForm>
|
<ActionTooltip notForm overlayText={item?.meVote ? <Window style={{ fill: '#fff' }} /> : '1 sat'}>
|
||||||
<UpArrow
|
<UpArrow
|
||||||
width={24}
|
width={24}
|
||||||
height={24}
|
height={24}
|
||||||
className={
|
className={
|
||||||
`${styles.upvote}
|
`${styles.upvote}
|
||||||
${className || ''}
|
${className || ''}
|
||||||
${meSats ? (meSats > 1 ? styles.stimi : styles.voted) : ''}`
|
${item?.meVote ? styles.voted : ''}`
|
||||||
}
|
}
|
||||||
onClick={
|
onClick={
|
||||||
session
|
session
|
||||||
? async (e) => {
|
? async (e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
if (meSats >= 1) {
|
if (item?.meVote) {
|
||||||
setItem({ itemId, act, strike })
|
setItem({ itemId: item.id, act, strike })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
strike()
|
strike()
|
||||||
if (!itemId) return
|
if (!item) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await act({ variables: { id: itemId, act: 'VOTE', sats: 1 } })
|
await act({ variables: { id: item.id, act: 'VOTE', sats: 1 } })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.toString().includes('insufficient funds')) {
|
if (error.toString().includes('insufficient funds')) {
|
||||||
setError(true)
|
setError(true)
|
||||||
|
@ -12,7 +12,10 @@ export const COMMENT_FIELDS = gql`
|
|||||||
}
|
}
|
||||||
sats
|
sats
|
||||||
boost
|
boost
|
||||||
meSats
|
tips
|
||||||
|
meVote
|
||||||
|
meBoost
|
||||||
|
meTip
|
||||||
ncomments
|
ncomments
|
||||||
root {
|
root {
|
||||||
id
|
id
|
||||||
|
@ -13,7 +13,10 @@ export const ITEM_FIELDS = gql`
|
|||||||
}
|
}
|
||||||
sats
|
sats
|
||||||
boost
|
boost
|
||||||
meSats
|
tips
|
||||||
|
meVote
|
||||||
|
meBoost
|
||||||
|
meTip
|
||||||
ncomments
|
ncomments
|
||||||
root {
|
root {
|
||||||
id
|
id
|
||||||
|
1
svgs/window-2-fill.svg
Normal file
1
svgs/window-2-fill.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 3h18a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zm17 7H4v9h16v-9zm-5-4v2h4V6h-4z"/></svg>
|
After Width: | Height: | Size: 240 B |
Loading…
x
Reference in New Issue
Block a user