add usage mvp usage charts
This commit is contained in:
parent
ddcb501267
commit
f024cd39a2
|
@ -0,0 +1,38 @@
|
|||
const PLACEHOLDERS_NUM = 616
|
||||
|
||||
export default {
|
||||
Query: {
|
||||
registrationGrowth: async (parent, args, { models }) => {
|
||||
return await models.$queryRaw(
|
||||
`SELECT date_trunc('month', created_at) AS time, count(*) as num
|
||||
FROM users
|
||||
WHERE id > ${PLACEHOLDERS_NUM} AND date_trunc('month', now_utc()) <> date_trunc('month', created_at)
|
||||
GROUP BY time
|
||||
ORDER BY time ASC`)
|
||||
},
|
||||
activeGrowth: async (parent, args, { models }) => {
|
||||
return await models.$queryRaw(
|
||||
`SELECT date_trunc('month', created_at) AS time, count(DISTINCT "userId") as num
|
||||
FROM "ItemAct"
|
||||
WHERE date_trunc('month', now_utc()) <> date_trunc('month', created_at)
|
||||
GROUP BY time
|
||||
ORDER BY time ASC`)
|
||||
},
|
||||
itemGrowth: async (parent, args, { models }) => {
|
||||
return await models.$queryRaw(
|
||||
`SELECT date_trunc('month', created_at) AS time, count(*) as num
|
||||
FROM "Item"
|
||||
WHERE date_trunc('month', now_utc()) <> date_trunc('month', created_at)
|
||||
GROUP BY time
|
||||
ORDER BY time ASC`)
|
||||
},
|
||||
spentGrowth: async (parent, args, { models }) => {
|
||||
return await models.$queryRaw(
|
||||
`SELECT date_trunc('month', created_at) AS time, sum(sats) as num
|
||||
FROM "ItemAct"
|
||||
WHERE date_trunc('month', now_utc()) <> date_trunc('month', created_at)
|
||||
GROUP BY time
|
||||
ORDER BY time ASC`)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,8 @@ import notifications from './notifications'
|
|||
import invite from './invite'
|
||||
import sub from './sub'
|
||||
import upload from './upload'
|
||||
import growth from './growth'
|
||||
import { GraphQLJSONObject } from 'graphql-type-json'
|
||||
|
||||
export default [user, item, message, wallet, lnurl, notifications, invite, sub,
|
||||
upload, { JSONObject: GraphQLJSONObject }]
|
||||
upload, growth, { JSONObject: GraphQLJSONObject }]
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import { gql } from 'apollo-server-micro'
|
||||
|
||||
export default gql`
|
||||
extend type Query {
|
||||
registrationGrowth: [TimeNum!]!
|
||||
activeGrowth: [TimeNum!]!
|
||||
itemGrowth: [TimeNum!]!
|
||||
spentGrowth: [TimeNum!]!
|
||||
}
|
||||
|
||||
type TimeNum {
|
||||
time: String!
|
||||
num: Int!
|
||||
}
|
||||
`
|
|
@ -9,6 +9,7 @@ import notifications from './notifications'
|
|||
import invite from './invite'
|
||||
import sub from './sub'
|
||||
import upload from './upload'
|
||||
import growth from './growth'
|
||||
|
||||
const link = gql`
|
||||
type Query {
|
||||
|
@ -25,4 +26,4 @@ const link = gql`
|
|||
`
|
||||
|
||||
export default [link, user, item, message, wallet, lnurl, notifications, invite,
|
||||
sub, upload]
|
||||
sub, upload, growth]
|
||||
|
|
|
@ -86,6 +86,25 @@ const ChatPopover = (
|
|||
</Popover>
|
||||
)
|
||||
|
||||
const AnalyticsPopover = (
|
||||
<Popover>
|
||||
<Popover.Content style={{ fontWeight: 500, fontSize: '.9rem' }}>
|
||||
<a
|
||||
href='https://plausible.io/stacker.news' className='text-dark d-inline-flex'
|
||||
target='_blank' rel='noreferrer'
|
||||
>
|
||||
visitors
|
||||
</a>
|
||||
<span className='mx-2 text-dark'> \ </span>
|
||||
<Link href='/usage' passHref>
|
||||
<a className='text-dark d-inline-flex'>
|
||||
usage
|
||||
</a>
|
||||
</Link>
|
||||
</Popover.Content>
|
||||
</Popover>
|
||||
)
|
||||
|
||||
export default function Footer ({ noLinks }) {
|
||||
const query = gql`
|
||||
{
|
||||
|
@ -129,12 +148,11 @@ export default function Footer ({ noLinks }) {
|
|||
</a>
|
||||
</Link>
|
||||
<span className='mx-2 text-muted'> \ </span>
|
||||
<a
|
||||
href='https://plausible.io/stacker.news' className='nav-link p-0 d-inline-flex'
|
||||
target='_blank' rel='noreferrer'
|
||||
>
|
||||
<OverlayTrigger trigger='click' placement='top' overlay={AnalyticsPopover} rootClose>
|
||||
<div className='nav-link p-0 d-inline-flex' style={{ cursor: 'pointer' }}>
|
||||
analytics
|
||||
</a>
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
<span className='mx-2 text-muted'> \ </span>
|
||||
<OverlayTrigger trigger='click' placement='top' overlay={ChatPopover} rootClose>
|
||||
<div className='nav-link p-0 d-inline-flex' style={{ cursor: 'pointer' }}>
|
||||
|
|
|
@ -990,6 +990,11 @@
|
|||
"form-data": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"@types/resize-observer-browser": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/resize-observer-browser/-/resize-observer-browser-0.1.7.tgz",
|
||||
"integrity": "sha512-G9eN0Sn0ii9PWQ3Vl72jDPgeJwRWhv2Qk/nQkJuWmRmOB4HX3/BhD5SE1dZs/hzPZL/WKnvF0RHdTSG54QJFyg=="
|
||||
},
|
||||
"@types/scheduler": {
|
||||
"version": "0.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
|
||||
|
@ -2656,6 +2661,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"css-unit-converter": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
|
||||
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
|
||||
},
|
||||
"css-what": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz",
|
||||
|
@ -2708,6 +2718,73 @@
|
|||
"array-find-index": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"d3-array": {
|
||||
"version": "2.12.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
|
||||
"integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
|
||||
"requires": {
|
||||
"internmap": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"d3-color": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz",
|
||||
"integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ=="
|
||||
},
|
||||
"d3-format": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz",
|
||||
"integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA=="
|
||||
},
|
||||
"d3-interpolate": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz",
|
||||
"integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==",
|
||||
"requires": {
|
||||
"d3-color": "1 - 2"
|
||||
}
|
||||
},
|
||||
"d3-path": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz",
|
||||
"integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA=="
|
||||
},
|
||||
"d3-scale": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz",
|
||||
"integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==",
|
||||
"requires": {
|
||||
"d3-array": "^2.3.0",
|
||||
"d3-format": "1 - 2",
|
||||
"d3-interpolate": "1.2.0 - 2",
|
||||
"d3-time": "^2.1.1",
|
||||
"d3-time-format": "2 - 3"
|
||||
}
|
||||
},
|
||||
"d3-shape": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-2.1.0.tgz",
|
||||
"integrity": "sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA==",
|
||||
"requires": {
|
||||
"d3-path": "1 - 2"
|
||||
}
|
||||
},
|
||||
"d3-time": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz",
|
||||
"integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==",
|
||||
"requires": {
|
||||
"d3-array": "2"
|
||||
}
|
||||
},
|
||||
"d3-time-format": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz",
|
||||
"integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==",
|
||||
"requires": {
|
||||
"d3-time": "1 - 2"
|
||||
}
|
||||
},
|
||||
"data-uri-to-buffer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz",
|
||||
|
@ -2731,6 +2808,11 @@
|
|||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
|
||||
},
|
||||
"decimal.js-light": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
|
||||
"integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="
|
||||
},
|
||||
"decode-named-character-reference": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.1.tgz",
|
||||
|
@ -3531,6 +3613,11 @@
|
|||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"fast-equals": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-2.0.4.tgz",
|
||||
"integrity": "sha512-caj/ZmjHljPrZtbzJ3kfH5ia/k4mTJe/qSiXAGzxZWRZgsgDV0cvNaQULqUX8t0/JVlzzEdYOwCN5DmzTxoD4w=="
|
||||
},
|
||||
"fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
|
@ -4244,6 +4331,11 @@
|
|||
"side-channel": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"internmap": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
|
||||
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
|
||||
},
|
||||
"invariant": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||
|
@ -6711,6 +6803,11 @@
|
|||
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
||||
"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
|
||||
},
|
||||
"performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
|
||||
},
|
||||
"pg": {
|
||||
"version": "8.7.1",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz",
|
||||
|
@ -7048,6 +7145,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"postcss-value-parser": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
|
||||
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
|
||||
},
|
||||
"postgres-array": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
|
||||
|
@ -7318,6 +7420,14 @@
|
|||
"inherits": "~2.0.3"
|
||||
}
|
||||
},
|
||||
"raf": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
||||
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
||||
"requires": {
|
||||
"performance-now": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
|
@ -7526,6 +7636,47 @@
|
|||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
|
||||
"integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg=="
|
||||
},
|
||||
"react-resize-detector": {
|
||||
"version": "6.7.8",
|
||||
"resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-6.7.8.tgz",
|
||||
"integrity": "sha512-0FaEcUBAbn+pq3PT5a9hHRebUfuS1SRLGLpIw8LydU7zX429I6XJgKerKAMPsJH0qWAl6o5bVKNqFJqr6tGPYw==",
|
||||
"requires": {
|
||||
"@types/resize-observer-browser": "^0.1.6",
|
||||
"lodash": "^4.17.21",
|
||||
"resize-observer-polyfill": "^1.5.1"
|
||||
}
|
||||
},
|
||||
"react-smooth": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.0.tgz",
|
||||
"integrity": "sha512-wK4dBBR6P21otowgMT9toZk+GngMplGS1O5gk+2WSiHEXIrQgDvhR5IIlT74Vtu//qpTcipkgo21dD7a7AUNxw==",
|
||||
"requires": {
|
||||
"fast-equals": "^2.0.0",
|
||||
"raf": "^3.4.0",
|
||||
"react-transition-group": "2.9.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"dom-helpers": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
|
||||
"integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.2"
|
||||
}
|
||||
},
|
||||
"react-transition-group": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
|
||||
"integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
|
||||
"requires": {
|
||||
"dom-helpers": "^3.4.0",
|
||||
"loose-envify": "^1.4.0",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-lifecycles-compat": "^3.0.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-string-replace": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/react-string-replace/-/react-string-replace-0.4.4.tgz",
|
||||
|
@ -7641,6 +7792,39 @@
|
|||
"picomatch": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"recharts": {
|
||||
"version": "2.1.10",
|
||||
"resolved": "https://registry.npmjs.org/recharts/-/recharts-2.1.10.tgz",
|
||||
"integrity": "sha512-me6c8m2Gs88X/nuM2gDSTDIhpSLNMbiTrlE4Cu53hjZNegT3g3xLlTrbYSAQuBCFWuWJAZXCmEuMr6AwizLyaA==",
|
||||
"requires": {
|
||||
"classnames": "^2.2.5",
|
||||
"d3-interpolate": "^2.0.0",
|
||||
"d3-scale": "^3.0.0",
|
||||
"d3-shape": "^2.0.0",
|
||||
"eventemitter3": "^4.0.1",
|
||||
"lodash": "^4.17.19",
|
||||
"react-is": "^16.10.2",
|
||||
"react-resize-detector": "^6.6.3",
|
||||
"react-smooth": "^2.0.0",
|
||||
"recharts-scale": "^0.4.4",
|
||||
"reduce-css-calc": "^2.1.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"eventemitter3": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"recharts-scale": {
|
||||
"version": "0.4.5",
|
||||
"resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz",
|
||||
"integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==",
|
||||
"requires": {
|
||||
"decimal.js-light": "^2.4.1"
|
||||
}
|
||||
},
|
||||
"redent": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
|
||||
|
@ -7660,6 +7844,15 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"reduce-css-calc": {
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
|
||||
"integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
|
||||
"requires": {
|
||||
"css-unit-converter": "^1.1.1",
|
||||
"postcss-value-parser": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"reflect-metadata": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
|
||||
|
@ -7784,6 +7977,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"resize-observer-polyfill": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
|
||||
"integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
"react-textarea-autosize": "^8.3.3",
|
||||
"react-twitter-embed": "^4.0.4",
|
||||
"react-youtube": "^7.14.0",
|
||||
"recharts": "^2.1.10",
|
||||
"remark-directive": "^2.0.1",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"remove-markdown": "^0.3.0",
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
import { gql } from '@apollo/client'
|
||||
import { getGetServerSideProps } from '../api/ssrApollo'
|
||||
import Layout from '../components/layout'
|
||||
import { LineChart, Line, XAxis, YAxis, Tooltip, Legend, ResponsiveContainer } from 'recharts'
|
||||
import { Col, Row } from 'react-bootstrap'
|
||||
import { formatSats } from '../lib/format'
|
||||
|
||||
export const getServerSideProps = getGetServerSideProps(
|
||||
gql`
|
||||
{
|
||||
registrationGrowth {
|
||||
time
|
||||
num
|
||||
}
|
||||
activeGrowth {
|
||||
time
|
||||
num
|
||||
}
|
||||
itemGrowth {
|
||||
time
|
||||
num
|
||||
}
|
||||
spentGrowth {
|
||||
time
|
||||
num
|
||||
}
|
||||
}`)
|
||||
|
||||
const dateFormatter = timeStr => {
|
||||
const date = new Date(timeStr)
|
||||
return `${('0' + (date.getMonth() + 1)).slice(-2)}/${String(date.getFullYear()).slice(-2)}`
|
||||
}
|
||||
|
||||
export default function Growth ({ data: { registrationGrowth, activeGrowth, itemGrowth, spentGrowth } }) {
|
||||
return (
|
||||
<Layout>
|
||||
<Row className='mt-3'>
|
||||
<Col>
|
||||
<GrowthLineChart data={registrationGrowth} xName='month' yName='registrations' />
|
||||
</Col>
|
||||
<Col>
|
||||
<GrowthLineChart data={activeGrowth} xName='month' yName='active users' />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className='mt-3'>
|
||||
<Col>
|
||||
<GrowthLineChart data={itemGrowth} xName='month' yName='items' />
|
||||
</Col>
|
||||
<Col>
|
||||
<GrowthLineChart data={spentGrowth} xName='month' yName='sats spent' />
|
||||
</Col>
|
||||
</Row>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
function GrowthLineChart ({ data, xName, yName }) {
|
||||
return (
|
||||
<ResponsiveContainer width='100%' height={300} minWidth={300}>
|
||||
<LineChart
|
||||
data={data}
|
||||
margin={{
|
||||
top: 5,
|
||||
right: 5,
|
||||
left: 0,
|
||||
bottom: 0
|
||||
}}
|
||||
>
|
||||
<XAxis
|
||||
dataKey='time' tickFormatter={dateFormatter} name={xName}
|
||||
tick={{ fill: 'var(--theme-grey)' }}
|
||||
/>
|
||||
<YAxis tickFormatter={formatSats} tick={{ fill: 'var(--theme-grey)' }} />
|
||||
<Tooltip labelFormatter={dateFormatter} contentStyle={{ color: 'var(--theme-color)', backgroundColor: 'var(--theme-body)' }} />
|
||||
<Legend />
|
||||
<Line type='monotone' dataKey='num' name={yName} stroke='var(--secondary)' />
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue