diff --git a/packages/frontend/src/scripts/components/inputs/DateInput.tsx b/packages/frontend/src/scripts/components/inputs/DateInput.tsx index 32f0b8a8..786d1df9 100644 --- a/packages/frontend/src/scripts/components/inputs/DateInput.tsx +++ b/packages/frontend/src/scripts/components/inputs/DateInput.tsx @@ -13,7 +13,8 @@ export const DateInput = (props: {class?: string, label: string, change?: (value const required = props.required function onChange(event: React.ChangeEvent) { - props.change && props.change(new Date(event.currentTarget.valueAsNumber)) + console.log(event.currentTarget.value) + props.change && props.change(new Date(event.currentTarget.value)) } return ( diff --git a/packages/frontend/src/scripts/components/views/ProductIssueComment.tsx b/packages/frontend/src/scripts/components/views/ProductIssueComment.tsx index 47b4db6d..5294b992 100644 --- a/packages/frontend/src/scripts/components/views/ProductIssueComment.tsx +++ b/packages/frontend/src/scripts/components/views/ProductIssueComment.tsx @@ -12,7 +12,7 @@ import { UserContext } from '../../contexts/User' import { useIssue, useProduct } from '../../hooks/entity' import { useComments, useMembers } from '../../hooks/list' import { Part, collectParts } from '../../functions/markdown' -import { formatDateTime } from '../../functions/time' +import { formatDateHourMinute } from '../../functions/time' import { computePath } from '../../functions/path' import { LegalFooter } from '../snippets/LegalFooter' import { ProductFooter, ProductFooterItem } from '../snippets/ProductFooter' @@ -177,7 +177,7 @@ export const ProductIssueCommentView = () => { - created this issue on {formatDateTime(new Date(issue.created))} + created this issue on {formatDateHourMinute(new Date(issue.created))}

diff --git a/packages/frontend/src/scripts/components/views/ProductMilestone.tsx b/packages/frontend/src/scripts/components/views/ProductMilestone.tsx index dcf3f921..5e54f041 100644 --- a/packages/frontend/src/scripts/components/views/ProductMilestone.tsx +++ b/packages/frontend/src/scripts/components/views/ProductMilestone.tsx @@ -10,7 +10,7 @@ import { UserContext } from '../../contexts/User' import { useProduct } from '../../hooks/entity' import { useAsyncHistory } from '../../hooks/history' import { useMilestones, useMembers } from '../../hooks/list' -import { formatDateTime } from '../../functions/time' +import { formatDateHourMinute } from '../../functions/time' import { LegalFooter } from '../snippets/LegalFooter' import { ProductFooter, ProductFooterItem } from '../snippets/ProductFooter' import { MilestoneProgressWidget } from '../widgets/MilestoneProgress' @@ -67,12 +67,12 @@ export const ProductMilestoneView = () => { ) }, { label: 'Start', class: 'nowrap center', content: milestone => ( - {formatDateTime(new Date(milestone.start))} + {formatDateHourMinute(new Date(milestone.start))} ) }, { label: 'End', class: 'nowrap center', content: milestone => ( - {formatDateTime(new Date(milestone.end))} + {formatDateHourMinute(new Date(milestone.end))} ) }, { label: 'Open', class: 'center', content: milestone => ( diff --git a/packages/frontend/src/scripts/components/views/ProductMilestoneIssue.tsx b/packages/frontend/src/scripts/components/views/ProductMilestoneIssue.tsx index 0d649809..ff85ff5e 100644 --- a/packages/frontend/src/scripts/components/views/ProductMilestoneIssue.tsx +++ b/packages/frontend/src/scripts/components/views/ProductMilestoneIssue.tsx @@ -12,7 +12,7 @@ import { useAsyncHistory } from '../../hooks/history' import { useMembers, useIssues } from '../../hooks/list' import { useIssuesComments } from '../../hooks/map' import { calculateActual } from '../../functions/burndown' -import { formatDateTime } from '../../functions/time' +import { formatDateHourMinute } from '../../functions/time' import { PartCount } from '../counts/Parts' import { LegalFooter } from '../snippets/LegalFooter' import { ProductFooter, ProductFooterItem } from '../snippets/ProductFooter' @@ -200,16 +200,16 @@ export const ProductMilestoneIssueView = () => { created this milestone on - {formatDateTime(new Date(milestone.created))} + {formatDateHourMinute(new Date(milestone.created))}

This milestone starts on - {formatDateTime(new Date(milestone.start))} + {formatDateHourMinute(new Date(milestone.start))} and ends on - {formatDateTime(new Date(milestone.end))} + {formatDateHourMinute(new Date(milestone.end))}

{contextUser ? ( diff --git a/packages/frontend/src/scripts/components/widgets/BurndownChart.tsx b/packages/frontend/src/scripts/components/widgets/BurndownChart.tsx index 735509fd..252b1b5d 100644 --- a/packages/frontend/src/scripts/components/widgets/BurndownChart.tsx +++ b/packages/frontend/src/scripts/components/widgets/BurndownChart.tsx @@ -3,27 +3,127 @@ import { useState } from 'react' import { CartesianGrid, Legend, Line, LineChart, ReferenceLine, ResponsiveContainer, XAxis, YAxis } from 'recharts' -/* +import { formatDate, formatDateHour, formatDateHourMinute, formatMonth } from '../../functions/time' + +function monthTickFormatter(time: number) { + return formatMonth(new Date(time)) +} + function dateTickFormatter(time: number) { return formatDate(new Date(time)) } -function dateTimeTickFormatter(time: number) { - return formatDateTime(new Date(time)) +function dateHourTickFormatter(time: number) { + return formatDateHour(new Date(time)) +} + +function dateHourMinuteTickFormatter(time: number) { + return formatDateHourMinute(new Date(time)) } -*/ export const BurndownChartWidget = (props: { start: number, end: number, total: number, actual: { time: number, actual: number }[] }) => { // CONSTANTS - const start = props.start - const end = props.end + let start = props.start + let end = props.end + + const span = end - start const now = Date.now() + + const startDate = new Date(start) + const endDate = new Date(end) + + let step: number + + if (span <= 1000 * 60 * 60) { + + step = 1000 * 60 + + startDate.setMinutes(startDate.getMinutes(), 0, 0) + start = startDate.getTime() + + endDate.setMinutes(endDate.getMinutes() + 1, 0, 0) + end = endDate.getTime() + + } else if (span <= 1000 * 60 * 60 * 24) { + + step = 1000 * 60 * 60 + + startDate.setHours(startDate.getHours(), 0, 0, 0) + start = startDate.getTime() + + endDate.setHours(endDate.getHours() + 1, 0, 0, 0) + end = endDate.getTime() + + } else if (span <= 1000 * 60 * 60 * 24 * 48) { + + step = 1000 * 60 * 60 * 24 + + startDate.setDate(startDate.getDate()) + startDate.setHours(0, 0, 0, 0) + start = startDate.getTime() + + endDate.setDate(endDate.getDate() + 1) + endDate.setHours(0, 0, 0, 0) + end = endDate.getTime() + + } else { + + startDate.setMonth(startDate.getMonth(), 2) + startDate.setHours(0, 0, 0, 0) + start = startDate.getTime() + + endDate.setMonth(endDate.getMonth() + 1, 2) + endDate.setHours(0, 0, 0, 0) + end = endDate.getTime() + + } + const total = props.total const actual = props.actual const padding = 50 + const domain = [start, end] + + const ticks = [] + if (step) { + for (let i = start; i <= end; i += step) { + ticks.push(i) + } + } else { + while (startDate <= endDate) { + ticks.push(startDate.getTime()) + startDate.setMonth(startDate.getMonth() + 1) + } + } + + let tickFormatter: (timestamp: number) => string + if (step) { + if (step <= 1000 * 60) { + tickFormatter = dateHourMinuteTickFormatter + } else if (step <= 1000 * 60 * 60) { + tickFormatter = dateHourTickFormatter + } else { + tickFormatter = dateTickFormatter + } + } else { + tickFormatter = monthTickFormatter + } + + let height: number + if (step) { + if (step <= 1000 * 60) { + height = 150 + } else if (step <= 1000 * 60 * 60) { + height = 130 + } else { + height = 90 + } + } else { + height = 70 + } + // INITIAL STATES const initialTarget = [{ time: start, target: total }, { time: end, target: 0 }] @@ -35,8 +135,8 @@ export const BurndownChartWidget = (props: { start: number, end: number, total: // EFFECTS React.useEffect(() => { - setTarget([{ time: start, target: total }, { time: end, target: 0 }]) - }, [start, end, total]) + setTarget([{ time: props.start, target: total }, { time: props.end, target: 0 }]) + }, [props.start, props.end, total]) // RETURN @@ -45,14 +145,14 @@ export const BurndownChartWidget = (props: { start: number, end: number, total: - + `${Math.round(value)}`} padding={{top: padding}}/> {now >= start && now <= end && ( )} - - + + diff --git a/packages/frontend/src/scripts/components/widgets/CommentView.tsx b/packages/frontend/src/scripts/components/widgets/CommentView.tsx index 2d91b462..606d2279 100644 --- a/packages/frontend/src/scripts/components/widgets/CommentView.tsx +++ b/packages/frontend/src/scripts/components/widgets/CommentView.tsx @@ -12,7 +12,7 @@ import { VersionContext } from '../../contexts/Version' import { useComment, useIssue } from '../../hooks/entity' import { useMembers, useVersions } from '../../hooks/list' import { collectParts, createProcessor } from '../../functions/markdown' -import { formatDateTime } from '../../functions/time' +import { formatDateHourMinute } from '../../functions/time' import { computePath } from '../../functions/path' import { ProductUserPicture } from '../values/ProductUserPicture' import { ProductUserName } from '../values/ProductUserName' @@ -310,7 +310,7 @@ export const CommentView = (props: { productId: string, issueId: string, comment

{comment ? ( <> - commented on {formatDateTime(new Date(comment.created))} {upload ? 'uploading ...' : action} + commented on {formatDateHourMinute(new Date(comment.created))} {upload ? 'uploading ...' : action} ) : ( <> diff --git a/packages/frontend/src/scripts/functions/burndown.ts b/packages/frontend/src/scripts/functions/burndown.ts index e622c5b9..a28ac115 100644 --- a/packages/frontend/src/scripts/functions/burndown.ts +++ b/packages/frontend/src/scripts/functions/burndown.ts @@ -50,7 +50,7 @@ export function calculateActual(startDate: number, endDate: number, issues: Issu actual.push({ time: startDate, actual: 0 }) } if (actual[actual.length - 1].time < endDate) { - actual.push({ time: endDate, actual: actual[actual.length - 1].actual}) + actual.push({ time: Math.min(endDate, Date.now()), actual: actual[actual.length - 1].actual}) } return actual diff --git a/packages/frontend/src/scripts/functions/time.ts b/packages/frontend/src/scripts/functions/time.ts index 5e72bf59..82205730 100644 --- a/packages/frontend/src/scripts/functions/time.ts +++ b/packages/frontend/src/scripts/functions/time.ts @@ -1,7 +1,15 @@ +export function formatMonth(date: Date) { + return date.toISOString().substring(0,7) +} + export function formatDate(date: Date) { return date.toISOString().substring(0,10) } -export function formatDateTime(date: Date) { +export function formatDateHour(date: Date) { + return `${formatDate(date)} @ ${date.toLocaleTimeString().substring(0,5)}` +} + +export function formatDateHourMinute(date: Date) { return `${formatDate(date)} @ ${date.toLocaleTimeString().substring(0,5)}` } \ No newline at end of file