update packages and reduce bundle size
This commit is contained in:
parent
356f7e072c
commit
e87610c45b
|
@ -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'
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
|
@ -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'>
|
||||
|
|
|
@ -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 (
|
||||
<>
|
||||
|
|
106
lib/validate.js
106
lib/validate.js
|
@ -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()
|
||||
})
|
||||
|
|
File diff suppressed because it is too large
Load Diff
60
package.json
60
package.json
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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!)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue