From 7605be6c77393ed98e179c27f3bc3915afb95f5c Mon Sep 17 00:00:00 2001 From: eug-vs Date: Fri, 9 Oct 2020 20:51:00 +0300 Subject: feat: create DateString component --- src/components/DateString/DateString.tsx | 22 ++++++++++++++++++++++ src/components/PollCard/PollCard.tsx | 12 ++---------- 2 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 src/components/DateString/DateString.tsx diff --git a/src/components/DateString/DateString.tsx b/src/components/DateString/DateString.tsx new file mode 100644 index 0000000..e31b52e --- /dev/null +++ b/src/components/DateString/DateString.tsx @@ -0,0 +1,22 @@ +import React from 'react'; + +interface PropTypes { + value: Date | string; +} + +const DATE_FORMAT = { + month: 'long', + day: 'numeric', + year: 'numeric', + hour: '2-digit', + minute: '2-digit' +}; + +const DateString: React.FC = ({ value }) => { + const date = new Date(value); + const formatted = date.toLocaleString('default', DATE_FORMAT); + + return <>{formatted}; +}; + +export default DateString; diff --git a/src/components/PollCard/PollCard.tsx b/src/components/PollCard/PollCard.tsx index a06bad8..7094d88 100644 --- a/src/components/PollCard/PollCard.tsx +++ b/src/components/PollCard/PollCard.tsx @@ -6,6 +6,7 @@ import { useSnackbar } from 'notistack'; import PercentageBar from './PercentageBar'; import UserStrip from '../UserStrip/UserStrip'; +import DateString from '../DateString/DateString'; import BackgroundImage from '../Image/BackgroundImage'; import { post } from '../../requests'; import { useAuth } from '../../hooks/useAuth'; @@ -15,14 +16,6 @@ interface PropTypes { setPoll: (poll: Poll) => void; } -const DATE_FORMAT = { - month: 'long', - day: 'numeric', - year: 'numeric', - hour: '2-digit', - minute: '2-digit' -}; - const useStyles = makeStyles(theme => ({ media: { display: 'flex', @@ -55,7 +48,6 @@ const PollCard: React.FC = React.memo(({ poll, setPoll }) => { const { author, contents: { left, right }, vote } = poll; const { enqueueSnackbar } = useSnackbar(); const { isAuthenticated } = useAuth(); - const date: string = new Date(poll.createdAt).toLocaleString('default', DATE_FORMAT); const handleVote = (which: Which) => () => { if (!isAuthenticated) { @@ -97,7 +89,7 @@ const PollCard: React.FC = React.memo(({ poll, setPoll }) => { return ( - + } /> {poll.description && ( {poll.description} -- cgit v1.2.3 From 31900353b6ea3e4570c15d1c1585685b4413d6d9 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Fri, 9 Oct 2020 21:46:45 +0300 Subject: feat: toggle between compact and full date format --- src/components/DateString/DateString.tsx | 27 +++++++++++++++++--- src/components/DateString/compactDateString.ts | 34 ++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 src/components/DateString/compactDateString.ts diff --git a/src/components/DateString/DateString.tsx b/src/components/DateString/DateString.tsx index e31b52e..3f2ceb2 100644 --- a/src/components/DateString/DateString.tsx +++ b/src/components/DateString/DateString.tsx @@ -1,9 +1,18 @@ -import React from 'react'; +import React, { useState, useMemo, useCallback } from 'react'; +import { makeStyles } from '@material-ui/core/styles'; +import compactDateString from './compactDateString'; interface PropTypes { value: Date | string; } +const useStyles = makeStyles({ + root: { + display: 'block', + cursor: 'pointer' + } +}); + const DATE_FORMAT = { month: 'long', day: 'numeric', @@ -13,10 +22,20 @@ const DATE_FORMAT = { }; const DateString: React.FC = ({ value }) => { - const date = new Date(value); - const formatted = date.toLocaleString('default', DATE_FORMAT); + const [isCompact, setIsCompact] = useState(true); + const classes = useStyles(); + + const toggleScompact = useCallback(() => setIsCompact(v => !v), [setIsCompact]); + + const date = useMemo(() => new Date(value), [value]); + const formatted = useMemo(() => date.toLocaleString('default', DATE_FORMAT), [date]); + const compact = useMemo(() => compactDateString(date), [date]); - return <>{formatted}; + return ( +
+ {isCompact ? compact : formatted} +
+ ); }; export default DateString; diff --git a/src/components/DateString/compactDateString.ts b/src/components/DateString/compactDateString.ts new file mode 100644 index 0000000..dffd912 --- /dev/null +++ b/src/components/DateString/compactDateString.ts @@ -0,0 +1,34 @@ +const metrics = [ + { name: 'minute', ratio: 60 }, + { name: 'hour', ratio: 60 }, + { name: 'day', ratio: 24 }, + { name: 'week', ratio: 7 }, + { name: 'month', ratio: 4 }, + { name: 'year', ratio: 12 } +]; + +const PRECISION = 0.75; + +const resolve = (value: number, metricIndex = 0): string => { + // Recursively divide value until it's ready to be presented as a string + const metric = metrics[metricIndex]; + const nextMetric = metrics[metricIndex + 1]; + const newValue = value / metric.ratio; + + if (newValue < nextMetric.ratio * PRECISION) { + const rounded = Math.round(newValue); + const isPlural = rounded > 1; + const count = isPlural ? rounded : 'a'; + const ending = isPlural ? 's' : ''; + return `${count} ${metric.name}${ending} ago`; + } + return resolve(newValue, metricIndex + 1); +}; + +const compactDateString = (date: Date): string => { + const now = new Date(); + const diff = (now.valueOf() - date.valueOf()) / 1000; + return resolve(diff); +}; + +export default compactDateString; -- cgit v1.2.3 From 4c73ebe644e7b781fee57bb295f8819bf6568628 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Fri, 9 Oct 2020 21:48:38 +0300 Subject: feat: display 'just now' if was just posted --- src/components/DateString/compactDateString.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/DateString/compactDateString.ts b/src/components/DateString/compactDateString.ts index dffd912..f067b1a 100644 --- a/src/components/DateString/compactDateString.ts +++ b/src/components/DateString/compactDateString.ts @@ -28,6 +28,7 @@ const resolve = (value: number, metricIndex = 0): string => { const compactDateString = (date: Date): string => { const now = new Date(); const diff = (now.valueOf() - date.valueOf()) / 1000; + if (diff < 60) return 'just now'; return resolve(diff); }; -- cgit v1.2.3 From 4a8149c0c43419e29cedd5117b6441bf7e6eadcd Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 10 Oct 2020 11:26:36 +0300 Subject: fix: format 'since' date in ProfileInfo --- src/containers/Profile/ProfileInfo.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/containers/Profile/ProfileInfo.tsx b/src/containers/Profile/ProfileInfo.tsx index 1f5a103..4f2957a 100644 --- a/src/containers/Profile/ProfileInfo.tsx +++ b/src/containers/Profile/ProfileInfo.tsx @@ -1,4 +1,4 @@ -import React, { useState, useCallback } from 'react'; +import React, { useState, useCallback, useMemo } from 'react'; import { Badge, Typography, CircularProgress } from '@material-ui/core/'; import { CameraAlt, CheckCircleOutline } from '@material-ui/icons/'; import { makeStyles } from '@material-ui/core/styles'; @@ -92,6 +92,15 @@ const useStyles = makeStyles(theme => ({ })); +const formatDate = (value: Date | string = ''): string => { + const date = new Date(value); + const day = ('0' + date.getDate()).slice(-2); + const month = ('0' + date.getMonth()).slice(-2); + const year = date.getFullYear(); + return `${year}-${month}-${day}`; +}; + + const ProfileInfo: React.FC = ({ savedPolls, totalVotes, setUserInfo, userInfo }) => { @@ -99,7 +108,7 @@ const ProfileInfo: React.FC = ({ const { user } = useAuth(); const [progress, setProgress] = useState(0); - const dateSince = new Date(userInfo?.createdAt || '').toLocaleDateString(); + const dateSince = useMemo(() => formatDate(userInfo?.createdAt), [userInfo]); const handleUpdateAvatar = useCallback(async (file: File) => { if (user) { -- cgit v1.2.3 From a1a2cb59616d833d503c3c090116fc0ad1e9d542 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 10 Oct 2020 11:48:05 +0300 Subject: fix: resolve eslint errors --- src/components/DateString/DateString.tsx | 2 +- src/containers/Profile/ProfileInfo.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/DateString/DateString.tsx b/src/components/DateString/DateString.tsx index 3f2ceb2..7c824cd 100644 --- a/src/components/DateString/DateString.tsx +++ b/src/components/DateString/DateString.tsx @@ -32,7 +32,7 @@ const DateString: React.FC = ({ value }) => { const compact = useMemo(() => compactDateString(date), [date]); return ( -
+
{isCompact ? compact : formatted}
); diff --git a/src/containers/Profile/ProfileInfo.tsx b/src/containers/Profile/ProfileInfo.tsx index 4f2957a..da952e9 100644 --- a/src/containers/Profile/ProfileInfo.tsx +++ b/src/containers/Profile/ProfileInfo.tsx @@ -94,8 +94,8 @@ const useStyles = makeStyles(theme => ({ const formatDate = (value: Date | string = ''): string => { const date = new Date(value); - const day = ('0' + date.getDate()).slice(-2); - const month = ('0' + date.getMonth()).slice(-2); + const day = (`0${date.getDate()}`).slice(-2); + const month = (`0${date.getMonth()}`).slice(-2); const year = date.getFullYear(); return `${year}-${month}-${day}`; }; -- cgit v1.2.3 From 5ee4f42b577449a58469fd3c7892455d097a6c79 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 10 Oct 2020 12:01:01 +0300 Subject: feat: increase diff rounding precision --- src/components/DateString/compactDateString.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/DateString/compactDateString.ts b/src/components/DateString/compactDateString.ts index f067b1a..8bff4b7 100644 --- a/src/components/DateString/compactDateString.ts +++ b/src/components/DateString/compactDateString.ts @@ -7,7 +7,7 @@ const metrics = [ { name: 'year', ratio: 12 } ]; -const PRECISION = 0.75; +const PRECISION = 0.85; const resolve = (value: number, metricIndex = 0): string => { // Recursively divide value until it's ready to be presented as a string -- cgit v1.2.3