Use module path aliases (#938)
* Use module path aliases * fix broken refactor * path mapping for svgs, style, and remaining places (bonus: lose babel dep) --------- Co-authored-by: keyan <keyan.kousha+huumn@gmail.com>
This commit is contained in:
parent
22ff832efb
commit
d237861ff5
20
.babelrc
20
.babelrc
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"presets": [
|
|
||||||
"next/babel"
|
|
||||||
],
|
|
||||||
"plugins": [
|
|
||||||
[
|
|
||||||
"inline-react-svg",
|
|
||||||
{
|
|
||||||
"svgo": {
|
|
||||||
"plugins": [
|
|
||||||
{
|
|
||||||
"name": "removeViewBox",
|
|
||||||
"active": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
import lndService from 'ln-service'
|
import lndService from 'ln-service'
|
||||||
import lnd from '../lnd'
|
import lnd from '@/api/lnd'
|
||||||
|
|
||||||
const cache = new Map()
|
const cache = new Map()
|
||||||
const expiresIn = 1000 * 30 // 30 seconds in milliseconds
|
const expiresIn = 1000 * 30 // 30 seconds in milliseconds
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import lndService from 'ln-service'
|
import lndService from 'ln-service'
|
||||||
import lnd from '../lnd'
|
import lnd from '@/api/lnd'
|
||||||
|
|
||||||
const cache = new Map()
|
const cache = new Map()
|
||||||
const expiresIn = 1000 * 30 // 30 seconds in milliseconds
|
const expiresIn = 1000 * 30 // 30 seconds in milliseconds
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { timeUnitForRange, whenRange } from '../../lib/time'
|
import { timeUnitForRange, whenRange } from '@/lib/time'
|
||||||
|
|
||||||
export function withClause (range) {
|
export function withClause (range) {
|
||||||
const unit = timeUnitForRange(range)
|
const unit = timeUnitForRange(range)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { ANON_USER_ID, AWS_S3_URL_REGEXP } from '../../lib/constants'
|
import { ANON_USER_ID, AWS_S3_URL_REGEXP } from '@/lib/constants'
|
||||||
import { msatsToSats } from '../../lib/format'
|
import { msatsToSats } from '@/lib/format'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Query: {
|
Query: {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { GraphQLError } from 'graphql'
|
import { GraphQLError } from 'graphql'
|
||||||
import { inviteSchema, ssValidate } from '../../lib/validate'
|
import { inviteSchema, ssValidate } from '@/lib/validate'
|
||||||
import { msatsToSats } from '../../lib/format'
|
import { msatsToSats } from '@/lib/format'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Query: {
|
Query: {
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
import { GraphQLError } from 'graphql'
|
import { GraphQLError } from 'graphql'
|
||||||
import { ensureProtocol, removeTracking, stripTrailingSlash } from '../../lib/url'
|
import { ensureProtocol, removeTracking, stripTrailingSlash } from '@/lib/url'
|
||||||
import serialize, { serializeInvoicable } from './serial'
|
import serialize, { serializeInvoicable } from './serial'
|
||||||
import { decodeCursor, LIMIT, nextCursorEncoded } from '../../lib/cursor'
|
import { decodeCursor, LIMIT, nextCursorEncoded } from '@/lib/cursor'
|
||||||
import { getMetadata, metadataRuleSets } from 'page-metadata-parser'
|
import { getMetadata, metadataRuleSets } from 'page-metadata-parser'
|
||||||
import { ruleSet as publicationDateRuleSet } from '../../lib/timedate-scraper'
|
import { ruleSet as publicationDateRuleSet } from '@/lib/timedate-scraper'
|
||||||
import domino from 'domino'
|
import domino from 'domino'
|
||||||
import {
|
import {
|
||||||
ITEM_SPAM_INTERVAL, ITEM_FILTER_THRESHOLD,
|
ITEM_SPAM_INTERVAL, ITEM_FILTER_THRESHOLD,
|
||||||
COMMENT_DEPTH_LIMIT, COMMENT_TYPE_QUERY,
|
COMMENT_DEPTH_LIMIT, COMMENT_TYPE_QUERY,
|
||||||
ANON_USER_ID, ANON_ITEM_SPAM_INTERVAL, POLL_COST,
|
ANON_USER_ID, ANON_ITEM_SPAM_INTERVAL, POLL_COST,
|
||||||
ITEM_ALLOW_EDITS, GLOBAL_SEED, ANON_FEE_MULTIPLIER, NOFOLLOW_LIMIT, UNKNOWN_LINK_REL
|
ITEM_ALLOW_EDITS, GLOBAL_SEED, ANON_FEE_MULTIPLIER, NOFOLLOW_LIMIT, UNKNOWN_LINK_REL
|
||||||
} from '../../lib/constants'
|
} from '@/lib/constants'
|
||||||
import { msatsToSats } from '../../lib/format'
|
import { msatsToSats } from '@/lib/format'
|
||||||
import { parse } from 'tldts'
|
import { parse } from 'tldts'
|
||||||
import uu from 'url-unshort'
|
import uu from 'url-unshort'
|
||||||
import { actSchema, advSchema, bountySchema, commentSchema, discussionSchema, jobSchema, linkSchema, pollSchema, ssValidate } from '../../lib/validate'
|
import { actSchema, advSchema, bountySchema, commentSchema, discussionSchema, jobSchema, linkSchema, pollSchema, ssValidate } from '@/lib/validate'
|
||||||
import { notifyItemParents, notifyUserSubscribers, notifyZapped, notifyTerritorySubscribers, notifyMention } from '../../lib/webPush'
|
import { notifyItemParents, notifyUserSubscribers, notifyZapped, notifyTerritorySubscribers, notifyMention } from '@/lib/webPush'
|
||||||
import { defaultCommentSort, isJob, deleteItemByAuthor, getDeleteCommand, hasDeleteCommand } from '../../lib/item'
|
import { defaultCommentSort, isJob, deleteItemByAuthor, getDeleteCommand, hasDeleteCommand } from '@/lib/item'
|
||||||
import { datePivot, whenRange } from '../../lib/time'
|
import { datePivot, whenRange } from '@/lib/time'
|
||||||
import { imageFeesInfo, uploadIdsFromText } from './image'
|
import { imageFeesInfo, uploadIdsFromText } from './image'
|
||||||
import assertGofacYourself from './ofac'
|
import assertGofacYourself from './ofac'
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { GraphQLError } from 'graphql'
|
import { GraphQLError } from 'graphql'
|
||||||
import { decodeCursor, LIMIT, nextNoteCursorEncoded } from '../../lib/cursor'
|
import { decodeCursor, LIMIT, nextNoteCursorEncoded } from '@/lib/cursor'
|
||||||
import { getItem, filterClause, whereClause, muteClause } from './item'
|
import { getItem, filterClause, whereClause, muteClause } from './item'
|
||||||
import { getInvoice } from './wallet'
|
import { getInvoice } from './wallet'
|
||||||
import { pushSubscriptionSchema, ssValidate } from '../../lib/validate'
|
import { pushSubscriptionSchema, ssValidate } from '@/lib/validate'
|
||||||
import { replyToSubscription } from '../../lib/webPush'
|
import { replyToSubscription } from '@/lib/webPush'
|
||||||
import { getSub } from './sub'
|
import { getSub } from './sub'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { GraphQLError } from 'graphql'
|
import { GraphQLError } from 'graphql'
|
||||||
import { withClause, intervalClause } from './growth'
|
import { withClause, intervalClause } from './growth'
|
||||||
import { timeUnitForRange, whenRange } from '../../lib/time'
|
import { timeUnitForRange, whenRange } from '@/lib/time'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Query: {
|
Query: {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { GraphQLError } from 'graphql'
|
import { GraphQLError } from 'graphql'
|
||||||
import { amountSchema, ssValidate } from '../../lib/validate'
|
import { amountSchema, ssValidate } from '@/lib/validate'
|
||||||
import { serializeInvoicable } from './serial'
|
import { serializeInvoicable } from './serial'
|
||||||
import { ANON_USER_ID } from '../../lib/constants'
|
import { ANON_USER_ID } from '@/lib/constants'
|
||||||
import { getItem } from './item'
|
import { getItem } from './item'
|
||||||
import { topUsers } from './user'
|
import { topUsers } from './user'
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { decodeCursor, LIMIT, nextCursorEncoded } from '../../lib/cursor'
|
import { decodeCursor, LIMIT, nextCursorEncoded } from '@/lib/cursor'
|
||||||
import { whenToFrom } from '../../lib/time'
|
import { whenToFrom } from '@/lib/time'
|
||||||
import { getItem, itemQueryWithMeta, SELECT } from './item'
|
import { getItem, itemQueryWithMeta, SELECT } from './item'
|
||||||
|
|
||||||
function queryParts (q) {
|
function queryParts (q) {
|
||||||
|
|
|
@ -3,8 +3,8 @@ import retry from 'async-retry'
|
||||||
import Prisma from '@prisma/client'
|
import Prisma from '@prisma/client'
|
||||||
import { settleHodlInvoice } from 'ln-service'
|
import { settleHodlInvoice } from 'ln-service'
|
||||||
import { createHmac } from './wallet'
|
import { createHmac } from './wallet'
|
||||||
import { msatsToSats, numWithUnits } from '../../lib/format'
|
import { msatsToSats, numWithUnits } from '@/lib/format'
|
||||||
import { BALANCE_LIMIT_MSATS } from '../../lib/constants'
|
import { BALANCE_LIMIT_MSATS } from '@/lib/constants'
|
||||||
|
|
||||||
export default async function serialize (models, ...calls) {
|
export default async function serialize (models, ...calls) {
|
||||||
return await retry(async bail => {
|
return await retry(async bail => {
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import { GraphQLError } from 'graphql'
|
import { GraphQLError } from 'graphql'
|
||||||
import { serializeInvoicable } from './serial'
|
import { serializeInvoicable } from './serial'
|
||||||
import { TERRITORY_COST_MONTHLY, TERRITORY_COST_ONCE, TERRITORY_COST_YEARLY, TERRITORY_PERIOD_COST } from '../../lib/constants'
|
import { TERRITORY_COST_MONTHLY, TERRITORY_COST_ONCE, TERRITORY_COST_YEARLY, TERRITORY_PERIOD_COST } from '@/lib/constants'
|
||||||
import { datePivot, whenRange } from '../../lib/time'
|
import { datePivot, whenRange } from '@/lib/time'
|
||||||
import { ssValidate, territorySchema } from '../../lib/validate'
|
import { ssValidate, territorySchema } from '@/lib/validate'
|
||||||
import { nextBilling, proratedBillingCost } from '../../lib/territory'
|
import { nextBilling, proratedBillingCost } from '@/lib/territory'
|
||||||
import { decodeCursor, LIMIT, nextCursorEncoded } from '../../lib/cursor'
|
import { decodeCursor, LIMIT, nextCursorEncoded } from '@/lib/cursor'
|
||||||
import { subViewGroup } from './growth'
|
import { subViewGroup } from './growth'
|
||||||
import { notifyTerritoryTransfer } from '../../lib/webPush'
|
import { notifyTerritoryTransfer } from '@/lib/webPush'
|
||||||
|
|
||||||
export function paySubQueries (sub, models) {
|
export function paySubQueries (sub, models) {
|
||||||
if (sub.billingType === 'ONCE') {
|
if (sub.billingType === 'ONCE') {
|
||||||
return []
|
return []
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { GraphQLError } from 'graphql'
|
import { GraphQLError } from 'graphql'
|
||||||
import { ANON_USER_ID, IMAGE_PIXELS_MAX, UPLOAD_SIZE_MAX, UPLOAD_SIZE_MAX_AVATAR, UPLOAD_TYPES_ALLOW } from '../../lib/constants'
|
import { ANON_USER_ID, IMAGE_PIXELS_MAX, UPLOAD_SIZE_MAX, UPLOAD_SIZE_MAX_AVATAR, UPLOAD_TYPES_ALLOW } from '@/lib/constants'
|
||||||
import { createPresignedPost } from '../s3'
|
import { createPresignedPost } from '@/api/s3'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Mutation: {
|
Mutation: {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { readFile } from 'fs/promises'
|
import { readFile } from 'fs/promises'
|
||||||
import { join, resolve } from 'path'
|
import { join, resolve } from 'path'
|
||||||
import { GraphQLError } from 'graphql'
|
import { GraphQLError } from 'graphql'
|
||||||
import { decodeCursor, LIMIT, nextCursorEncoded } from '../../lib/cursor'
|
import { decodeCursor, LIMIT, nextCursorEncoded } from '@/lib/cursor'
|
||||||
import { msatsToSats } from '../../lib/format'
|
import { msatsToSats } from '@/lib/format'
|
||||||
import { bioSchema, emailSchema, settingsSchema, ssValidate, userSchema } from '../../lib/validate'
|
import { bioSchema, emailSchema, settingsSchema, ssValidate, userSchema } from '@/lib/validate'
|
||||||
import { getItem, updateItem, filterClause, createItem, whereClause, muteClause } from './item'
|
import { getItem, updateItem, filterClause, createItem, whereClause, muteClause } from './item'
|
||||||
import { ANON_USER_ID, DELETE_USER_ID, RESERVED_MAX_USER_ID, SN_USER_IDS } from '../../lib/constants'
|
import { ANON_USER_ID, DELETE_USER_ID, RESERVED_MAX_USER_ID, SN_USER_IDS } from '@/lib/constants'
|
||||||
import { viewGroup } from './growth'
|
import { viewGroup } from './growth'
|
||||||
import { whenRange } from '../../lib/time'
|
import { whenRange } from '@/lib/time'
|
||||||
|
|
||||||
const contributors = new Set()
|
const contributors = new Set()
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,14 @@ import { getIdentity, createHodlInvoice, createInvoice, decodePaymentRequest, pa
|
||||||
import { GraphQLError } from 'graphql'
|
import { GraphQLError } from 'graphql'
|
||||||
import crypto from 'crypto'
|
import crypto from 'crypto'
|
||||||
import serialize from './serial'
|
import serialize from './serial'
|
||||||
import { decodeCursor, LIMIT, nextCursorEncoded } from '../../lib/cursor'
|
import { decodeCursor, LIMIT, nextCursorEncoded } from '@/lib/cursor'
|
||||||
import lnpr from 'bolt11'
|
import lnpr from 'bolt11'
|
||||||
import { SELECT } from './item'
|
import { SELECT } from './item'
|
||||||
import { lnAddrOptions } from '../../lib/lnurl'
|
import { lnAddrOptions } from '@/lib/lnurl'
|
||||||
import { msatsToSats, msatsToSatsDecimal, ensureB64 } from '../../lib/format'
|
import { msatsToSats, msatsToSatsDecimal, ensureB64 } from '@/lib/format'
|
||||||
import { LNDAutowithdrawSchema, amountSchema, lnAddrAutowithdrawSchema, lnAddrSchema, ssValidate, withdrawlSchema } from '../../lib/validate'
|
import { LNDAutowithdrawSchema, amountSchema, lnAddrAutowithdrawSchema, lnAddrSchema, ssValidate, withdrawlSchema } from '@/lib/validate'
|
||||||
import { ANON_BALANCE_LIMIT_MSATS, ANON_INV_PENDING_LIMIT, ANON_USER_ID, BALANCE_LIMIT_MSATS, INVOICE_RETENTION_DAYS, INV_PENDING_LIMIT, USER_IDS_BALANCE_NO_LIMIT } from '../../lib/constants'
|
import { ANON_BALANCE_LIMIT_MSATS, ANON_INV_PENDING_LIMIT, ANON_USER_ID, BALANCE_LIMIT_MSATS, INVOICE_RETENTION_DAYS, INV_PENDING_LIMIT, USER_IDS_BALANCE_NO_LIMIT } from '@/lib/constants'
|
||||||
import { datePivot } from '../../lib/time'
|
import { datePivot } from '@/lib/time'
|
||||||
import assertGofacYourself from './ofac'
|
import assertGofacYourself from './ofac'
|
||||||
|
|
||||||
export async function getInvoice (parent, { id }, { me, models, lnd }) {
|
export async function getInvoice (parent, { id }, { me, models, lnd }) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import AWS from 'aws-sdk'
|
import AWS from 'aws-sdk'
|
||||||
import { MEDIA_URL } from '../../lib/constants'
|
import { MEDIA_URL } from '@/lib/constants'
|
||||||
|
|
||||||
const bucketRegion = 'us-east-1'
|
const bucketRegion = 'us-east-1'
|
||||||
const Bucket = process.env.NEXT_PUBLIC_AWS_UPLOAD_BUCKET
|
const Bucket = process.env.NEXT_PUBLIC_AWS_UPLOAD_BUCKET
|
||||||
|
|
|
@ -7,12 +7,12 @@ import models from './models'
|
||||||
import { print } from 'graphql'
|
import { print } from 'graphql'
|
||||||
import lnd from './lnd'
|
import lnd from './lnd'
|
||||||
import search from './search'
|
import search from './search'
|
||||||
import { ME } from '../fragments/users'
|
import { ME } from '@/fragments/users'
|
||||||
import { PRICE } from '../fragments/price'
|
import { PRICE } from '@/fragments/price'
|
||||||
import { BLOCK_HEIGHT } from '../fragments/blockHeight'
|
import { BLOCK_HEIGHT } from '@/fragments/blockHeight'
|
||||||
import { CHAIN_FEE } from '../fragments/chainFee'
|
import { CHAIN_FEE } from '@/fragments/chainFee'
|
||||||
import { getServerSession } from 'next-auth/next'
|
import { getServerSession } from 'next-auth/next'
|
||||||
import { getAuthOptions } from '../pages/api/auth/[...nextauth]'
|
import { getAuthOptions } from '@/pages/api/auth/[...nextauth]'
|
||||||
|
|
||||||
export default async function getSSRApolloClient ({ req, res, me = null }) {
|
export default async function getSSRApolloClient ({ req, res, me = null }) {
|
||||||
const session = req && await getServerSession(req, res, getAuthOptions(req))
|
const session = req && await getServerSession(req, res, getAuthOptions(req))
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
import webPush from 'web-push'
|
||||||
|
import models from '@/api/models'
|
||||||
|
import { COMMENT_DEPTH_LIMIT } from '@/lib/constants'
|
||||||
|
import removeMd from 'remove-markdown'
|
||||||
|
|
||||||
|
const webPushEnabled = process.env.NODE_ENV === 'production' ||
|
||||||
|
(process.env.VAPID_MAILTO && process.env.NEXT_PUBLIC_VAPID_PUBKEY && process.env.VAPID_PRIVKEY)
|
||||||
|
|
||||||
|
if (webPushEnabled) {
|
||||||
|
webPush.setVapidDetails(
|
||||||
|
process.env.VAPID_MAILTO,
|
||||||
|
process.env.NEXT_PUBLIC_VAPID_PUBKEY,
|
||||||
|
process.env.VAPID_PRIVKEY
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
console.warn('VAPID_* env vars not set, skipping webPush setup')
|
||||||
|
}
|
||||||
|
|
||||||
|
const createPayload = (notification) => {
|
||||||
|
// https://web.dev/push-notifications-display-a-notification/#visual-options
|
||||||
|
let { title, body, ...options } = notification
|
||||||
|
if (body) body = removeMd(body)
|
||||||
|
return JSON.stringify({
|
||||||
|
title,
|
||||||
|
options: {
|
||||||
|
body,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
icon: '/icons/icon_x96.png',
|
||||||
|
...options
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const createUserFilter = (tag) => {
|
||||||
|
// filter users by notification settings
|
||||||
|
const tagMap = {
|
||||||
|
REPLY: 'noteAllDescendants',
|
||||||
|
MENTION: 'noteMentions',
|
||||||
|
TIP: 'noteItemSats',
|
||||||
|
FORWARDEDTIP: 'noteForwardedSats',
|
||||||
|
REFERRAL: 'noteInvites',
|
||||||
|
INVITE: 'noteInvites',
|
||||||
|
EARN: 'noteEarning',
|
||||||
|
DEPOSIT: 'noteDeposits',
|
||||||
|
STREAK: 'noteCowboyHat'
|
||||||
|
}
|
||||||
|
const key = tagMap[tag.split('-')[0]]
|
||||||
|
return key ? { user: { [key]: true } } : undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const createItemUrl = async ({ id }) => {
|
||||||
|
const [rootItem] = await models.$queryRawUnsafe(
|
||||||
|
'SELECT subpath(path, -LEAST(nlevel(path), $1::INTEGER), 1)::text AS id FROM "Item" WHERE id = $2::INTEGER',
|
||||||
|
COMMENT_DEPTH_LIMIT + 1, Number(id)
|
||||||
|
)
|
||||||
|
return `/items/${rootItem.id}` + (rootItem.id !== id ? `?commentId=${id}` : '')
|
||||||
|
}
|
||||||
|
|
||||||
|
const sendNotification = (subscription, payload) => {
|
||||||
|
if (!webPushEnabled) {
|
||||||
|
console.warn('webPush not configured. skipping notification')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { id, endpoint, p256dh, auth } = subscription
|
||||||
|
return webPush.sendNotification({ endpoint, keys: { p256dh, auth } }, payload)
|
||||||
|
.catch(async (err) => {
|
||||||
|
if (err.statusCode === 400) {
|
||||||
|
console.log('[webPush] invalid request: ', err)
|
||||||
|
} else if ([401, 403].includes(err.statusCode)) {
|
||||||
|
console.log('[webPush] auth error: ', err)
|
||||||
|
} else if (err.statusCode === 404 || err.statusCode === 410) {
|
||||||
|
console.log('[webPush] subscription has expired or is no longer valid: ', err)
|
||||||
|
const deletedSubscripton = await models.pushSubscription.delete({ where: { id } })
|
||||||
|
console.log(`[webPush] deleted subscription ${id} of user ${deletedSubscripton.userId} due to push error`)
|
||||||
|
} else if (err.statusCode === 413) {
|
||||||
|
console.log('[webPush] payload too large: ', err)
|
||||||
|
} else if (err.statusCode === 429) {
|
||||||
|
console.log('[webPush] too many requests: ', err)
|
||||||
|
} else {
|
||||||
|
console.log('[webPush] error: ', err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sendUserNotification (userId, notification) {
|
||||||
|
try {
|
||||||
|
notification.data ??= {}
|
||||||
|
if (notification.item) {
|
||||||
|
notification.data.url ??= await createItemUrl(notification.item)
|
||||||
|
notification.data.itemId ??= notification.item.id
|
||||||
|
delete notification.item
|
||||||
|
}
|
||||||
|
const userFilter = createUserFilter(notification.tag)
|
||||||
|
const payload = createPayload(notification)
|
||||||
|
const subscriptions = await models.pushSubscription.findMany({
|
||||||
|
where: { userId, ...userFilter }
|
||||||
|
})
|
||||||
|
await Promise.allSettled(
|
||||||
|
subscriptions.map(subscription => sendNotification(subscription, payload))
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
console.log('[webPush] error sending user notification: ', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function replyToSubscription (subscriptionId, notification) {
|
||||||
|
try {
|
||||||
|
const payload = createPayload(notification)
|
||||||
|
const subscription = await models.pushSubscription.findUnique({ where: { id: subscriptionId } })
|
||||||
|
await sendNotification(subscription, payload)
|
||||||
|
} catch (err) {
|
||||||
|
console.log('[webPush] error sending subscription reply: ', err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
import Accordion from 'react-bootstrap/Accordion'
|
import Accordion from 'react-bootstrap/Accordion'
|
||||||
import AccordionContext from 'react-bootstrap/AccordionContext'
|
import AccordionContext from 'react-bootstrap/AccordionContext'
|
||||||
import { useAccordionButton } from 'react-bootstrap/AccordionButton'
|
import { useAccordionButton } from 'react-bootstrap/AccordionButton'
|
||||||
import ArrowRight from '../svgs/arrow-right-s-fill.svg'
|
import ArrowRight from '@/svgs/arrow-right-s-fill.svg'
|
||||||
import ArrowDown from '../svgs/arrow-down-s-fill.svg'
|
import ArrowDown from '@/svgs/arrow-down-s-fill.svg'
|
||||||
import { useContext } from 'react'
|
import { useContext } from 'react'
|
||||||
|
|
||||||
function ContextAwareToggle ({ children, headerColor = 'var(--theme-grey)', eventKey }) {
|
function ContextAwareToggle ({ children, headerColor = 'var(--theme-grey)', eventKey }) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Dropdown from 'react-bootstrap/Dropdown'
|
import Dropdown from 'react-bootstrap/Dropdown'
|
||||||
import styles from './item.module.css'
|
import styles from './item.module.css'
|
||||||
import MoreIcon from '../svgs/more-fill.svg'
|
import MoreIcon from '@/svgs/more-fill.svg'
|
||||||
|
|
||||||
export default function ActionDropdown ({ children }) {
|
export default function ActionDropdown ({ children }) {
|
||||||
if (!children) {
|
if (!children) {
|
||||||
|
|
|
@ -2,10 +2,10 @@ import { useState, useEffect } from 'react'
|
||||||
import AccordianItem from './accordian-item'
|
import AccordianItem from './accordian-item'
|
||||||
import { Input, InputUserSuggest, VariableInput, Checkbox } from './form'
|
import { Input, InputUserSuggest, VariableInput, Checkbox } from './form'
|
||||||
import InputGroup from 'react-bootstrap/InputGroup'
|
import InputGroup from 'react-bootstrap/InputGroup'
|
||||||
import { BOOST_MIN, BOOST_MULT, MAX_FORWARDS } from '../lib/constants'
|
import { BOOST_MIN, BOOST_MULT, MAX_FORWARDS } from '@/lib/constants'
|
||||||
import { DEFAULT_CROSSPOSTING_RELAYS } from '../lib/nostr'
|
import { DEFAULT_CROSSPOSTING_RELAYS } from '@/lib/nostr'
|
||||||
import Info from './info'
|
import Info from './info'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
import styles from './adv-post-form.module.css'
|
import styles from './adv-post-form.module.css'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { useFeeButton } from './fee-button'
|
import { useFeeButton } from './fee-button'
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Checkbox, Input } from './form'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { isNumber } from 'mathjs'
|
import { isNumber } from 'mathjs'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
|
|
||||||
function autoWithdrawThreshold ({ me }) {
|
function autoWithdrawThreshold ({ me }) {
|
||||||
return isNumber(me?.privates?.autoWithdrawThreshold) ? me?.privates?.autoWithdrawThreshold : 10000
|
return isNumber(me?.privates?.autoWithdrawThreshold) ? me?.privates?.autoWithdrawThreshold : 10000
|
||||||
|
|
|
@ -2,8 +2,8 @@ import { useRef, useState } from 'react'
|
||||||
import AvatarEditor from 'react-avatar-editor'
|
import AvatarEditor from 'react-avatar-editor'
|
||||||
import Button from 'react-bootstrap/Button'
|
import Button from 'react-bootstrap/Button'
|
||||||
import BootstrapForm from 'react-bootstrap/Form'
|
import BootstrapForm from 'react-bootstrap/Form'
|
||||||
import EditImage from '../svgs/image-edit-fill.svg'
|
import EditImage from '@/svgs/image-edit-fill.svg'
|
||||||
import Moon from '../svgs/moon-fill.svg'
|
import Moon from '@/svgs/moon-fill.svg'
|
||||||
import { useShowModal } from './modal'
|
import { useShowModal } from './modal'
|
||||||
import { ImageUpload } from './image'
|
import { ImageUpload } from './image'
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import Alert from 'react-bootstrap/Alert'
|
import Alert from 'react-bootstrap/Alert'
|
||||||
import styles from './banners.module.css'
|
import styles from './banners.module.css'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useMe } from '../components/me'
|
import { useMe } from '@/components/me'
|
||||||
import { useMutation } from '@apollo/client'
|
import { useMutation } from '@apollo/client'
|
||||||
import { WELCOME_BANNER_MUTATION } from '../fragments/users'
|
import { WELCOME_BANNER_MUTATION } from '@/fragments/users'
|
||||||
import { useToast } from '../components/toast'
|
import { useToast } from '@/components/toast'
|
||||||
import { BALANCE_LIMIT_MSATS } from '../lib/constants'
|
import { BALANCE_LIMIT_MSATS } from '@/lib/constants'
|
||||||
import { msatsToSats, numWithUnits } from '../lib/format'
|
import { msatsToSats, numWithUnits } from '@/lib/format'
|
||||||
|
|
||||||
export function WelcomeBanner ({ Banner }) {
|
export function WelcomeBanner ({ Banner }) {
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { createContext, useContext, useMemo } from 'react'
|
import { createContext, useContext, useMemo } from 'react'
|
||||||
import { useQuery } from '@apollo/client'
|
import { useQuery } from '@apollo/client'
|
||||||
import { SSR } from '../lib/constants'
|
import { SSR } from '@/lib/constants'
|
||||||
import { BLOCK_HEIGHT } from '../fragments/blockHeight'
|
import { BLOCK_HEIGHT } from '@/fragments/blockHeight'
|
||||||
|
|
||||||
export const BlockHeightContext = createContext({
|
export const BlockHeightContext = createContext({
|
||||||
height: 0
|
height: 0
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import { Form, Input, MarkdownInput } from '../components/form'
|
import { Form, Input, MarkdownInput } from '@/components/form'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { gql, useApolloClient, useMutation } from '@apollo/client'
|
import { gql, useApolloClient, useMutation } from '@apollo/client'
|
||||||
import Countdown from './countdown'
|
import Countdown from './countdown'
|
||||||
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
||||||
import InputGroup from 'react-bootstrap/InputGroup'
|
import InputGroup from 'react-bootstrap/InputGroup'
|
||||||
import useCrossposter from './use-crossposter'
|
import useCrossposter from './use-crossposter'
|
||||||
import { bountySchema } from '../lib/validate'
|
import { bountySchema } from '@/lib/validate'
|
||||||
import { SubSelectInitial } from './sub-select'
|
import { SubSelectInitial } from './sub-select'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { normalizeForwards, toastDeleteScheduled } from '../lib/form'
|
import { normalizeForwards, toastDeleteScheduled } from '@/lib/form'
|
||||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
import { MAX_TITLE_LENGTH } from '@/lib/constants'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import { ItemButtonBar } from './post'
|
import { ItemButtonBar } from './post'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { createContext, useContext, useMemo } from 'react'
|
import { createContext, useContext, useMemo } from 'react'
|
||||||
import { useQuery } from '@apollo/client'
|
import { useQuery } from '@apollo/client'
|
||||||
import { SSR } from '../lib/constants'
|
import { SSR } from '@/lib/constants'
|
||||||
import { CHAIN_FEE } from '../fragments/chainFee'
|
import { CHAIN_FEE } from '@/fragments/chainFee'
|
||||||
|
|
||||||
export const ChainFeeContext = createContext({
|
export const ChainFeeContext = createContext({
|
||||||
fee: 0
|
fee: 0
|
||||||
|
|
|
@ -12,9 +12,9 @@ import { ResponsiveContainer } from 'recharts/lib/component/ResponsiveContainer'
|
||||||
import { PieChart } from 'recharts/lib/chart/PieChart'
|
import { PieChart } from 'recharts/lib/chart/PieChart'
|
||||||
import { Cell } from 'recharts/lib/component/Cell'
|
import { Cell } from 'recharts/lib/component/Cell'
|
||||||
import { Pie } from 'recharts/lib/polar/Pie'
|
import { Pie } from 'recharts/lib/polar/Pie'
|
||||||
import { abbrNum } from '../lib/format'
|
import { abbrNum } from '@/lib/format'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { timeUnitForRange } from '../lib/time'
|
import { timeUnitForRange } from '@/lib/time'
|
||||||
|
|
||||||
const dateFormatter = (when, from, to) => {
|
const dateFormatter = (when, from, to) => {
|
||||||
const unit = xAxisName(when, from, to)
|
const unit = xAxisName(when, from, to)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { Form, MarkdownInput } from '../components/form'
|
import { Form, MarkdownInput } from '@/components/form'
|
||||||
import { gql, useMutation } from '@apollo/client'
|
import { gql, useMutation } from '@apollo/client'
|
||||||
import styles from './reply.module.css'
|
import styles from './reply.module.css'
|
||||||
import { commentSchema } from '../lib/validate'
|
import { commentSchema } from '@/lib/validate'
|
||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import { toastDeleteScheduled } from '../lib/form'
|
import { toastDeleteScheduled } from '@/lib/form'
|
||||||
import { FeeButtonProvider } from './fee-button'
|
import { FeeButtonProvider } from './fee-button'
|
||||||
import { ItemButtonBar } from './post'
|
import { ItemButtonBar } from './post'
|
||||||
|
|
||||||
|
|
|
@ -5,16 +5,16 @@ import Link from 'next/link'
|
||||||
import Reply, { ReplyOnAnotherPage } from './reply'
|
import Reply, { ReplyOnAnotherPage } from './reply'
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import UpVote from './upvote'
|
import UpVote from './upvote'
|
||||||
import Eye from '../svgs/eye-fill.svg'
|
import Eye from '@/svgs/eye-fill.svg'
|
||||||
import EyeClose from '../svgs/eye-close-line.svg'
|
import EyeClose from '@/svgs/eye-close-line.svg'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import CommentEdit from './comment-edit'
|
import CommentEdit from './comment-edit'
|
||||||
import { ANON_USER_ID, COMMENT_DEPTH_LIMIT, UNKNOWN_LINK_REL } from '../lib/constants'
|
import { ANON_USER_ID, COMMENT_DEPTH_LIMIT, UNKNOWN_LINK_REL } from '@/lib/constants'
|
||||||
import { ignoreClick } from '../lib/clicks'
|
import { ignoreClick } from '@/lib/clicks'
|
||||||
import PayBounty from './pay-bounty'
|
import PayBounty from './pay-bounty'
|
||||||
import BountyIcon from '../svgs/bounty-bag.svg'
|
import BountyIcon from '@/svgs/bounty-bag.svg'
|
||||||
import ActionTooltip from './action-tooltip'
|
import ActionTooltip from './action-tooltip'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
import Share from './share'
|
import Share from './share'
|
||||||
import ItemInfo from './item-info'
|
import ItemInfo from './item-info'
|
||||||
import Badge from 'react-bootstrap/Badge'
|
import Badge from 'react-bootstrap/Badge'
|
||||||
|
@ -22,9 +22,9 @@ import { RootProvider, useRoot } from './root'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { useQuoteReply } from './use-quote-reply'
|
import { useQuoteReply } from './use-quote-reply'
|
||||||
import { DownZap } from './dont-link-this'
|
import { DownZap } from './dont-link-this'
|
||||||
import Skull from '../svgs/death-skull.svg'
|
import Skull from '@/svgs/death-skull.svg'
|
||||||
import { commentSubTreeRootId } from '../lib/item'
|
import { commentSubTreeRootId } from '@/lib/item'
|
||||||
import Pin from '../svgs/pushpin-fill.svg'
|
import Pin from '@/svgs/pushpin-fill.svg'
|
||||||
|
|
||||||
function Parent ({ item, rootText }) {
|
function Parent ({ item, rootText }) {
|
||||||
const root = useRoot()
|
const root = useRoot()
|
||||||
|
|
|
@ -3,8 +3,8 @@ import Comment, { CommentSkeleton } from './comment'
|
||||||
import styles from './header.module.css'
|
import styles from './header.module.css'
|
||||||
import Nav from 'react-bootstrap/Nav'
|
import Nav from 'react-bootstrap/Nav'
|
||||||
import Navbar from 'react-bootstrap/Navbar'
|
import Navbar from 'react-bootstrap/Navbar'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
import { defaultCommentSort } from '../lib/item'
|
import { defaultCommentSort } from '@/lib/item'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
export function CommentsHeader ({ handleSort, pinned, bio, parentCreatedAt, commentSats }) {
|
export function CommentsHeader ({ handleSort, pinned, bio, parentCreatedAt, commentSats }) {
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import { Form, Input, MarkdownInput } from '../components/form'
|
import { Form, Input, MarkdownInput } from '@/components/form'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { gql, useApolloClient, useLazyQuery, useMutation } from '@apollo/client'
|
import { gql, useApolloClient, useLazyQuery, useMutation } from '@apollo/client'
|
||||||
import Countdown from './countdown'
|
import Countdown from './countdown'
|
||||||
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
||||||
import { ITEM_FIELDS } from '../fragments/items'
|
import { ITEM_FIELDS } from '@/fragments/items'
|
||||||
import AccordianItem from './accordian-item'
|
import AccordianItem from './accordian-item'
|
||||||
import Item from './item'
|
import Item from './item'
|
||||||
import { discussionSchema } from '../lib/validate'
|
import { discussionSchema } from '@/lib/validate'
|
||||||
import { SubSelectInitial } from './sub-select'
|
import { SubSelectInitial } from './sub-select'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { normalizeForwards, toastDeleteScheduled } from '../lib/form'
|
import { normalizeForwards, toastDeleteScheduled } from '@/lib/form'
|
||||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
import { MAX_TITLE_LENGTH } from '@/lib/constants'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import useCrossposter from './use-crossposter'
|
import useCrossposter from './use-crossposter'
|
||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
|
|
|
@ -3,9 +3,9 @@ import { useShowModal } from './modal'
|
||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import ItemAct from './item-act'
|
import ItemAct from './item-act'
|
||||||
import AccordianItem from './accordian-item'
|
import AccordianItem from './accordian-item'
|
||||||
import Flag from '../svgs/flag-fill.svg'
|
import Flag from '@/svgs/flag-fill.svg'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import getColor from '../lib/rainbow'
|
import getColor from '@/lib/rainbow'
|
||||||
import { gql, useMutation } from '@apollo/client'
|
import { gql, useMutation } from '@apollo/client'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Component } from 'react'
|
import { Component } from 'react'
|
||||||
import { StaticLayout } from './layout'
|
import { StaticLayout } from './layout'
|
||||||
import styles from '../styles/error.module.css'
|
import styles from '@/styles/error.module.css'
|
||||||
import Image from 'react-bootstrap/Image'
|
import Image from 'react-bootstrap/Image'
|
||||||
import copy from 'clipboard-copy'
|
import copy from 'clipboard-copy'
|
||||||
import { LoggerContext } from './logger'
|
import { LoggerContext } from './logger'
|
||||||
|
|
|
@ -4,10 +4,10 @@ import ActionTooltip from './action-tooltip'
|
||||||
import Info from './info'
|
import Info from './info'
|
||||||
import styles from './fee-button.module.css'
|
import styles from './fee-button.module.css'
|
||||||
import { gql, useQuery } from '@apollo/client'
|
import { gql, useQuery } from '@apollo/client'
|
||||||
import { ANON_FEE_MULTIPLIER, SSR } from '../lib/constants'
|
import { ANON_FEE_MULTIPLIER, SSR } from '@/lib/constants'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import AnonIcon from '../svgs/spy-fill.svg'
|
import AnonIcon from '@/svgs/spy-fill.svg'
|
||||||
import { useShowModal } from './modal'
|
import { useShowModal } from './modal'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { SubmitButton } from './form'
|
import { SubmitButton } from './form'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { gql, useQuery } from '@apollo/client'
|
import { gql, useQuery } from '@apollo/client'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { RewardLine } from '../pages/rewards'
|
import { RewardLine } from '@/pages/rewards'
|
||||||
import { SSR } from '../lib/constants'
|
import { SSR } from '@/lib/constants'
|
||||||
|
|
||||||
const REWARDS = gql`
|
const REWARDS = gql`
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,15 +3,15 @@ import OverlayTrigger from 'react-bootstrap/OverlayTrigger'
|
||||||
import Popover from 'react-bootstrap/Popover'
|
import Popover from 'react-bootstrap/Popover'
|
||||||
import { CopyInput } from './form'
|
import { CopyInput } from './form'
|
||||||
import styles from './footer.module.css'
|
import styles from './footer.module.css'
|
||||||
import Texas from '../svgs/texas.svg'
|
import Texas from '@/svgs/texas.svg'
|
||||||
import Github from '../svgs/github-fill.svg'
|
import Github from '@/svgs/github-fill.svg'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import Sun from '../svgs/sun-fill.svg'
|
import Sun from '@/svgs/sun-fill.svg'
|
||||||
import Moon from '../svgs/moon-fill.svg'
|
import Moon from '@/svgs/moon-fill.svg'
|
||||||
import No from '../svgs/no.svg'
|
import No from '@/svgs/no.svg'
|
||||||
import Bolt from '../svgs/bolt.svg'
|
import Bolt from '@/svgs/bolt.svg'
|
||||||
import Amboss from '../svgs/amboss.svg'
|
import Amboss from '@/svgs/amboss.svg'
|
||||||
import Mempool from '../svgs/bimi.svg'
|
import Mempool from '@/svgs/bimi.svg'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import Rewards from './footer-rewards'
|
import Rewards from './footer-rewards'
|
||||||
import useDarkMode from './dark-mode'
|
import useDarkMode from './dark-mode'
|
||||||
|
|
|
@ -8,27 +8,27 @@ import Col from 'react-bootstrap/Col'
|
||||||
import Dropdown from 'react-bootstrap/Dropdown'
|
import Dropdown from 'react-bootstrap/Dropdown'
|
||||||
import Nav from 'react-bootstrap/Nav'
|
import Nav from 'react-bootstrap/Nav'
|
||||||
import Row from 'react-bootstrap/Row'
|
import Row from 'react-bootstrap/Row'
|
||||||
import Markdown from '../svgs/markdown-line.svg'
|
import Markdown from '@/svgs/markdown-line.svg'
|
||||||
import AddImageIcon from '../svgs/image-add-line.svg'
|
import AddImageIcon from '@/svgs/image-add-line.svg'
|
||||||
import styles from './form.module.css'
|
import styles from './form.module.css'
|
||||||
import Text from '../components/text'
|
import Text from '@/components/text'
|
||||||
import AddIcon from '../svgs/add-fill.svg'
|
import AddIcon from '@/svgs/add-fill.svg'
|
||||||
import CloseIcon from '../svgs/close-line.svg'
|
import CloseIcon from '@/svgs/close-line.svg'
|
||||||
import { gql, useLazyQuery } from '@apollo/client'
|
import { gql, useLazyQuery } from '@apollo/client'
|
||||||
import { USER_SUGGESTIONS } from '../fragments/users'
|
import { USER_SUGGESTIONS } from '@/fragments/users'
|
||||||
import TextareaAutosize from 'react-textarea-autosize'
|
import TextareaAutosize from 'react-textarea-autosize'
|
||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import { useInvoiceable } from './invoice'
|
import { useInvoiceable } from './invoice'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
import textAreaCaret from 'textarea-caret'
|
import textAreaCaret from 'textarea-caret'
|
||||||
import ReactDatePicker from 'react-datepicker'
|
import ReactDatePicker from 'react-datepicker'
|
||||||
import 'react-datepicker/dist/react-datepicker.css'
|
import 'react-datepicker/dist/react-datepicker.css'
|
||||||
import useDebounceCallback, { debounce } from './use-debounce-callback'
|
import useDebounceCallback, { debounce } from './use-debounce-callback'
|
||||||
import { ImageUpload } from './image'
|
import { ImageUpload } from './image'
|
||||||
import { AWS_S3_URL_REGEXP } from '../lib/constants'
|
import { AWS_S3_URL_REGEXP } from '@/lib/constants'
|
||||||
import { whenRange } from '../lib/time'
|
import { whenRange } from '@/lib/time'
|
||||||
import { useFeeButton } from './fee-button'
|
import { useFeeButton } from './fee-button'
|
||||||
import Thumb from '../svgs/thumb-up-fill.svg'
|
import Thumb from '@/svgs/thumb-up-fill.svg'
|
||||||
import Info from './info'
|
import Info from './info'
|
||||||
|
|
||||||
export function SubmitButton ({
|
export function SubmitButton ({
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import Badge from 'react-bootstrap/Badge'
|
import Badge from 'react-bootstrap/Badge'
|
||||||
import OverlayTrigger from 'react-bootstrap/OverlayTrigger'
|
import OverlayTrigger from 'react-bootstrap/OverlayTrigger'
|
||||||
import Tooltip from 'react-bootstrap/Tooltip'
|
import Tooltip from 'react-bootstrap/Tooltip'
|
||||||
import CowboyHatIcon from '../svgs/cowboy.svg'
|
import CowboyHatIcon from '@/svgs/cowboy.svg'
|
||||||
import AnonIcon from '../svgs/spy-fill.svg'
|
import AnonIcon from '@/svgs/spy-fill.svg'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
import { AD_USER_ID, ANON_USER_ID } from '../lib/constants'
|
import { AD_USER_ID, ANON_USER_ID } from '@/lib/constants'
|
||||||
|
|
||||||
export default function Hat ({ user, badge, className = 'ms-1', height = 16, width = 16 }) {
|
export default function Hat ({ user, badge, className = 'ms-1', height = 16, width = 16 }) {
|
||||||
if (!user || Number(user.id) === AD_USER_ID) return null
|
if (!user || Number(user.id) === AD_USER_ID) return null
|
||||||
|
|
|
@ -11,20 +11,20 @@ import { useMe } from './me'
|
||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
import { signOut } from 'next-auth/react'
|
import { signOut } from 'next-auth/react'
|
||||||
import { useCallback, useEffect } from 'react'
|
import { useCallback, useEffect } from 'react'
|
||||||
import { randInRange } from '../lib/rand'
|
import { randInRange } from '@/lib/rand'
|
||||||
import { abbrNum, msatsToSats } from '../lib/format'
|
import { abbrNum, msatsToSats } from '@/lib/format'
|
||||||
import NoteIcon from '../svgs/notification-4-fill.svg'
|
import NoteIcon from '@/svgs/notification-4-fill.svg'
|
||||||
import { useQuery } from '@apollo/client'
|
import { useQuery } from '@apollo/client'
|
||||||
import LightningIcon from '../svgs/bolt.svg'
|
import LightningIcon from '@/svgs/bolt.svg'
|
||||||
import SearchIcon from '../svgs/search-line.svg'
|
import SearchIcon from '@/svgs/search-line.svg'
|
||||||
import BackArrow from '../svgs/arrow-left-line.svg'
|
import BackArrow from '@/svgs/arrow-left-line.svg'
|
||||||
import { BALANCE_LIMIT_MSATS, SSR } from '../lib/constants'
|
import { BALANCE_LIMIT_MSATS, SSR } from '@/lib/constants'
|
||||||
import { useLightning } from './lightning'
|
import { useLightning } from './lightning'
|
||||||
import { HAS_NOTIFICATIONS } from '../fragments/notifications'
|
import { HAS_NOTIFICATIONS } from '@/fragments/notifications'
|
||||||
import AnonIcon from '../svgs/spy-fill.svg'
|
import AnonIcon from '@/svgs/spy-fill.svg'
|
||||||
import Hat from './hat'
|
import Hat from './hat'
|
||||||
import HiddenWalletSummary from './hidden-wallet-summary'
|
import HiddenWalletSummary from './hidden-wallet-summary'
|
||||||
import { clearNotifications } from '../lib/badge'
|
import { clearNotifications } from '@/lib/badge'
|
||||||
import { useServiceWorker } from './serviceworker'
|
import { useServiceWorker } from './serviceworker'
|
||||||
import SubSelect from './sub-select'
|
import SubSelect from './sub-select'
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { useState, useRef, useEffect } from 'react'
|
import { useState, useRef, useEffect } from 'react'
|
||||||
import { abbrNum, numWithUnits } from '../lib/format'
|
import { abbrNum, numWithUnits } from '@/lib/format'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
|
|
||||||
export default function HiddenWalletSummary ({ abbreviate, fixedWidth }) {
|
export default function HiddenWalletSummary ({ abbreviate, fixedWidth }) {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import styles from './text.module.css'
|
import styles from './text.module.css'
|
||||||
import { Fragment, useState, useEffect, useMemo, useCallback, forwardRef, useRef, memo } from 'react'
|
import { Fragment, useState, useEffect, useMemo, useCallback, forwardRef, useRef, memo } from 'react'
|
||||||
import { IMGPROXY_URL_REGEXP } from '../lib/url'
|
import { IMGPROXY_URL_REGEXP } from '@/lib/url'
|
||||||
import { useShowModal } from './modal'
|
import { useShowModal } from './modal'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { Dropdown } from 'react-bootstrap'
|
import { Dropdown } from 'react-bootstrap'
|
||||||
import { UNKNOWN_LINK_REL, UPLOAD_TYPES_ALLOW, MEDIA_URL } from '../lib/constants'
|
import { UNKNOWN_LINK_REL, UPLOAD_TYPES_ALLOW, MEDIA_URL } from '@/lib/constants'
|
||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import { useMutation } from '@apollo/client'
|
import { useMutation } from '@apollo/client'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import InfoIcon from '../svgs/information-fill.svg'
|
import InfoIcon from '@/svgs/information-fill.svg'
|
||||||
import { useShowModal } from './modal'
|
import { useShowModal } from './modal'
|
||||||
|
|
||||||
export default function Info ({ children, label, iconClassName = 'fill-theme-color' }) {
|
export default function Info ({ children, label, iconClassName = 'fill-theme-color' }) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { CopyInput } from './form'
|
import { CopyInput } from './form'
|
||||||
import { gql, useMutation } from '@apollo/client'
|
import { gql, useMutation } from '@apollo/client'
|
||||||
import { INVITE_FIELDS } from '../fragments/invites'
|
import { INVITE_FIELDS } from '@/fragments/invites'
|
||||||
import styles from '../styles/invites.module.css'
|
import styles from '@/styles/invites.module.css'
|
||||||
|
|
||||||
export default function Invite ({ invite, active }) {
|
export default function Invite ({ invite, active }) {
|
||||||
const [revokeInvite] = useMutation(
|
const [revokeInvite] = useMutation(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Moon from '../svgs/moon-fill.svg'
|
import Moon from '@/svgs/moon-fill.svg'
|
||||||
import Check from '../svgs/check-double-line.svg'
|
import Check from '@/svgs/check-double-line.svg'
|
||||||
import ThumbDown from '../svgs/thumb-down-fill.svg'
|
import ThumbDown from '@/svgs/thumb-down-fill.svg'
|
||||||
|
|
||||||
function InvoiceDefaultStatus ({ status }) {
|
function InvoiceDefaultStatus ({ status }) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -2,10 +2,10 @@ import { useState, useCallback, useEffect } from 'react'
|
||||||
import { useApolloClient, useMutation, useQuery } from '@apollo/client'
|
import { useApolloClient, useMutation, useQuery } from '@apollo/client'
|
||||||
import { Button } from 'react-bootstrap'
|
import { Button } from 'react-bootstrap'
|
||||||
import { gql } from 'graphql-tag'
|
import { gql } from 'graphql-tag'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
import AccordianItem from './accordian-item'
|
import AccordianItem from './accordian-item'
|
||||||
import Qr, { QrSkeleton } from './qr'
|
import Qr, { QrSkeleton } from './qr'
|
||||||
import { INVOICE } from '../fragments/wallet'
|
import { INVOICE } from '@/fragments/wallet'
|
||||||
import InvoiceStatus from './invoice-status'
|
import InvoiceStatus from './invoice-status'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { useShowModal } from './modal'
|
import { useShowModal } from './modal'
|
||||||
|
|
|
@ -3,8 +3,8 @@ import InputGroup from 'react-bootstrap/InputGroup'
|
||||||
import React, { useState, useRef, useEffect, useCallback } from 'react'
|
import React, { useState, useRef, useEffect, useCallback } from 'react'
|
||||||
import { Form, Input, SubmitButton } from './form'
|
import { Form, Input, SubmitButton } from './form'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import UpBolt from '../svgs/bolt.svg'
|
import UpBolt from '@/svgs/bolt.svg'
|
||||||
import { amountSchema } from '../lib/validate'
|
import { amountSchema } from '@/lib/validate'
|
||||||
import { gql, useApolloClient, useMutation } from '@apollo/client'
|
import { gql, useApolloClient, useMutation } from '@apollo/client'
|
||||||
import { payOrLoginError, useInvoiceModal } from './invoice'
|
import { payOrLoginError, useInvoiceModal } from './invoice'
|
||||||
import { TOAST_DEFAULT_DELAY_MS, useToast, withToastFlow } from './toast'
|
import { TOAST_DEFAULT_DELAY_MS, useToast, withToastFlow } from './toast'
|
||||||
|
|
|
@ -5,7 +5,7 @@ import Comment from './comment'
|
||||||
import Text, { SearchText } from './text'
|
import Text, { SearchText } from './text'
|
||||||
import ZoomableImage from './image'
|
import ZoomableImage from './image'
|
||||||
import Comments from './comments'
|
import Comments from './comments'
|
||||||
import styles from '../styles/item.module.css'
|
import styles from '@/styles/item.module.css'
|
||||||
import itemStyles from './item.module.css'
|
import itemStyles from './item.module.css'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import Button from 'react-bootstrap/Button'
|
import Button from 'react-bootstrap/Button'
|
||||||
|
@ -14,18 +14,18 @@ import YouTube from 'react-youtube'
|
||||||
import useDarkMode from './dark-mode'
|
import useDarkMode from './dark-mode'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import Poll from './poll'
|
import Poll from './poll'
|
||||||
import { commentsViewed } from '../lib/new-comments'
|
import { commentsViewed } from '@/lib/new-comments'
|
||||||
import Related from './related'
|
import Related from './related'
|
||||||
import PastBounties from './past-bounties'
|
import PastBounties from './past-bounties'
|
||||||
import Check from '../svgs/check-double-line.svg'
|
import Check from '@/svgs/check-double-line.svg'
|
||||||
import Share from './share'
|
import Share from './share'
|
||||||
import Toc from './table-of-contents'
|
import Toc from './table-of-contents'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { RootProvider } from './root'
|
import { RootProvider } from './root'
|
||||||
import { IMGPROXY_URL_REGEXP } from '../lib/url'
|
import { IMGPROXY_URL_REGEXP } from '@/lib/url'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
import { useQuoteReply } from './use-quote-reply'
|
import { useQuoteReply } from './use-quote-reply'
|
||||||
import { UNKNOWN_LINK_REL } from '../lib/constants'
|
import { UNKNOWN_LINK_REL } from '@/lib/constants'
|
||||||
|
|
||||||
function BioItem ({ item, handleClick }) {
|
function BioItem ({ item, handleClick }) {
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
|
|
|
@ -4,9 +4,9 @@ import { useEffect, useState } from 'react'
|
||||||
import Badge from 'react-bootstrap/Badge'
|
import Badge from 'react-bootstrap/Badge'
|
||||||
import Dropdown from 'react-bootstrap/Dropdown'
|
import Dropdown from 'react-bootstrap/Dropdown'
|
||||||
import Countdown from './countdown'
|
import Countdown from './countdown'
|
||||||
import { abbrNum, numWithUnits } from '../lib/format'
|
import { abbrNum, numWithUnits } from '@/lib/format'
|
||||||
import { newComments, commentsViewedAt } from '../lib/new-comments'
|
import { newComments, commentsViewedAt } from '@/lib/new-comments'
|
||||||
import { timeSince } from '../lib/time'
|
import { timeSince } from '@/lib/time'
|
||||||
import { DeleteDropdownItem } from './delete'
|
import { DeleteDropdownItem } from './delete'
|
||||||
import styles from './item.module.css'
|
import styles from './item.module.css'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
|
@ -15,7 +15,7 @@ import BookmarkDropdownItem from './bookmark'
|
||||||
import SubscribeDropdownItem from './subscribe'
|
import SubscribeDropdownItem from './subscribe'
|
||||||
import { CopyLinkDropdownItem, CrosspostDropdownItem } from './share'
|
import { CopyLinkDropdownItem, CrosspostDropdownItem } from './share'
|
||||||
import Hat from './hat'
|
import Hat from './hat'
|
||||||
import { AD_USER_ID } from '../lib/constants'
|
import { AD_USER_ID } from '@/lib/constants'
|
||||||
import ActionDropdown from './action-dropdown'
|
import ActionDropdown from './action-dropdown'
|
||||||
import MuteDropdownItem from './mute'
|
import MuteDropdownItem from './mute'
|
||||||
import { DropdownItemUpVote } from './upvote'
|
import { DropdownItemUpVote } from './upvote'
|
||||||
|
|
|
@ -6,11 +6,11 @@ import Image from 'react-bootstrap/Image'
|
||||||
import { SearchTitle } from './item'
|
import { SearchTitle } from './item'
|
||||||
import styles from './item.module.css'
|
import styles from './item.module.css'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { timeSince } from '../lib/time'
|
import { timeSince } from '@/lib/time'
|
||||||
import EmailIcon from '../svgs/mail-open-line.svg'
|
import EmailIcon from '@/svgs/mail-open-line.svg'
|
||||||
import Share from './share'
|
import Share from './share'
|
||||||
import Hat from './hat'
|
import Hat from './hat'
|
||||||
import { MEDIA_URL } from '../lib/constants'
|
import { MEDIA_URL } from '@/lib/constants'
|
||||||
|
|
||||||
export default function ItemJob ({ item, toc, rank, children }) {
|
export default function ItemJob ({ item, toc, rank, children }) {
|
||||||
const isEmail = string().email().isValidSync(item.url)
|
const isEmail = string().email().isValidSync(item.url)
|
||||||
|
|
|
@ -2,22 +2,22 @@ import Link from 'next/link'
|
||||||
import styles from './item.module.css'
|
import styles from './item.module.css'
|
||||||
import UpVote from './upvote'
|
import UpVote from './upvote'
|
||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
import { AD_USER_ID, UNKNOWN_LINK_REL } from '../lib/constants'
|
import { AD_USER_ID, UNKNOWN_LINK_REL } from '@/lib/constants'
|
||||||
import Pin from '../svgs/pushpin-fill.svg'
|
import Pin from '@/svgs/pushpin-fill.svg'
|
||||||
import reactStringReplace from 'react-string-replace'
|
import reactStringReplace from 'react-string-replace'
|
||||||
import PollIcon from '../svgs/bar-chart-horizontal-fill.svg'
|
import PollIcon from '@/svgs/bar-chart-horizontal-fill.svg'
|
||||||
import BountyIcon from '../svgs/bounty-bag.svg'
|
import BountyIcon from '@/svgs/bounty-bag.svg'
|
||||||
import ActionTooltip from './action-tooltip'
|
import ActionTooltip from './action-tooltip'
|
||||||
import ImageIcon from '../svgs/image-fill.svg'
|
import ImageIcon from '@/svgs/image-fill.svg'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
import ItemInfo from './item-info'
|
import ItemInfo from './item-info'
|
||||||
import Prism from '../svgs/prism.svg'
|
import Prism from '@/svgs/prism.svg'
|
||||||
import { commentsViewedAt } from '../lib/new-comments'
|
import { commentsViewedAt } from '@/lib/new-comments'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { Badge } from 'react-bootstrap'
|
import { Badge } from 'react-bootstrap'
|
||||||
import AdIcon from '../svgs/advertisement-fill.svg'
|
import AdIcon from '@/svgs/advertisement-fill.svg'
|
||||||
import { DownZap } from './dont-link-this'
|
import { DownZap } from './dont-link-this'
|
||||||
import { timeLeft } from '../lib/time'
|
import { timeLeft } from '@/lib/time'
|
||||||
|
|
||||||
export function SearchTitle ({ title }) {
|
export function SearchTitle ({ title }) {
|
||||||
return reactStringReplace(title, /\*\*\*([^*]+)\*\*\*/g, (match, i) => {
|
return reactStringReplace(title, /\*\*\*([^*]+)\*\*\*/g, (match, i) => {
|
||||||
|
|
|
@ -5,8 +5,8 @@ import styles from './items.module.css'
|
||||||
import MoreFooter from './more-footer'
|
import MoreFooter from './more-footer'
|
||||||
import { Fragment, useCallback, useMemo } from 'react'
|
import { Fragment, useCallback, useMemo } from 'react'
|
||||||
import { CommentFlat } from './comment'
|
import { CommentFlat } from './comment'
|
||||||
import { SUB_ITEMS } from '../fragments/subs'
|
import { SUB_ITEMS } from '@/fragments/subs'
|
||||||
import { LIMIT } from '../lib/cursor'
|
import { LIMIT } from '@/lib/cursor'
|
||||||
import ItemFull from './item-full'
|
import ItemFull from './item-full'
|
||||||
import { useData } from './use-data'
|
import { useData } from './use-data'
|
||||||
|
|
||||||
|
|
|
@ -8,16 +8,16 @@ import Alert from 'react-bootstrap/Alert'
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import Info from './info'
|
import Info from './info'
|
||||||
import AccordianItem from './accordian-item'
|
import AccordianItem from './accordian-item'
|
||||||
import styles from '../styles/post.module.css'
|
import styles from '@/styles/post.module.css'
|
||||||
import { useLazyQuery, gql, useMutation } from '@apollo/client'
|
import { useLazyQuery, gql, useMutation } from '@apollo/client'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { usePrice } from './price'
|
import { usePrice } from './price'
|
||||||
import Avatar from './avatar'
|
import Avatar from './avatar'
|
||||||
import { jobSchema } from '../lib/validate'
|
import { jobSchema } from '@/lib/validate'
|
||||||
import { MAX_TITLE_LENGTH, MEDIA_URL } from '../lib/constants'
|
import { MAX_TITLE_LENGTH, MEDIA_URL } from '@/lib/constants'
|
||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import { toastDeleteScheduled } from '../lib/form'
|
import { toastDeleteScheduled } from '@/lib/form'
|
||||||
import { ItemButtonBar } from './post'
|
import { ItemButtonBar } from './post'
|
||||||
|
|
||||||
function satsMin2Mo (minute) {
|
function satsMin2Mo (minute) {
|
||||||
|
|
|
@ -7,9 +7,9 @@ import Row from 'react-bootstrap/Row'
|
||||||
import AccordianItem from './accordian-item'
|
import AccordianItem from './accordian-item'
|
||||||
import Qr, { QrSkeleton } from './qr'
|
import Qr, { QrSkeleton } from './qr'
|
||||||
import styles from './lightning-auth.module.css'
|
import styles from './lightning-auth.module.css'
|
||||||
import BackIcon from '../svgs/arrow-left-line.svg'
|
import BackIcon from '@/svgs/arrow-left-line.svg'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { SSR } from '../lib/constants'
|
import { SSR } from '@/lib/constants'
|
||||||
|
|
||||||
function QrAuth ({ k1, encodedUrl, callbackUrl }) {
|
function QrAuth ({ k1, encodedUrl, callbackUrl }) {
|
||||||
const query = gql`
|
const query = gql`
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useRef, useEffect, useContext } from 'react'
|
import React, { useRef, useEffect, useContext } from 'react'
|
||||||
import { randInRange } from '../lib/rand'
|
import { randInRange } from '@/lib/rand'
|
||||||
|
|
||||||
export const LightningContext = React.createContext(() => {})
|
export const LightningContext = React.createContext(() => {})
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { useState, useEffect, useCallback } from 'react'
|
import { useState, useEffect, useCallback } from 'react'
|
||||||
import { Form, Input, MarkdownInput } from '../components/form'
|
import { Form, Input, MarkdownInput } from '@/components/form'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { gql, useApolloClient, useLazyQuery, useMutation } from '@apollo/client'
|
import { gql, useApolloClient, useLazyQuery, useMutation } from '@apollo/client'
|
||||||
import Countdown from './countdown'
|
import Countdown from './countdown'
|
||||||
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
||||||
import { ITEM_FIELDS } from '../fragments/items'
|
import { ITEM_FIELDS } from '@/fragments/items'
|
||||||
import Item from './item'
|
import Item from './item'
|
||||||
import AccordianItem from './accordian-item'
|
import AccordianItem from './accordian-item'
|
||||||
import { linkSchema } from '../lib/validate'
|
import { linkSchema } from '@/lib/validate'
|
||||||
import Moon from '../svgs/moon-fill.svg'
|
import Moon from '@/svgs/moon-fill.svg'
|
||||||
import { normalizeForwards, toastDeleteScheduled } from '../lib/form'
|
import { normalizeForwards, toastDeleteScheduled } from '@/lib/form'
|
||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import { SubSelectInitial } from './sub-select'
|
import { SubSelectInitial } from './sub-select'
|
||||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
import { MAX_TITLE_LENGTH } from '@/lib/constants'
|
||||||
import useCrossposter from './use-crossposter'
|
import useCrossposter from './use-crossposter'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { ItemButtonBar } from './post'
|
import { ItemButtonBar } from './post'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import fancyNames from '../lib/fancy-names.json'
|
import fancyNames from '@/lib/fancy-names.json'
|
||||||
|
|
||||||
const generateFancyName = () => {
|
const generateFancyName = () => {
|
||||||
// 100 adjectives * 100 nouns * 10000 = 100M possible names
|
// 100 adjectives * 100 nouns * 10000 = 100M possible names
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import GithubIcon from '../svgs/github-fill.svg'
|
import GithubIcon from '@/svgs/github-fill.svg'
|
||||||
import TwitterIcon from '../svgs/twitter-fill.svg'
|
import TwitterIcon from '@/svgs/twitter-fill.svg'
|
||||||
import LightningIcon from '../svgs/bolt.svg'
|
import LightningIcon from '@/svgs/bolt.svg'
|
||||||
import NostrIcon from '../svgs/nostr.svg'
|
import NostrIcon from '@/svgs/nostr.svg'
|
||||||
import Button from 'react-bootstrap/Button'
|
import Button from 'react-bootstrap/Button'
|
||||||
|
|
||||||
export default function LoginButton ({ text, type, className, onClick }) {
|
export default function LoginButton ({ text, type, className, onClick }) {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { signIn } from 'next-auth/react'
|
import { signIn } from 'next-auth/react'
|
||||||
import styles from './login.module.css'
|
import styles from './login.module.css'
|
||||||
import { Form, Input, SubmitButton } from '../components/form'
|
import { Form, Input, SubmitButton } from '@/components/form'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import Alert from 'react-bootstrap/Alert'
|
import Alert from 'react-bootstrap/Alert'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { LightningAuthWithExplainer } from './lightning-auth'
|
import { LightningAuthWithExplainer } from './lightning-auth'
|
||||||
import NostrAuth from './nostr-auth'
|
import NostrAuth from './nostr-auth'
|
||||||
import LoginButton from './login-button'
|
import LoginButton from './login-button'
|
||||||
import { emailSchema } from '../lib/validate'
|
import { emailSchema } from '@/lib/validate'
|
||||||
|
|
||||||
export function EmailLoginForm ({ text, callbackUrl }) {
|
export function EmailLoginForm ({ text, callbackUrl }) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useContext } from 'react'
|
import React, { useContext } from 'react'
|
||||||
import { useQuery } from '@apollo/client'
|
import { useQuery } from '@apollo/client'
|
||||||
import { ME } from '../fragments/users'
|
import { ME } from '@/fragments/users'
|
||||||
import { SSR } from '../lib/constants'
|
import { SSR } from '@/lib/constants'
|
||||||
|
|
||||||
export const MeContext = React.createContext({
|
export const MeContext = React.createContext({
|
||||||
me: null
|
me: null
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
||||||
import Modal from 'react-bootstrap/Modal'
|
import Modal from 'react-bootstrap/Modal'
|
||||||
import BackArrow from '../svgs/arrow-left-line.svg'
|
import BackArrow from '@/svgs/arrow-left-line.svg'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import ActionDropdown from './action-dropdown'
|
import ActionDropdown from './action-dropdown'
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,9 @@ import Col from 'react-bootstrap/Col'
|
||||||
import Row from 'react-bootstrap/Row'
|
import Row from 'react-bootstrap/Row'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import AccordianItem from './accordian-item'
|
import AccordianItem from './accordian-item'
|
||||||
import BackIcon from '../svgs/arrow-left-line.svg'
|
import BackIcon from '@/svgs/arrow-left-line.svg'
|
||||||
import styles from './lightning-auth.module.css'
|
import styles from './lightning-auth.module.css'
|
||||||
import { callWithTimeout } from '../lib/nostr'
|
import { callWithTimeout } from '@/lib/nostr'
|
||||||
|
|
||||||
function ExtensionError ({ message, details }) {
|
function ExtensionError ({ message, details }) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -3,17 +3,17 @@ import { useQuery } from '@apollo/client'
|
||||||
import Comment, { CommentSkeleton } from './comment'
|
import Comment, { CommentSkeleton } from './comment'
|
||||||
import Item from './item'
|
import Item from './item'
|
||||||
import ItemJob from './item-job'
|
import ItemJob from './item-job'
|
||||||
import { NOTIFICATIONS } from '../fragments/notifications'
|
import { NOTIFICATIONS } from '@/fragments/notifications'
|
||||||
import MoreFooter from './more-footer'
|
import MoreFooter from './more-footer'
|
||||||
import Invite from './invite'
|
import Invite from './invite'
|
||||||
import { ignoreClick } from '../lib/clicks'
|
import { ignoreClick } from '@/lib/clicks'
|
||||||
import { dayMonthYear, timeSince } from '../lib/time'
|
import { dayMonthYear, timeSince } from '@/lib/time'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import Check from '../svgs/check-double-line.svg'
|
import Check from '@/svgs/check-double-line.svg'
|
||||||
import HandCoin from '../svgs/hand-coin-fill.svg'
|
import HandCoin from '@/svgs/hand-coin-fill.svg'
|
||||||
import { LOST_BLURBS, FOUND_BLURBS, UNKNOWN_LINK_REL } from '../lib/constants'
|
import { LOST_BLURBS, FOUND_BLURBS, UNKNOWN_LINK_REL } from '@/lib/constants'
|
||||||
import CowboyHatIcon from '../svgs/cowboy.svg'
|
import CowboyHatIcon from '@/svgs/cowboy.svg'
|
||||||
import BaldIcon from '../svgs/bald.svg'
|
import BaldIcon from '@/svgs/bald.svg'
|
||||||
import { RootProvider } from './root'
|
import { RootProvider } from './root'
|
||||||
import Alert from 'react-bootstrap/Alert'
|
import Alert from 'react-bootstrap/Alert'
|
||||||
import styles from './notifications.module.css'
|
import styles from './notifications.module.css'
|
||||||
|
@ -21,14 +21,14 @@ import { useServiceWorker } from './serviceworker'
|
||||||
import { Checkbox, Form } from './form'
|
import { Checkbox, Form } from './form'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useData } from './use-data'
|
import { useData } from './use-data'
|
||||||
import { nostrZapDetails } from '../lib/nostr'
|
import { nostrZapDetails } from '@/lib/nostr'
|
||||||
import Text from './text'
|
import Text from './text'
|
||||||
import NostrIcon from '../svgs/nostr.svg'
|
import NostrIcon from '@/svgs/nostr.svg'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
import BountyIcon from '../svgs/bounty-bag.svg'
|
import BountyIcon from '@/svgs/bounty-bag.svg'
|
||||||
import { LongCountdown } from './countdown'
|
import { LongCountdown } from './countdown'
|
||||||
import { nextBillingWithGrace } from '../lib/territory'
|
import { nextBillingWithGrace } from '@/lib/territory'
|
||||||
import { commentSubTreeRootId } from '../lib/item'
|
import { commentSubTreeRootId } from '@/lib/item'
|
||||||
|
|
||||||
function Notification ({ n, fresh }) {
|
function Notification ({ n, fresh }) {
|
||||||
const type = n.__typename
|
const type = n.__typename
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import Moon from '../svgs/moon-fill.svg'
|
import Moon from '@/svgs/moon-fill.svg'
|
||||||
|
|
||||||
export default function PageLoading () {
|
export default function PageLoading () {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -3,7 +3,7 @@ import Button from 'react-bootstrap/Button'
|
||||||
import styles from './pay-bounty.module.css'
|
import styles from './pay-bounty.module.css'
|
||||||
import ActionTooltip from './action-tooltip'
|
import ActionTooltip from './action-tooltip'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
import { useShowModal } from './modal'
|
import { useShowModal } from './modal'
|
||||||
import { useRoot } from './root'
|
import { useRoot } from './root'
|
||||||
import { payOrLoginError, useInvoiceModal } from './invoice'
|
import { payOrLoginError, useInvoiceModal } from './invoice'
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { DateTimeInput, Form, Input, MarkdownInput, VariableInput } from '../components/form'
|
import { DateTimeInput, Form, Input, MarkdownInput, VariableInput } from '@/components/form'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { gql, useApolloClient, useMutation } from '@apollo/client'
|
import { gql, useApolloClient, useMutation } from '@apollo/client'
|
||||||
import Countdown from './countdown'
|
import Countdown from './countdown'
|
||||||
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
||||||
import { MAX_POLL_CHOICE_LENGTH, MAX_POLL_NUM_CHOICES, MAX_TITLE_LENGTH } from '../lib/constants'
|
import { MAX_POLL_CHOICE_LENGTH, MAX_POLL_NUM_CHOICES, MAX_TITLE_LENGTH } from '@/lib/constants'
|
||||||
import { datePivot } from '../lib/time'
|
import { datePivot } from '@/lib/time'
|
||||||
import { pollSchema } from '../lib/validate'
|
import { pollSchema } from '@/lib/validate'
|
||||||
import { SubSelectInitial } from './sub-select'
|
import { SubSelectInitial } from './sub-select'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { normalizeForwards, toastDeleteScheduled } from '../lib/form'
|
import { normalizeForwards, toastDeleteScheduled } from '@/lib/form'
|
||||||
import useCrossposter from './use-crossposter'
|
import useCrossposter from './use-crossposter'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { gql, useMutation } from '@apollo/client'
|
import { gql, useMutation } from '@apollo/client'
|
||||||
import Button from 'react-bootstrap/Button'
|
import Button from 'react-bootstrap/Button'
|
||||||
import { fixedDecimal, numWithUnits } from '../lib/format'
|
import { fixedDecimal, numWithUnits } from '@/lib/format'
|
||||||
import { timeLeft } from '../lib/time'
|
import { timeLeft } from '@/lib/time'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import styles from './poll.module.css'
|
import styles from './poll.module.css'
|
||||||
import Check from '../svgs/checkbox-circle-fill.svg'
|
import Check from '@/svgs/checkbox-circle-fill.svg'
|
||||||
import { signIn } from 'next-auth/react'
|
import { signIn } from 'next-auth/react'
|
||||||
import ActionTooltip from './action-tooltip'
|
import ActionTooltip from './action-tooltip'
|
||||||
import { POLL_COST } from '../lib/constants'
|
import { POLL_COST } from '@/lib/constants'
|
||||||
import { payOrLoginError, useInvoiceModal } from './invoice'
|
import { payOrLoginError, useInvoiceModal } from './invoice'
|
||||||
|
|
||||||
export default function Poll ({ item }) {
|
export default function Poll ({ item }) {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import React, { useContext, useEffect, useMemo, useState } from 'react'
|
import React, { useContext, useEffect, useMemo, useState } from 'react'
|
||||||
import { useQuery } from '@apollo/client'
|
import { useQuery } from '@apollo/client'
|
||||||
import { fixedDecimal } from '../lib/format'
|
import { fixedDecimal } from '@/lib/format'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { PRICE } from '../fragments/price'
|
import { PRICE } from '@/fragments/price'
|
||||||
import { CURRENCY_SYMBOLS } from '../lib/currency'
|
import { CURRENCY_SYMBOLS } from '@/lib/currency'
|
||||||
import { SSR } from '../lib/constants'
|
import { SSR } from '@/lib/constants'
|
||||||
import { useBlockHeight } from './block-height'
|
import { useBlockHeight } from './block-height'
|
||||||
import { useChainFee } from './chain-fee'
|
import { useChainFee } from './chain-fee'
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ITEM_TYPES, ITEM_TYPES_UNIVERSAL } from '../lib/constants'
|
import { ITEM_TYPES, ITEM_TYPES_UNIVERSAL } from '@/lib/constants'
|
||||||
import { Select } from './form'
|
import { Select } from './form'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { RELATED_ITEMS } from '../fragments/items'
|
import { RELATED_ITEMS } from '@/fragments/items'
|
||||||
import AccordianItem from './accordian-item'
|
import AccordianItem from './accordian-item'
|
||||||
import Items from './items'
|
import Items from './items'
|
||||||
import { NavigateFooter } from './more-footer'
|
import { NavigateFooter } from './more-footer'
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import { Form, MarkdownInput } from '../components/form'
|
import { Form, MarkdownInput } from '@/components/form'
|
||||||
import { gql, useMutation } from '@apollo/client'
|
import { gql, useMutation } from '@apollo/client'
|
||||||
import styles from './reply.module.css'
|
import styles from './reply.module.css'
|
||||||
import { COMMENTS } from '../fragments/comments'
|
import { COMMENTS } from '@/fragments/comments'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { forwardRef, useCallback, useEffect, useState, useRef } from 'react'
|
import { forwardRef, useCallback, useEffect, useState, useRef } from 'react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { FeeButtonProvider, postCommentBaseLineItems, postCommentUseRemoteLineItems } from './fee-button'
|
import { FeeButtonProvider, postCommentBaseLineItems, postCommentUseRemoteLineItems } 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 { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import { toastDeleteScheduled } from '../lib/form'
|
import { toastDeleteScheduled } from '@/lib/form'
|
||||||
import { ItemButtonBar } from './post'
|
import { ItemButtonBar } from './post'
|
||||||
import { useShowModal } from './modal'
|
import { useShowModal } from './modal'
|
||||||
import { Button } from 'react-bootstrap'
|
import { Button } from 'react-bootstrap'
|
||||||
import { useRoot } from './root'
|
import { useRoot } from './root'
|
||||||
import { commentSubTreeRootId } from '../lib/item'
|
import { commentSubTreeRootId } from '@/lib/item'
|
||||||
|
|
||||||
export function ReplyOnAnotherPage ({ item }) {
|
export function ReplyOnAnotherPage ({ item }) {
|
||||||
const rootId = commentSubTreeRootId(item)
|
const rootId = commentSubTreeRootId(item)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import Container from 'react-bootstrap/Container'
|
import Container from 'react-bootstrap/Container'
|
||||||
import styles from './search.module.css'
|
import styles from './search.module.css'
|
||||||
import SearchIcon from '../svgs/search-line.svg'
|
import SearchIcon from '@/svgs/search-line.svg'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { Form, Input, Select, DatePicker, SubmitButton } from './form'
|
import { Form, Input, Select, DatePicker, SubmitButton } from './form'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { whenToFrom } from '../lib/time'
|
import { whenToFrom } from '@/lib/time'
|
||||||
|
|
||||||
export default function Search ({ sub }) {
|
export default function Search ({ sub }) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { NextSeo } from 'next-seo'
|
import { NextSeo } from 'next-seo'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import removeMd from 'remove-markdown'
|
import removeMd from 'remove-markdown'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
|
|
||||||
export function SeoSearch ({ sub }) {
|
export function SeoSearch ({ sub }) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import Dropdown from 'react-bootstrap/Dropdown'
|
import Dropdown from 'react-bootstrap/Dropdown'
|
||||||
import ShareIcon from '../svgs/share-fill.svg'
|
import ShareIcon from '@/svgs/share-fill.svg'
|
||||||
import copy from 'clipboard-copy'
|
import copy from 'clipboard-copy'
|
||||||
import useCrossposter from './use-crossposter'
|
import useCrossposter from './use-crossposter'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import { SSR } from '../lib/constants'
|
import { SSR } from '@/lib/constants'
|
||||||
import { commentSubTreeRootId } from '../lib/item'
|
import { commentSubTreeRootId } from '@/lib/item'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
const referrurl = (ipath, me) => {
|
const referrurl = (ipath, me) => {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import Alert from 'react-bootstrap/Alert'
|
import Alert from 'react-bootstrap/Alert'
|
||||||
import YouTube from '../svgs/youtube-line.svg'
|
import YouTube from '@/svgs/youtube-line.svg'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { gql, useQuery } from '@apollo/client'
|
import { gql, useQuery } from '@apollo/client'
|
||||||
import { datePivot } from '../lib/time'
|
import { datePivot } from '@/lib/time'
|
||||||
|
|
||||||
export default function Snl ({ ignorePreference }) {
|
export default function Snl ({ ignorePreference }) {
|
||||||
const [show, setShow] = useState()
|
const [show, setShow] = useState()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useCallback, useContext, useState } from 'react'
|
import React, { useCallback, useContext, useState } from 'react'
|
||||||
import { randInRange } from '../lib/rand'
|
import { randInRange } from '@/lib/rand'
|
||||||
|
|
||||||
export const SnowContext = React.createContext(() => {})
|
export const SnowContext = React.createContext(() => {})
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { Select } from './form'
|
import { Select } from './form'
|
||||||
import { SSR } from '../lib/constants'
|
import { SSR } from '@/lib/constants'
|
||||||
import { SUBS } from '../fragments/subs'
|
import { SUBS } from '@/fragments/subs'
|
||||||
import { useQuery } from '@apollo/client'
|
import { useQuery } from '@apollo/client'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import styles from './sub-select.module.css'
|
import styles from './sub-select.module.css'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useMemo, useState } from 'react'
|
import React, { useMemo, useState } from 'react'
|
||||||
import Dropdown from 'react-bootstrap/Dropdown'
|
import Dropdown from 'react-bootstrap/Dropdown'
|
||||||
import FormControl from 'react-bootstrap/FormControl'
|
import FormControl from 'react-bootstrap/FormControl'
|
||||||
import TocIcon from '../svgs/list-unordered.svg'
|
import TocIcon from '@/svgs/list-unordered.svg'
|
||||||
import { fromMarkdown } from 'mdast-util-from-markdown'
|
import { fromMarkdown } from 'mdast-util-from-markdown'
|
||||||
import { visit } from 'unist-util-visit'
|
import { visit } from 'unist-util-visit'
|
||||||
import { toString } from 'mdast-util-to-string'
|
import { toString } from 'mdast-util-to-string'
|
||||||
|
|
|
@ -5,13 +5,13 @@ import FeeButton, { FeeButtonProvider } from './fee-button'
|
||||||
import { gql, useApolloClient, useLazyQuery, useMutation } from '@apollo/client'
|
import { gql, useApolloClient, useLazyQuery, useMutation } from '@apollo/client'
|
||||||
import { useCallback, useMemo, useState } from 'react'
|
import { useCallback, useMemo, useState } from 'react'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { MAX_TERRITORY_DESC_LENGTH, POST_TYPES, TERRITORY_BILLING_OPTIONS, TERRITORY_PERIOD_COST } from '../lib/constants'
|
import { MAX_TERRITORY_DESC_LENGTH, POST_TYPES, TERRITORY_BILLING_OPTIONS, TERRITORY_PERIOD_COST } from '@/lib/constants'
|
||||||
import { territorySchema } from '../lib/validate'
|
import { territorySchema } from '@/lib/validate'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import Info from './info'
|
import Info from './info'
|
||||||
import { abbrNum } from '../lib/format'
|
import { abbrNum } from '@/lib/format'
|
||||||
import { purchasedType } from '../lib/territory'
|
import { purchasedType } from '@/lib/territory'
|
||||||
import { SUB } from '../fragments/subs'
|
import { SUB } from '@/fragments/subs'
|
||||||
|
|
||||||
export default function TerritoryForm ({ sub }) {
|
export default function TerritoryForm ({ sub }) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { AccordianCard } from './accordian-item'
|
||||||
import TerritoryPaymentDue, { TerritoryBillingLine } from './territory-payment-due'
|
import TerritoryPaymentDue, { TerritoryBillingLine } from './territory-payment-due'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import Text from './text'
|
import Text from './text'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
import styles from './item.module.css'
|
import styles from './item.module.css'
|
||||||
import Hat from './hat'
|
import Hat from './hat'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { abbrNum, numWithUnits } from '../lib/format'
|
import { abbrNum, numWithUnits } from '@/lib/format'
|
||||||
import styles from './item.module.css'
|
import styles from './item.module.css'
|
||||||
import React, { useEffect, useMemo, useState } from 'react'
|
import React, { useEffect, useMemo, useState } from 'react'
|
||||||
import { useQuery } from '@apollo/client'
|
import { useQuery } from '@apollo/client'
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { Alert } from 'react-bootstrap'
|
import { Alert } from 'react-bootstrap'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import FeeButton, { FeeButtonProvider } from './fee-button'
|
import FeeButton, { FeeButtonProvider } from './fee-button'
|
||||||
import { TERRITORY_BILLING_OPTIONS } from '../lib/constants'
|
import { TERRITORY_BILLING_OPTIONS } from '@/lib/constants'
|
||||||
import { Form } from './form'
|
import { Form } from './form'
|
||||||
import { timeSince } from '../lib/time'
|
import { timeSince } from '@/lib/time'
|
||||||
import { LongCountdown } from './countdown'
|
import { LongCountdown } from './countdown'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { useApolloClient, useMutation } from '@apollo/client'
|
import { useApolloClient, useMutation } from '@apollo/client'
|
||||||
import { SUB_PAY } from '../fragments/subs'
|
import { SUB_PAY } from '@/fragments/subs'
|
||||||
import { nextBillingWithGrace } from '../lib/territory'
|
import { nextBillingWithGrace } from '@/lib/territory'
|
||||||
|
|
||||||
export default function TerritoryPaymentDue ({ sub }) {
|
export default function TerritoryPaymentDue ({ sub }) {
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useShowModal } from './modal'
|
||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import { Button, Dropdown, InputGroup } from 'react-bootstrap'
|
import { Button, Dropdown, InputGroup } from 'react-bootstrap'
|
||||||
import { Form, InputUserSuggest, SubmitButton } from './form'
|
import { Form, InputUserSuggest, SubmitButton } from './form'
|
||||||
import { territoryTransferSchema } from '../lib/validate'
|
import { territoryTransferSchema } from '@/lib/validate'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
|
|
|
@ -4,22 +4,22 @@ import YouTube from 'react-youtube'
|
||||||
import gfm from 'remark-gfm'
|
import gfm from 'remark-gfm'
|
||||||
import { LightAsync as SyntaxHighlighter } from 'react-syntax-highlighter'
|
import { LightAsync as SyntaxHighlighter } from 'react-syntax-highlighter'
|
||||||
import atomDark from 'react-syntax-highlighter/dist/cjs/styles/prism/atom-dark'
|
import atomDark from 'react-syntax-highlighter/dist/cjs/styles/prism/atom-dark'
|
||||||
import mention from '../lib/remark-mention'
|
import mention from '@/lib/remark-mention'
|
||||||
import sub from '../lib/remark-sub'
|
import sub from '@/lib/remark-sub'
|
||||||
import React, { useState, memo, useRef, useCallback, useMemo, useEffect } from 'react'
|
import React, { useState, memo, useRef, useCallback, useMemo, useEffect } from 'react'
|
||||||
import GithubSlugger from 'github-slugger'
|
import GithubSlugger from 'github-slugger'
|
||||||
import LinkIcon from '../svgs/link.svg'
|
import LinkIcon from '@/svgs/link.svg'
|
||||||
import Thumb from '../svgs/thumb-up-fill.svg'
|
import Thumb from '@/svgs/thumb-up-fill.svg'
|
||||||
import { toString } from 'mdast-util-to-string'
|
import { toString } from 'mdast-util-to-string'
|
||||||
import copy from 'clipboard-copy'
|
import copy from 'clipboard-copy'
|
||||||
import ZoomableImage, { decodeOriginalUrl } from './image'
|
import ZoomableImage, { decodeOriginalUrl } from './image'
|
||||||
import { IMGPROXY_URL_REGEXP, parseInternalLinks } from '../lib/url'
|
import { IMGPROXY_URL_REGEXP, parseInternalLinks } from '@/lib/url'
|
||||||
import reactStringReplace from 'react-string-replace'
|
import reactStringReplace from 'react-string-replace'
|
||||||
import { rehypeInlineCodeProperty } from '../lib/md'
|
import { rehypeInlineCodeProperty } from '@/lib/md'
|
||||||
import { Button } from 'react-bootstrap'
|
import { Button } from 'react-bootstrap'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { UNKNOWN_LINK_REL } from '../lib/constants'
|
import { UNKNOWN_LINK_REL } from '@/lib/constants'
|
||||||
import isEqual from 'lodash/isEqual'
|
import isEqual from 'lodash/isEqual'
|
||||||
|
|
||||||
export function SearchText ({ text }) {
|
export function SearchText ({ text }) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { Form, Select, DatePicker } from './form'
|
import { Form, Select, DatePicker } from './form'
|
||||||
import { ITEM_SORTS, SUB_SORTS, USER_SORTS, WHENS } from '../lib/constants'
|
import { ITEM_SORTS, SUB_SORTS, USER_SORTS, WHENS } from '@/lib/constants'
|
||||||
import { whenToFrom } from '../lib/time'
|
import { whenToFrom } from '@/lib/time'
|
||||||
|
|
||||||
export default function TopHeader ({ sub, cat }) {
|
export default function TopHeader ({ sub, cat }) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import UpBolt from '../svgs/bolt.svg'
|
import UpBolt from '@/svgs/bolt.svg'
|
||||||
import styles from './upvote.module.css'
|
import styles from './upvote.module.css'
|
||||||
import { gql, useMutation } from '@apollo/client'
|
import { gql, useMutation } from '@apollo/client'
|
||||||
import ActionTooltip from './action-tooltip'
|
import ActionTooltip from './action-tooltip'
|
||||||
import ItemAct, { useAct, useZap } from './item-act'
|
import ItemAct, { useAct, useZap } from './item-act'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import getColor from '../lib/rainbow'
|
import getColor from '@/lib/rainbow'
|
||||||
import { useCallback, useMemo, useRef, useState } from 'react'
|
import { useCallback, useMemo, useRef, useState } from 'react'
|
||||||
import LongPressable from 'react-longpressable'
|
import LongPressable from 'react-longpressable'
|
||||||
import Overlay from 'react-bootstrap/Overlay'
|
import Overlay from 'react-bootstrap/Overlay'
|
||||||
import Popover from 'react-bootstrap/Popover'
|
import Popover from 'react-bootstrap/Popover'
|
||||||
import { useShowModal } from './modal'
|
import { useShowModal } from './modal'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
import { Dropdown } from 'react-bootstrap'
|
import { Dropdown } from 'react-bootstrap'
|
||||||
|
|
||||||
const UpvotePopover = ({ target, show, handleClose }) => {
|
const UpvotePopover = ({ target, show, handleClose }) => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { Select, DatePicker } from './form'
|
import { Select, DatePicker } from './form'
|
||||||
import { WHENS } from '../lib/constants'
|
import { WHENS } from '@/lib/constants'
|
||||||
import { whenToFrom } from '../lib/time'
|
import { whenToFrom } from '@/lib/time'
|
||||||
|
|
||||||
export function UsageHeader () {
|
export function UsageHeader () {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import { Button } from 'react-bootstrap'
|
import { Button } from 'react-bootstrap'
|
||||||
import { DEFAULT_CROSSPOSTING_RELAYS, crosspost, callWithTimeout } from '../lib/nostr'
|
import { DEFAULT_CROSSPOSTING_RELAYS, crosspost, callWithTimeout } from '@/lib/nostr'
|
||||||
import { gql, useMutation, useQuery, useLazyQuery } from '@apollo/client'
|
import { gql, useMutation, useQuery, useLazyQuery } from '@apollo/client'
|
||||||
import { SETTINGS } from '../fragments/users'
|
import { SETTINGS } from '@/fragments/users'
|
||||||
import { ITEM_FULL_FIELDS, POLL_FIELDS } from '../fragments/items'
|
import { ITEM_FULL_FIELDS, POLL_FIELDS } from '@/fragments/items'
|
||||||
|
|
||||||
async function discussionToEvent (item) {
|
async function discussionToEvent (item) {
|
||||||
const createdAt = Math.floor(Date.now() / 1000)
|
const createdAt = Math.floor(Date.now() / 1000)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { quote as quoteMd } from '../lib/md'
|
import { quote as quoteMd } from '@/lib/md'
|
||||||
|
|
||||||
export function useQuoteReply ({ text }) {
|
export function useQuoteReply ({ text }) {
|
||||||
const ref = useRef(null)
|
const ref = useRef(null)
|
||||||
|
|
|
@ -9,26 +9,26 @@ import { Form, Input, SubmitButton } from './form'
|
||||||
import { gql, useApolloClient, useMutation } from '@apollo/client'
|
import { gql, useApolloClient, useMutation } from '@apollo/client'
|
||||||
import styles from './user-header.module.css'
|
import styles from './user-header.module.css'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { NAME_MUTATION } from '../fragments/users'
|
import { NAME_MUTATION } from '@/fragments/users'
|
||||||
import QRCode from 'qrcode.react'
|
import QRCode from 'qrcode.react'
|
||||||
import LightningIcon from '../svgs/bolt.svg'
|
import LightningIcon from '@/svgs/bolt.svg'
|
||||||
import { encodeLNUrl } from '../lib/lnurl'
|
import { encodeLNUrl } from '@/lib/lnurl'
|
||||||
import Avatar from './avatar'
|
import Avatar from './avatar'
|
||||||
import { userSchema } from '../lib/validate'
|
import { userSchema } from '@/lib/validate'
|
||||||
import { useShowModal } from './modal'
|
import { useShowModal } from './modal'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { numWithUnits } from '@/lib/format'
|
||||||
import Hat from './hat'
|
import Hat from './hat'
|
||||||
import SubscribeUserDropdownItem from './subscribeUser'
|
import SubscribeUserDropdownItem from './subscribeUser'
|
||||||
import ActionDropdown from './action-dropdown'
|
import ActionDropdown from './action-dropdown'
|
||||||
import CodeIcon from '../svgs/terminal-box-fill.svg'
|
import CodeIcon from '@/svgs/terminal-box-fill.svg'
|
||||||
import MuteDropdownItem from './mute'
|
import MuteDropdownItem from './mute'
|
||||||
import copy from 'clipboard-copy'
|
import copy from 'clipboard-copy'
|
||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import { hexToBech32 } from '../lib/nostr'
|
import { hexToBech32 } from '@/lib/nostr'
|
||||||
import NostrIcon from '../svgs/nostr.svg'
|
import NostrIcon from '@/svgs/nostr.svg'
|
||||||
import GithubIcon from '../svgs/github-fill.svg'
|
import GithubIcon from '@/svgs/github-fill.svg'
|
||||||
import TwitterIcon from '../svgs/twitter-fill.svg'
|
import TwitterIcon from '@/svgs/twitter-fill.svg'
|
||||||
import { UNKNOWN_LINK_REL, MEDIA_URL } from '../lib/constants'
|
import { UNKNOWN_LINK_REL, MEDIA_URL } from '@/lib/constants'
|
||||||
|
|
||||||
export default function UserHeader ({ user }) {
|
export default function UserHeader ({ user }) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import Image from 'react-bootstrap/Image'
|
import Image from 'react-bootstrap/Image'
|
||||||
import { abbrNum, numWithUnits } from '../lib/format'
|
import { abbrNum, numWithUnits } from '@/lib/format'
|
||||||
import styles from './item.module.css'
|
import styles from './item.module.css'
|
||||||
import userStyles from './user-header.module.css'
|
import userStyles from './user-header.module.css'
|
||||||
import React, { useEffect, useMemo, useState } from 'react'
|
import React, { useEffect, useMemo, useState } from 'react'
|
||||||
|
@ -9,7 +9,7 @@ import MoreFooter from './more-footer'
|
||||||
import { useData } from './use-data'
|
import { useData } from './use-data'
|
||||||
import Hat from './hat'
|
import Hat from './hat'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { MEDIA_URL } from '../lib/constants'
|
import { MEDIA_URL } from '@/lib/constants'
|
||||||
|
|
||||||
// all of this nonsense is to show the stat we are sorting by first
|
// all of this nonsense is to show the stat we are sorting by first
|
||||||
const Stacked = ({ user }) => (user.optional.stacked !== null && <span>{abbrNum(user.optional.stacked)} stacked</span>)
|
const Stacked = ({ user }) => (user.optional.stacked !== null && <span>{abbrNum(user.optional.stacked)} stacked</span>)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Badge, Button, Card } from 'react-bootstrap'
|
import { Badge, Button, Card } from 'react-bootstrap'
|
||||||
import styles from '../styles/wallet.module.css'
|
import styles from '@/styles/wallet.module.css'
|
||||||
import Plug from '../svgs/plug.svg'
|
import Plug from '@/svgs/plug.svg'
|
||||||
import Gear from '../svgs/settings-5-fill.svg'
|
import Gear from '@/svgs/settings-5-fill.svg'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import CancelButton from './cancel-button'
|
import CancelButton from './cancel-button'
|
||||||
import { SubmitButton } from './form'
|
import { SubmitButton } from './form'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { createContext, useCallback, useContext, useEffect, useState } from 'react'
|
import { createContext, useCallback, useContext, useEffect, useState } from 'react'
|
||||||
import { LNbitsProvider, useLNbits } from './lnbits'
|
import { LNbitsProvider, useLNbits } from './lnbits'
|
||||||
import { NWCProvider, useNWC } from './nwc'
|
import { NWCProvider, useNWC } from './nwc'
|
||||||
import { useToast, withToastFlow } from '../toast'
|
import { useToast, withToastFlow } from '@/components/toast'
|
||||||
import { gql, useMutation } from '@apollo/client'
|
import { gql, useMutation } from '@apollo/client'
|
||||||
|
|
||||||
const WebLNContext = createContext({})
|
const WebLNContext = createContext({})
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react'
|
import { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react'
|
||||||
import { Relay, finalizeEvent, nip04 } from 'nostr-tools'
|
import { Relay, finalizeEvent, nip04 } from 'nostr-tools'
|
||||||
import { parseNwcUrl } from '../../lib/url'
|
import { parseNwcUrl } from '@/lib/url'
|
||||||
|
|
||||||
const NWCContext = createContext()
|
const NWCContext = createContext()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/api/*": [
|
||||||
|
"api/*"
|
||||||
|
],
|
||||||
|
"@/lib/*": [
|
||||||
|
"lib/*"
|
||||||
|
],
|
||||||
|
"@/fragments/*": [
|
||||||
|
"fragments/*"
|
||||||
|
],
|
||||||
|
"@/pages/*": [
|
||||||
|
"pages/*"
|
||||||
|
],
|
||||||
|
"@/components/*": [
|
||||||
|
"components/*"
|
||||||
|
],
|
||||||
|
"@/styles/*": [
|
||||||
|
"styles/*"
|
||||||
|
],
|
||||||
|
"@/svgs/*": [
|
||||||
|
"svgs/*"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,143 @@
|
||||||
|
import { sendUserNotification } from '@/api/webPush'
|
||||||
|
import { ANON_USER_ID } from '@/lib/constants'
|
||||||
|
import { msatsToSats, numWithUnits } from '@/lib/format'
|
||||||
|
|
||||||
|
export const notifyUserSubscribers = async ({ models, item }) => {
|
||||||
|
try {
|
||||||
|
const isPost = !!item.title
|
||||||
|
const userSubs = await models.userSubscription.findMany({
|
||||||
|
where: {
|
||||||
|
followeeId: Number(item.userId),
|
||||||
|
[isPost ? 'postsSubscribedAt' : 'commentsSubscribedAt']: { not: null }
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
followee: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const subType = isPost ? 'POST' : 'COMMENT'
|
||||||
|
const tag = `FOLLOW-${item.userId}-${subType}`
|
||||||
|
await Promise.allSettled(userSubs.map(({ followerId, followee }) => sendUserNotification(followerId, {
|
||||||
|
title: `@${followee.name} ${isPost ? 'created a post' : 'replied to a post'}`,
|
||||||
|
body: isPost ? item.title : item.text,
|
||||||
|
item,
|
||||||
|
data: { followeeName: followee.name, subType },
|
||||||
|
tag
|
||||||
|
})))
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const notifyTerritorySubscribers = async ({ models, item }) => {
|
||||||
|
try {
|
||||||
|
const isPost = !!item.title
|
||||||
|
const { subName } = item
|
||||||
|
|
||||||
|
// only notify on posts in subs
|
||||||
|
if (!isPost || !subName) return
|
||||||
|
|
||||||
|
const territorySubs = await models.subSubscription.findMany({
|
||||||
|
where: {
|
||||||
|
subName
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const author = await models.user.findUnique({ where: { id: item.userId } })
|
||||||
|
|
||||||
|
const tag = `TERRITORY_POST-${subName}`
|
||||||
|
await Promise.allSettled(
|
||||||
|
territorySubs
|
||||||
|
// don't send push notification to author itself
|
||||||
|
.filter(({ userId }) => userId !== author.id)
|
||||||
|
.map(({ userId }) =>
|
||||||
|
sendUserNotification(userId, {
|
||||||
|
title: `@${author.name} created a post in ~${subName}`,
|
||||||
|
body: item.title,
|
||||||
|
item,
|
||||||
|
data: { subName },
|
||||||
|
tag
|
||||||
|
})))
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const notifyItemParents = async ({ models, item, me }) => {
|
||||||
|
try {
|
||||||
|
const user = await models.user.findUnique({ where: { id: me?.id || ANON_USER_ID } })
|
||||||
|
const parents = await models.$queryRawUnsafe(
|
||||||
|
'SELECT DISTINCT p."userId" FROM "Item" i JOIN "Item" p ON p.path @> i.path WHERE i.id = $1 and p."userId" <> $2 ' +
|
||||||
|
'AND NOT EXISTS (SELECT 1 FROM "Mute" m WHERE m."muterId" = p."userId" AND m."mutedId" = $2)',
|
||||||
|
Number(item.parentId), Number(user.id))
|
||||||
|
Promise.allSettled(
|
||||||
|
parents.map(({ userId }) => sendUserNotification(userId, {
|
||||||
|
title: `@${user.name} replied to you`,
|
||||||
|
body: item.text,
|
||||||
|
item,
|
||||||
|
tag: 'REPLY'
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const notifyZapped = async ({ models, id }) => {
|
||||||
|
try {
|
||||||
|
const updatedItem = await models.item.findUnique({ where: { id: Number(id) } })
|
||||||
|
const forwards = await models.itemForward.findMany({ where: { itemId: Number(id) } })
|
||||||
|
const userPromises = forwards.map(fwd => models.user.findUnique({ where: { id: fwd.userId } }))
|
||||||
|
const userResults = await Promise.allSettled(userPromises)
|
||||||
|
const mappedForwards = forwards.map((fwd, index) => ({ ...fwd, user: userResults[index].value ?? null }))
|
||||||
|
let forwardedSats = 0
|
||||||
|
let forwardedUsers = ''
|
||||||
|
if (mappedForwards.length) {
|
||||||
|
forwardedSats = Math.floor(msatsToSats(updatedItem.msats) * mappedForwards.map(fwd => fwd.pct).reduce((sum, cur) => sum + cur) / 100)
|
||||||
|
forwardedUsers = mappedForwards.map(fwd => `@${fwd.user.name}`).join(', ')
|
||||||
|
}
|
||||||
|
let notificationTitle
|
||||||
|
if (updatedItem.title) {
|
||||||
|
if (forwards.length > 0) {
|
||||||
|
notificationTitle = `your post forwarded ${numWithUnits(forwardedSats)} to ${forwardedUsers}`
|
||||||
|
} else {
|
||||||
|
notificationTitle = `your post stacked ${numWithUnits(msatsToSats(updatedItem.msats))}`
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (forwards.length > 0) {
|
||||||
|
// I don't think this case is possible
|
||||||
|
notificationTitle = `your reply forwarded ${numWithUnits(forwardedSats)} to ${forwardedUsers}`
|
||||||
|
} else {
|
||||||
|
notificationTitle = `your reply stacked ${numWithUnits(msatsToSats(updatedItem.msats))}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await sendUserNotification(updatedItem.userId, {
|
||||||
|
title: notificationTitle,
|
||||||
|
body: updatedItem.title ? updatedItem.title : updatedItem.text,
|
||||||
|
item: updatedItem,
|
||||||
|
tag: `TIP-${updatedItem.id}`
|
||||||
|
})
|
||||||
|
|
||||||
|
// send push notifications to forwarded recipients
|
||||||
|
if (mappedForwards.length) {
|
||||||
|
await Promise.allSettled(mappedForwards.map(forward => sendUserNotification(forward.user.id, {
|
||||||
|
title: `you were forwarded ${numWithUnits(msatsToSats(updatedItem.msats) * forward.pct / 100)}`,
|
||||||
|
body: updatedItem.title ?? updatedItem.text,
|
||||||
|
item: updatedItem,
|
||||||
|
tag: `FORWARDEDTIP-${updatedItem.id}`
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const notifyTerritoryTransfer = async ({ models, sub, to }) => {
|
||||||
|
try {
|
||||||
|
await sendUserNotification(to.id, {
|
||||||
|
title: `~${sub.name} was transferred to you`,
|
||||||
|
tag: `TERRITORY_TRANSFER-${sub.name}`
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import getSSRApolloClient from '../api/ssrApollo'
|
import getSSRApolloClient from '@/api/ssrApollo'
|
||||||
|
|
||||||
const SITE_URL = 'https://stacker.news'
|
const SITE_URL = 'https://stacker.news'
|
||||||
const SITE_TITLE = 'stacker news'
|
const SITE_TITLE = 'stacker news'
|
||||||
|
|
|
@ -7,8 +7,8 @@ import {
|
||||||
import { SUPPORTED_CURRENCIES } from './currency'
|
import { SUPPORTED_CURRENCIES } from './currency'
|
||||||
import { NOSTR_MAX_RELAY_NUM, NOSTR_PUBKEY_BECH32, NOSTR_PUBKEY_HEX } from './nostr'
|
import { NOSTR_MAX_RELAY_NUM, NOSTR_PUBKEY_BECH32, NOSTR_PUBKEY_HEX } from './nostr'
|
||||||
import { msatsToSats, numWithUnits, abbrNum, ensureB64 } from './format'
|
import { msatsToSats, numWithUnits, abbrNum, ensureB64 } from './format'
|
||||||
import * as usersFragments from '../fragments/users'
|
import * as usersFragments from '@/fragments/users'
|
||||||
import * as subsFragments from '../fragments/subs'
|
import * as subsFragments from '@/fragments/subs'
|
||||||
import { isInvoicableMacaroon, isInvoiceMacaroon } from './macaroon'
|
import { isInvoicableMacaroon, isInvoiceMacaroon } from './macaroon'
|
||||||
import { parseNwcUrl } from './url'
|
import { parseNwcUrl } from './url'
|
||||||
import { datePivot } from './time'
|
import { datePivot } from './time'
|
||||||
|
|
|
@ -2,7 +2,7 @@ import webPush from 'web-push'
|
||||||
import removeMd from 'remove-markdown'
|
import removeMd from 'remove-markdown'
|
||||||
import { ANON_USER_ID, COMMENT_DEPTH_LIMIT, FOUND_BLURBS, LOST_BLURBS } from './constants'
|
import { ANON_USER_ID, COMMENT_DEPTH_LIMIT, FOUND_BLURBS, LOST_BLURBS } from './constants'
|
||||||
import { msatsToSats, numWithUnits } from './format'
|
import { msatsToSats, numWithUnits } from './format'
|
||||||
import models from '../api/models'
|
import models from '@/api/models'
|
||||||
|
|
||||||
const webPushEnabled = process.env.NODE_ENV === 'production' ||
|
const webPushEnabled = process.env.NODE_ENV === 'production' ||
|
||||||
(process.env.VAPID_MAILTO && process.env.NEXT_PUBLIC_VAPID_PUBKEY && process.env.VAPID_PRIVKEY)
|
(process.env.VAPID_MAILTO && process.env.NEXT_PUBLIC_VAPID_PUBKEY && process.env.VAPID_PRIVKEY)
|
||||||
|
@ -250,7 +250,7 @@ export const notifyMention = async (userId, item) => {
|
||||||
body: item.text,
|
body: item.text,
|
||||||
item,
|
item,
|
||||||
tag: 'MENTION'
|
tag: 'MENTION'
|
||||||
}).catch(console.error)
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
}
|
}
|
||||||
|
@ -258,7 +258,15 @@ export const notifyMention = async (userId, item) => {
|
||||||
|
|
||||||
export const notifyReferral = async (userId) => {
|
export const notifyReferral = async (userId) => {
|
||||||
try {
|
try {
|
||||||
await sendUserNotification(userId, { title: 'someone joined via one of your referral links', tag: 'REFERRAL' }).catch(console.error)
|
await sendUserNotification(userId, { title: 'someone joined via one of your referral links', tag: 'REFERRAL' })
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const notifyInvite = async (userId) => {
|
||||||
|
try {
|
||||||
|
await sendUserNotification(userId, { title: 'your invite has been redeemed', tag: 'INVITE' })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
}
|
}
|
||||||
|
@ -315,7 +323,7 @@ export async function notifyNewStreak (userId, streak) {
|
||||||
title: 'you found a cowboy hat',
|
title: 'you found a cowboy hat',
|
||||||
body: blurb,
|
body: blurb,
|
||||||
tag: 'STREAK-FOUND'
|
tag: 'STREAK-FOUND'
|
||||||
}).catch(console.error)
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue