From 2dd49171e2bb14faa033d56ac1b195945d665b33 Mon Sep 17 00:00:00 2001 From: keyan Date: Fri, 10 Sep 2021 16:13:52 -0500 Subject: [PATCH] complete tips --- api/resolvers/item.js | 64 ++++++++++++++++++++++++++++++++-- api/typeDefs/item.js | 12 +++++-- components/action-tooltip.js | 4 +-- components/comment.js | 14 ++++++-- components/item.js | 7 +++- components/seo.js | 12 +++++-- components/upvote.js | 67 ++++++++++++++++++++++++------------ fragments/comments.js | 5 ++- fragments/items.js | 5 ++- svgs/window-2-fill.svg | 1 + 10 files changed, 155 insertions(+), 36 deletions(-) create mode 100644 svgs/window-2-fill.svg diff --git a/api/resolvers/item.js b/api/resolvers/item.js index e3271cbe..36404912 100644 --- a/api/resolvers/item.js +++ b/api/resolvers/item.js @@ -219,8 +219,23 @@ export default { 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)})`) - return sats + + return { + sats, + act + } } }, @@ -260,7 +275,20 @@ export default { 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 const { sum: { sats } } = await models.itemAct.aggregate({ @@ -276,6 +304,38 @@ export default { 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 }) => { if (!item.parentId) { return null diff --git a/api/typeDefs/item.js b/api/typeDefs/item.js index 9aa36d4a..36c2c177 100644 --- a/api/typeDefs/item.js +++ b/api/typeDefs/item.js @@ -15,6 +15,11 @@ export default gql` TIP } + type ItemActResult { + sats: Int! + act: ItemAct! + } + extend type Mutation { createLink(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! createComment(text: String!, parentId: ID!): 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 { @@ -48,7 +53,10 @@ export default gql` depth: Int! sats: Int! boost: Int! - meSats: Int! + tips: Int! + meVote: Int! + meBoost: Int! + meTip: Int! ncomments: Int! comments: [Item!]! path: String diff --git a/components/action-tooltip.js b/components/action-tooltip.js index 9421ee8e..07d862aa 100644 --- a/components/action-tooltip.js +++ b/components/action-tooltip.js @@ -1,7 +1,7 @@ import { useFormikContext } from 'formik' 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 let formik if (!notForm) { @@ -12,7 +12,7 @@ export default function ActionTooltip ({ children, notForm }) { placement='bottom' overlay={ - 1 sat + {overlayText || '1 sat'} } trigger={['hover', 'focus']} diff --git a/components/comment.js b/components/comment.js index 20023d4e..ddcba996 100644 --- a/components/comment.js +++ b/components/comment.js @@ -63,14 +63,22 @@ export default function Comment ({ item, children, replyOpen, includeParent, roo ref={ref} className={includeParent ? '' : `${styles.comment} ${collapse ? styles.collapsed : ''}`} >
- +
{item.sats} sats \ - {item.boost} boost - \ + {item.boost > 0 && + <> + {item.boost} boost + \ + } + {item.tips > 0 && + <> + {item.tips} tipped + \ + } e.stopPropagation()} className='text-reset'>{item.ncomments} replies diff --git a/components/item.js b/components/item.js index 033f128a..36e90519 100644 --- a/components/item.js +++ b/components/item.js @@ -22,7 +22,7 @@ export default function Item ({ item, rank, children }) {
) :
}
- +
@@ -44,6 +44,11 @@ export default function Item ({ item, rank, children }) { {item.boost} boost \ } + {item.tips > 0 && + <> + {item.tips} tipped + \ + } {item.ncomments} comments diff --git a/components/seo.js b/components/seo.js index 19d4bd9c..606eb5d5 100644 --- a/components/seo.js +++ b/components/seo.js @@ -20,9 +20,17 @@ export default function Seo ({ item, user }) { desc = desc.replace(/\s+/g, ' ') } } 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) { desc = `@${user.name} has [${user.stacked} stacked, ${user.sats} sats, ${user.nitems} posts, ${user.ncomments} comments]` diff --git a/components/upvote.js b/components/upvote.js index 8684b8d0..ce0d5ffc 100644 --- a/components/upvote.js +++ b/components/upvote.js @@ -6,38 +6,61 @@ import { signIn, useSession } from 'next-auth/client' import { useFundError } from './fund-error' import ActionTooltip from './action-tooltip' 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 { setError } = useFundError() const { setItem } = useItemAct() const [act] = useMutation( gql` 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 // which can be stale - const item = cache.readFragment({ - id: `Item:${itemId}`, - fragment: gql` - fragment actedItem on Item { - meSats - } - ` - }) cache.modify({ - id: `Item:${itemId}`, + id: `Item:${item.id}`, fields: { - meSats (existingMeSats = 0) { - return existingMeSats + act + meVote (existingMeVote = 0) { + 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) { - return item.meSats === 0 ? existingSats + act : existingSats + if (act === 'VOTE') { + return existingSats + sats + } + return existingSats }, 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 ( {({ strike }) => - + : '1 sat'}> 1 ? styles.stimi : styles.voted) : ''}` + ${item?.meVote ? styles.voted : ''}` } onClick={ session ? async (e) => { e.stopPropagation() - if (meSats >= 1) { - setItem({ itemId, act, strike }) + if (item?.meVote) { + setItem({ itemId: item.id, act, strike }) return } strike() - if (!itemId) return + if (!item) return try { - await act({ variables: { id: itemId, act: 'VOTE', sats: 1 } }) + await act({ variables: { id: item.id, act: 'VOTE', sats: 1 } }) } catch (error) { if (error.toString().includes('insufficient funds')) { setError(true) diff --git a/fragments/comments.js b/fragments/comments.js index 9bdbbd55..2235c586 100644 --- a/fragments/comments.js +++ b/fragments/comments.js @@ -12,7 +12,10 @@ export const COMMENT_FIELDS = gql` } sats boost - meSats + tips + meVote + meBoost + meTip ncomments root { id diff --git a/fragments/items.js b/fragments/items.js index c7828e55..592a375d 100644 --- a/fragments/items.js +++ b/fragments/items.js @@ -13,7 +13,10 @@ export const ITEM_FIELDS = gql` } sats boost - meSats + tips + meVote + meBoost + meTip ncomments root { id diff --git a/svgs/window-2-fill.svg b/svgs/window-2-fill.svg new file mode 100644 index 00000000..737b0d53 --- /dev/null +++ b/svgs/window-2-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file