From 7ce642ef1d4f543b01192afe92e942b1debd1a09 Mon Sep 17 00:00:00 2001 From: viet nguyen Date: Mon, 17 Jul 2023 00:14:43 -0700 Subject: [PATCH 1/4] feat: (wip) add log book overview chart --- package.json | 2 +- src/pages/u2/[...slug].tsx | 30 +++-- yarn.lock | 244 +++++++++++++++++++++---------------- 3 files changed, 165 insertions(+), 111 deletions(-) diff --git a/package.json b/package.json index 208411e61..cf55509b4 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "react-swipeable": "^7.0.0", "react-toastify": "^9.1.1", "react-use": "^17.4.0", - "recharts": "^2.1.9", + "recharts": "^2.7.2", "swr": "^2.1.5", "tailwindcss-radix": "^2.5.0", "typesense": "^1.2.1", diff --git a/src/pages/u2/[...slug].tsx b/src/pages/u2/[...slug].tsx index a17640ad0..37a8be3c1 100644 --- a/src/pages/u2/[...slug].tsx +++ b/src/pages/u2/[...slug].tsx @@ -1,8 +1,11 @@ -import { NextPage, GetStaticProps } from 'next' import React from 'react' + +import { NextPage, GetStaticProps } from 'next' +import dynamic from 'next/dynamic' import Link from 'next/link' import { getTicksByUser } from '../../js/graphql/api' import { TickType } from '../../js/types' +import { OverviewChartProps } from '../../components/logbook/OverviewChart' interface TicksIndexPageProps { username: string @@ -18,13 +21,18 @@ interface TicksIndexPageProps { */ const Index: NextPage = ({ username, ticks }) => { return ( -
-

{username}

-
- {ticks?.map(Tick)} - {ticks?.length === 0 &&
No ticks
} -
-
+ <> +
+ +
+
+

{username}

+
+ {ticks?.map(Tick)} + {ticks?.length === 0 &&
No ticks
} +
+
+ ) } @@ -69,3 +77,9 @@ export const getStaticProps: GetStaticProps( + async () => + await import('../../components/logbook/OverviewChart').then( + module => module.default), { ssr: false } +) diff --git a/yarn.lock b/yarn.lock index a6a46045d..8826d4656 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2578,41 +2578,56 @@ dependencies: "@types/node" "*" -"@types/d3-color@^2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-2.0.3.tgz#8bc4589073c80e33d126345542f588056511fe82" - integrity sha512-+0EtEjBfKEDtH9Rk3u3kLOUXM5F+iZK+WvASPb0MhIZl8J8NUvGeZRwKCXl+P3HkYx5TdU4YtcibpqHkSR9n7w== +"@types/d3-array@^3.0.3": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.0.5.tgz#857c1afffd3f51319bbc5b301956aca68acaa7b8" + integrity sha512-Qk7fpJ6qFp+26VeQ47WY0mkwXaiq8+76RJcncDEfMc2ocRzXLO67bLFRNI4OX1aGBoPzsM5Y2T+/m1pldOgD+A== -"@types/d3-interpolate@^2.0.0": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-2.0.2.tgz#78eddf7278b19e48e8652603045528d46897aba0" - integrity sha512-lElyqlUfIPyWG/cD475vl6msPL4aMU7eJvx1//Q177L8mdXoVPFl1djIESF2FKnc0NyaHvQlJpWwKJYwAhUoCw== +"@types/d3-color@*": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-3.1.0.tgz#6594da178ded6c7c3842f3cc0ac84b156f12f2d4" + integrity sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA== + +"@types/d3-ease@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-3.0.0.tgz#c29926f8b596f9dadaeca062a32a45365681eae0" + integrity sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA== + +"@types/d3-interpolate@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz#e7d17fa4a5830ad56fe22ce3b4fac8541a9572dc" + integrity sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw== dependencies: - "@types/d3-color" "^2" + "@types/d3-color" "*" -"@types/d3-path@^2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-2.0.2.tgz#6052f38f6186319769dfabab61b5514b0e02c75c" - integrity sha512-3YHpvDw9LzONaJzejXLOwZ3LqwwkoXb9LI2YN7Hbd6pkGo5nIlJ09ul4bQhBN4hQZJKmUpX8HkVqbzgUKY48cg== +"@types/d3-path@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-3.0.0.tgz#939e3a784ae4f80b1fde8098b91af1776ff1312b" + integrity sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg== -"@types/d3-scale@^3.0.0": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-3.3.2.tgz#18c94e90f4f1c6b1ee14a70f14bfca2bd1c61d06" - integrity sha512-gGqr7x1ost9px3FvIfUMi5XA/F/yAf4UkUDtdQhpH92XCT0Oa7zkkRzY61gPVJq+DxpHn/btouw5ohWkbBsCzQ== +"@types/d3-scale@^4.0.2": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.3.tgz#7a5780e934e52b6f63ad9c24b105e33dd58102b5" + integrity sha512-PATBiMCpvHJSMtZAMEhc2WyL+hnzarKzI6wAHYjhsonjWJYGq5BXTzQjv4l8m2jO183/4wZ90rKvSeT7o72xNQ== dependencies: - "@types/d3-time" "^2" + "@types/d3-time" "*" -"@types/d3-shape@^2.0.0": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-2.1.3.tgz#35d397b9e687abaa0de82343b250b9897b8cacf3" - integrity sha512-HAhCel3wP93kh4/rq+7atLdybcESZ5bRHDEZUojClyZWsRuEMo3A52NGYJSh48SxfxEU6RZIVbZL2YFZ2OAlzQ== +"@types/d3-shape@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-3.1.1.tgz#15cc497751dac31192d7aef4e67a8d2c62354b95" + integrity sha512-6Uh86YFF7LGg4PQkuO2oG6EMBRLuW9cbavUW46zkIO5kuS2PfTqo2o9SkgtQzguBHbLgNnU90UNsITpsX1My+A== dependencies: - "@types/d3-path" "^2" + "@types/d3-path" "*" -"@types/d3-time@^2": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-2.1.1.tgz#743fdc821c81f86537cbfece07093ac39b4bc342" - integrity sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg== +"@types/d3-time@*", "@types/d3-time@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.0.tgz#e1ac0f3e9e195135361fa1a1d62f795d87e6e819" + integrity sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg== + +"@types/d3-timer@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.0.tgz#e2505f1c21ec08bda8915238e397fb71d2fc54ce" + integrity sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g== "@types/debounce-promise@^3.1.1": version "3.1.5" @@ -3868,66 +3883,76 @@ csvtojson@^2.0.10: lodash "^4.17.3" strip-bom "^2.0.0" -d3-array@2, d3-array@^2.3.0: - version "2.12.1" - resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.12.1.tgz#e20b41aafcdffdf5d50928004ececf815a465e81" - integrity sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ== +"d3-array@2 - 3", "d3-array@2.10.0 - 3", d3-array@^3.1.6: + version "3.2.4" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5" + integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg== dependencies: - internmap "^1.0.0" + internmap "1 - 2" -"d3-color@1 - 2": - version "2.0.0" - resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-2.0.0.tgz#8d625cab42ed9b8f601a1760a389f7ea9189d62e" - integrity sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ== +"d3-color@1 - 3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" + integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== -"d3-format@1 - 2": - version "2.0.0" - resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-2.0.0.tgz#a10bcc0f986c372b729ba447382413aabf5b0767" - integrity sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA== +d3-ease@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" + integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== -"d3-interpolate@1.2.0 - 2", d3-interpolate@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-2.0.1.tgz#98be499cfb8a3b94d4ff616900501a64abc91163" - integrity sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ== +"d3-format@1 - 3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641" + integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== + +"d3-interpolate@1.2.0 - 3", d3-interpolate@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" + integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== dependencies: - d3-color "1 - 2" + d3-color "1 - 3" -"d3-path@1 - 2": - version "2.0.0" - resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-2.0.0.tgz#55d86ac131a0548adae241eebfb56b4582dd09d8" - integrity sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA== +d3-path@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526" + integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ== -d3-scale@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-3.3.0.tgz#28c600b29f47e5b9cd2df9749c206727966203f3" - integrity sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ== +d3-scale@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396" + integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ== dependencies: - 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-array "2.10.0 - 3" + d3-format "1 - 3" + d3-interpolate "1.2.0 - 3" + d3-time "2.1.1 - 3" + d3-time-format "2 - 4" -d3-shape@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-2.1.0.tgz#3b6a82ccafbc45de55b57fcf956c584ded3b666f" - integrity sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA== +d3-shape@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5" + integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA== dependencies: - d3-path "1 - 2" + d3-path "^3.1.0" -"d3-time-format@2 - 3": - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-3.0.0.tgz#df8056c83659e01f20ac5da5fdeae7c08d5f1bb6" - integrity sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag== +"d3-time-format@2 - 4": + version "4.1.0" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a" + integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg== dependencies: - d3-time "1 - 2" + d3-time "1 - 3" -"d3-time@1 - 2", d3-time@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-2.1.1.tgz#e9d8a8a88691f4548e68ca085e5ff956724a6682" - integrity sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ== +"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7" + integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q== dependencies: - d3-array "2" + d3-array "2 - 3" + +d3-timer@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" + integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== daisyui@^2.24.0: version "2.38.1" @@ -4637,10 +4662,10 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-equals@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-2.0.4.tgz#3add9410585e2d7364c2deeb6a707beadb24b927" - integrity sha512-caj/ZmjHljPrZtbzJ3kfH5ia/k4mTJe/qSiXAGzxZWRZgsgDV0cvNaQULqUX8t0/JVlzzEdYOwCN5DmzTxoD4w== +fast-equals@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-5.0.1.tgz#a4eefe3c5d1c0d021aeed0bc10ba5e0c12ee405d" + integrity sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ== fast-glob@^3.2.12, fast-glob@^3.2.9: version "3.2.12" @@ -5268,10 +5293,10 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" -internmap@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95" - integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== +"internmap@1 - 2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009" + integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg== invariant@^2.2.4: version "2.2.4" @@ -7257,10 +7282,10 @@ react-remove-scroll@2.5.5: use-callback-ref "^1.3.0" use-sidecar "^1.1.2" -react-resize-detector@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-7.1.2.tgz#8ef975dd8c3d56f9a5160ac382ef7136dcd2d86c" - integrity sha512-zXnPJ2m8+6oq9Nn8zsep/orts9vQv3elrpA+R8XTcW7DVVUJ9vwDwMXaBtykAYjMnkCIaOoK9vObyR7ZgFNlOw== +react-resize-detector@^8.0.4: + version "8.1.0" + resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-8.1.0.tgz#1c7817db8bc886e2dbd3fbe3b26ea8e56be0524a" + integrity sha512-S7szxlaIuiy5UqLhLL1KY3aoyGHbZzsTpYal9eYMwCyKqoqoVLCmIgAgNyIM1FhnP2KyBygASJxdhejrzjMb+w== dependencies: lodash "^4.17.21" @@ -7282,12 +7307,12 @@ react-shallow-renderer@^16.15.0: object-assign "^4.1.1" react-is "^16.12.0 || ^17.0.0 || ^18.0.0" -react-smooth@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-2.0.1.tgz#74c7309916d6ccca182c4b30c8992f179e6c5a05" - integrity sha512-Own9TA0GPPf3as4vSwFhDouVfXP15ie/wIHklhyKBH5AN6NFtdk0UpHBnonV11BtqDkAWlt40MOUc+5srmW7NA== +react-smooth@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-2.0.3.tgz#2845fa8f22914f2e4445856d5688fb8a7d72f3ae" + integrity sha512-yl4y3XiMorss7ayF5QnBiSprig0+qFHui8uh7Hgg46QX5O+aRMRKlfGGNGLHno35JkQSvSYY8eCWkBfHfrSHfg== dependencies: - fast-equals "^2.0.0" + fast-equals "^5.0.0" react-transition-group "2.9.0" react-style-singleton@^2.2.1: @@ -7409,25 +7434,20 @@ recharts-scale@^0.4.4: dependencies: decimal.js-light "^2.4.1" -recharts@^2.1.9: - version "2.1.16" - resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.1.16.tgz#f1448175dbce1988421276b0655c8a74d8a1e0a7" - integrity sha512-aYn1plTjYzRCo3UGxtWsduslwYd+Cuww3h/YAAEoRdGe0LRnBgYgaXSlVrNFkWOOSXrBavpmnli9h7pvRuk5wg== +recharts@^2.7.2: + version "2.7.2" + resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.7.2.tgz#6d813681910ad33a4bbf3bdd06c6f64f20b39319" + integrity sha512-HMKRBkGoOXHW+7JcRa6+MukPSifNtJlqbc+JreGVNA407VLE/vOP+8n3YYjprDVVIF9E2ZgwWnL3D7K/LUFzBg== dependencies: - "@types/d3-interpolate" "^2.0.0" - "@types/d3-scale" "^3.0.0" - "@types/d3-shape" "^2.0.0" 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 "^7.1.2" - react-smooth "^2.0.1" + react-resize-detector "^8.0.4" + react-smooth "^2.0.2" recharts-scale "^0.4.4" reduce-css-calc "^2.1.8" + victory-vendor "^36.6.8" redent@^3.0.0: version "3.0.0" @@ -8523,6 +8543,26 @@ v8-to-istanbul@^9.0.1: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" +victory-vendor@^36.6.8: + version "36.6.11" + resolved "https://registry.yarnpkg.com/victory-vendor/-/victory-vendor-36.6.11.tgz#acae770717c2dae541a54929c304ecab5ab6ac2a" + integrity sha512-nT8kCiJp8dQh8g991J/R5w5eE2KnO8EAIP0xocWlh9l2okngMWglOPoMZzJvek8Q1KUc4XE/mJxTZnvOB1sTYg== + dependencies: + "@types/d3-array" "^3.0.3" + "@types/d3-ease" "^3.0.0" + "@types/d3-interpolate" "^3.0.1" + "@types/d3-scale" "^4.0.2" + "@types/d3-shape" "^3.1.0" + "@types/d3-time" "^3.0.0" + "@types/d3-timer" "^3.0.0" + d3-array "^3.1.6" + d3-ease "^3.0.1" + d3-interpolate "^3.0.1" + d3-scale "^4.0.2" + d3-shape "^3.1.0" + d3-time "^3.0.0" + d3-timer "^3.0.1" + vt-pbf@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/vt-pbf/-/vt-pbf-3.1.3.tgz#68fd150756465e2edae1cc5c048e063916dcfaac" From 8204792f2a0bfb642cae6a42cc9a3edf2517d1d9 Mon Sep 17 00:00:00 2001 From: viet nguyen Date: Mon, 17 Jul 2023 20:23:35 -0700 Subject: [PATCH 2/4] feat: introduce climb log overview chart --- package.json | 1 + src/components/logbook/OverviewChart.tsx | 198 +++++++++++++++++++++ src/components/users/ImportFromMtnProj.tsx | 6 +- src/components/users/PublicProfile.tsx | 2 +- src/js/types.ts | 2 +- src/pages/climbs/[id].tsx | 5 - src/pages/u2/[...slug].tsx | 15 +- yarn.lock | 5 + 8 files changed, 222 insertions(+), 12 deletions(-) create mode 100644 src/components/logbook/OverviewChart.tsx diff --git a/package.json b/package.json index cf55509b4..56247088a 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "react-toastify": "^9.1.1", "react-use": "^17.4.0", "recharts": "^2.7.2", + "simple-statistics": "^7.8.3", "swr": "^2.1.5", "tailwindcss-radix": "^2.5.0", "typesense": "^1.2.1", diff --git a/src/components/logbook/OverviewChart.tsx b/src/components/logbook/OverviewChart.tsx new file mode 100644 index 000000000..fd1a2fddb --- /dev/null +++ b/src/components/logbook/OverviewChart.tsx @@ -0,0 +1,198 @@ +import { + ResponsiveContainer, ComposedChart, CartesianGrid, XAxis, YAxis, Bar, Line, + Tooltip, LineProps, Brush +} from 'recharts' +import { groupBy } from 'underscore' +import { lastDayOfMonth, format } from 'date-fns' +import { getScale } from '@openbeta/sandbag' +import { linearRegression, linearRegressionLine, minSorted, maxSorted, medianSorted } from 'simple-statistics' + +import { TickType } from '../../js/types' + +export interface OverviewChartProps { + tickList: TickType[] +} + +/** + * Proof of concept chart showing climbs aggregated by a time interval + */ +const OverviewChart: React.FC = ({ tickList }) => { + /** + * Assume grades are YDS or Vscale for now since we don't store + * grade context with ticks, nor do we have a way to get score + * without knowing the grade system + */ + const ydsScale = getScale('yds') + const vScale = getScale('vscale') + + const agg = groupBy(tickList, getYearMonthFromDate) + + const xyRegressionData: number[][] = [] + + const chartData: ChartDataPayloadProps[] = Object.entries(agg).reverse().map(value => { + const x = parseInt(value[0]) + const gradeScores = value[1].reduce((acc, curr) => { + let score = ydsScale?.getScore(curr.grade)?.[0] as number ?? -1 + + if (score < 0) { + score = vScale?.getScore(curr.grade)[0] as number ?? -1 + } + if (score > 0) { + acc.push(score) + } + return acc + }, []) + + const gradeScoresSorted = gradeScores.sort((a, b) => a - b) + let medianScore = -1 + if (gradeScores.length > 0) { + medianScore = medianSorted(gradeScoresSorted) + xyRegressionData.push([x, medianScore]) + } + return { + date: x, + total: value[1].length, + score: medianScore, + low: minSorted(gradeScoresSorted), + high: maxSorted(gradeScoresSorted) + } + }) + + const linearFn = linearRegressionLine(linearRegression(xyRegressionData)) + + const chartData2 = chartData.reduce((acc, curr) => { + if (curr.score > 0) { + acc.push({ + ...curr, + linearReg: linearFn(curr.date) + }) + } + return acc + }, []) + + return ( +
+ + + + { + return parseInt(value) <= 0 ? ' ' : value + }} + /> + + } + isAnimationActive={false} + /> + + + + + + + + + + + + + } /> + + { + return format(value, 'MMM yyyy') + }} + /> + + + +
+ ) +} + +export default OverviewChart + +const getYearMonthFromDate = (tick: TickType): number => lastDayOfMonth(tick.dateClimbed).getTime() + +const xAxisFormatter = (data: any): any => { + return format(data, 'MMM yy') +} + +/** + * Make median score looks like a candle stick + */ +const CustomizeMedianDot: React.FC = (props) => { + const { cx, cy, payload } = props + if (cx == null || cy == null || payload == null) return null + const lengthOffset = payload.total * 1.2 + return ( + <> + + + + ) +} + +const CustomTooltip: React.FC = ({ active, payload, label }) => { + if (active === true && payload != null && payload.length > 0) { + return ( +
+
Total climbs: {payload[4].value}
+
Median: {payload[0].value}
+
Low: {payload[1].value}
+
High: {payload[2].value}
+
+ ) + } + + return null +} + +interface ChartDataPayloadProps { + date: number + total: number + score: number + low: number + high: number + linearReg?: number +} diff --git a/src/components/users/ImportFromMtnProj.tsx b/src/components/users/ImportFromMtnProj.tsx index 3c1655997..c32899abd 100644 --- a/src/components/users/ImportFromMtnProj.tsx +++ b/src/components/users/ImportFromMtnProj.tsx @@ -1,4 +1,5 @@ import { Fragment, useEffect, useState } from 'react' +import { useRouter } from 'next/router' import { Transition } from '@headlessui/react' import { FolderArrowDownIcon, XMarkIcon } from '@heroicons/react/24/outline' import { useMutation } from '@apollo/client' @@ -10,6 +11,7 @@ import { MUTATION_IMPORT_TICKS } from '../../js/graphql/gql/fragments' interface Props { isButton: boolean + username: string } // regex pattern to validate mountain project input const pattern = /^https:\/\/www.mountainproject.com\/user\/\d{9}\/[a-zA-Z-]*/ @@ -22,7 +24,8 @@ const pattern = /^https:\/\/www.mountainproject.com\/user\/\d{9}\/[a-zA-Z-]*/ * if the isButton prop is false, the component will be rendered as a modal * @returns JSX element */ -export function ImportFromMtnProj ({ isButton }: Props): JSX.Element { +export function ImportFromMtnProj ({ isButton, username }: Props): JSX.Element { + const router = useRouter() const [mpUID, setMPUID] = useState('') const session = useSession() const [show, setShow] = useState(false) @@ -75,6 +78,7 @@ export function ImportFromMtnProj ({ isButton }: Props): JSX.Element { const ticksCount: number = ticks?.length ?? 0 toast.info(`${ticksCount} ticks have been imported!`) + await router.replace(`/u2/${username}`) } else { setErrors(['Sorry, something went wrong. Please try again later']) } diff --git a/src/components/users/PublicProfile.tsx b/src/components/users/PublicProfile.tsx index 9b5a5d29a..5aa9864b5 100644 --- a/src/components/users/PublicProfile.tsx +++ b/src/components/users/PublicProfile.tsx @@ -63,7 +63,7 @@ export default function PublicProfile ({ userProfile: initialUserProfile }: Publ
View ticks
} - {userProfile != null && isAuthorized && } + {username != null && isAuthorized && } {userProfile != null && } {userProfile != null && } diff --git a/src/js/types.ts b/src/js/types.ts index dd3ac6aba..fe4e3d905 100644 --- a/src/js/types.ts +++ b/src/js/types.ts @@ -340,7 +340,7 @@ export interface TickType { climbId: string style: string attemptType: string - dateClimbed: Date + dateClimbed: number grade: string source: string } diff --git a/src/pages/climbs/[id].tsx b/src/pages/climbs/[id].tsx index 408f63119..8b31c9dcb 100644 --- a/src/pages/climbs/[id].tsx +++ b/src/pages/climbs/[id].tsx @@ -20,7 +20,6 @@ import RouteTypeChips from '../../components/ui/RouteTypeChips' import PhotoMontage, { Skeleton as PhotoMontageSkeleton } from '../../components/media/PhotoMontage' import { useClimbSeo } from '../../js/hooks/seo/useClimbSeo' import TickButton from '../../components/users/TickButton' -import { ImportFromMtnProj } from '../../components/users/ImportFromMtnProj' import EditModeToggle from '../../components/editor/EditModeToggle' import { AREA_NAME_FORM_VALIDATION_RULES } from '../../components/edit/EditAreaForm' import useUpdateClimbsCmd from '../../js/hooks/useUpdateClimbsCmd' @@ -288,10 +287,6 @@ const Body = ({ climb, leftClimb, rightClimb }: ClimbPageProps): JSX.Element => } - -
- -
diff --git a/src/pages/u2/[...slug].tsx b/src/pages/u2/[...slug].tsx index 37a8be3c1..e9f228f91 100644 --- a/src/pages/u2/[...slug].tsx +++ b/src/pages/u2/[...slug].tsx @@ -6,6 +6,8 @@ import Link from 'next/link' import { getTicksByUser } from '../../js/graphql/api' import { TickType } from '../../js/types' import { OverviewChartProps } from '../../components/logbook/OverviewChart' +import ImportFromMtnProj from '../../components/users/ImportFromMtnProj' +import Layout from '../../components/layout' interface TicksIndexPageProps { username: string @@ -21,18 +23,23 @@ interface TicksIndexPageProps { */ const Index: NextPage = ({ username, ticks }) => { return ( - <> -
+ +
-

{username}

+

{username}

+ +

Log book

{ticks?.map(Tick)} {ticks?.length === 0 &&
No ticks
}
- +
) } diff --git a/yarn.lock b/yarn.lock index 8826d4656..fcf70dda4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7776,6 +7776,11 @@ signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +simple-statistics@^7.8.3: + version "7.8.3" + resolved "https://registry.yarnpkg.com/simple-statistics/-/simple-statistics-7.8.3.tgz#62998dd7786ba14fa27b07f4f3cd498466f7961a" + integrity sha512-JFvMY00t6SBGtwMuJ+nqgsx9ylkMiJ5JlK9bkj8AdvniIe5615wWQYkKHXe84XtSuc40G/tlrPu0A5/NlJvv8A== + simple-swizzle@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" From 29678c40493abb40b2f506c0ad5ba32dd7273714 Mon Sep 17 00:00:00 2001 From: viet nguyen Date: Mon, 17 Jul 2023 20:35:18 -0700 Subject: [PATCH 3/4] test: update snapshot --- package.json | 5 ++--- .../ui/__tests__/__snapshots__/CounterPie.tsx.snap | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 56247088a..cb4fe7c1a 100644 --- a/package.json +++ b/package.json @@ -89,8 +89,7 @@ "local": "NEXT_PUBLIC_API_SERVER=http://localhost:4000 node ./src/server.js ", "develop": "next dev", "start": "next start", - "test": "jest --testPathIgnorePatterns=/tests/e2e/ --", - "test-all": "jest", + "test": "jest", "prepare": "husky install" }, "devDependencies": { @@ -143,4 +142,4 @@ "engines": { "node": "18" } -} +} \ No newline at end of file diff --git a/src/components/ui/__tests__/__snapshots__/CounterPie.tsx.snap b/src/components/ui/__tests__/__snapshots__/CounterPie.tsx.snap index c91f7d247..53b15dfc1 100644 --- a/src/components/ui/__tests__/__snapshots__/CounterPie.tsx.snap +++ b/src/components/ui/__tests__/__snapshots__/CounterPie.tsx.snap @@ -16,7 +16,7 @@ exports[`renders correctly 1`] = ` "height": "100%", "maxHeight": undefined, "minHeight": undefined, - "minWidth": undefined, + "minWidth": 0, "width": "100%", } } From db6e2acce5a22bb62508bdc1b0c842d8a2d5b5e9 Mon Sep 17 00:00:00 2001 From: viet nguyen Date: Mon, 17 Jul 2023 20:38:21 -0700 Subject: [PATCH 4/4] test: update snapshot --- .github/workflows/nodejs.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 269a0f1c4..aefa37013 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -44,12 +44,6 @@ jobs: run: yarn test if: ${{ github.event_name == 'pull_request' }} - - name: Run unit & e2e tests - run: yarn test-all - env: - SIRV_CLIENT_SECRET_RW: ${{ secrets.SIRV_CLIENT_SECRET_RW }} - if: ${{ github.event_name != 'pull_request' }} - - name: Build project run: yarn build if: ${{ github.event_name != 'pull_request' }}