From d68a35144bdd8b776fa190e80fd1183300bf08a4 Mon Sep 17 00:00:00 2001 From: noah Date: Thu, 30 Nov 2023 11:47:48 -0800 Subject: [PATCH] Fix time ago components not updating (#1496) --- apps/dapp/package.json | 1 + apps/sda/package.json | 1 + package.json | 2 + packages/i18n/locales/en/translation.json | 2 +- .../components/proposal/ProposalVotes.tsx | 38 ++++++++---- .../hooks/useTranslatedTimeDeltaFormatter.ts | 13 +++- patches/react-timeago+7.1.0.patch | 61 +++++++++++++++++++ yarn.lock | 48 +++++++++++++-- 8 files changed, 145 insertions(+), 21 deletions(-) create mode 100644 patches/react-timeago+7.1.0.patch diff --git a/apps/dapp/package.json b/apps/dapp/package.json index 1053e2a9d5..68221e6920 100644 --- a/apps/dapp/package.json +++ b/apps/dapp/package.json @@ -4,6 +4,7 @@ "license": "AGPL-3.0-only", "scripts": { "analyze": "ANALYZE=true next build", + "postinstall": "cd ../.. && npm run postinstall", "prepare": "npm run build:worker", "prebuild": "npm run build:worker && cd ../../packages/state && npm run build:gql", "build": "next build --debug", diff --git a/apps/sda/package.json b/apps/sda/package.json index 381cd91041..fa82dc938e 100644 --- a/apps/sda/package.json +++ b/apps/sda/package.json @@ -4,6 +4,7 @@ "license": "AGPL-3.0-only", "scripts": { "analyze": "ANALYZE=true next build", + "postinstall": "cd ../.. && npm run postinstall", "prebuild": "cd ../../packages/state && npm run build:gql", "build": "next build --debug", "dev": "next dev", diff --git a/package.json b/package.json index ae98ea82d3..3d036b4cea 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "packages/*" ], "scripts": { + "postinstall": "patch-package", "build": "turbo run build --continue --filter=\"!@dao-dao/storybook\"", "build:no-apps": "turbo run build --continue --filter=\"!@dao-dao/storybook\" --filter=\"!@dao-dao/dapp\" --filter=\"!@dao-dao/sda\"", "dev": "yarn dapp dev", @@ -29,6 +30,7 @@ "@types/jest": "^29.5.0", "jest": "^29.5.0", "lerna": "^6.4.1", + "patch-package": "^8.0.0", "ts-jest": "^29.0.5", "turbo": "latest", "turbo-ignore": "latest" diff --git a/packages/i18n/locales/en/translation.json b/packages/i18n/locales/en/translation.json index e8090d8eff..261d6e479f 100644 --- a/packages/i18n/locales/en/translation.json +++ b/packages/i18n/locales/en/translation.json @@ -1085,8 +1085,8 @@ "vetoed": "Vetoed", "vetoing": "Vetoing", "voteOnGovernanceProposalDescription": "Vote on an open chain governance proposal, as an individual or as a validator.", - "voteTallyRefreshesSeconds": "Vote tally refreshes every {{seconds}} seconds.", "voteUntilExpirationExplanation": "Although the proposal outcome is determined, you may cast a vote until the proposal expires to be included in the final tally.", + "votesRefreshAutomatically": "Votes refresh automatically.", "votingModuleAdapterCreationDiscord": "Want to help us support this voting module? Join the <2><0>DAO DAO Discord<1/> and post in #dao-help.", "votingModuleNotYetSupported": "This DAO uses a voting module that our UI does not yet support. Functionality may be limited.", "votingPowerAtCreationTooltip": "This was your voting power at the time of proposal creation.", diff --git a/packages/stateless/components/proposal/ProposalVotes.tsx b/packages/stateless/components/proposal/ProposalVotes.tsx index bdf832555c..c60b0186e0 100644 --- a/packages/stateless/components/proposal/ProposalVotes.tsx +++ b/packages/stateless/components/proposal/ProposalVotes.tsx @@ -12,7 +12,7 @@ import { useTranslation } from 'react-i18next' import TimeAgo from 'react-timeago' import { LoadingData, StatefulEntityDisplayProps } from '@dao-dao/types' -import { formatPercentOf100 } from '@dao-dao/utils' +import { formatDateTimeTz, formatPercentOf100 } from '@dao-dao/utils' import { useTranslatedTimeDeltaFormatter } from '../../hooks' import { Button } from '../buttons' @@ -112,7 +112,7 @@ export const ProposalVotes = ({ {votingOpen && (

- {t('info.voteTallyRefreshesSeconds', { seconds: 30 })} + {t('info.votesRefreshAutomatically')}

)} @@ -147,18 +147,30 @@ export const ProposalVotes = ({ ) => ( {!hideVotedAt && ( - + + )} { const { t } = useTranslation() - const timeDeltaFormatter: Formatter = (value, unit, suffix) => - t( + const timeDeltaFormatter: Formatter = (value, unit, suffix) => { + const lessThanOneMinute = unit === 'second' && value < 60 + if (lessThanOneMinute) { + value = 1 + unit = 'minute' + } + + return t( words ? suffix === 'ago' ? 'format.timeAgo' @@ -26,10 +32,11 @@ export const useTranslatedTimeDeltaFormatter = ({ : 'format.inTime' : 'format.time', { - value, + value: lessThanOneMinute ? '< 1' : value, unit: t(`unit.${unit}s`, { count: value }).toLocaleLowerCase(), } ) + } return timeDeltaFormatter } diff --git a/patches/react-timeago+7.1.0.patch b/patches/react-timeago+7.1.0.patch new file mode 100644 index 0000000000..c887c400c5 --- /dev/null +++ b/patches/react-timeago+7.1.0.patch @@ -0,0 +1,61 @@ +diff --git a/node_modules/react-timeago/es6/index.js b/node_modules/react-timeago/es6/index.js +index 086df64..b6609fe 100644 +--- a/node_modules/react-timeago/es6/index.js ++++ b/node_modules/react-timeago/es6/index.js +@@ -23,6 +23,10 @@ export default function TimeAgo({ + ...passDownProps + }) { + const [timeNow, setTimeNow] = useState(now()); ++ // When date changes, update timeNow. ++ useEffect(() => { ++ setTimeNow(now()) ++ }, [date, now]); + useEffect(() => { + if (!live) { + return; +diff --git a/node_modules/react-timeago/es6/index.js.flow b/node_modules/react-timeago/es6/index.js.flow +index a376240..c916207 100644 +--- a/node_modules/react-timeago/es6/index.js.flow ++++ b/node_modules/react-timeago/es6/index.js.flow +@@ -69,6 +69,10 @@ export default function TimeAgo({ + ...passDownProps + }: Props): null | React.MixedElement { + const [timeNow, setTimeNow] = useState(now()) ++ // When date changes, update timeNow. ++ useEffect(() => { ++ setTimeNow(now()) ++ }, [date, now]) + useEffect(() => { + if (!live) { + return +diff --git a/node_modules/react-timeago/lib/index.js b/node_modules/react-timeago/lib/index.js +index 7f1109b..30a2366 100644 +--- a/node_modules/react-timeago/lib/index.js ++++ b/node_modules/react-timeago/lib/index.js +@@ -77,6 +77,11 @@ function TimeAgo(_ref) { + timeNow = _useState2[0], + setTimeNow = _useState2[1]; + ++ // When date changes, update timeNow. ++ (0, React.useEffect)(function () { ++ setTimeNow(now()); ++ }, [date, now]); ++ + (0, React.useEffect)(function () { + if (!live) { + return; +diff --git a/node_modules/react-timeago/lib/index.js.flow b/node_modules/react-timeago/lib/index.js.flow +index a376240..c916207 100644 +--- a/node_modules/react-timeago/lib/index.js.flow ++++ b/node_modules/react-timeago/lib/index.js.flow +@@ -69,6 +69,10 @@ export default function TimeAgo({ + ...passDownProps + }: Props): null | React.MixedElement { + const [timeNow, setTimeNow] = useState(now()) ++ // When date changes, update timeNow. ++ useEffect(() => { ++ setTimeNow(now()) ++ }, [date, now]) + useEffect(() => { + if (!live) { + return diff --git a/yarn.lock b/yarn.lock index 25c0e01cc0..bf2c74088c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13249,7 +13249,7 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1: +chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -13404,6 +13404,11 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.2.tgz#6d2967ffa407466481c6c90b6e16b3098f080128" integrity sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg== +ci-info@^3.7.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -16227,6 +16232,13 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" +find-yarn-workspace-root@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" + integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== + dependencies: + micromatch "^4.0.2" + flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -19611,6 +19623,13 @@ kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +klaw-sync@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" + integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== + dependencies: + graceful-fs "^4.1.11" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" @@ -21998,7 +22017,7 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -open@^7.0.3: +open@^7.0.3, open@^7.4.2: version "7.4.2" resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== @@ -22442,6 +22461,27 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== +patch-package@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-8.0.0.tgz#d191e2f1b6e06a4624a0116bcb88edd6714ede61" + integrity sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA== + dependencies: + "@yarnpkg/lockfile" "^1.1.0" + chalk "^4.1.2" + ci-info "^3.7.0" + cross-spawn "^7.0.3" + find-yarn-workspace-root "^2.0.0" + fs-extra "^9.0.0" + json-stable-stringify "^1.0.2" + klaw-sync "^6.0.0" + minimist "^1.2.6" + open "^7.4.2" + rimraf "^2.6.3" + semver "^7.5.3" + slash "^2.0.0" + tmp "^0.0.33" + yaml "^2.2.2" + path-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" @@ -24610,7 +24650,7 @@ semver@^7.0.0, semver@^7.1.1: dependencies: lru-cache "^6.0.0" -semver@^7.3.8, semver@^7.5.0, semver@^7.5.4: +semver@^7.3.8, semver@^7.5.0, semver@^7.5.3, semver@^7.5.4: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -27732,7 +27772,7 @@ yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yaml@^2.3.1: +yaml@^2.2.2, yaml@^2.3.1: version "2.3.4" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==