diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index d7c4f8be..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: Bug report -about: Report a problem -title: '' -labels: bug -assignees: '' - ---- - -*Note: this template is meant to help you report the bug so that we can fix it faster, ie not all of these sections are required* - -**Description** -A clear and concise description of what the bug is. - -**Steps to Reproduce** -A clear and concise way we might be able to reproduce the bug. - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Logs** -If applicable, add your browsers console logs. - -**Environment:** -If you only experience the issue on certain devices or browsers, provide that info. - - Device: [e.g. iPhone6] - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..d05bbe6f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,65 @@ +name: 🐞 Bug report +description: Create a bug report to help us fix it +title: "bug report" +labels: [bug] +body: + - type: checkboxes + attributes: + label: Is there an existing issue for this? + description: Please search to see if an issue already exists for the bug you encountered. + options: + - label: I have searched the existing issues + required: true + - type: textarea + attributes: + label: Describe the bug + description: A clear and concise description of what the bug is. Include images if relevant. + placeholder: I accidentally deleted the internet. Here's my story ... + validations: + required: true + - type: textarea + attributes: + label: Screenshots + description: | + Add screenshots to help explain your problem. You can also add a video here. + + Tip: You can attach images or video files by clicking this area to highlight it and then dragging files in. + validations: + required: false + - type: textarea + attributes: + label: Steps To Reproduce + description: Steps to reproduce the bug. + placeholder: | + 1. Go to '...' + 2. Click on '...' + 3. Scroll to '...' + 4. See error + validations: + required: true + - type: textarea + attributes: + label: Expected behavior + description: A clear and concise description of what you expected to happen + validations: + required: true + - type: textarea + attributes: + label: Logs + description: If applicable, add your browser's console logs here + - type: textarea + attributes: + label: Device information + placeholder: | + - OS: [e.g. Windows] + - Browser: [e.g. chrome, safari, firefox] + - Browser Version: [e.g. 22] + validations: + required: false + - type: textarea + attributes: + label: Additional context + description: | + Do you have links to discussions about this on SN or other references? + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..075e285b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Questions + url: https://stacker.news/~meta + about: If you simply have a question, you can ask it in ~meta or the saloon. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index ba14c610..00000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest a feature -title: '' -labels: feature -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000..0c4c5a53 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,32 @@ +name: ✨ Feature request +description: Request a feature you'd like to see in SN! +title: "feature request" +labels: [feature] +body: + - type: markdown + attributes: + value: | + We're always looking for suggestions on how we could improve SN! + - type: textarea + attributes: + label: Describe the problem you're trying to solve + description: | + Is your feature request related to a problem? Add a clear and concise description of what the problem is. + validations: + required: true + - type: textarea + attributes: + label: Describe the solution you'd like + description: A clear and concise description of what you want to happen. + validations: + required: true + - type: textarea + attributes: + label: Describe alternatives you've considered + description: | + A clear and concise description of any alternative solutions or features you have considered. + - type: textarea + attributes: + label: Additional context + description: | + Add any other additional context or screenshots about the feature request here. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 309e2e77..e46d30f1 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,45 +1,22 @@ ## Description - +_A clear and concise description of what you changed and why._ ## Screenshots - - ## Additional Context - +_Was anything unclear during your work on this PR? Anything we should definitely take a closer look at?_ ## Checklist **Are your changes backwards compatible? Please answer below:** - - **On a scale of 1-10 how well and how have you QA'd this change and any features it might affect? Please answer below:** - **For frontend changes: Tested on mobile? Please answer below:** - **Did you introduce any new environment variables? If so, call them out explicitly here:** - - diff --git a/api/paidAction/index.js b/api/paidAction/index.js index 424198be..fcbfb4e3 100644 --- a/api/paidAction/index.js +++ b/api/paidAction/index.js @@ -258,8 +258,10 @@ export async function createLightningInvoice (actionType, args, context) { expiry: INVOICE_EXPIRE_SECS }, { models }) + // the sender (me) decides if the wrapped invoice has a description + // whereas the recipient decides if their invoice has a description const { invoice: wrappedInvoice, maxFee } = await wrapInvoice( - bolt11, { msats: cost, description }, { lnd }) + bolt11, { msats: cost, description }, { me, lnd }) return { bolt11, diff --git a/components/comment.js b/components/comment.js index 176ab6f1..62e455f3 100644 --- a/components/comment.js +++ b/components/comment.js @@ -180,7 +180,8 @@ export default function Comment ({ } } - onEdit={e => { setEdit(!edit) }} + edit={edit} + toggleEdit={e => { setEdit(!edit) }} editText={edit ? 'cancel' : 'edit'} />} diff --git a/components/item-info.js b/components/item-info.js index ba0c3732..921d57f5 100644 --- a/components/item-info.js +++ b/components/item-info.js @@ -30,7 +30,7 @@ import classNames from 'classnames' export default function ItemInfo ({ item, full, commentsText = 'comments', - commentTextSingular = 'comment', className, embellishUser, extraInfo, onEdit, editText, + commentTextSingular = 'comment', className, embellishUser, extraInfo, edit, toggleEdit, editText, onQuoteReply, extraBadges, nested, pinnable, showActionDropdown = true, showUser = true, setDisableRetry, disableRetry }) { @@ -151,8 +151,8 @@ export default function ItemInfo ({ showActionDropdown && <> @@ -311,7 +311,7 @@ function PaymentInfo ({ item, disableRetry, setDisableRetry }) { ) } -function EditInfo ({ item, canEdit, setCanEdit, onEdit, editText, editThreshold }) { +function EditInfo ({ item, edit, canEdit, setCanEdit, toggleEdit, editText, editThreshold }) { const router = useRouter() if (canEdit) { @@ -320,7 +320,7 @@ function EditInfo ({ item, canEdit, setCanEdit, onEdit, editText, editThreshold \ onEdit ? onEdit() : router.push(`/items/${item.id}/edit`)} + onClick={() => toggleEdit ? toggleEdit() : router.push(`/items/${item.id}/edit`)} > {editText || 'edit'} {(!item.invoice?.actionState || item.invoice?.actionState === 'PAID') @@ -334,5 +334,21 @@ function EditInfo ({ item, canEdit, setCanEdit, onEdit, editText, editThreshold ) } + if (edit && !canEdit) { + // if we're still editing after timer ran out + return ( + <> + \ + toggleEdit ? toggleEdit() : router.push(`/items/${item.id}`)} + > + cancel + 00:00 + + + ) + } + return null } diff --git a/components/text.js b/components/text.js index fe70f0a2..43b9a387 100644 --- a/components/text.js +++ b/components/text.js @@ -17,6 +17,7 @@ import ItemPopover from './item-popover' import classNames from 'classnames' import { CarouselProvider, useCarousel } from './carousel' import rehypeSN from '@/lib/rehype-sn' +import remarkUnicode from '@/lib/remark-unicode' import Embed from './embed' import remarkMath from 'remark-math' import rehypeMathjax from 'rehype-mathjax' @@ -33,7 +34,7 @@ const rehypeSNStyled = () => rehypeSN({ }] }) -const remarkPlugins = [gfm, [remarkMath, { singleDollarTextMath: false }]] +const remarkPlugins = [gfm, remarkUnicode, [remarkMath, { singleDollarTextMath: false }]] const rehypePlugins = [rehypeSNStyled, rehypeMathjax] export function SearchText ({ text }) { diff --git a/components/wallet-card.js b/components/wallet-card.js index aedd792c..e1ae443c 100644 --- a/components/wallet-card.js +++ b/components/wallet-card.js @@ -51,10 +51,18 @@ export default function WalletCard ({ wallet, draggable, onDragStart, onDragEnte {title} {badges?.map( - badge => - - {badge} - )} + badge => { + let style = '' + switch (badge) { + case 'receive': style = styles.receive; break + case 'send': style = styles.send; break + } + return ( + + {badge} + + ) + })} diff --git a/lib/remark-unicode.js b/lib/remark-unicode.js new file mode 100644 index 00000000..19c830ad --- /dev/null +++ b/lib/remark-unicode.js @@ -0,0 +1,31 @@ +import { visit } from 'unist-util-visit' + +export default function remarkFilterUnicode () { + return (tree) => { + try { + visit(tree, 'paragraph', (node) => { + node.children = node.children.map(child => { + if (child.type !== 'inlineMath') return child + + // if inline math contains currency symbols, rehypeMathjax will throw + // see https://github.com/stackernews/stacker.news/issues/1525 + // and https://github.com/stackernews/stacker.news/pull/1526 + + let { hChildren } = child.data + hChildren = hChildren.map(child2 => { + return { ...child2, value: filterUnicode(child2.value) } + }) + child.data.hChildren = hChildren + + return { ...child, value: filterUnicode(child.value) } + }) + }) + } catch (err) { + console.error(err) + } + } +} + +function filterUnicode (text) { + return text.replace(/\p{Sc}/u, '') +} diff --git a/pages/invites/index.js b/pages/invites/index.js index b00c03d7..37c71b13 100644 --- a/pages/invites/index.js +++ b/pages/invites/index.js @@ -27,6 +27,7 @@ function InviteForm () { fields: { invites (existingInviteRefs = []) { const newInviteRef = cache.writeFragment({ + fragmentName: 'InviteFields', data: createInvite, fragment: INVITE_FIELDS }) diff --git a/prisma/migrations/20241101151907_fix_territory_revenue/migration.sql b/prisma/migrations/20241101151907_fix_territory_revenue/migration.sql new file mode 100644 index 00000000..0a92b67f --- /dev/null +++ b/prisma/migrations/20241101151907_fix_territory_revenue/migration.sql @@ -0,0 +1,28 @@ +-- fix revenue for users who have multiple revenue entries for the same day +WITH revenue_days AS ( + SELECT coalesce(sum(msats), 0) as revenue_msats, "userId", created_at + FROM "SubAct" + WHERE type = 'REVENUE' + GROUP BY "userId", created_at + HAVING COUNT(*) > 1 +), +revenue_total AS ( + SELECT coalesce(sum(revenue_msats), 0) as revenue_msats, "userId" + FROM revenue_days + GROUP BY "userId" +) +UPDATE users SET msats = users.msats + revenue_total.revenue_msats +FROM revenue_total +WHERE users.id = revenue_total."userId"; + +-- fix stacked msats for users who have territory revenue +-- prior to this, we were not updating stacked msats for territory revenue +WITH territory_revenue AS ( + SELECT coalesce(sum(msats), 0) as revenue_msats, "userId" + FROM "SubAct" + WHERE type = 'REVENUE' + GROUP BY "userId" +) +UPDATE users SET "stackedMsats" = users."stackedMsats" + territory_revenue.revenue_msats +FROM territory_revenue +WHERE users.id = territory_revenue."userId"; diff --git a/styles/wallet.module.css b/styles/wallet.module.css index e4e8744a..133734d4 100644 --- a/styles/wallet.module.css +++ b/styles/wallet.module.css @@ -40,6 +40,14 @@ margin-right: 0.2rem; } +.receive { + color: #20c997 !important; +} + +.send { + color: var(--bs-primary) !important; +} + .attach { color: var(--bs-body-color) !important; text-align: center; diff --git a/wallets/blink/index.js b/wallets/blink/index.js index 6cbc3ff8..dc93d042 100644 --- a/wallets/blink/index.js +++ b/wallets/blink/index.js @@ -28,7 +28,7 @@ export const fields = [ export const card = { title: 'Blink', subtitle: 'use [Blink](https://blink.sv/) for payments', - badges: ['send only'] + badges: ['send'] } export const fieldValidation = blinkSchema diff --git a/wallets/cln/index.js b/wallets/cln/index.js index 644b7748..31e05606 100644 --- a/wallets/cln/index.js +++ b/wallets/cln/index.js @@ -36,7 +36,7 @@ export const fields = [ export const card = { title: 'CLN', subtitle: 'autowithdraw to your Core Lightning node via [CLNRest](https://docs.corelightning.org/docs/rest)', - badges: ['receive only'] + badges: ['receive'] } export const fieldValidation = CLNAutowithdrawSchema diff --git a/wallets/lightning-address/index.js b/wallets/lightning-address/index.js index ff502a3a..9a881d03 100644 --- a/wallets/lightning-address/index.js +++ b/wallets/lightning-address/index.js @@ -15,7 +15,7 @@ export const fields = [ export const card = { title: 'lightning address', subtitle: 'autowithdraw to a lightning address', - badges: ['receive only'] + badges: ['receive'] } export const fieldValidation = lnAddrAutowithdrawSchema diff --git a/wallets/lnbits/index.js b/wallets/lnbits/index.js index 3473f47e..a4425911 100644 --- a/wallets/lnbits/index.js +++ b/wallets/lnbits/index.js @@ -29,7 +29,7 @@ export const fields = [ export const card = { title: 'LNbits', subtitle: 'use [LNbits](https://lnbits.com/) for payments', - badges: ['send & receive'] + badges: ['send', 'receive'] } export const fieldValidation = lnbitsSchema diff --git a/wallets/lnc/index.js b/wallets/lnc/index.js index e349b6dd..b86153da 100644 --- a/wallets/lnc/index.js +++ b/wallets/lnc/index.js @@ -33,7 +33,7 @@ export const fields = [ export const card = { title: 'LNC', subtitle: 'use Lightning Node Connect for LND payments', - badges: ['send only', 'budgetable'] + badges: ['send', 'budgetable'] } export const fieldValidation = lncSchema diff --git a/wallets/lnd/index.js b/wallets/lnd/index.js index c884b909..21123cb5 100644 --- a/wallets/lnd/index.js +++ b/wallets/lnd/index.js @@ -37,7 +37,7 @@ export const fields = [ export const card = { title: 'LND', subtitle: 'autowithdraw to your Lightning Labs node', - badges: ['receive only'] + badges: ['receive'] } export const fieldValidation = LNDAutowithdrawSchema diff --git a/wallets/nwc/index.js b/wallets/nwc/index.js index fe443968..cd125769 100644 --- a/wallets/nwc/index.js +++ b/wallets/nwc/index.js @@ -27,7 +27,7 @@ export const fields = [ export const card = { title: 'NWC', subtitle: 'use Nostr Wallet Connect for payments', - badges: ['send & receive', 'budgetable'] + badges: ['send', 'receive', 'budgetable'] } export const fieldValidation = nwcSchema diff --git a/wallets/phoenixd/index.js b/wallets/phoenixd/index.js index 51625937..5a24e304 100644 --- a/wallets/phoenixd/index.js +++ b/wallets/phoenixd/index.js @@ -33,7 +33,7 @@ export const fields = [ export const card = { title: 'phoenixd', subtitle: 'use [phoenixd](https://phoenix.acinq.co/server) for payments', - badges: ['send & receive'] + badges: ['send', 'receive'] } // phoenixd::TODO diff --git a/wallets/webln/index.js b/wallets/webln/index.js index 6bfb26d5..75ca3dd8 100644 --- a/wallets/webln/index.js +++ b/wallets/webln/index.js @@ -20,7 +20,7 @@ export const fieldValidation = ({ enabled }) => { export const card = { title: 'WebLN', subtitle: 'use a [WebLN provider](https://www.webln.guide/ressources/webln-providers) for payments', - badges: ['send only'] + badges: ['send'] } export default function WebLnProvider ({ children }) { diff --git a/wallets/wrap.js b/wallets/wrap.js index ae63a6ed..b470587b 100644 --- a/wallets/wrap.js +++ b/wallets/wrap.js @@ -22,7 +22,7 @@ const ZAP_SYBIL_FEE_MULT = 10 / 7 // the fee for the zap sybil service maxFee: number } */ -export default async function wrapInvoice (bolt11, { msats, description, descriptionHash }, { lnd }) { +export default async function wrapInvoice (bolt11, { msats, description, descriptionHash }, { me, lnd }) { try { console.group('wrapInvoice', description) @@ -112,6 +112,11 @@ export default async function wrapInvoice (bolt11, { msats, description, descrip wrapped.description = inv.description } + if (me?.hideInvoiceDesc) { + wrapped.description = undefined + wrapped.description_hash = undefined + } + // validate the expiration if (new Date(inv.expires_at) < new Date(Date.now() + INCOMING_EXPIRATION_BUFFER_MSECS)) { throw new Error('Invoice expiration is too soon') diff --git a/worker/territory.js b/worker/territory.js index 21bb87b7..d7a7f479 100644 --- a/worker/territory.js +++ b/worker/territory.js @@ -72,10 +72,17 @@ export async function territoryRevenue ({ models }) { FROM revenue WHERE revenue > 1000 RETURNING * + ), + "SubActResultTotal" AS ( + SELECT coalesce(sum(msats), 0) as total_msats, "userId" + FROM "SubActResult" + GROUP BY "userId" ) - UPDATE users SET msats = users.msats + "SubActResult".msats - FROM "SubActResult" - WHERE users.id = "SubActResult"."userId"`, + UPDATE users + SET msats = users.msats + "SubActResultTotal".total_msats, + "stackedMsats" = users."stackedMsats" + "SubActResultTotal".total_msats + FROM "SubActResultTotal" + WHERE users.id = "SubActResultTotal"."userId"`, { models } ) }