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 lnd from '../lnd'
|
||||
import lnd from '@/api/lnd'
|
||||
|
||||
const cache = new Map()
|
||||
const expiresIn = 1000 * 30 // 30 seconds in milliseconds
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import lndService from 'ln-service'
|
||||
import lnd from '../lnd'
|
||||
import lnd from '@/api/lnd'
|
||||
|
||||
const cache = new Map()
|
||||
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) {
|
||||
const unit = timeUnitForRange(range)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { ANON_USER_ID, AWS_S3_URL_REGEXP } from '../../lib/constants'
|
||||
import { msatsToSats } from '../../lib/format'
|
||||
import { ANON_USER_ID, AWS_S3_URL_REGEXP } from '@/lib/constants'
|
||||
import { msatsToSats } from '@/lib/format'
|
||||
|
||||
export default {
|
||||
Query: {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GraphQLError } from 'graphql'
|
||||
import { inviteSchema, ssValidate } from '../../lib/validate'
|
||||
import { msatsToSats } from '../../lib/format'
|
||||
import { inviteSchema, ssValidate } from '@/lib/validate'
|
||||
import { msatsToSats } from '@/lib/format'
|
||||
|
||||
export default {
|
||||
Query: {
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
import { GraphQLError } from 'graphql'
|
||||
import { ensureProtocol, removeTracking, stripTrailingSlash } from '../../lib/url'
|
||||
import { ensureProtocol, removeTracking, stripTrailingSlash } from '@/lib/url'
|
||||
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 { ruleSet as publicationDateRuleSet } from '../../lib/timedate-scraper'
|
||||
import { ruleSet as publicationDateRuleSet } from '@/lib/timedate-scraper'
|
||||
import domino from 'domino'
|
||||
import {
|
||||
ITEM_SPAM_INTERVAL, ITEM_FILTER_THRESHOLD,
|
||||
COMMENT_DEPTH_LIMIT, COMMENT_TYPE_QUERY,
|
||||
ANON_USER_ID, ANON_ITEM_SPAM_INTERVAL, POLL_COST,
|
||||
ITEM_ALLOW_EDITS, GLOBAL_SEED, ANON_FEE_MULTIPLIER, NOFOLLOW_LIMIT, UNKNOWN_LINK_REL
|
||||
} from '../../lib/constants'
|
||||
import { msatsToSats } from '../../lib/format'
|
||||
} from '@/lib/constants'
|
||||
import { msatsToSats } from '@/lib/format'
|
||||
import { parse } from 'tldts'
|
||||
import uu from 'url-unshort'
|
||||
import { actSchema, advSchema, bountySchema, commentSchema, discussionSchema, jobSchema, linkSchema, pollSchema, ssValidate } from '../../lib/validate'
|
||||
import { notifyItemParents, notifyUserSubscribers, notifyZapped, notifyTerritorySubscribers, notifyMention } from '../../lib/webPush'
|
||||
import { defaultCommentSort, isJob, deleteItemByAuthor, getDeleteCommand, hasDeleteCommand } from '../../lib/item'
|
||||
import { datePivot, whenRange } from '../../lib/time'
|
||||
import { actSchema, advSchema, bountySchema, commentSchema, discussionSchema, jobSchema, linkSchema, pollSchema, ssValidate } from '@/lib/validate'
|
||||
import { notifyItemParents, notifyUserSubscribers, notifyZapped, notifyTerritorySubscribers, notifyMention } from '@/lib/webPush'
|
||||
import { defaultCommentSort, isJob, deleteItemByAuthor, getDeleteCommand, hasDeleteCommand } from '@/lib/item'
|
||||
import { datePivot, whenRange } from '@/lib/time'
|
||||
import { imageFeesInfo, uploadIdsFromText } from './image'
|
||||
import assertGofacYourself from './ofac'
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
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 { getInvoice } from './wallet'
|
||||
import { pushSubscriptionSchema, ssValidate } from '../../lib/validate'
|
||||
import { replyToSubscription } from '../../lib/webPush'
|
||||
import { pushSubscriptionSchema, ssValidate } from '@/lib/validate'
|
||||
import { replyToSubscription } from '@/lib/webPush'
|
||||
import { getSub } from './sub'
|
||||
|
||||
export default {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GraphQLError } from 'graphql'
|
||||
import { withClause, intervalClause } from './growth'
|
||||
import { timeUnitForRange, whenRange } from '../../lib/time'
|
||||
import { timeUnitForRange, whenRange } from '@/lib/time'
|
||||
|
||||
export default {
|
||||
Query: {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { GraphQLError } from 'graphql'
|
||||
import { amountSchema, ssValidate } from '../../lib/validate'
|
||||
import { amountSchema, ssValidate } from '@/lib/validate'
|
||||
import { serializeInvoicable } from './serial'
|
||||
import { ANON_USER_ID } from '../../lib/constants'
|
||||
import { ANON_USER_ID } from '@/lib/constants'
|
||||
import { getItem } from './item'
|
||||
import { topUsers } from './user'
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { decodeCursor, LIMIT, nextCursorEncoded } from '../../lib/cursor'
|
||||
import { whenToFrom } from '../../lib/time'
|
||||
import { decodeCursor, LIMIT, nextCursorEncoded } from '@/lib/cursor'
|
||||
import { whenToFrom } from '@/lib/time'
|
||||
import { getItem, itemQueryWithMeta, SELECT } from './item'
|
||||
|
||||
function queryParts (q) {
|
||||
|
|
|
@ -3,8 +3,8 @@ import retry from 'async-retry'
|
|||
import Prisma from '@prisma/client'
|
||||
import { settleHodlInvoice } from 'ln-service'
|
||||
import { createHmac } from './wallet'
|
||||
import { msatsToSats, numWithUnits } from '../../lib/format'
|
||||
import { BALANCE_LIMIT_MSATS } from '../../lib/constants'
|
||||
import { msatsToSats, numWithUnits } from '@/lib/format'
|
||||
import { BALANCE_LIMIT_MSATS } from '@/lib/constants'
|
||||
|
||||
export default async function serialize (models, ...calls) {
|
||||
return await retry(async bail => {
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import { GraphQLError } from 'graphql'
|
||||
import { serializeInvoicable } from './serial'
|
||||
import { TERRITORY_COST_MONTHLY, TERRITORY_COST_ONCE, TERRITORY_COST_YEARLY, TERRITORY_PERIOD_COST } from '../../lib/constants'
|
||||
import { datePivot, whenRange } from '../../lib/time'
|
||||
import { ssValidate, territorySchema } from '../../lib/validate'
|
||||
import { nextBilling, proratedBillingCost } from '../../lib/territory'
|
||||
import { decodeCursor, LIMIT, nextCursorEncoded } from '../../lib/cursor'
|
||||
import { TERRITORY_COST_MONTHLY, TERRITORY_COST_ONCE, TERRITORY_COST_YEARLY, TERRITORY_PERIOD_COST } from '@/lib/constants'
|
||||
import { datePivot, whenRange } from '@/lib/time'
|
||||
import { ssValidate, territorySchema } from '@/lib/validate'
|
||||
import { nextBilling, proratedBillingCost } from '@/lib/territory'
|
||||
import { decodeCursor, LIMIT, nextCursorEncoded } from '@/lib/cursor'
|
||||
import { subViewGroup } from './growth'
|
||||
import { notifyTerritoryTransfer } from '../../lib/webPush'
|
||||
|
||||
import { notifyTerritoryTransfer } from '@/lib/webPush'
|
||||
export function paySubQueries (sub, models) {
|
||||
if (sub.billingType === 'ONCE') {
|
||||
return []
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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 { createPresignedPost } from '../s3'
|
||||
import { ANON_USER_ID, IMAGE_PIXELS_MAX, UPLOAD_SIZE_MAX, UPLOAD_SIZE_MAX_AVATAR, UPLOAD_TYPES_ALLOW } from '@/lib/constants'
|
||||
import { createPresignedPost } from '@/api/s3'
|
||||
|
||||
export default {
|
||||
Mutation: {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { readFile } from 'fs/promises'
|
||||
import { join, resolve } from 'path'
|
||||
import { GraphQLError } from 'graphql'
|
||||
import { decodeCursor, LIMIT, nextCursorEncoded } from '../../lib/cursor'
|
||||
import { msatsToSats } from '../../lib/format'
|
||||
import { bioSchema, emailSchema, settingsSchema, ssValidate, userSchema } from '../../lib/validate'
|
||||
import { decodeCursor, LIMIT, nextCursorEncoded } from '@/lib/cursor'
|
||||
import { msatsToSats } from '@/lib/format'
|
||||
import { bioSchema, emailSchema, settingsSchema, ssValidate, userSchema } from '@/lib/validate'
|
||||
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 { whenRange } from '../../lib/time'
|
||||
import { whenRange } from '@/lib/time'
|
||||
|
||||
const contributors = new Set()
|
||||
|
||||
|
|
|
@ -2,14 +2,14 @@ import { getIdentity, createHodlInvoice, createInvoice, decodePaymentRequest, pa
|
|||
import { GraphQLError } from 'graphql'
|
||||
import crypto from 'crypto'
|
||||
import serialize from './serial'
|
||||
import { decodeCursor, LIMIT, nextCursorEncoded } from '../../lib/cursor'
|
||||
import { decodeCursor, LIMIT, nextCursorEncoded } from '@/lib/cursor'
|
||||
import lnpr from 'bolt11'
|
||||
import { SELECT } from './item'
|
||||
import { lnAddrOptions } from '../../lib/lnurl'
|
||||
import { msatsToSats, msatsToSatsDecimal, ensureB64 } from '../../lib/format'
|
||||
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 { datePivot } from '../../lib/time'
|
||||
import { lnAddrOptions } from '@/lib/lnurl'
|
||||
import { msatsToSats, msatsToSatsDecimal, ensureB64 } from '@/lib/format'
|
||||
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 { datePivot } from '@/lib/time'
|
||||
import assertGofacYourself from './ofac'
|
||||
|
||||
export async function getInvoice (parent, { id }, { me, models, lnd }) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import AWS from 'aws-sdk'
|
||||
import { MEDIA_URL } from '../../lib/constants'
|
||||
import { MEDIA_URL } from '@/lib/constants'
|
||||
|
||||
const bucketRegion = 'us-east-1'
|
||||
const Bucket = process.env.NEXT_PUBLIC_AWS_UPLOAD_BUCKET
|
||||
|
|
|
@ -7,12 +7,12 @@ import models from './models'
|
|||
import { print } from 'graphql'
|
||||
import lnd from './lnd'
|
||||
import search from './search'
|
||||
import { ME } from '../fragments/users'
|
||||
import { PRICE } from '../fragments/price'
|
||||
import { BLOCK_HEIGHT } from '../fragments/blockHeight'
|
||||
import { CHAIN_FEE } from '../fragments/chainFee'
|
||||
import { ME } from '@/fragments/users'
|
||||
import { PRICE } from '@/fragments/price'
|
||||
import { BLOCK_HEIGHT } from '@/fragments/blockHeight'
|
||||
import { CHAIN_FEE } from '@/fragments/chainFee'
|
||||
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 }) {
|
||||
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 AccordionContext from 'react-bootstrap/AccordionContext'
|
||||
import { useAccordionButton } from 'react-bootstrap/AccordionButton'
|
||||
import ArrowRight from '../svgs/arrow-right-s-fill.svg'
|
||||
import ArrowDown from '../svgs/arrow-down-s-fill.svg'
|
||||
import ArrowRight from '@/svgs/arrow-right-s-fill.svg'
|
||||
import ArrowDown from '@/svgs/arrow-down-s-fill.svg'
|
||||
import { useContext } from 'react'
|
||||
|
||||
function ContextAwareToggle ({ children, headerColor = 'var(--theme-grey)', eventKey }) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Dropdown from 'react-bootstrap/Dropdown'
|
||||
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 }) {
|
||||
if (!children) {
|
||||
|
|
|
@ -2,10 +2,10 @@ import { useState, useEffect } from 'react'
|
|||
import AccordianItem from './accordian-item'
|
||||
import { Input, InputUserSuggest, VariableInput, Checkbox } from './form'
|
||||
import InputGroup from 'react-bootstrap/InputGroup'
|
||||
import { BOOST_MIN, BOOST_MULT, MAX_FORWARDS } from '../lib/constants'
|
||||
import { DEFAULT_CROSSPOSTING_RELAYS } from '../lib/nostr'
|
||||
import { BOOST_MIN, BOOST_MULT, MAX_FORWARDS } from '@/lib/constants'
|
||||
import { DEFAULT_CROSSPOSTING_RELAYS } from '@/lib/nostr'
|
||||
import Info from './info'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import styles from './adv-post-form.module.css'
|
||||
import { useMe } from './me'
|
||||
import { useFeeButton } from './fee-button'
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Checkbox, Input } from './form'
|
|||
import { useMe } from './me'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { isNumber } from 'mathjs'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
|
||||
function autoWithdrawThreshold ({ me }) {
|
||||
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 Button from 'react-bootstrap/Button'
|
||||
import BootstrapForm from 'react-bootstrap/Form'
|
||||
import EditImage from '../svgs/image-edit-fill.svg'
|
||||
import Moon from '../svgs/moon-fill.svg'
|
||||
import EditImage from '@/svgs/image-edit-fill.svg'
|
||||
import Moon from '@/svgs/moon-fill.svg'
|
||||
import { useShowModal } from './modal'
|
||||
import { ImageUpload } from './image'
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import Alert from 'react-bootstrap/Alert'
|
||||
import styles from './banners.module.css'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useMe } from '../components/me'
|
||||
import { useMe } from '@/components/me'
|
||||
import { useMutation } from '@apollo/client'
|
||||
import { WELCOME_BANNER_MUTATION } from '../fragments/users'
|
||||
import { useToast } from '../components/toast'
|
||||
import { BALANCE_LIMIT_MSATS } from '../lib/constants'
|
||||
import { msatsToSats, numWithUnits } from '../lib/format'
|
||||
import { WELCOME_BANNER_MUTATION } from '@/fragments/users'
|
||||
import { useToast } from '@/components/toast'
|
||||
import { BALANCE_LIMIT_MSATS } from '@/lib/constants'
|
||||
import { msatsToSats, numWithUnits } from '@/lib/format'
|
||||
|
||||
export function WelcomeBanner ({ Banner }) {
|
||||
const me = useMe()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { createContext, useContext, useMemo } from 'react'
|
||||
import { useQuery } from '@apollo/client'
|
||||
import { SSR } from '../lib/constants'
|
||||
import { BLOCK_HEIGHT } from '../fragments/blockHeight'
|
||||
import { SSR } from '@/lib/constants'
|
||||
import { BLOCK_HEIGHT } from '@/fragments/blockHeight'
|
||||
|
||||
export const BlockHeightContext = createContext({
|
||||
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 { gql, useApolloClient, useMutation } from '@apollo/client'
|
||||
import Countdown from './countdown'
|
||||
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
||||
import InputGroup from 'react-bootstrap/InputGroup'
|
||||
import useCrossposter from './use-crossposter'
|
||||
import { bountySchema } from '../lib/validate'
|
||||
import { bountySchema } from '@/lib/validate'
|
||||
import { SubSelectInitial } from './sub-select'
|
||||
import { useCallback } from 'react'
|
||||
import { normalizeForwards, toastDeleteScheduled } from '../lib/form'
|
||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
import { normalizeForwards, toastDeleteScheduled } from '@/lib/form'
|
||||
import { MAX_TITLE_LENGTH } from '@/lib/constants'
|
||||
import { useMe } from './me'
|
||||
import { useToast } from './toast'
|
||||
import { ItemButtonBar } from './post'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { createContext, useContext, useMemo } from 'react'
|
||||
import { useQuery } from '@apollo/client'
|
||||
import { SSR } from '../lib/constants'
|
||||
import { CHAIN_FEE } from '../fragments/chainFee'
|
||||
import { SSR } from '@/lib/constants'
|
||||
import { CHAIN_FEE } from '@/fragments/chainFee'
|
||||
|
||||
export const ChainFeeContext = createContext({
|
||||
fee: 0
|
||||
|
|
|
@ -12,9 +12,9 @@ import { ResponsiveContainer } from 'recharts/lib/component/ResponsiveContainer'
|
|||
import { PieChart } from 'recharts/lib/chart/PieChart'
|
||||
import { Cell } from 'recharts/lib/component/Cell'
|
||||
import { Pie } from 'recharts/lib/polar/Pie'
|
||||
import { abbrNum } from '../lib/format'
|
||||
import { abbrNum } from '@/lib/format'
|
||||
import { useRouter } from 'next/router'
|
||||
import { timeUnitForRange } from '../lib/time'
|
||||
import { timeUnitForRange } from '@/lib/time'
|
||||
|
||||
const dateFormatter = (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 styles from './reply.module.css'
|
||||
import { commentSchema } from '../lib/validate'
|
||||
import { commentSchema } from '@/lib/validate'
|
||||
import { useToast } from './toast'
|
||||
import { toastDeleteScheduled } from '../lib/form'
|
||||
import { toastDeleteScheduled } from '@/lib/form'
|
||||
import { FeeButtonProvider } from './fee-button'
|
||||
import { ItemButtonBar } from './post'
|
||||
|
||||
|
|
|
@ -5,16 +5,16 @@ import Link from 'next/link'
|
|||
import Reply, { ReplyOnAnotherPage } from './reply'
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import UpVote from './upvote'
|
||||
import Eye from '../svgs/eye-fill.svg'
|
||||
import EyeClose from '../svgs/eye-close-line.svg'
|
||||
import Eye from '@/svgs/eye-fill.svg'
|
||||
import EyeClose from '@/svgs/eye-close-line.svg'
|
||||
import { useRouter } from 'next/router'
|
||||
import CommentEdit from './comment-edit'
|
||||
import { ANON_USER_ID, COMMENT_DEPTH_LIMIT, UNKNOWN_LINK_REL } from '../lib/constants'
|
||||
import { ignoreClick } from '../lib/clicks'
|
||||
import { ANON_USER_ID, COMMENT_DEPTH_LIMIT, UNKNOWN_LINK_REL } from '@/lib/constants'
|
||||
import { ignoreClick } from '@/lib/clicks'
|
||||
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 { numWithUnits } from '../lib/format'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import Share from './share'
|
||||
import ItemInfo from './item-info'
|
||||
import Badge from 'react-bootstrap/Badge'
|
||||
|
@ -22,9 +22,9 @@ import { RootProvider, useRoot } from './root'
|
|||
import { useMe } from './me'
|
||||
import { useQuoteReply } from './use-quote-reply'
|
||||
import { DownZap } from './dont-link-this'
|
||||
import Skull from '../svgs/death-skull.svg'
|
||||
import { commentSubTreeRootId } from '../lib/item'
|
||||
import Pin from '../svgs/pushpin-fill.svg'
|
||||
import Skull from '@/svgs/death-skull.svg'
|
||||
import { commentSubTreeRootId } from '@/lib/item'
|
||||
import Pin from '@/svgs/pushpin-fill.svg'
|
||||
|
||||
function Parent ({ item, rootText }) {
|
||||
const root = useRoot()
|
||||
|
|
|
@ -3,8 +3,8 @@ import Comment, { CommentSkeleton } from './comment'
|
|||
import styles from './header.module.css'
|
||||
import Nav from 'react-bootstrap/Nav'
|
||||
import Navbar from 'react-bootstrap/Navbar'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import { defaultCommentSort } from '../lib/item'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import { defaultCommentSort } from '@/lib/item'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
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 { gql, useApolloClient, useLazyQuery, useMutation } from '@apollo/client'
|
||||
import Countdown from './countdown'
|
||||
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 Item from './item'
|
||||
import { discussionSchema } from '../lib/validate'
|
||||
import { discussionSchema } from '@/lib/validate'
|
||||
import { SubSelectInitial } from './sub-select'
|
||||
import { useCallback } from 'react'
|
||||
import { normalizeForwards, toastDeleteScheduled } from '../lib/form'
|
||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
import { normalizeForwards, toastDeleteScheduled } from '@/lib/form'
|
||||
import { MAX_TITLE_LENGTH } from '@/lib/constants'
|
||||
import { useMe } from './me'
|
||||
import useCrossposter from './use-crossposter'
|
||||
import { useToast } from './toast'
|
||||
|
|
|
@ -3,9 +3,9 @@ import { useShowModal } from './modal'
|
|||
import { useToast } from './toast'
|
||||
import ItemAct from './item-act'
|
||||
import AccordianItem from './accordian-item'
|
||||
import Flag from '../svgs/flag-fill.svg'
|
||||
import Flag from '@/svgs/flag-fill.svg'
|
||||
import { useMemo } from 'react'
|
||||
import getColor from '../lib/rainbow'
|
||||
import getColor from '@/lib/rainbow'
|
||||
import { gql, useMutation } from '@apollo/client'
|
||||
import { useMe } from './me'
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Component } from 'react'
|
||||
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 copy from 'clipboard-copy'
|
||||
import { LoggerContext } from './logger'
|
||||
|
|
|
@ -4,10 +4,10 @@ import ActionTooltip from './action-tooltip'
|
|||
import Info from './info'
|
||||
import styles from './fee-button.module.css'
|
||||
import { gql, useQuery } from '@apollo/client'
|
||||
import { ANON_FEE_MULTIPLIER, SSR } from '../lib/constants'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import { ANON_FEE_MULTIPLIER, SSR } from '@/lib/constants'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import { useMe } from './me'
|
||||
import AnonIcon from '../svgs/spy-fill.svg'
|
||||
import AnonIcon from '@/svgs/spy-fill.svg'
|
||||
import { useShowModal } from './modal'
|
||||
import Link from 'next/link'
|
||||
import { SubmitButton } from './form'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { gql, useQuery } from '@apollo/client'
|
||||
import Link from 'next/link'
|
||||
import { RewardLine } from '../pages/rewards'
|
||||
import { SSR } from '../lib/constants'
|
||||
import { RewardLine } from '@/pages/rewards'
|
||||
import { SSR } from '@/lib/constants'
|
||||
|
||||
const REWARDS = gql`
|
||||
{
|
||||
|
|
|
@ -3,15 +3,15 @@ import OverlayTrigger from 'react-bootstrap/OverlayTrigger'
|
|||
import Popover from 'react-bootstrap/Popover'
|
||||
import { CopyInput } from './form'
|
||||
import styles from './footer.module.css'
|
||||
import Texas from '../svgs/texas.svg'
|
||||
import Github from '../svgs/github-fill.svg'
|
||||
import Texas from '@/svgs/texas.svg'
|
||||
import Github from '@/svgs/github-fill.svg'
|
||||
import Link from 'next/link'
|
||||
import Sun from '../svgs/sun-fill.svg'
|
||||
import Moon from '../svgs/moon-fill.svg'
|
||||
import No from '../svgs/no.svg'
|
||||
import Bolt from '../svgs/bolt.svg'
|
||||
import Amboss from '../svgs/amboss.svg'
|
||||
import Mempool from '../svgs/bimi.svg'
|
||||
import Sun from '@/svgs/sun-fill.svg'
|
||||
import Moon from '@/svgs/moon-fill.svg'
|
||||
import No from '@/svgs/no.svg'
|
||||
import Bolt from '@/svgs/bolt.svg'
|
||||
import Amboss from '@/svgs/amboss.svg'
|
||||
import Mempool from '@/svgs/bimi.svg'
|
||||
import { useEffect, useState } from 'react'
|
||||
import Rewards from './footer-rewards'
|
||||
import useDarkMode from './dark-mode'
|
||||
|
|
|
@ -8,27 +8,27 @@ import Col from 'react-bootstrap/Col'
|
|||
import Dropdown from 'react-bootstrap/Dropdown'
|
||||
import Nav from 'react-bootstrap/Nav'
|
||||
import Row from 'react-bootstrap/Row'
|
||||
import Markdown from '../svgs/markdown-line.svg'
|
||||
import AddImageIcon from '../svgs/image-add-line.svg'
|
||||
import Markdown from '@/svgs/markdown-line.svg'
|
||||
import AddImageIcon from '@/svgs/image-add-line.svg'
|
||||
import styles from './form.module.css'
|
||||
import Text from '../components/text'
|
||||
import AddIcon from '../svgs/add-fill.svg'
|
||||
import CloseIcon from '../svgs/close-line.svg'
|
||||
import Text from '@/components/text'
|
||||
import AddIcon from '@/svgs/add-fill.svg'
|
||||
import CloseIcon from '@/svgs/close-line.svg'
|
||||
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 { useToast } from './toast'
|
||||
import { useInvoiceable } from './invoice'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import textAreaCaret from 'textarea-caret'
|
||||
import ReactDatePicker from 'react-datepicker'
|
||||
import 'react-datepicker/dist/react-datepicker.css'
|
||||
import useDebounceCallback, { debounce } from './use-debounce-callback'
|
||||
import { ImageUpload } from './image'
|
||||
import { AWS_S3_URL_REGEXP } from '../lib/constants'
|
||||
import { whenRange } from '../lib/time'
|
||||
import { AWS_S3_URL_REGEXP } from '@/lib/constants'
|
||||
import { whenRange } from '@/lib/time'
|
||||
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'
|
||||
|
||||
export function SubmitButton ({
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import Badge from 'react-bootstrap/Badge'
|
||||
import OverlayTrigger from 'react-bootstrap/OverlayTrigger'
|
||||
import Tooltip from 'react-bootstrap/Tooltip'
|
||||
import CowboyHatIcon from '../svgs/cowboy.svg'
|
||||
import AnonIcon from '../svgs/spy-fill.svg'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import { AD_USER_ID, ANON_USER_ID } from '../lib/constants'
|
||||
import CowboyHatIcon from '@/svgs/cowboy.svg'
|
||||
import AnonIcon from '@/svgs/spy-fill.svg'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import { AD_USER_ID, ANON_USER_ID } from '@/lib/constants'
|
||||
|
||||
export default function Hat ({ user, badge, className = 'ms-1', height = 16, width = 16 }) {
|
||||
if (!user || Number(user.id) === AD_USER_ID) return null
|
||||
|
|
|
@ -11,20 +11,20 @@ import { useMe } from './me'
|
|||
import Head from 'next/head'
|
||||
import { signOut } from 'next-auth/react'
|
||||
import { useCallback, useEffect } from 'react'
|
||||
import { randInRange } from '../lib/rand'
|
||||
import { abbrNum, msatsToSats } from '../lib/format'
|
||||
import NoteIcon from '../svgs/notification-4-fill.svg'
|
||||
import { randInRange } from '@/lib/rand'
|
||||
import { abbrNum, msatsToSats } from '@/lib/format'
|
||||
import NoteIcon from '@/svgs/notification-4-fill.svg'
|
||||
import { useQuery } from '@apollo/client'
|
||||
import LightningIcon from '../svgs/bolt.svg'
|
||||
import SearchIcon from '../svgs/search-line.svg'
|
||||
import BackArrow from '../svgs/arrow-left-line.svg'
|
||||
import { BALANCE_LIMIT_MSATS, SSR } from '../lib/constants'
|
||||
import LightningIcon from '@/svgs/bolt.svg'
|
||||
import SearchIcon from '@/svgs/search-line.svg'
|
||||
import BackArrow from '@/svgs/arrow-left-line.svg'
|
||||
import { BALANCE_LIMIT_MSATS, SSR } from '@/lib/constants'
|
||||
import { useLightning } from './lightning'
|
||||
import { HAS_NOTIFICATIONS } from '../fragments/notifications'
|
||||
import AnonIcon from '../svgs/spy-fill.svg'
|
||||
import { HAS_NOTIFICATIONS } from '@/fragments/notifications'
|
||||
import AnonIcon from '@/svgs/spy-fill.svg'
|
||||
import Hat from './hat'
|
||||
import HiddenWalletSummary from './hidden-wallet-summary'
|
||||
import { clearNotifications } from '../lib/badge'
|
||||
import { clearNotifications } from '@/lib/badge'
|
||||
import { useServiceWorker } from './serviceworker'
|
||||
import SubSelect from './sub-select'
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useState, useRef, useEffect } from 'react'
|
||||
import { abbrNum, numWithUnits } from '../lib/format'
|
||||
import { abbrNum, numWithUnits } from '@/lib/format'
|
||||
import { useMe } from './me'
|
||||
|
||||
export default function HiddenWalletSummary ({ abbreviate, fixedWidth }) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import styles from './text.module.css'
|
||||
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 { useMe } from './me'
|
||||
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 gql from 'graphql-tag'
|
||||
import { useMutation } from '@apollo/client'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react'
|
||||
import InfoIcon from '../svgs/information-fill.svg'
|
||||
import InfoIcon from '@/svgs/information-fill.svg'
|
||||
import { useShowModal } from './modal'
|
||||
|
||||
export default function Info ({ children, label, iconClassName = 'fill-theme-color' }) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { CopyInput } from './form'
|
||||
import { gql, useMutation } from '@apollo/client'
|
||||
import { INVITE_FIELDS } from '../fragments/invites'
|
||||
import styles from '../styles/invites.module.css'
|
||||
import { INVITE_FIELDS } from '@/fragments/invites'
|
||||
import styles from '@/styles/invites.module.css'
|
||||
|
||||
export default function Invite ({ invite, active }) {
|
||||
const [revokeInvite] = useMutation(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Moon from '../svgs/moon-fill.svg'
|
||||
import Check from '../svgs/check-double-line.svg'
|
||||
import ThumbDown from '../svgs/thumb-down-fill.svg'
|
||||
import Moon from '@/svgs/moon-fill.svg'
|
||||
import Check from '@/svgs/check-double-line.svg'
|
||||
import ThumbDown from '@/svgs/thumb-down-fill.svg'
|
||||
|
||||
function InvoiceDefaultStatus ({ status }) {
|
||||
return (
|
||||
|
|
|
@ -2,10 +2,10 @@ import { useState, useCallback, useEffect } from 'react'
|
|||
import { useApolloClient, useMutation, useQuery } from '@apollo/client'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import { gql } from 'graphql-tag'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import AccordianItem from './accordian-item'
|
||||
import Qr, { QrSkeleton } from './qr'
|
||||
import { INVOICE } from '../fragments/wallet'
|
||||
import { INVOICE } from '@/fragments/wallet'
|
||||
import InvoiceStatus from './invoice-status'
|
||||
import { useMe } from './me'
|
||||
import { useShowModal } from './modal'
|
||||
|
|
|
@ -3,8 +3,8 @@ import InputGroup from 'react-bootstrap/InputGroup'
|
|||
import React, { useState, useRef, useEffect, useCallback } from 'react'
|
||||
import { Form, Input, SubmitButton } from './form'
|
||||
import { useMe } from './me'
|
||||
import UpBolt from '../svgs/bolt.svg'
|
||||
import { amountSchema } from '../lib/validate'
|
||||
import UpBolt from '@/svgs/bolt.svg'
|
||||
import { amountSchema } from '@/lib/validate'
|
||||
import { gql, useApolloClient, useMutation } from '@apollo/client'
|
||||
import { payOrLoginError, useInvoiceModal } from './invoice'
|
||||
import { TOAST_DEFAULT_DELAY_MS, useToast, withToastFlow } from './toast'
|
||||
|
|
|
@ -5,7 +5,7 @@ import Comment from './comment'
|
|||
import Text, { SearchText } from './text'
|
||||
import ZoomableImage from './image'
|
||||
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 { useMe } from './me'
|
||||
import Button from 'react-bootstrap/Button'
|
||||
|
@ -14,18 +14,18 @@ import YouTube from 'react-youtube'
|
|||
import useDarkMode from './dark-mode'
|
||||
import { useEffect, useState } from 'react'
|
||||
import Poll from './poll'
|
||||
import { commentsViewed } from '../lib/new-comments'
|
||||
import { commentsViewed } from '@/lib/new-comments'
|
||||
import Related from './related'
|
||||
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 Toc from './table-of-contents'
|
||||
import Link from 'next/link'
|
||||
import { RootProvider } from './root'
|
||||
import { IMGPROXY_URL_REGEXP } from '../lib/url'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import { IMGPROXY_URL_REGEXP } from '@/lib/url'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import { useQuoteReply } from './use-quote-reply'
|
||||
import { UNKNOWN_LINK_REL } from '../lib/constants'
|
||||
import { UNKNOWN_LINK_REL } from '@/lib/constants'
|
||||
|
||||
function BioItem ({ item, handleClick }) {
|
||||
const me = useMe()
|
||||
|
|
|
@ -4,9 +4,9 @@ import { useEffect, useState } from 'react'
|
|||
import Badge from 'react-bootstrap/Badge'
|
||||
import Dropdown from 'react-bootstrap/Dropdown'
|
||||
import Countdown from './countdown'
|
||||
import { abbrNum, numWithUnits } from '../lib/format'
|
||||
import { newComments, commentsViewedAt } from '../lib/new-comments'
|
||||
import { timeSince } from '../lib/time'
|
||||
import { abbrNum, numWithUnits } from '@/lib/format'
|
||||
import { newComments, commentsViewedAt } from '@/lib/new-comments'
|
||||
import { timeSince } from '@/lib/time'
|
||||
import { DeleteDropdownItem } from './delete'
|
||||
import styles from './item.module.css'
|
||||
import { useMe } from './me'
|
||||
|
@ -15,7 +15,7 @@ import BookmarkDropdownItem from './bookmark'
|
|||
import SubscribeDropdownItem from './subscribe'
|
||||
import { CopyLinkDropdownItem, CrosspostDropdownItem } from './share'
|
||||
import Hat from './hat'
|
||||
import { AD_USER_ID } from '../lib/constants'
|
||||
import { AD_USER_ID } from '@/lib/constants'
|
||||
import ActionDropdown from './action-dropdown'
|
||||
import MuteDropdownItem from './mute'
|
||||
import { DropdownItemUpVote } from './upvote'
|
||||
|
|
|
@ -6,11 +6,11 @@ import Image from 'react-bootstrap/Image'
|
|||
import { SearchTitle } from './item'
|
||||
import styles from './item.module.css'
|
||||
import Link from 'next/link'
|
||||
import { timeSince } from '../lib/time'
|
||||
import EmailIcon from '../svgs/mail-open-line.svg'
|
||||
import { timeSince } from '@/lib/time'
|
||||
import EmailIcon from '@/svgs/mail-open-line.svg'
|
||||
import Share from './share'
|
||||
import Hat from './hat'
|
||||
import { MEDIA_URL } from '../lib/constants'
|
||||
import { MEDIA_URL } from '@/lib/constants'
|
||||
|
||||
export default function ItemJob ({ item, toc, rank, children }) {
|
||||
const isEmail = string().email().isValidSync(item.url)
|
||||
|
|
|
@ -2,22 +2,22 @@ import Link from 'next/link'
|
|||
import styles from './item.module.css'
|
||||
import UpVote from './upvote'
|
||||
import { useRef } from 'react'
|
||||
import { AD_USER_ID, UNKNOWN_LINK_REL } from '../lib/constants'
|
||||
import Pin from '../svgs/pushpin-fill.svg'
|
||||
import { AD_USER_ID, UNKNOWN_LINK_REL } from '@/lib/constants'
|
||||
import Pin from '@/svgs/pushpin-fill.svg'
|
||||
import reactStringReplace from 'react-string-replace'
|
||||
import PollIcon from '../svgs/bar-chart-horizontal-fill.svg'
|
||||
import BountyIcon from '../svgs/bounty-bag.svg'
|
||||
import PollIcon from '@/svgs/bar-chart-horizontal-fill.svg'
|
||||
import BountyIcon from '@/svgs/bounty-bag.svg'
|
||||
import ActionTooltip from './action-tooltip'
|
||||
import ImageIcon from '../svgs/image-fill.svg'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import ImageIcon from '@/svgs/image-fill.svg'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import ItemInfo from './item-info'
|
||||
import Prism from '../svgs/prism.svg'
|
||||
import { commentsViewedAt } from '../lib/new-comments'
|
||||
import Prism from '@/svgs/prism.svg'
|
||||
import { commentsViewedAt } from '@/lib/new-comments'
|
||||
import { useRouter } from 'next/router'
|
||||
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 { timeLeft } from '../lib/time'
|
||||
import { timeLeft } from '@/lib/time'
|
||||
|
||||
export function SearchTitle ({ title }) {
|
||||
return reactStringReplace(title, /\*\*\*([^*]+)\*\*\*/g, (match, i) => {
|
||||
|
|
|
@ -5,8 +5,8 @@ import styles from './items.module.css'
|
|||
import MoreFooter from './more-footer'
|
||||
import { Fragment, useCallback, useMemo } from 'react'
|
||||
import { CommentFlat } from './comment'
|
||||
import { SUB_ITEMS } from '../fragments/subs'
|
||||
import { LIMIT } from '../lib/cursor'
|
||||
import { SUB_ITEMS } from '@/fragments/subs'
|
||||
import { LIMIT } from '@/lib/cursor'
|
||||
import ItemFull from './item-full'
|
||||
import { useData } from './use-data'
|
||||
|
||||
|
|
|
@ -8,16 +8,16 @@ import Alert from 'react-bootstrap/Alert'
|
|||
import { useCallback, useEffect, useState } from 'react'
|
||||
import Info from './info'
|
||||
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 { useRouter } from 'next/router'
|
||||
import Link from 'next/link'
|
||||
import { usePrice } from './price'
|
||||
import Avatar from './avatar'
|
||||
import { jobSchema } from '../lib/validate'
|
||||
import { MAX_TITLE_LENGTH, MEDIA_URL } from '../lib/constants'
|
||||
import { jobSchema } from '@/lib/validate'
|
||||
import { MAX_TITLE_LENGTH, MEDIA_URL } from '@/lib/constants'
|
||||
import { useToast } from './toast'
|
||||
import { toastDeleteScheduled } from '../lib/form'
|
||||
import { toastDeleteScheduled } from '@/lib/form'
|
||||
import { ItemButtonBar } from './post'
|
||||
|
||||
function satsMin2Mo (minute) {
|
||||
|
|
|
@ -7,9 +7,9 @@ import Row from 'react-bootstrap/Row'
|
|||
import AccordianItem from './accordian-item'
|
||||
import Qr, { QrSkeleton } from './qr'
|
||||
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 { SSR } from '../lib/constants'
|
||||
import { SSR } from '@/lib/constants'
|
||||
|
||||
function QrAuth ({ k1, encodedUrl, callbackUrl }) {
|
||||
const query = gql`
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useRef, useEffect, useContext } from 'react'
|
||||
import { randInRange } from '../lib/rand'
|
||||
import { randInRange } from '@/lib/rand'
|
||||
|
||||
export const LightningContext = React.createContext(() => {})
|
||||
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
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 { gql, useApolloClient, useLazyQuery, useMutation } from '@apollo/client'
|
||||
import Countdown from './countdown'
|
||||
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
||||
import { ITEM_FIELDS } from '../fragments/items'
|
||||
import { ITEM_FIELDS } from '@/fragments/items'
|
||||
import Item from './item'
|
||||
import AccordianItem from './accordian-item'
|
||||
import { linkSchema } from '../lib/validate'
|
||||
import Moon from '../svgs/moon-fill.svg'
|
||||
import { normalizeForwards, toastDeleteScheduled } from '../lib/form'
|
||||
import { linkSchema } from '@/lib/validate'
|
||||
import Moon from '@/svgs/moon-fill.svg'
|
||||
import { normalizeForwards, toastDeleteScheduled } from '@/lib/form'
|
||||
import { useToast } from './toast'
|
||||
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 { useMe } from './me'
|
||||
import { ItemButtonBar } from './post'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
||||
import { useMe } from './me'
|
||||
import fancyNames from '../lib/fancy-names.json'
|
||||
import fancyNames from '@/lib/fancy-names.json'
|
||||
|
||||
const generateFancyName = () => {
|
||||
// 100 adjectives * 100 nouns * 10000 = 100M possible names
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import GithubIcon from '../svgs/github-fill.svg'
|
||||
import TwitterIcon from '../svgs/twitter-fill.svg'
|
||||
import LightningIcon from '../svgs/bolt.svg'
|
||||
import NostrIcon from '../svgs/nostr.svg'
|
||||
import GithubIcon from '@/svgs/github-fill.svg'
|
||||
import TwitterIcon from '@/svgs/twitter-fill.svg'
|
||||
import LightningIcon from '@/svgs/bolt.svg'
|
||||
import NostrIcon from '@/svgs/nostr.svg'
|
||||
import Button from 'react-bootstrap/Button'
|
||||
|
||||
export default function LoginButton ({ text, type, className, onClick }) {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { signIn } from 'next-auth/react'
|
||||
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 Alert from 'react-bootstrap/Alert'
|
||||
import { useRouter } from 'next/router'
|
||||
import { LightningAuthWithExplainer } from './lightning-auth'
|
||||
import NostrAuth from './nostr-auth'
|
||||
import LoginButton from './login-button'
|
||||
import { emailSchema } from '../lib/validate'
|
||||
import { emailSchema } from '@/lib/validate'
|
||||
|
||||
export function EmailLoginForm ({ text, callbackUrl }) {
|
||||
return (
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useContext } from 'react'
|
||||
import { useQuery } from '@apollo/client'
|
||||
import { ME } from '../fragments/users'
|
||||
import { SSR } from '../lib/constants'
|
||||
import { ME } from '@/fragments/users'
|
||||
import { SSR } from '@/lib/constants'
|
||||
|
||||
export const MeContext = React.createContext({
|
||||
me: null
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
||||
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 ActionDropdown from './action-dropdown'
|
||||
|
||||
|
|
|
@ -6,9 +6,9 @@ import Col from 'react-bootstrap/Col'
|
|||
import Row from 'react-bootstrap/Row'
|
||||
import { useRouter } from 'next/router'
|
||||
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 { callWithTimeout } from '../lib/nostr'
|
||||
import { callWithTimeout } from '@/lib/nostr'
|
||||
|
||||
function ExtensionError ({ message, details }) {
|
||||
return (
|
||||
|
|
|
@ -3,17 +3,17 @@ import { useQuery } from '@apollo/client'
|
|||
import Comment, { CommentSkeleton } from './comment'
|
||||
import Item from './item'
|
||||
import ItemJob from './item-job'
|
||||
import { NOTIFICATIONS } from '../fragments/notifications'
|
||||
import { NOTIFICATIONS } from '@/fragments/notifications'
|
||||
import MoreFooter from './more-footer'
|
||||
import Invite from './invite'
|
||||
import { ignoreClick } from '../lib/clicks'
|
||||
import { dayMonthYear, timeSince } from '../lib/time'
|
||||
import { ignoreClick } from '@/lib/clicks'
|
||||
import { dayMonthYear, timeSince } from '@/lib/time'
|
||||
import Link from 'next/link'
|
||||
import Check from '../svgs/check-double-line.svg'
|
||||
import HandCoin from '../svgs/hand-coin-fill.svg'
|
||||
import { LOST_BLURBS, FOUND_BLURBS, UNKNOWN_LINK_REL } from '../lib/constants'
|
||||
import CowboyHatIcon from '../svgs/cowboy.svg'
|
||||
import BaldIcon from '../svgs/bald.svg'
|
||||
import Check from '@/svgs/check-double-line.svg'
|
||||
import HandCoin from '@/svgs/hand-coin-fill.svg'
|
||||
import { LOST_BLURBS, FOUND_BLURBS, UNKNOWN_LINK_REL } from '@/lib/constants'
|
||||
import CowboyHatIcon from '@/svgs/cowboy.svg'
|
||||
import BaldIcon from '@/svgs/bald.svg'
|
||||
import { RootProvider } from './root'
|
||||
import Alert from 'react-bootstrap/Alert'
|
||||
import styles from './notifications.module.css'
|
||||
|
@ -21,14 +21,14 @@ import { useServiceWorker } from './serviceworker'
|
|||
import { Checkbox, Form } from './form'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useData } from './use-data'
|
||||
import { nostrZapDetails } from '../lib/nostr'
|
||||
import { nostrZapDetails } from '@/lib/nostr'
|
||||
import Text from './text'
|
||||
import NostrIcon from '../svgs/nostr.svg'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import BountyIcon from '../svgs/bounty-bag.svg'
|
||||
import NostrIcon from '@/svgs/nostr.svg'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import BountyIcon from '@/svgs/bounty-bag.svg'
|
||||
import { LongCountdown } from './countdown'
|
||||
import { nextBillingWithGrace } from '../lib/territory'
|
||||
import { commentSubTreeRootId } from '../lib/item'
|
||||
import { nextBillingWithGrace } from '@/lib/territory'
|
||||
import { commentSubTreeRootId } from '@/lib/item'
|
||||
|
||||
function Notification ({ n, fresh }) {
|
||||
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 () {
|
||||
return (
|
||||
|
|
|
@ -3,7 +3,7 @@ import Button from 'react-bootstrap/Button'
|
|||
import styles from './pay-bounty.module.css'
|
||||
import ActionTooltip from './action-tooltip'
|
||||
import { useMe } from './me'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import { useShowModal } from './modal'
|
||||
import { useRoot } from './root'
|
||||
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 { gql, useApolloClient, useMutation } from '@apollo/client'
|
||||
import Countdown from './countdown'
|
||||
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
||||
import { MAX_POLL_CHOICE_LENGTH, MAX_POLL_NUM_CHOICES, MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
import { datePivot } from '../lib/time'
|
||||
import { pollSchema } from '../lib/validate'
|
||||
import { MAX_POLL_CHOICE_LENGTH, MAX_POLL_NUM_CHOICES, MAX_TITLE_LENGTH } from '@/lib/constants'
|
||||
import { datePivot } from '@/lib/time'
|
||||
import { pollSchema } from '@/lib/validate'
|
||||
import { SubSelectInitial } from './sub-select'
|
||||
import { useCallback } from 'react'
|
||||
import { normalizeForwards, toastDeleteScheduled } from '../lib/form'
|
||||
import { normalizeForwards, toastDeleteScheduled } from '@/lib/form'
|
||||
import useCrossposter from './use-crossposter'
|
||||
import { useMe } from './me'
|
||||
import { useToast } from './toast'
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { gql, useMutation } from '@apollo/client'
|
||||
import Button from 'react-bootstrap/Button'
|
||||
import { fixedDecimal, numWithUnits } from '../lib/format'
|
||||
import { timeLeft } from '../lib/time'
|
||||
import { fixedDecimal, numWithUnits } from '@/lib/format'
|
||||
import { timeLeft } from '@/lib/time'
|
||||
import { useMe } from './me'
|
||||
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 ActionTooltip from './action-tooltip'
|
||||
import { POLL_COST } from '../lib/constants'
|
||||
import { POLL_COST } from '@/lib/constants'
|
||||
import { payOrLoginError, useInvoiceModal } from './invoice'
|
||||
|
||||
export default function Poll ({ item }) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import React, { useContext, useEffect, useMemo, useState } from 'react'
|
||||
import { useQuery } from '@apollo/client'
|
||||
import { fixedDecimal } from '../lib/format'
|
||||
import { fixedDecimal } from '@/lib/format'
|
||||
import { useMe } from './me'
|
||||
import { PRICE } from '../fragments/price'
|
||||
import { CURRENCY_SYMBOLS } from '../lib/currency'
|
||||
import { SSR } from '../lib/constants'
|
||||
import { PRICE } from '@/fragments/price'
|
||||
import { CURRENCY_SYMBOLS } from '@/lib/currency'
|
||||
import { SSR } from '@/lib/constants'
|
||||
import { useBlockHeight } from './block-height'
|
||||
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 { 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 Items from './items'
|
||||
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 styles from './reply.module.css'
|
||||
import { COMMENTS } from '../fragments/comments'
|
||||
import { COMMENTS } from '@/fragments/comments'
|
||||
import { useMe } from './me'
|
||||
import { forwardRef, useCallback, useEffect, useState, useRef } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { FeeButtonProvider, postCommentBaseLineItems, postCommentUseRemoteLineItems } from './fee-button'
|
||||
import { commentsViewedAfterComment } from '../lib/new-comments'
|
||||
import { commentSchema } from '../lib/validate'
|
||||
import { commentsViewedAfterComment } from '@/lib/new-comments'
|
||||
import { commentSchema } from '@/lib/validate'
|
||||
import { useToast } from './toast'
|
||||
import { toastDeleteScheduled } from '../lib/form'
|
||||
import { toastDeleteScheduled } from '@/lib/form'
|
||||
import { ItemButtonBar } from './post'
|
||||
import { useShowModal } from './modal'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import { useRoot } from './root'
|
||||
import { commentSubTreeRootId } from '../lib/item'
|
||||
import { commentSubTreeRootId } from '@/lib/item'
|
||||
|
||||
export function ReplyOnAnotherPage ({ item }) {
|
||||
const rootId = commentSubTreeRootId(item)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import Container from 'react-bootstrap/Container'
|
||||
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 { Form, Input, Select, DatePicker, SubmitButton } from './form'
|
||||
import { useRouter } from 'next/router'
|
||||
import { whenToFrom } from '../lib/time'
|
||||
import { whenToFrom } from '@/lib/time'
|
||||
|
||||
export default function Search ({ sub }) {
|
||||
const router = useRouter()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { NextSeo } from 'next-seo'
|
||||
import { useRouter } from 'next/router'
|
||||
import removeMd from 'remove-markdown'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
|
||||
export function SeoSearch ({ sub }) {
|
||||
const router = useRouter()
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
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 useCrossposter from './use-crossposter'
|
||||
import { useMe } from './me'
|
||||
import { useToast } from './toast'
|
||||
import { SSR } from '../lib/constants'
|
||||
import { commentSubTreeRootId } from '../lib/item'
|
||||
import { SSR } from '@/lib/constants'
|
||||
import { commentSubTreeRootId } from '@/lib/item'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
const referrurl = (ipath, me) => {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
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 { gql, useQuery } from '@apollo/client'
|
||||
import { datePivot } from '../lib/time'
|
||||
import { datePivot } from '@/lib/time'
|
||||
|
||||
export default function Snl ({ ignorePreference }) {
|
||||
const [show, setShow] = useState()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useCallback, useContext, useState } from 'react'
|
||||
import { randInRange } from '../lib/rand'
|
||||
import { randInRange } from '@/lib/rand'
|
||||
|
||||
export const SnowContext = React.createContext(() => {})
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useRouter } from 'next/router'
|
||||
import { Select } from './form'
|
||||
import { SSR } from '../lib/constants'
|
||||
import { SUBS } from '../fragments/subs'
|
||||
import { SSR } from '@/lib/constants'
|
||||
import { SUBS } from '@/fragments/subs'
|
||||
import { useQuery } from '@apollo/client'
|
||||
import { useEffect, useState } from 'react'
|
||||
import styles from './sub-select.module.css'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useMemo, useState } from 'react'
|
||||
import Dropdown from 'react-bootstrap/Dropdown'
|
||||
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 { visit } from 'unist-util-visit'
|
||||
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 { useCallback, useMemo, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { MAX_TERRITORY_DESC_LENGTH, POST_TYPES, TERRITORY_BILLING_OPTIONS, TERRITORY_PERIOD_COST } from '../lib/constants'
|
||||
import { territorySchema } from '../lib/validate'
|
||||
import { MAX_TERRITORY_DESC_LENGTH, POST_TYPES, TERRITORY_BILLING_OPTIONS, TERRITORY_PERIOD_COST } from '@/lib/constants'
|
||||
import { territorySchema } from '@/lib/validate'
|
||||
import { useMe } from './me'
|
||||
import Info from './info'
|
||||
import { abbrNum } from '../lib/format'
|
||||
import { purchasedType } from '../lib/territory'
|
||||
import { SUB } from '../fragments/subs'
|
||||
import { abbrNum } from '@/lib/format'
|
||||
import { purchasedType } from '@/lib/territory'
|
||||
import { SUB } from '@/fragments/subs'
|
||||
|
||||
export default function TerritoryForm ({ sub }) {
|
||||
const router = useRouter()
|
||||
|
|
|
@ -3,7 +3,7 @@ import { AccordianCard } from './accordian-item'
|
|||
import TerritoryPaymentDue, { TerritoryBillingLine } from './territory-payment-due'
|
||||
import Link from 'next/link'
|
||||
import Text from './text'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import styles from './item.module.css'
|
||||
import Hat from './hat'
|
||||
import { useMe } from './me'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Link from 'next/link'
|
||||
import { abbrNum, numWithUnits } from '../lib/format'
|
||||
import { abbrNum, numWithUnits } from '@/lib/format'
|
||||
import styles from './item.module.css'
|
||||
import React, { useEffect, useMemo, useState } from 'react'
|
||||
import { useQuery } from '@apollo/client'
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { Alert } from 'react-bootstrap'
|
||||
import { useMe } from './me'
|
||||
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 { timeSince } from '../lib/time'
|
||||
import { timeSince } from '@/lib/time'
|
||||
import { LongCountdown } from './countdown'
|
||||
import { useCallback } from 'react'
|
||||
import { useApolloClient, useMutation } from '@apollo/client'
|
||||
import { SUB_PAY } from '../fragments/subs'
|
||||
import { nextBillingWithGrace } from '../lib/territory'
|
||||
import { SUB_PAY } from '@/fragments/subs'
|
||||
import { nextBillingWithGrace } from '@/lib/territory'
|
||||
|
||||
export default function TerritoryPaymentDue ({ sub }) {
|
||||
const me = useMe()
|
||||
|
|
|
@ -3,7 +3,7 @@ import { useShowModal } from './modal'
|
|||
import { useToast } from './toast'
|
||||
import { Button, Dropdown, InputGroup } from 'react-bootstrap'
|
||||
import { Form, InputUserSuggest, SubmitButton } from './form'
|
||||
import { territoryTransferSchema } from '../lib/validate'
|
||||
import { territoryTransferSchema } from '@/lib/validate'
|
||||
import { useCallback } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { useMe } from './me'
|
||||
|
|
|
@ -4,22 +4,22 @@ import YouTube from 'react-youtube'
|
|||
import gfm from 'remark-gfm'
|
||||
import { LightAsync as SyntaxHighlighter } from 'react-syntax-highlighter'
|
||||
import atomDark from 'react-syntax-highlighter/dist/cjs/styles/prism/atom-dark'
|
||||
import mention from '../lib/remark-mention'
|
||||
import sub from '../lib/remark-sub'
|
||||
import mention from '@/lib/remark-mention'
|
||||
import sub from '@/lib/remark-sub'
|
||||
import React, { useState, memo, useRef, useCallback, useMemo, useEffect } from 'react'
|
||||
import GithubSlugger from 'github-slugger'
|
||||
import LinkIcon from '../svgs/link.svg'
|
||||
import Thumb from '../svgs/thumb-up-fill.svg'
|
||||
import LinkIcon from '@/svgs/link.svg'
|
||||
import Thumb from '@/svgs/thumb-up-fill.svg'
|
||||
import { toString } from 'mdast-util-to-string'
|
||||
import copy from 'clipboard-copy'
|
||||
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 { rehypeInlineCodeProperty } from '../lib/md'
|
||||
import { rehypeInlineCodeProperty } from '@/lib/md'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import { useRouter } from 'next/router'
|
||||
import Link from 'next/link'
|
||||
import { UNKNOWN_LINK_REL } from '../lib/constants'
|
||||
import { UNKNOWN_LINK_REL } from '@/lib/constants'
|
||||
import isEqual from 'lodash/isEqual'
|
||||
|
||||
export function SearchText ({ text }) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useRouter } from 'next/router'
|
||||
import { Form, Select, DatePicker } from './form'
|
||||
import { ITEM_SORTS, SUB_SORTS, USER_SORTS, WHENS } from '../lib/constants'
|
||||
import { whenToFrom } from '../lib/time'
|
||||
import { ITEM_SORTS, SUB_SORTS, USER_SORTS, WHENS } from '@/lib/constants'
|
||||
import { whenToFrom } from '@/lib/time'
|
||||
|
||||
export default function TopHeader ({ sub, cat }) {
|
||||
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 { gql, useMutation } from '@apollo/client'
|
||||
import ActionTooltip from './action-tooltip'
|
||||
import ItemAct, { useAct, useZap } from './item-act'
|
||||
import { useMe } from './me'
|
||||
import getColor from '../lib/rainbow'
|
||||
import getColor from '@/lib/rainbow'
|
||||
import { useCallback, useMemo, useRef, useState } from 'react'
|
||||
import LongPressable from 'react-longpressable'
|
||||
import Overlay from 'react-bootstrap/Overlay'
|
||||
import Popover from 'react-bootstrap/Popover'
|
||||
import { useShowModal } from './modal'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import { Dropdown } from 'react-bootstrap'
|
||||
|
||||
const UpvotePopover = ({ target, show, handleClose }) => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useRouter } from 'next/router'
|
||||
import { Select, DatePicker } from './form'
|
||||
import { WHENS } from '../lib/constants'
|
||||
import { whenToFrom } from '../lib/time'
|
||||
import { WHENS } from '@/lib/constants'
|
||||
import { whenToFrom } from '@/lib/time'
|
||||
|
||||
export function UsageHeader () {
|
||||
const router = useRouter()
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { useCallback } from 'react'
|
||||
import { useToast } from './toast'
|
||||
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 { SETTINGS } from '../fragments/users'
|
||||
import { ITEM_FULL_FIELDS, POLL_FIELDS } from '../fragments/items'
|
||||
import { SETTINGS } from '@/fragments/users'
|
||||
import { ITEM_FULL_FIELDS, POLL_FIELDS } from '@/fragments/items'
|
||||
|
||||
async function discussionToEvent (item) {
|
||||
const createdAt = Math.floor(Date.now() / 1000)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 }) {
|
||||
const ref = useRef(null)
|
||||
|
|
|
@ -9,26 +9,26 @@ import { Form, Input, SubmitButton } from './form'
|
|||
import { gql, useApolloClient, useMutation } from '@apollo/client'
|
||||
import styles from './user-header.module.css'
|
||||
import { useMe } from './me'
|
||||
import { NAME_MUTATION } from '../fragments/users'
|
||||
import { NAME_MUTATION } from '@/fragments/users'
|
||||
import QRCode from 'qrcode.react'
|
||||
import LightningIcon from '../svgs/bolt.svg'
|
||||
import { encodeLNUrl } from '../lib/lnurl'
|
||||
import LightningIcon from '@/svgs/bolt.svg'
|
||||
import { encodeLNUrl } from '@/lib/lnurl'
|
||||
import Avatar from './avatar'
|
||||
import { userSchema } from '../lib/validate'
|
||||
import { userSchema } from '@/lib/validate'
|
||||
import { useShowModal } from './modal'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import Hat from './hat'
|
||||
import SubscribeUserDropdownItem from './subscribeUser'
|
||||
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 copy from 'clipboard-copy'
|
||||
import { useToast } from './toast'
|
||||
import { hexToBech32 } from '../lib/nostr'
|
||||
import NostrIcon from '../svgs/nostr.svg'
|
||||
import GithubIcon from '../svgs/github-fill.svg'
|
||||
import TwitterIcon from '../svgs/twitter-fill.svg'
|
||||
import { UNKNOWN_LINK_REL, MEDIA_URL } from '../lib/constants'
|
||||
import { hexToBech32 } from '@/lib/nostr'
|
||||
import NostrIcon from '@/svgs/nostr.svg'
|
||||
import GithubIcon from '@/svgs/github-fill.svg'
|
||||
import TwitterIcon from '@/svgs/twitter-fill.svg'
|
||||
import { UNKNOWN_LINK_REL, MEDIA_URL } from '@/lib/constants'
|
||||
|
||||
export default function UserHeader ({ user }) {
|
||||
const router = useRouter()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Link from 'next/link'
|
||||
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 userStyles from './user-header.module.css'
|
||||
import React, { useEffect, useMemo, useState } from 'react'
|
||||
|
@ -9,7 +9,7 @@ import MoreFooter from './more-footer'
|
|||
import { useData } from './use-data'
|
||||
import Hat from './hat'
|
||||
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
|
||||
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 styles from '../styles/wallet.module.css'
|
||||
import Plug from '../svgs/plug.svg'
|
||||
import Gear from '../svgs/settings-5-fill.svg'
|
||||
import styles from '@/styles/wallet.module.css'
|
||||
import Plug from '@/svgs/plug.svg'
|
||||
import Gear from '@/svgs/settings-5-fill.svg'
|
||||
import Link from 'next/link'
|
||||
import CancelButton from './cancel-button'
|
||||
import { SubmitButton } from './form'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { createContext, useCallback, useContext, useEffect, useState } from 'react'
|
||||
import { LNbitsProvider, useLNbits } from './lnbits'
|
||||
import { NWCProvider, useNWC } from './nwc'
|
||||
import { useToast, withToastFlow } from '../toast'
|
||||
import { useToast, withToastFlow } from '@/components/toast'
|
||||
import { gql, useMutation } from '@apollo/client'
|
||||
|
||||
const WebLNContext = createContext({})
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react'
|
||||
import { Relay, finalizeEvent, nip04 } from 'nostr-tools'
|
||||
import { parseNwcUrl } from '../../lib/url'
|
||||
import { parseNwcUrl } from '@/lib/url'
|
||||
|
||||
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_TITLE = 'stacker news'
|
||||
|
|
|
@ -7,8 +7,8 @@ import {
|
|||
import { SUPPORTED_CURRENCIES } from './currency'
|
||||
import { NOSTR_MAX_RELAY_NUM, NOSTR_PUBKEY_BECH32, NOSTR_PUBKEY_HEX } from './nostr'
|
||||
import { msatsToSats, numWithUnits, abbrNum, ensureB64 } from './format'
|
||||
import * as usersFragments from '../fragments/users'
|
||||
import * as subsFragments from '../fragments/subs'
|
||||
import * as usersFragments from '@/fragments/users'
|
||||
import * as subsFragments from '@/fragments/subs'
|
||||
import { isInvoicableMacaroon, isInvoiceMacaroon } from './macaroon'
|
||||
import { parseNwcUrl } from './url'
|
||||
import { datePivot } from './time'
|
||||
|
|
|
@ -2,7 +2,7 @@ import webPush from 'web-push'
|
|||
import removeMd from 'remove-markdown'
|
||||
import { ANON_USER_ID, COMMENT_DEPTH_LIMIT, FOUND_BLURBS, LOST_BLURBS } from './constants'
|
||||
import { msatsToSats, numWithUnits } from './format'
|
||||
import models from '../api/models'
|
||||
import models from '@/api/models'
|
||||
|
||||
const webPushEnabled = process.env.NODE_ENV === 'production' ||
|
||||
(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,
|
||||
item,
|
||||
tag: 'MENTION'
|
||||
}).catch(console.error)
|
||||
})
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
|
@ -258,7 +258,15 @@ export const notifyMention = async (userId, item) => {
|
|||
|
||||
export const notifyReferral = async (userId) => {
|
||||
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) {
|
||||
console.error(err)
|
||||
}
|
||||
|
@ -315,7 +323,7 @@ export async function notifyNewStreak (userId, streak) {
|
|||
title: 'you found a cowboy hat',
|
||||
body: blurb,
|
||||
tag: 'STREAK-FOUND'
|
||||
}).catch(console.error)
|
||||
})
|
||||
} catch (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