tip walkthrough
This commit is contained in:
parent
ed0d4f2235
commit
4d3ab603da
@ -44,6 +44,15 @@ export default {
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
setWalkthrough: async (parent, { upvotePopover, tipPopover }, { me, models }) => {
|
||||||
|
if (!me) {
|
||||||
|
throw new AuthenticationError('you must be logged in')
|
||||||
|
}
|
||||||
|
|
||||||
|
await models.user.update({ where: { id: me.id }, data: { upvotePopover, tipPopover } })
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
setTheme: async (parent, { theme }, { me, models }) => {
|
setTheme: async (parent, { theme }, { me, models }) => {
|
||||||
if (!me) {
|
if (!me) {
|
||||||
throw new AuthenticationError('you must be logged in')
|
throw new AuthenticationError('you must be logged in')
|
||||||
|
@ -13,6 +13,7 @@ export default gql`
|
|||||||
setSettings(tipDefault: Int!): Boolean
|
setSettings(tipDefault: Int!): Boolean
|
||||||
setTheme(theme: String!): Boolean
|
setTheme(theme: String!): Boolean
|
||||||
upsertBio(bio: String!): User!
|
upsertBio(bio: String!): User!
|
||||||
|
setWalkthrough(tipPopover: Boolean, upvotePopover: Boolean): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type User {
|
type User {
|
||||||
@ -31,5 +32,7 @@ export default gql`
|
|||||||
sats: Int!
|
sats: Int!
|
||||||
msats: Int!
|
msats: Int!
|
||||||
theme: String!
|
theme: String!
|
||||||
|
upvotePopover: Boolean!
|
||||||
|
tipPopover: Boolean!
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
@ -8,16 +8,104 @@ import ActionTooltip from './action-tooltip'
|
|||||||
import { useItemAct } from './item-act'
|
import { useItemAct } from './item-act'
|
||||||
import Window from '../svgs/window-2-fill.svg'
|
import Window from '../svgs/window-2-fill.svg'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { useState } from 'react'
|
import { useRef, useState } from 'react'
|
||||||
import LongPressable from 'react-longpressable'
|
import LongPressable from 'react-longpressable'
|
||||||
import Rainbow from '../lib/rainbow'
|
import Rainbow from '../lib/rainbow'
|
||||||
import { OverlayTrigger, Popover } from 'react-bootstrap'
|
import { Overlay, Popover } from 'react-bootstrap'
|
||||||
|
|
||||||
|
const getColor = (meSats) => {
|
||||||
|
if (!meSats || meSats <= 10) {
|
||||||
|
return 'var(--secondary)'
|
||||||
|
}
|
||||||
|
|
||||||
|
const idx = Math.min(
|
||||||
|
Math.floor((Math.log(meSats) / Math.log(100000)) * (Rainbow.length - 1)),
|
||||||
|
Rainbow.length - 1)
|
||||||
|
return Rainbow[idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
const UpvotePopover = ({ target, show, handleClose }) => (
|
||||||
|
<Overlay
|
||||||
|
show={show}
|
||||||
|
target={target}
|
||||||
|
placement='right'
|
||||||
|
>
|
||||||
|
<Popover id='popover-basic'>
|
||||||
|
<Popover.Title className='d-flex justify-content-between alert-dismissible' as='h3'>Tipping
|
||||||
|
<button type='button' className='close' onClick={handleClose}><span aria-hidden='true'>×</span><span className='sr-only'>Close alert</span></button>
|
||||||
|
</Popover.Title>
|
||||||
|
<Popover.Content>
|
||||||
|
Press bolt again to tip 1 sat
|
||||||
|
</Popover.Content>
|
||||||
|
</Popover>
|
||||||
|
</Overlay>
|
||||||
|
)
|
||||||
|
|
||||||
|
const TipPopover = ({ target, show, handleClose }) => (
|
||||||
|
<Overlay
|
||||||
|
show={show}
|
||||||
|
target={target}
|
||||||
|
placement='right'
|
||||||
|
>
|
||||||
|
<Popover id='popover-basic'>
|
||||||
|
<Popover.Title className='d-flex justify-content-between alert-dismissible' as='h3'>Press and hold
|
||||||
|
<button type='button' class='close' onClick={handleClose}><span aria-hidden='true'>×</span><span class='sr-only'>Close alert</span></button>
|
||||||
|
</Popover.Title>
|
||||||
|
<Popover.Content>
|
||||||
|
Press and hold bolt to tip a custom amount
|
||||||
|
</Popover.Content>
|
||||||
|
</Popover>
|
||||||
|
</Overlay>
|
||||||
|
)
|
||||||
|
|
||||||
export default function UpVote ({ item, className }) {
|
export default function UpVote ({ item, className }) {
|
||||||
const { setError } = useFundError()
|
const { setError } = useFundError()
|
||||||
const { setItem } = useItemAct()
|
const { setItem } = useItemAct()
|
||||||
const [voteLock, setVoteLock] = useState()
|
const [voteLock, setVoteLock] = useState()
|
||||||
|
const [voteShow, _setVoteShow] = useState(false)
|
||||||
|
const [tipShow, _setTipShow] = useState(false)
|
||||||
|
const ref = useRef()
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
|
const [setWalkthrough] = useMutation(
|
||||||
|
gql`
|
||||||
|
mutation setWalkthrough($upvotePopover: Boolean, $tipPopover: Boolean) {
|
||||||
|
setWalkthrough(upvotePopover: $upvotePopover, tipPopover: $tipPopover)
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: 1. create functions that updates user to say that they've performed the
|
||||||
|
// actions so they don't get reprompted, 2. check that the user hasn't been prompted
|
||||||
|
// before prompting ... we can probably just create one toggle function for each
|
||||||
|
// that does these checks
|
||||||
|
|
||||||
|
const setVoteShow = (yes) => {
|
||||||
|
if (!me) return
|
||||||
|
|
||||||
|
if (yes && !me.upvotePopover) {
|
||||||
|
_setVoteShow(yes)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (voteShow && !yes) {
|
||||||
|
_setVoteShow(yes)
|
||||||
|
setWalkthrough({ variables: { upvotePopover: true } })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setTipShow = (yes) => {
|
||||||
|
if (!me) return
|
||||||
|
|
||||||
|
// if we want to show it, yet we still haven't shown
|
||||||
|
if (yes && !me.tipPopover) {
|
||||||
|
_setTipShow(yes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it's currently showing and we want to hide it
|
||||||
|
if (tipShow && !yes) {
|
||||||
|
_setTipShow(yes)
|
||||||
|
setWalkthrough({ variables: { tipPopover: true } })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const [act] = useMutation(
|
const [act] = useMutation(
|
||||||
gql`
|
gql`
|
||||||
mutation act($id: ID!, $act: ItemAct! $sats: Int!, $tipDefault: Boolean) {
|
mutation act($id: ID!, $act: ItemAct! $sats: Int!, $tipDefault: Boolean) {
|
||||||
@ -29,6 +117,13 @@ export default function UpVote ({ item, className }) {
|
|||||||
update (cache, { data: { act: { act, sats } } }) {
|
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
|
||||||
|
if (act === 'VOTE') {
|
||||||
|
setVoteShow(true)
|
||||||
|
}
|
||||||
|
if (act === 'TIP') {
|
||||||
|
setTipShow(true)
|
||||||
|
}
|
||||||
|
|
||||||
cache.modify({
|
cache.modify({
|
||||||
id: `Item:${item.id}`,
|
id: `Item:${item.id}`,
|
||||||
fields: {
|
fields: {
|
||||||
@ -85,26 +180,6 @@ export default function UpVote ({ item, className }) {
|
|||||||
return '1 sat'
|
return '1 sat'
|
||||||
}
|
}
|
||||||
|
|
||||||
const getColor = (meSats) => {
|
|
||||||
if (!meSats || meSats <= 10) {
|
|
||||||
return 'var(--secondary)'
|
|
||||||
}
|
|
||||||
|
|
||||||
const idx = Math.min(
|
|
||||||
Math.floor((Math.log(meSats) / Math.log(100000)) * (Rainbow.length - 1)),
|
|
||||||
Rainbow.length - 1)
|
|
||||||
return Rainbow[idx]
|
|
||||||
}
|
|
||||||
|
|
||||||
const popover = (
|
|
||||||
<Popover id='popover-basic'>
|
|
||||||
<Popover.Title as='h3'>Tipping</Popover.Title>
|
|
||||||
<Popover.Content>
|
|
||||||
Press bolt again to tip
|
|
||||||
</Popover.Content>
|
|
||||||
</Popover>
|
|
||||||
)
|
|
||||||
|
|
||||||
const noSelfTips = item?.meVote && item?.mine
|
const noSelfTips = item?.meVote && item?.mine
|
||||||
// 12 px default height
|
// 12 px default height
|
||||||
const cover = (item?.meSats < 10 ? ((10 - item.meSats) / 10.0) : 0) * 12
|
const cover = (item?.meSats < 10 ? ((10 - item.meSats) / 10.0) : 0) * 12
|
||||||
@ -112,6 +187,7 @@ export default function UpVote ({ item, className }) {
|
|||||||
return (
|
return (
|
||||||
<LightningConsumer>
|
<LightningConsumer>
|
||||||
{({ strike }) =>
|
{({ strike }) =>
|
||||||
|
<div ref={ref}>
|
||||||
<LongPressable
|
<LongPressable
|
||||||
onLongPress={
|
onLongPress={
|
||||||
async (e) => {
|
async (e) => {
|
||||||
@ -124,6 +200,7 @@ export default function UpVote ({ item, className }) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTipShow(false)
|
||||||
setItem({ itemId: item.id, act, strike })
|
setItem({ itemId: item.id, act, strike })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,6 +217,7 @@ export default function UpVote ({ item, className }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (item?.meVote) {
|
if (item?.meVote) {
|
||||||
|
setVoteShow(false)
|
||||||
if (me?.tipDefault) {
|
if (me?.tipDefault) {
|
||||||
try {
|
try {
|
||||||
strike()
|
strike()
|
||||||
@ -172,10 +250,10 @@ export default function UpVote ({ item, className }) {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<ActionTooltip notForm disable={noSelfTips} overlayText={overlayText()}>
|
<ActionTooltip notForm disable={noSelfTips} overlayText={overlayText()}>
|
||||||
<div className={`${noSelfTips ? styles.noSelfTips : ''}
|
<div
|
||||||
|
className={`${noSelfTips ? styles.noSelfTips : ''}
|
||||||
${styles.upvoteWrapper}`}
|
${styles.upvoteWrapper}`}
|
||||||
>
|
>
|
||||||
<OverlayTrigger placement='right' overlay={popover} show>
|
|
||||||
<UpBolt
|
<UpBolt
|
||||||
width={24}
|
width={24}
|
||||||
height={24}
|
height={24}
|
||||||
@ -195,11 +273,17 @@ export default function UpVote ({ item, className }) {
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</OverlayTrigger>
|
<div
|
||||||
<div className={styles.cover} style={{ top: item?.parentId ? '9px' : '4px', height: `${cover}px` }} />
|
className={styles.cover} onClick={e => {
|
||||||
|
e.stopPropagation()
|
||||||
|
}} style={{ top: item?.parentId ? '9px' : '4px', height: `${cover}px` }}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ActionTooltip>
|
</ActionTooltip>
|
||||||
</LongPressable>}
|
</LongPressable>
|
||||||
|
<TipPopover target={ref.current} show={tipShow} handleClose={() => setTipShow(false)} />
|
||||||
|
<UpvotePopover target={ref.current} show={voteShow} handleClose={() => setVoteShow(false)} />
|
||||||
|
</div>}
|
||||||
</LightningConsumer>
|
</LightningConsumer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ export const ME = gql`
|
|||||||
}
|
}
|
||||||
hasInvites
|
hasInvites
|
||||||
theme
|
theme
|
||||||
|
upvotePopover
|
||||||
|
tipPopover
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
|
3
prisma/migrations/20211206213650_popovers/migration.sql
Normal file
3
prisma/migrations/20211206213650_popovers/migration.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "users" ADD COLUMN "tipPopover" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
ADD COLUMN "upvotePopover" BOOLEAN NOT NULL DEFAULT false;
|
@ -37,6 +37,9 @@ model User {
|
|||||||
pubkey String? @unique
|
pubkey String? @unique
|
||||||
theme String @default("light")
|
theme String @default("light")
|
||||||
|
|
||||||
|
upvotePopover Boolean @default(false)
|
||||||
|
tipPopover Boolean @default(false)
|
||||||
|
|
||||||
@@index([createdAt])
|
@@index([createdAt])
|
||||||
@@map(name: "users")
|
@@map(name: "users")
|
||||||
}
|
}
|
||||||
|
@ -230,6 +230,10 @@ textarea.form-control {
|
|||||||
font-family: 'lightning';
|
font-family: 'lightning';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.popover-header.alert-dismissible .close {
|
||||||
|
padding: .5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
.alert-dismissible .close::after {
|
.alert-dismissible .close::after {
|
||||||
content: 'X';
|
content: 'X';
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user