refine tipping experience, removing notion of upvote from UX

This commit is contained in:
keyan 2022-01-20 17:04:12 -06:00
parent b6b5cea1f5
commit 5d49ecc536
11 changed files with 70 additions and 153 deletions

View File

@ -362,7 +362,7 @@ export default {
return await updateItem(parent, { id, data: { text } }, { me, models })
},
act: async (parent, { id, act, sats, tipDefault }, { me, models }) => {
act: async (parent, { id, sats }, { me, models }) => {
// need to make sure we are logged in
if (!me) {
throw new AuthenticationError('you must be logged in')
@ -372,26 +372,20 @@ 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')
}
// if tipDefault, set on user
if (tipDefault) {
await models.user.update({ where: { id: me.id }, data: { tipDefault: sats } })
}
// disallow self tips
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)})`)
const [{ item_act: vote }] = await serialize(models, models.$queryRaw`SELECT item_act(${Number(id)}, ${me.id}, 'TIP', ${Number(sats)})`)
return {
sats,
act
vote,
sats
}
}
},
@ -448,6 +442,27 @@ export default {
},
where: {
itemId: item.id,
userId: {
not: item.userId
},
act: {
not: 'BOOST'
}
}
})
return sats || 0
},
upvotes: async (item, args, { models }) => {
const { sum: { sats } } = await models.itemAct.aggregate({
sum: {
sats: true
},
where: {
itemId: item.id,
userId: {
not: item.userId
},
act: 'VOTE'
}
})
@ -467,35 +482,6 @@ export default {
return sats || 0
},
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({
sum: {
sats: true
},
where: {
itemId: item.id,
userId: me.id,
act: 'VOTE'
}
})
return sats || 0
},
meSats: async (item, args, { me, models }) => {
if (!me) return 0
@ -522,22 +508,6 @@ export default {
mine: async (item, args, { me, models }) => {
return me?.id === item.userId
},
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

View File

@ -10,15 +10,9 @@ export default gql`
dupes(url: String!): [Item!]
}
enum ItemAct {
VOTE
BOOST
TIP
}
type ItemActResult {
vote: Int!
sats: Int!
act: ItemAct!
}
extend type Mutation {
@ -28,7 +22,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, tipDefault: Boolean): ItemActResult!
act(id: ID!, sats: Int): ItemActResult!
}
type Items {
@ -53,13 +47,11 @@ export default gql`
root: Item
user: User!
depth: Int!
sats: Int!
boost: Int!
tips: Int!
mine: Boolean!
meVote: Int!
boost: Int!
sats: Int!
upvotes: Int!
meSats: Int!
meTip: Int!
ncomments: Int!
comments: [Item!]!
path: String

View File

@ -79,7 +79,7 @@ export default function Comment ({
<div className={`${itemStyles.hunk} ${styles.hunk}`}>
<div className='d-flex align-items-center'>
<div className={`${itemStyles.other} ${styles.other}`}>
<span title={`${item.sats} upvotes \\ ${item.tips} tipped${item.meSats > 0 ? ` (${item.meSats} from me)` : ''}`}>{item.sats + item.tips} sats</span>
<span title={`from ${item.upvotes} users (${item.meSats} from me)`}>{item.sats} sats</span>
<span> \ </span>
{item.boost > 0 &&
<>

View File

@ -57,13 +57,11 @@ export function ItemActModal () {
default: false
}}
schema={ActSchema}
onSubmit={async ({ amount, tipDefault, submit }) => {
onSubmit={async ({ amount }) => {
await item.act({
variables: {
id: item.itemId,
act: submit,
sats: Number(amount),
tipDefault
sats: Number(amount)
}
})
await item.strike()

View File

@ -50,7 +50,7 @@ export default function Item ({ item, rank, children }) {
<div className={`${styles.other}`}>
{!item.position &&
<>
<span title={`${item.sats} upvotes \\ ${item.tips} tipped${item.meSats > 0 ? ` (${item.meSats} from me)` : ''}`}>{item.sats + item.tips} sats</span>
<span title={`from ${item.upvotes} users (${item.meSats} sats from me)`}>{item.sats} sats</span>
<span> \ </span>
</>}
{item.boost > 0 &&

View File

@ -20,7 +20,7 @@ export default function Seo ({ item, user }) {
desc = desc.replace(/\s+/g, ' ')
}
} else {
desc = `@${item.user.name} stacked ${(item.sats > 0 ? item.sats - 1 : 0) + item.tips} sats ${item.url ? `posting ${item.url}` : 'with this discussion'}`
desc = `@${item.user.name} stacked ${item.sats} sats ${item.url ? `posting ${item.url}` : 'with this discussion'}`
}
if (item.ncomments) {
desc += ` [${item.ncomments} comments`

View File

@ -104,60 +104,29 @@ export default function UpVote ({ item, className }) {
const [act] = useMutation(
gql`
mutation act($id: ID!, $act: ItemAct! $sats: Int!, $tipDefault: Boolean) {
act(id: $id, act: $act, sats: $sats, tipDefault: $tipDefault) {
act,
mutation act($id: ID!, $sats: Int!) {
act(id: $id, sats: $sats) {
vote,
sats
}
}`, {
update (cache, { data: { act: { act, sats } } }) {
// read in the cached object so we don't use meSats prop
// which can be stale
if (act === 'VOTE') {
setVoteShow(true)
}
if (act === 'TIP') {
setTipShow(true)
}
update (cache, { data: { act: { vote, sats } } }) {
cache.modify({
id: `Item:${item.id}`,
fields: {
meVote (existingMeVote = 0) {
if (act === 'VOTE') {
return existingMeVote + sats
}
return existingMeVote
},
meTip (existingMeTip = 0) {
if (act === 'TIP') {
return existingMeTip + sats
}
return existingMeTip
},
sats (existingSats = 0) {
if (act === 'VOTE') {
return existingSats + sats
}
return existingSats
return existingSats + sats
},
meSats (existingSats = 0) {
if (act === 'VOTE' || act === 'TIP') {
return existingSats + sats
if (existingSats === 0) {
setVoteShow(true)
} else {
setTipShow(true)
}
return existingSats
return existingSats + sats
},
boost (existingBoost = 0) {
if (act === 'BOOST') {
return existingBoost + sats
}
return existingBoost
},
tips (existingTips = 0) {
if (act === 'TIP') {
return existingTips + sats
}
return existingTips
upvotes (existingUpvotes = 0) {
return existingUpvotes + vote
}
}
})
@ -166,15 +135,12 @@ export default function UpVote ({ item, className }) {
)
const overlayText = () => {
if (item?.meVote) {
if (me?.tipDefault) {
return `${me.tipDefault} sat${me.tipDefault > 1 ? 's' : ''}`
}
return '1 sat'
if (me?.tipDefault) {
return `${me.tipDefault} sat${me.tipDefault > 1 ? 's' : ''}`
}
return '1 sat'
}
const noSelfTips = item?.meVote && item?.mine
const color = getColor(item?.meSats)
return (
<LightningConsumer>
@ -186,7 +152,7 @@ export default function UpVote ({ item, className }) {
if (!item || voteLock) return
// we can't tip ourselves
if (noSelfTips) {
if (item?.mine) {
return
}
@ -200,26 +166,19 @@ export default function UpVote ({ item, className }) {
if (!item || voteLock) return
// we can't tip ourselves
if (noSelfTips) {
if (item?.mine) {
return
}
if (item?.meVote) {
if (item?.meSats) {
setVoteShow(false)
try {
strike()
await act({ variables: { id: item.id, act: 'TIP', sats: me.tipDefault || 1 } })
} catch (e) {
console.log(e)
}
return
}
strike()
try {
setVoteLock(true)
await act({ variables: { id: item.id, act: 'VOTE', sats: 1 } })
await act({ variables: { id: item.id, sats: me.tipDefault || 1 } })
} catch (error) {
if (error.toString().includes('insufficient funds')) {
setError(true)
@ -233,9 +192,9 @@ export default function UpVote ({ item, className }) {
: signIn
}
>
<ActionTooltip notForm disable={noSelfTips} overlayText={overlayText()}>
<ActionTooltip notForm disable={item?.mine} overlayText={overlayText()}>
<div
className={`${noSelfTips ? styles.noSelfTips : ''}
className={`${item?.mine ? styles.noSelfTips : ''}
${styles.upvoteWrapper}`}
>
<UpBolt
@ -244,7 +203,7 @@ export default function UpVote ({ item, className }) {
className={
`${styles.upvote}
${className || ''}
${noSelfTips ? styles.noSelfTips : ''}
${item?.mine ? styles.noSelfTips : ''}
${item?.meSats ? styles.voted : ''}`
}
style={item?.meSats

View File

@ -10,7 +10,7 @@
padding-right: .2rem;
}
.noSelfTips .upvote.voted {
.noSelfTips {
fill: transparent !important;
filter: none !important;
}

View File

@ -11,11 +11,9 @@ export const COMMENT_FIELDS = gql`
id
}
sats
upvotes
boost
tips
meVote
meSats
meTip
mine
ncomments
root {

View File

@ -13,11 +13,9 @@ export const ITEM_FIELDS = gql`
id
}
sats
upvotes
boost
tips
meVote
meSats
meTip
ncomments
mine
root {

View File

@ -37,9 +37,11 @@ BEGIN
INSERT INTO "ItemAct" (sats, "itemId", "userId", act, created_at, updated_at)
VALUES (act_sats, item_id, user_id, 'TIP', now_utc(), now_utc());
END IF;
RETURN 1;
END IF;
END IF;
RETURN act_sats;
RETURN 0;
END;
$$;