update packages and reduce bundle size

This commit is contained in:
keyan 2023-07-24 17:50:12 -05:00
parent 356f7e072c
commit e87610c45b
10 changed files with 1987 additions and 2610 deletions

View File

@ -1,6 +1,6 @@
import { ApolloClient, InMemoryCache } from '@apollo/client'
import { SchemaLink } from '@apollo/client/link/schema'
import { makeExecutableSchema } from 'graphql-tools'
import { makeExecutableSchema } from '@graphql-tools/schema'
import { getSession } from 'next-auth/client'
import resolvers from './resolvers'
import typeDefs from './typeDefs'

View File

@ -9,6 +9,9 @@ import { Bar } from 'recharts/lib/cartesian/Bar'
import { Tooltip } from 'recharts/lib/component/Tooltip'
import { Legend } from 'recharts/lib/component/Legend'
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 { useRouter } from 'next/router'
@ -169,3 +172,29 @@ export function WhenComposedChart ({ data, lineNames, areaNames, barNames }) {
</ResponsiveContainer>
)
}
export function GrowthPieChart ({ data }) {
return (
<ResponsiveContainer width='100%' height={250} minWidth={200}>
<PieChart margin={{ top: 5, right: 5, bottom: 5, left: 5 }}>
<Pie
dataKey='value'
isAnimationActive={false}
data={data}
cx='50%'
cy='50%'
outerRadius={80}
fill='var(--bs-secondary)'
label
>
{
data.map((entry, index) => (
<Cell key={`cell-${index}`} fill={COLORS[index]} />
))
}
</Pie>
<Tooltip />
</PieChart>
</ResponsiveContainer>
)
}

View File

@ -46,9 +46,11 @@ export default function FeeButton ({ parentId, hasImgLink, baseFee, ChildButton,
const { data } = useQuery(query, { pollInterval: 1000, nextFetchPolicy: 'cache-and-network' })
const repetition = data?.itemRepetition || 0
const formik = useFormikContext()
const boost = formik?.values?.boost || 0
const boost = Number(formik?.values?.boost) || 0
const cost = baseFee * (hasImgLink ? 10 : 1) * Math.pow(10, repetition) + Number(boost)
console.log('cost', cost, 'baseFee', baseFee, repetition, hasImgLink, boost)
const show = alwaysShow || !formik?.isSubmitting
return (
<div className='d-flex align-items-center'>

View File

@ -1,4 +1,4 @@
import * as Yup from 'yup'
import { string } from 'yup'
import Toc from './table-of-contents'
import Badge from 'react-bootstrap/Badge'
import Button from 'react-bootstrap/Button'
@ -12,7 +12,7 @@ import Share from './share'
import CowboyHat from './cowboy-hat'
export default function ItemJob ({ item, toc, rank, children }) {
const isEmail = Yup.string().email().isValidSync(item.url)
const isEmail = string().email().isValidSync(item.url)
return (
<>

View File

@ -1,4 +1,4 @@
import * as Yup from 'yup'
import { string, ValidationError, number, object, array, addMethod } from 'yup'
import { BOOST_MIN, MAX_POLL_CHOICE_LENGTH, MAX_TITLE_LENGTH, MAX_POLL_NUM_CHOICES, MIN_POLL_NUM_CHOICES, SUBS_NO_JOBS } from './constants'
import { NAME_QUERY } from '../fragments/users'
import { URL_REGEXP, WS_REGEXP } from './url'
@ -13,14 +13,14 @@ export async function ssValidate (schema, data, ...args) {
await schema.validate(data)
}
} catch (e) {
if (e instanceof Yup.ValidationError) {
if (e instanceof ValidationError) {
throw new Error(`${e.path}: ${e.message}`)
}
throw e
}
}
Yup.addMethod(Yup.string, 'or', function (schemas, msg) {
addMethod(string, 'or', function (schemas, msg) {
return this.test({
name: 'or',
message: msg,
@ -36,12 +36,12 @@ Yup.addMethod(Yup.string, 'or', function (schemas, msg) {
})
})
const titleValidator = Yup.string().required('required').trim().max(
const titleValidator = string().required('required').trim().max(
MAX_TITLE_LENGTH,
({ max, value }) => `${Math.abs(max - value.length)} too many`
)
const intValidator = Yup.number().typeError('must be a number').integer('must be whole')
const intValidator = number().typeError('must be a number').integer('must be whole')
async function usernameExists (client, name) {
if (!client) {
@ -70,7 +70,7 @@ export function advPostSchemaMembers (client) {
},
message: `must be divisble be ${BOOST_MIN}`
}),
forward: Yup.string()
forward: string()
.test({
name: 'name',
test: async name => {
@ -84,12 +84,12 @@ export function advPostSchemaMembers (client) {
export function subSelectSchemaMembers (client) {
return {
sub: Yup.string().required('required').oneOf(SUBS_NO_JOBS, 'required')
sub: string().required('required').oneOf(SUBS_NO_JOBS, 'required')
}
}
export function bountySchema (client) {
return Yup.object({
return object({
title: titleValidator,
bounty: intValidator
.min(1000, 'must be at least 1000')
@ -100,7 +100,7 @@ export function bountySchema (client) {
}
export function discussionSchema (client) {
return Yup.object({
return object({
title: titleValidator,
...advPostSchemaMembers(client),
...subSelectSchemaMembers()
@ -108,19 +108,19 @@ export function discussionSchema (client) {
}
export function linkSchema (client) {
return Yup.object({
return object({
title: titleValidator,
url: Yup.string().matches(URL_REGEXP, 'invalid url').required('required'),
url: string().matches(URL_REGEXP, 'invalid url').required('required'),
...advPostSchemaMembers(client),
...subSelectSchemaMembers()
})
}
export function pollSchema (client, numExistingChoices = 0) {
return Yup.object({
return object({
title: titleValidator,
options: Yup.array().of(
Yup.string().trim().test('my-test', 'required', function (value) {
options: array().of(
string().trim().test('my-test', 'required', function (value) {
return (this.path !== 'options[0]' && this.path !== 'options[1]') || value
}).max(MAX_POLL_CHOICE_LENGTH,
({ max, value }) => `${Math.abs(max - value.length)} too many characters`
@ -138,8 +138,8 @@ export function pollSchema (client, numExistingChoices = 0) {
}
export function userSchema (client) {
return Yup.object({
name: Yup.string()
return object({
name: string()
.required('required')
.matches(/^[\w_]+$/, 'only letters, numbers, and _')
.max(32, 'too long')
@ -154,85 +154,85 @@ export function userSchema (client) {
})
}
export const commentSchema = Yup.object({
text: Yup.string().required('required').trim()
export const commentSchema = object({
text: string().required('required').trim()
})
export const jobSchema = Yup.object({
export const jobSchema = object({
title: titleValidator,
company: Yup.string().required('required').trim(),
text: Yup.string().required('required').trim(),
url: Yup.string()
.or([Yup.string().email(), Yup.string().url()], 'invalid url or email')
company: string().required('required').trim(),
text: string().required('required').trim(),
url: string()
.or([string().email(), string().url()], 'invalid url or email')
.required('required'),
maxBid: intValidator.min(0, 'must be at least 0').required('required'),
location: Yup.string().test(
location: string().test(
'no-remote',
"don't write remote, just check the box",
v => !v?.match(/\bremote\b/gi))
.when('remote', {
is: (value) => !value,
then: Yup.string().required('required').trim()
then: string().required('required').trim()
})
})
export const emailSchema = Yup.object({
email: Yup.string().email('email is no good').required('required')
export const emailSchema = object({
email: string().email('email is no good').required('required')
})
export const urlSchema = Yup.object({
url: Yup.string().matches(URL_REGEXP, 'invalid url').required('required')
export const urlSchema = object({
url: string().matches(URL_REGEXP, 'invalid url').required('required')
})
export const namedUrlSchema = Yup.object({
text: Yup.string().required('required').trim(),
url: Yup.string().matches(URL_REGEXP, 'invalid url').required('required')
export const namedUrlSchema = object({
text: string().required('required').trim(),
url: string().matches(URL_REGEXP, 'invalid url').required('required')
})
export const amountSchema = Yup.object({
export const amountSchema = object({
amount: intValidator.required('required').positive('must be positive')
})
export const settingsSchema = Yup.object({
export const settingsSchema = object({
tipDefault: intValidator.required('required').positive('must be positive'),
fiatCurrency: Yup.string().required('required').oneOf(SUPPORTED_CURRENCIES),
nostrPubkey: Yup.string().nullable()
fiatCurrency: string().required('required').oneOf(SUPPORTED_CURRENCIES),
nostrPubkey: string().nullable()
.or([
Yup.string().nullable().matches(NOSTR_PUBKEY_HEX, 'must be 64 hex chars'),
Yup.string().nullable().matches(NOSTR_PUBKEY_BECH32, 'invalid bech32 encoding')], 'invalid pubkey'),
nostrRelays: Yup.array().of(
Yup.string().matches(WS_REGEXP, 'invalid web socket address')
string().nullable().matches(NOSTR_PUBKEY_HEX, 'must be 64 hex chars'),
string().nullable().matches(NOSTR_PUBKEY_BECH32, 'invalid bech32 encoding')], 'invalid pubkey'),
nostrRelays: array().of(
string().matches(WS_REGEXP, 'invalid web socket address')
).max(NOSTR_MAX_RELAY_NUM,
({ max, value }) => `${Math.abs(max - value.length)} too many`)
})
const warningMessage = 'If I logout, even accidentally, I will never be able to access my account again'
export const lastAuthRemovalSchema = Yup.object({
warning: Yup.string().matches(warningMessage, 'does not match').required('required')
export const lastAuthRemovalSchema = object({
warning: string().matches(warningMessage, 'does not match').required('required')
})
export const withdrawlSchema = Yup.object({
invoice: Yup.string().required('required').trim(),
export const withdrawlSchema = object({
invoice: string().required('required').trim(),
maxFee: intValidator.required('required').min(0, 'must be at least 0')
})
export const lnAddrSchema = Yup.object({
addr: Yup.string().email('address is no good').required('required'),
export const lnAddrSchema = object({
addr: string().email('address is no good').required('required'),
amount: intValidator.required('required').positive('must be positive'),
maxFee: intValidator.required('required').min(0, 'must be at least 0')
})
export const bioSchema = Yup.object({
bio: Yup.string().required('required').trim()
export const bioSchema = object({
bio: string().required('required').trim()
})
export const inviteSchema = Yup.object({
export const inviteSchema = object({
gift: intValidator.positive('must be greater than 0').required('required'),
limit: intValidator.positive('must be positive')
})
export const pushSubscriptionSchema = Yup.object({
endpoint: Yup.string().url().required('required').trim(),
p256dh: Yup.string().required('required').trim(),
auth: Yup.string().required('required').trim()
export const pushSubscriptionSchema = object({
endpoint: string().url().required('required').trim(),
p256dh: string().required('required').trim(),
auth: string().required('required').trim()
})

4333
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,79 +10,75 @@
},
"dependencies": {
"@apollo/client": "^3.7.17",
"@apollo/server": "^4.7.5",
"@apollo/server": "^4.8.1",
"@as-integrations/next": "^2.0.1",
"@graphql-tools/schema": "^10.0.0",
"@noble/secp256k1": "^1.7.1",
"@opensearch-project/opensearch": "^1.1.0",
"@opensearch-project/opensearch": "^2.3.1",
"@prisma/client": "^2.30.3",
"@synonymdev/slashtags-auth": "^1.0.0-alpha.5",
"@synonymdev/slashtags-sdk": "^1.0.0-alpha.36",
"acorn": "^8.10.0",
"ajv": "^8.12.0",
"async-retry": "^1.3.1",
"aws-sdk": "^2.1248.0",
"babel-plugin-inline-react-svg": "^2.0.1",
"aws-sdk": "^2.1421.0",
"babel-plugin-inline-react-svg": "^2.0.2",
"bech32": "^2.0.0",
"bolt11": "^1.4.0",
"bolt11": "^1.4.1",
"bootstrap": "^5.3.0",
"browserslist": "^4.21.4",
"canonical-json": "0.0.4",
"clipboard-copy": "^4.0.1",
"cross-fetch": "^3.1.5",
"cross-fetch": "^3.1.8",
"domino": "^2.1.6",
"eslint-config-next": "^13.4.10",
"formik": "^2.2.6",
"eslint-config-next": "^13.4.12",
"formik": "^2.4.2",
"github-slugger": "^1.5.0",
"graphql": "^16.7.1",
"graphql-tag": "^2.12.6",
"graphql-tools": "^8.3.10",
"graphql-type-json": "^0.3.2",
"jquery": "^3.6.1",
"ln-service": "^54.2.6",
"mathjs": "^11.8.2",
"ln-service": "^56.9.0",
"mathjs": "^11.9.1",
"mdast-util-find-and-replace": "^1.1.1",
"mdast-util-from-markdown": "^1.2.0",
"mdast-util-to-string": "^3.1.0",
"next": "^13.4.10",
"mdast-util-from-markdown": "^1.3.1",
"mdast-util-to-string": "^3.2.0",
"next": "^13.4.12",
"next-auth": "^3.29.10",
"next-plausible": "^3.10.1",
"next-seo": "^4.29.0",
"nextjs-progressbar": "0.0.16",
"node-s3-url-encode": "^0.0.4",
"nostr": "^0.2.7",
"nostr": "^0.2.8",
"opentimestamps": "^0.4.9",
"page-metadata-parser": "^1.1.4",
"pageres": "^7.1.0",
"pg-boss": "^7.4.0",
"popper.js": "^1.16.1",
"pg-boss": "^9.0.3",
"prisma": "^2.30.3",
"qrcode.react": "^3.1.0",
"react": "^18.2.0",
"react-avatar-editor": "^13.0.0",
"react-bootstrap": "^2.8.0",
"react-countdown": "^2.3.3",
"react-countdown": "^2.3.5",
"react-dom": "^18.2.0",
"react-longpressable": "^1.1.1",
"react-markdown": "^8.0.7",
"react-string-replace": "^0.4.4",
"react-syntax-highlighter": "^15.5.0",
"react-textarea-autosize": "^8.3.4",
"react-textarea-autosize": "^8.5.2",
"react-twitter-embed": "^4.0.4",
"react-youtube": "^7.14.0",
"recharts": "^2.1.16",
"recharts": "^2.7.2",
"remark-directive": "^2.0.1",
"remark-gfm": "^3.0.1",
"remove-markdown": "^0.3.0",
"sass": "^1.56.0",
"sass": "^1.64.1",
"secp256k1": "^4.0.3",
"swr": "^1.3.0",
"tldts": "^5.7.104",
"tldts": "^5.7.112",
"typescript": "^5.1.6",
"unist-util-visit": "^4.1.1",
"unist-util-visit": "^4.1.2",
"url-unshort": "^6.1.0",
"uuid": "^8.3.2",
"web-push": "^3.6.2",
"webln": "^0.2.2",
"webln": "^0.3.2",
"webpack": "^5.88.2",
"workbox-precaching": "^7.0.0",
"workbox-recipes": "^7.0.0",
@ -90,7 +86,7 @@
"workbox-strategies": "^7.0.0",
"workbox-webpack-plugin": "^7.0.0",
"workbox-window": "^7.0.0",
"yup": "^0.32.11"
"yup": "^1.2.0"
},
"engines": {
"node": "16.16.0"
@ -108,10 +104,10 @@
}
},
"devDependencies": {
"@babel/core": "^7.20.2",
"@babel/eslint-parser": "^7.19.1",
"eslint": "^7.32.0",
"@babel/core": "^7.22.9",
"@babel/eslint-parser": "^7.22.9",
"eslint": "^8.45.0",
"eslint-plugin-compat": "^4.1.4",
"standard": "^16.0.4"
"standard": "^17.1.0"
}
}

View File

@ -5,10 +5,14 @@ import { getGetServerSideProps } from '../../api/ssrApollo'
import { CopyInput, Form, Select } from '../../components/form'
import { CenterLayout } from '../../components/layout'
import { useMe } from '../../components/me'
import { WhenComposedChart } from '../../components/when-charts'
import { useQuery } from '@apollo/client'
import PageLoading from '../../components/page-loading'
import { WHENS } from '../../lib/constants'
import dynamic from 'next/dynamic'
const WhenComposedChart = dynamic(() => import('../../components/charts').then(mod => mod.WhenComposedChart), {
loading: () => <div>Loading...</div>
})
const REFERRALS = gql`
query Referrals($when: String!)

View File

@ -17,6 +17,11 @@ import Countdown from 'react-countdown'
import { abbrNum } from '../lib/format'
import PageLoading from '../components/page-loading'
import { useShowModal } from '../components/modal'
import dynamic from 'next/dynamic'
const GrowthPieChart = dynamic(() => import('../components/charts').then(mod => mod.GrowthPieChart), {
loading: () => <div>Loading...</div>
})
const REWARDS = gql`
{
@ -97,32 +102,6 @@ const COLORS = [
'var(--bs-grey)'
]
function GrowthPieChart ({ data }) {
return (
<ResponsiveContainer width='100%' height={250} minWidth={200}>
<PieChart margin={{ top: 5, right: 5, bottom: 5, left: 5 }}>
<Pie
dataKey='value'
isAnimationActive={false}
data={data}
cx='50%'
cy='50%'
outerRadius={80}
fill='var(--bs-secondary)'
label
>
{
data.map((entry, index) => (
<Cell key={`cell-${index}`} fill={COLORS[index]} />
))
}
</Pie>
<Tooltip />
</PieChart>
</ResponsiveContainer>
)
}
export function DonateButton () {
const showModal = useShowModal()
const [donateToRewards] = useMutation(

View File

@ -4,8 +4,15 @@ import Layout from '../../components/layout'
import Col from 'react-bootstrap/Col'
import Row from 'react-bootstrap/Row'
import { UsageHeader } from '../../components/usage-header'
import { WhenLineChart, WhenAreaChart } from '../../components/when-charts'
import { useRouter } from 'next/router'
import dynamic from "next/dynamic"
const WhenAreaChart = dynamic(() => import('../../components/charts').then(mod => mod.WhenAreaChart), {
loading: () => <div>Loading...</div>
});
const WhenLineChart = dynamic(() => import('../../components/charts').then(mod => mod.WhenLineChart), {
loading: () => <div>Loading...</div>
});
export const getServerSideProps = getGetServerSideProps(
gql`
@ -61,37 +68,38 @@ export default function Growth ({
const router = useRouter()
const { when } = router.query
const avg = ['year', 'forever'].includes(when) ? 'avg daily ' : ''
return (
<Layout>
<UsageHeader />
<Row>
<Col className='mt-3'>
<div className='text-center text-muted fw-bold'>{avg}stackers</div>
<WhenLineChart data={stackerGrowth} />
<WhenLineChart data={stackerGrowth} />
</Col>
<Col className='mt-3'>
<div className='text-center text-muted fw-bold'>stacking</div>
<WhenAreaChart data={stackingGrowth} />
<WhenAreaChart data={stackingGrowth} />
</Col>
</Row>
<Row>
<Col className='mt-3'>
<div className='text-center text-muted fw-bold'>{avg}spenders</div>
<WhenLineChart data={spenderGrowth} />
<WhenLineChart data={spenderGrowth} />
</Col>
<Col className='mt-3'>
<div className='text-center text-muted fw-bold'>spending</div>
<WhenAreaChart data={spendingGrowth} />
<WhenAreaChart data={spendingGrowth} />
</Col>
</Row>
<Row>
<Col className='mt-3'>
<div className='text-center text-muted fw-bold'>registrations</div>
<WhenAreaChart data={registrationGrowth} />
<WhenAreaChart data={registrationGrowth} />
</Col>
<Col className='mt-3'>
<div className='text-center text-muted fw-bold'>items</div>
<WhenAreaChart data={itemGrowth} />
<WhenAreaChart data={itemGrowth} />
</Col>
</Row>
</Layout>