UBER-832: fixed DatePresenter (#3653)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2023-09-03 19:35:43 +03:00 committed by GitHub
parent 25514b58ab
commit bf9dd1b494
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 75 additions and 46 deletions

View File

@ -1081,12 +1081,21 @@
&:not(.only-icon) .btn-icon, &:not(.only-icon) .btn-icon,
&:not(.only-icon) .icon { margin-right: .375rem !important; } &:not(.only-icon) .icon { margin-right: .375rem !important; }
.icon, .btn-icon { color: var(--theme-halfcontent-color) !important; }
.label { .label {
font-size: 0.8125rem !important; font-size: 0.8125rem !important;
color: var(--theme-halfcontent-color) !important; color: var(--theme-halfcontent-color) !important;
} }
} }
.list-container .listitems-container,
.list-container .listitems-container:hover,
.list-container .antiButton.list,
.list-container .antiButton.list:hover {
.icon, .btn-icon { color: var(--theme-halfcontent-color) !important; }
}
.list-container .datetime-button .btn-icon.normal,
.list-container .datetime-button:hover .btn-icon.normal {
color: var(--theme-halfcontent-color) !important;
}
/* Kanban - global style */ /* Kanban - global style */
.kanban-container .card-container .antiButton.link-bordered { padding: 0 .5rem; } .kanban-container .card-container .antiButton.link-bordered { padding: 0 .5rem; }

View File

@ -24,6 +24,7 @@
import Label from '../Label.svelte' import Label from '../Label.svelte'
import DatePopup from './DatePopup.svelte' import DatePopup from './DatePopup.svelte'
import DPCalendar from './icons/DPCalendar.svelte' import DPCalendar from './icons/DPCalendar.svelte'
import DPCalendarOver from './icons/DPCalendarOver.svelte'
import { getMonthName } from './internal/DateUtils' import { getMonthName } from './internal/DateUtils'
import { ComponentType } from 'svelte' import { ComponentType } from 'svelte'
@ -33,6 +34,7 @@
export let editable: boolean = false export let editable: boolean = false
export let icon: Asset | AnySvelteComponent | ComponentType | undefined = undefined export let icon: Asset | AnySvelteComponent | ComponentType | undefined = undefined
export let iconModifier: 'normal' | 'warning' | 'critical' | 'overdue' = 'normal' export let iconModifier: 'normal' | 'warning' | 'critical' | 'overdue' = 'normal'
export let shouldIgnoreOverdue: boolean = false
export let labelNull: IntlString = ui.string.NoDate export let labelNull: IntlString = ui.string.NoDate
export let showIcon = true export let showIcon = true
export let shouldShowLabel: boolean = true export let shouldShowLabel: boolean = true
@ -94,7 +96,10 @@
> >
{#if showIcon} {#if showIcon}
<div class="btn-icon {iconModifier}" class:buttonIconNoLabel={!shouldShowLabel}> <div class="btn-icon {iconModifier}" class:buttonIconNoLabel={!shouldShowLabel}>
<Icon icon={icon ?? DPCalendar} size="full" /> <Icon
icon={icon ?? (iconModifier === 'overdue' && !shouldIgnoreOverdue) ? DPCalendarOver : DPCalendar}
size={'full'}
/>
</div> </div>
{/if} {/if}
{#if value !== null && value !== undefined} {#if value !== null && value !== undefined}

View File

@ -23,12 +23,14 @@
import IconClose from '../icons/Close.svelte' import IconClose from '../icons/Close.svelte'
import DatePopup from './DatePopup.svelte' import DatePopup from './DatePopup.svelte'
import DPCalendar from './icons/DPCalendar.svelte' import DPCalendar from './icons/DPCalendar.svelte'
import DPCalendarOver from './icons/DPCalendarOver.svelte'
import { daysInMonth, getMonthName } from './internal/DateUtils' import { daysInMonth, getMonthName } from './internal/DateUtils'
export let value: number | null | undefined = null export let value: number | null | undefined = null
export let mode: DateRangeMode = DateRangeMode.DATE export let mode: DateRangeMode = DateRangeMode.DATE
export let editable: boolean = false export let editable: boolean = false
export let iconModifier: 'normal' | 'warning' | 'overdue' = 'normal' export let iconModifier: 'overdue' | 'critical' | 'warning' | 'normal' = 'normal'
export let shouldIgnoreOverdue: boolean = false
export let labelNull: IntlString = ui.string.NoDate export let labelNull: IntlString = ui.string.NoDate
export let kind: 'default' | 'no-border' | 'link' | 'regular' = 'default' export let kind: 'default' | 'no-border' | 'link' | 'regular' = 'default'
export let size: 'small' | 'medium' | 'large' = 'small' export let size: 'small' | 'medium' | 'large' = 'small'
@ -397,7 +399,7 @@
{/if} {/if}
{:else} {:else}
<div class="btn-icon {iconModifier}"> <div class="btn-icon {iconModifier}">
<Icon icon={DPCalendar} size={'full'} /> <Icon icon={iconModifier === 'overdue' && !shouldIgnoreOverdue ? DPCalendarOver : DPCalendar} size={'full'} />
</div> </div>
{#if value !== undefined && value !== null && value.toString() !== ''} {#if value !== undefined && value !== null && value.toString() !== ''}
{#if withDate} {#if withDate}
@ -469,6 +471,9 @@
&.overdue { &.overdue {
color: var(--theme-error-color); color: var(--theme-error-color);
} }
&.critical {
color: var(--theme-error-color);
}
} }
&.default { &.default {
@ -525,6 +530,9 @@
&.overdue { &.overdue {
color: var(--theme-error-color); color: var(--theme-error-color);
} }
&.critical {
color: var(--theme-error-color);
}
} }
.time-divider { .time-divider {
background-color: var(--theme-divider-color); background-color: var(--theme-divider-color);

View File

@ -22,7 +22,7 @@
export let formattedDate: string = '' export let formattedDate: string = ''
export let daysDifference: number = 0 export let daysDifference: number = 0
export let isOverdue: boolean = false export let isOverdue: boolean = false
export let iconModifier: 'warning' | 'critical' | 'overdue' | undefined = undefined export let iconModifier: 'warning' | 'critical' | 'overdue' | 'normal' = 'normal'
export let shouldIgnoreOverdue: boolean = false export let shouldIgnoreOverdue: boolean = false
</script> </script>
@ -42,14 +42,14 @@
params={{ value: formattedDate }} params={{ value: formattedDate }}
/> />
</div> </div>
<div class="description">
{#if !shouldIgnoreOverdue} {#if !shouldIgnoreOverdue}
<div class="description">
<Label <Label
label={isOverdue ? ui.string.DueDatePopupOverdueDescription : ui.string.DueDatePopupDescription} label={isOverdue ? ui.string.DueDatePopupOverdueDescription : ui.string.DueDatePopupDescription}
params={{ value: daysDifference }} params={{ value: daysDifference }}
/> />
{/if}
</div> </div>
{/if}
</div> </div>
</div> </div>
{/if} {/if}
@ -58,11 +58,13 @@
.root { .root {
display: flex; display: flex;
width: 10rem; width: 10rem;
min-width: 0;
} }
.iconContainer { .iconContainer {
color: var(--content-color); margin-top: 0.125rem;
margin-right: 1rem; margin-right: 0.5rem;
color: var(--theme-caption-color);
&.mIconContainerWarning { &.mIconContainerWarning {
color: var(--theme-warning-color); color: var(--theme-warning-color);
@ -80,12 +82,12 @@
} }
.title { .title {
color: var(--caption-color); color: var(--theme-caption-color);
font-weight: 500; font-weight: 500;
} }
.description { .description {
margin-top: 0.25rem; margin-top: 0.25rem;
color: var(--dark-color); color: var(--theme-dark-color);
} }
</style> </style>

View File

@ -17,7 +17,7 @@
import DueDatePopup from './DueDatePopup.svelte' import DueDatePopup from './DueDatePopup.svelte'
import { tooltip } from '../../tooltips' import { tooltip } from '../../tooltips'
import DatePresenter from './DatePresenter.svelte' import DatePresenter from './DatePresenter.svelte'
import { getDaysDifference } from './internal/DateUtils' import { getDaysDifference, getDueDateIconModifier, getFormattedDate } from './internal/DateUtils'
import { ButtonKind, ButtonSize } from '../../types' import { ButtonKind, ButtonSize } from '../../types'
export let value: number | null = null export let value: number | null = null
@ -33,14 +33,10 @@
$: isOverdue = value !== null && value < today.getTime() $: isOverdue = value !== null && value < today.getTime()
$: dueDate = value === null ? null : new Date(value) $: dueDate = value === null ? null : new Date(value)
$: daysDifference = dueDate === null ? null : getDaysDifference(today, dueDate) $: daysDifference = dueDate === null ? null : getDaysDifference(today, dueDate)
$: iconModifier = getDueDateIconModifier(isOverdue, daysDifference) $: iconModifier = getDueDateIconModifier(isOverdue, daysDifference, shouldIgnoreOverdue)
let formattedDate = getFormattedDate(value) let formattedDate = getFormattedDate(value)
$: formattedDate = getFormattedDate(value) $: formattedDate = getFormattedDate(value)
function getFormattedDate (value: number | null): string {
return !value ? '' : new Date(value).toLocaleString('default', { month: 'short', day: 'numeric' })
}
const handleDueDateChanged = async (event: CustomEvent<Timestamp>) => { const handleDueDateChanged = async (event: CustomEvent<Timestamp>) => {
const newDate = event.detail const newDate = event.detail
@ -50,29 +46,6 @@
onChange(newDate) onChange(newDate)
} }
const WARNING_DAYS = 7
const getDueDateIconModifier = (
isOverdue: boolean,
daysDifference: number | null
): 'overdue' | 'critical' | 'warning' | undefined => {
if (shouldIgnoreOverdue) {
return
}
if (isOverdue) {
return 'overdue'
}
if (daysDifference === 0) {
return 'critical'
}
if (daysDifference !== null && daysDifference <= WARNING_DAYS) {
return 'warning'
}
}
</script> </script>
{#if shouldRender} {#if shouldRender}
@ -93,6 +66,15 @@
} }
: undefined} : undefined}
> >
<DatePresenter {value} {editable} {iconModifier} {kind} {size} {width} on:change={handleDueDateChanged} /> <DatePresenter
{value}
{editable}
{iconModifier}
{kind}
{size}
{width}
{shouldIgnoreOverdue}
on:change={handleDueDateChanged}
/>
</div> </div>
{/if} {/if}

View File

@ -3,8 +3,13 @@
export let fill: string = 'currentColor' export let fill: string = 'currentColor'
</script> </script>
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> <svg class="svg-{size}" {fill} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<path <path
d="M11 1C13.2091 1 15 2.79086 15 5V6.25C15 6.66421 14.6642 7 14.25 7C13.8358 7 13.5 6.66421 13.5 6.25V6H2.5V11C2.5 12.3807 3.61929 13.5 5 13.5H6.25C6.66421 13.5 7 13.8358 7 14.25C7 14.6642 6.66421 15 6.25 15H5C2.79086 15 1 13.2091 1 11V5C1 2.79086 2.79086 1 5 1H11ZM9.53033 8.46967L11.5 10.4393L13.4697 8.46967C13.7626 8.17678 14.2374 8.17678 14.5303 8.46967C14.8232 8.76256 14.8232 9.23744 14.5303 9.53033L12.5607 11.5L14.5303 13.4697C14.8232 13.7626 14.8232 14.2374 14.5303 14.5303C14.2374 14.8232 13.7626 14.8232 13.4697 14.5303L11.5 12.5607L9.53033 14.5303C9.23744 14.8232 8.76256 14.8232 8.46967 14.5303C8.17678 14.2374 8.17678 13.7626 8.46967 13.4697L10.4393 11.5L8.46967 9.53033C8.17678 9.23744 8.17678 8.76256 8.46967 8.46967C8.76256 8.17678 9.23744 8.17678 9.53033 8.46967Z" fill-rule="evenodd"
clip-rule="evenodd"
d="M4 7.99988V23.9999C4 26.209 5.79086 27.9999 8 27.9999H17C17.5523 27.9999 18 27.5522 18 26.9999C18 26.4476 17.5523 25.9999 17 25.9999H8C6.89543 25.9999 6 25.1044 6 23.9999V13.9999H26V17C26 17.5523 26.4477 18 27 18C27.5523 18 28 17.5523 28 17V7.99988C28 5.79074 26.2091 3.99988 24 3.99988H21.9995V2.99988C21.9995 2.44759 21.5518 1.99988 20.9995 1.99988C20.4472 1.99988 19.9995 2.44759 19.9995 2.99988V3.99988H12V2.99988C12 2.44759 11.5523 1.99988 11 1.99988C10.4477 1.99988 10 2.44759 10 2.99988V3.99988H8C5.79086 3.99988 4 5.79074 4 7.99988ZM19.9995 5.99988V6.99988C19.9995 7.55216 20.4472 7.99988 20.9995 7.99988C21.5518 7.99988 21.9995 7.55216 21.9995 6.99988V5.99988H24C25.1046 5.99988 26 6.89531 26 7.99988V11.9999H6V7.99988C6 6.89531 6.89543 5.99988 8 5.99988H10V6.99988C10 7.55216 10.4477 7.99988 11 7.99988C11.5523 7.99988 12 7.55216 12 6.99988V5.99988H19.9995Z"
/>
<path
d="M20.2929 21.7071C19.9024 21.3166 19.9024 20.6834 20.2929 20.2929C20.6834 19.9024 21.3166 19.9024 21.7071 20.2929L25 23.5858L28.2929 20.2929C28.6834 19.9024 29.3166 19.9024 29.7071 20.2929C30.0976 20.6834 30.0976 21.3166 29.7071 21.7071L26.4142 25L29.7071 28.2929C30.0976 28.6834 30.0976 29.3166 29.7071 29.7071C29.3166 30.0976 28.6834 30.0976 28.2929 29.7071L25 26.4136L21.6849 29.7287C21.2929 30.0975 20.6761 30.0903 20.2929 29.7071C19.9024 29.3166 19.9024 28.6834 20.2929 28.2929L23.5858 25L20.2929 21.7071Z"
/> />
</svg> </svg>

View File

@ -108,3 +108,21 @@ export const getDaysDifference = (from: Date, to: Date): number => {
export const getMillisecondsInMonth = (date: Date): number => { export const getMillisecondsInMonth = (date: Date): number => {
return daysInMonth(date) * MILLISECONDS_IN_DAY return daysInMonth(date) * MILLISECONDS_IN_DAY
} }
const WARNING_DAYS = 7
export const getDueDateIconModifier = (
isOverdue: boolean,
daysDifference: number | null,
shouldIgnoreOverdue: boolean
): 'overdue' | 'critical' | 'warning' | 'normal' => {
if (shouldIgnoreOverdue) return 'normal'
if (isOverdue) return 'overdue'
if (daysDifference === 0) return 'critical'
if (daysDifference !== null && daysDifference <= WARNING_DAYS) return 'warning'
return 'normal'
}
export function getFormattedDate (value: number | null): string {
return value === null ? '' : new Date(value).toLocaleString('default', { month: 'short', day: 'numeric' })
}

View File

@ -11,7 +11,7 @@
export let editable: boolean = true export let editable: boolean = true
const client = getClient() const client = getClient()
$: shouldIgnoreOverdue = object.doneState != null $: shouldIgnoreOverdue = object.doneState !== null
const handleDueDateChanged = async (newDueDate: number | undefined | null) => { const handleDueDateChanged = async (newDueDate: number | undefined | null) => {
if (newDueDate === undefined || object.dueDate === newDueDate) { if (newDueDate === undefined || object.dueDate === newDueDate) {