different freebie rules

This commit is contained in:
keyan 2023-06-20 12:55:45 -05:00
parent 03e0646560
commit 431947eeee
4 changed files with 96 additions and 7 deletions

View File

@ -2,7 +2,7 @@ import { useState } from 'react'
import { Modal } from 'react-bootstrap'
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()
return (
@ -17,7 +17,7 @@ export default function Info ({ children }) {
</Modal.Body>
</Modal>
<InfoIcon
width={18} height={18} className='fill-theme-color pointer ml-1'
width={18} height={18} className={`${iconClassName} pointer ml-1`}
onClick={(e) => {
e.preventDefault()
setInfo(true)

View File

@ -9,6 +9,22 @@ import { LinkForm } from './link-form'
import { PollForm } from './poll-form'
import { BountyForm } from './bounty-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 }) {
const me = useMe()
@ -18,9 +34,7 @@ export function PostForm ({ type, sub, children }) {
if (!type) {
return (
<div className='align-items-center'>
{me?.freePosts && me?.sats < 1
? <div className='text-center font-weight-bold mb-3 text-success'>{me.freePosts} free posts left</div>
: null}
{me?.sats < 1 && <FreebieDialog />}
<SubSelect noForm sub={sub?.name} />
<Link href={prefix + '/post?type=link'}>
<Button variant='secondary'>link</Button>
@ -29,7 +43,7 @@ export function PostForm ({ type, sub, children }) {
<Link href={prefix + '/post?type=discussion'}>
<Button variant='secondary'>discussion</Button>
</Link>
<div className='d-flex mt-3'>
<div className='d-flex mt-4'>
<AccordianItem
headerColor='#6c757d'
header={<div className='font-weight-bold text-muted'>more types</div>}

View File

@ -9,6 +9,7 @@ import Link from 'next/link'
import FeeButton from './fee-button'
import { commentsViewedAfterComment } from '../lib/new-comments'
import { commentSchema } from '../lib/validate'
import Info from './info'
export function ReplyOnAnotherPage ({ parentId }) {
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 }) {
const [reply, setReply] = useState(replyOpen)
const me = useMe()
@ -117,7 +133,7 @@ export default function Reply ({ item, onSuccess, replyOpen, children, placehold
autoFocus={!replyOpen}
required
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}
/>
{reply &&

View 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;
$$;