different freebie rules
This commit is contained in:
parent
03e0646560
commit
431947eeee
@ -2,7 +2,7 @@ import { useState } from 'react'
|
|||||||
import { Modal } from 'react-bootstrap'
|
import { Modal } from 'react-bootstrap'
|
||||||
import InfoIcon from '../svgs/information-fill.svg'
|
import InfoIcon from '../svgs/information-fill.svg'
|
||||||
|
|
||||||
export default function Info ({ children }) {
|
export default function Info ({ children, iconClassName = 'fill-theme-color' }) {
|
||||||
const [info, setInfo] = useState()
|
const [info, setInfo] = useState()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -17,7 +17,7 @@ export default function Info ({ children }) {
|
|||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
</Modal>
|
</Modal>
|
||||||
<InfoIcon
|
<InfoIcon
|
||||||
width={18} height={18} className='fill-theme-color pointer ml-1'
|
width={18} height={18} className={`${iconClassName} pointer ml-1`}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
setInfo(true)
|
setInfo(true)
|
||||||
|
@ -9,6 +9,22 @@ import { LinkForm } from './link-form'
|
|||||||
import { PollForm } from './poll-form'
|
import { PollForm } from './poll-form'
|
||||||
import { BountyForm } from './bounty-form'
|
import { BountyForm } from './bounty-form'
|
||||||
import SubSelect from './sub-select-form'
|
import SubSelect from './sub-select-form'
|
||||||
|
import Info from './info'
|
||||||
|
|
||||||
|
function FreebieDialog () {
|
||||||
|
return (
|
||||||
|
<div className='text-center mb-4 text-muted'>
|
||||||
|
you have no sats, so this one is on us
|
||||||
|
<Info>
|
||||||
|
<ul className='font-weight-bold'>
|
||||||
|
<li>Free posts have limited visibility and are hidden on the recent tab until other stackers zap them.</li>
|
||||||
|
<li>Free posts will not cover posts that cost more than 1 sat.</li>
|
||||||
|
<li>To get fully visibile and unrestricted posts right away, fund your account with a few sats or earn some on Stacker News.</li>
|
||||||
|
</ul>
|
||||||
|
</Info>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function PostForm ({ type, sub, children }) {
|
export function PostForm ({ type, sub, children }) {
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
@ -18,9 +34,7 @@ export function PostForm ({ type, sub, children }) {
|
|||||||
if (!type) {
|
if (!type) {
|
||||||
return (
|
return (
|
||||||
<div className='align-items-center'>
|
<div className='align-items-center'>
|
||||||
{me?.freePosts && me?.sats < 1
|
{me?.sats < 1 && <FreebieDialog />}
|
||||||
? <div className='text-center font-weight-bold mb-3 text-success'>{me.freePosts} free posts left</div>
|
|
||||||
: null}
|
|
||||||
<SubSelect noForm sub={sub?.name} />
|
<SubSelect noForm sub={sub?.name} />
|
||||||
<Link href={prefix + '/post?type=link'}>
|
<Link href={prefix + '/post?type=link'}>
|
||||||
<Button variant='secondary'>link</Button>
|
<Button variant='secondary'>link</Button>
|
||||||
@ -29,7 +43,7 @@ export function PostForm ({ type, sub, children }) {
|
|||||||
<Link href={prefix + '/post?type=discussion'}>
|
<Link href={prefix + '/post?type=discussion'}>
|
||||||
<Button variant='secondary'>discussion</Button>
|
<Button variant='secondary'>discussion</Button>
|
||||||
</Link>
|
</Link>
|
||||||
<div className='d-flex mt-3'>
|
<div className='d-flex mt-4'>
|
||||||
<AccordianItem
|
<AccordianItem
|
||||||
headerColor='#6c757d'
|
headerColor='#6c757d'
|
||||||
header={<div className='font-weight-bold text-muted'>more types</div>}
|
header={<div className='font-weight-bold text-muted'>more types</div>}
|
||||||
|
@ -9,6 +9,7 @@ import Link from 'next/link'
|
|||||||
import FeeButton from './fee-button'
|
import FeeButton from './fee-button'
|
||||||
import { commentsViewedAfterComment } from '../lib/new-comments'
|
import { commentsViewedAfterComment } from '../lib/new-comments'
|
||||||
import { commentSchema } from '../lib/validate'
|
import { commentSchema } from '../lib/validate'
|
||||||
|
import Info from './info'
|
||||||
|
|
||||||
export function ReplyOnAnotherPage ({ parentId }) {
|
export function ReplyOnAnotherPage ({ parentId }) {
|
||||||
return (
|
return (
|
||||||
@ -18,6 +19,21 @@ export function ReplyOnAnotherPage ({ parentId }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function FreebieDialog () {
|
||||||
|
return (
|
||||||
|
<div className='text-muted'>
|
||||||
|
you have no sats, so this one is on us
|
||||||
|
<Info>
|
||||||
|
<ul className='font-weight-bold'>
|
||||||
|
<li>Free comments have limited visibility and are listed at the bottom of the comment section until other stackers zap them.</li>
|
||||||
|
<li>Free comments will not cover comments that cost more than 1 sat.</li>
|
||||||
|
<li>To get fully visibile and unrestricted comments right away, fund your account with a few sats or earn some on Stacker News.</li>
|
||||||
|
</ul>
|
||||||
|
</Info>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default function Reply ({ item, onSuccess, replyOpen, children, placeholder }) {
|
export default function Reply ({ item, onSuccess, replyOpen, children, placeholder }) {
|
||||||
const [reply, setReply] = useState(replyOpen)
|
const [reply, setReply] = useState(replyOpen)
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
@ -117,7 +133,7 @@ export default function Reply ({ item, onSuccess, replyOpen, children, placehold
|
|||||||
autoFocus={!replyOpen}
|
autoFocus={!replyOpen}
|
||||||
required
|
required
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
hint={me?.freeComments && me?.sats < 1 ? <span className='text-success'>{me.freeComments} free comments left</span> : null}
|
hint={me?.sats < 1 && <FreebieDialog />}
|
||||||
innerRef={replyInput}
|
innerRef={replyInput}
|
||||||
/>
|
/>
|
||||||
{reply &&
|
{reply &&
|
||||||
|
59
prisma/migrations/20230620164842_freebies4ever/migration.sql
Normal file
59
prisma/migrations/20230620164842_freebies4ever/migration.sql
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
CREATE OR REPLACE FUNCTION create_item(
|
||||||
|
sub TEXT, title TEXT, url TEXT, text TEXT, boost INTEGER, bounty INTEGER,
|
||||||
|
parent_id INTEGER, user_id INTEGER, fwd_user_id INTEGER,
|
||||||
|
spam_within INTERVAL)
|
||||||
|
RETURNS "Item"
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
user_msats BIGINT;
|
||||||
|
cost_msats BIGINT;
|
||||||
|
freebie BOOLEAN;
|
||||||
|
item "Item";
|
||||||
|
med_votes FLOAT;
|
||||||
|
BEGIN
|
||||||
|
PERFORM ASSERT_SERIALIZED();
|
||||||
|
|
||||||
|
SELECT msats INTO user_msats FROM users WHERE id = user_id;
|
||||||
|
|
||||||
|
cost_msats := 1000 * POWER(10, item_spam(parent_id, user_id, spam_within));
|
||||||
|
-- it's only a freebie if it's a 1 sat cost, they have < 1 sat, boost = 0, and they have freebies left
|
||||||
|
freebie := (cost_msats <= 1000) AND (user_msats < 1000) AND (boost = 0);
|
||||||
|
|
||||||
|
IF NOT freebie AND cost_msats > user_msats THEN
|
||||||
|
RAISE EXCEPTION 'SN_INSUFFICIENT_FUNDS';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- get this user's median item score
|
||||||
|
SELECT COALESCE(percentile_cont(0.5) WITHIN GROUP(ORDER BY "weightedVotes" - "weightedDownVotes"), 0) INTO med_votes FROM "Item" WHERE "userId" = user_id;
|
||||||
|
|
||||||
|
-- if their median votes are positive, start at 0
|
||||||
|
-- if the median votes are negative, start their post with that many down votes
|
||||||
|
-- basically: if their median post is bad, presume this post is too
|
||||||
|
IF med_votes >= 0 THEN
|
||||||
|
med_votes := 0;
|
||||||
|
ELSE
|
||||||
|
med_votes := ABS(med_votes);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
INSERT INTO "Item"
|
||||||
|
("subName", title, url, text, bounty, "userId", "parentId", "fwdUserId",
|
||||||
|
freebie, "weightedDownVotes", created_at, updated_at)
|
||||||
|
VALUES
|
||||||
|
(sub, title, url, text, bounty, user_id, parent_id, fwd_user_id,
|
||||||
|
freebie, med_votes, now_utc(), now_utc()) RETURNING * INTO item;
|
||||||
|
|
||||||
|
IF NOT freebie THEN
|
||||||
|
UPDATE users SET msats = msats - cost_msats WHERE id = user_id;
|
||||||
|
|
||||||
|
INSERT INTO "ItemAct" (msats, "itemId", "userId", act, created_at, updated_at)
|
||||||
|
VALUES (cost_msats, item.id, user_id, 'FEE', now_utc(), now_utc());
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF boost > 0 THEN
|
||||||
|
PERFORM item_act(item.id, user_id, 'BOOST', boost);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN item;
|
||||||
|
END;
|
||||||
|
$$;
|
Loading…
x
Reference in New Issue
Block a user