feat: show next due date for items

This commit is contained in:
2026-04-13 10:26:51 +03:00
parent 6a0cc16cfc
commit 7bcaea3edd
5 changed files with 50 additions and 3 deletions

View File

@@ -57,6 +57,7 @@ vi.mock('@/api/images', () => ({
vi.mock('@/utils/rrule', () => ({
formatRrule: (rrule: string) => rrule,
formatNextRecurrence: () => null,
}))
import ChecklistItemRow from './ChecklistItemRow.vue'

View File

@@ -24,7 +24,7 @@
</NcCheckboxRadioSwitch>
<div class="checklist-row__meta">
<span v-if="item.quantity" class="checklist-row__quantity">&times; {{ item.quantity }}</span>
<span v-if="item.rrule" class="checklist-row__recurrence" :title="item.rrule">
<span v-if="item.rrule" class="checklist-row__recurrence" :title="recurrenceTooltip">
<RepeatIcon :size="14" />
{{ formatRrule(item.rrule) }}
</span>
@@ -77,7 +77,7 @@ import DeleteIcon from '@icons/Delete.vue'
import ArrowRightIcon from '@icons/ArrowRight.vue'
import { categoryIconComponent } from '@/components/CategoryPicker'
import { itemImagePreviewUrl } from '@/api/images'
import { formatRrule } from '@/utils/rrule'
import { formatRrule, formatNextRecurrence } from '@/utils/rrule'
import type { ChecklistItem, Category } from '@/api/types'
const props = withDefaults(
@@ -127,6 +127,15 @@ const thumbUrl = computed(() =>
: '',
)
const recurrenceTooltip = computed(() => {
const next = formatNextRecurrence(
props.item.nextDueAt,
props.item.repeatFromCompletion,
props.item.done,
)
return next ? t('pantry', 'Next: {next}', { next }) : formatRrule(props.item.rrule!)
})
const strings = {
viewImage: t('pantry', 'View image'),
viewItem: t('pantry', 'View item'),

View File

@@ -45,6 +45,7 @@ vi.mock('@/api/images', () => ({
vi.mock('@/utils/rrule', () => ({
formatRrule: (rrule: string) => rrule,
formatNextRecurrence: () => null,
}))
import ChecklistItemViewDialog from './ChecklistItemViewDialog.vue'

View File

@@ -40,6 +40,10 @@
{{ formatRrule(item.rrule) }}
</span>
</div>
<div v-if="nextRecurrence" class="item-view__row">
<span class="item-view__label">{{ strings.nextRecurrence }}:</span>
<span>{{ nextRecurrence }}</span>
</div>
<div v-if="item.done" class="item-view__row">
<span class="item-view__label">{{ strings.status }}:</span>
<span>{{ strings.done }}</span>
@@ -67,7 +71,7 @@ import RepeatIcon from '@icons/Repeat.vue'
import PencilIcon from '@icons/Pencil.vue'
import { categoryIconComponent } from '@/components/CategoryPicker'
import { itemImagePreviewUrl } from '@/api/images'
import { formatRrule } from '@/utils/rrule'
import { formatRrule, formatNextRecurrence } from '@/utils/rrule'
import type { ChecklistItem, Category } from '@/api/types'
const props = defineProps<{
@@ -89,11 +93,18 @@ const largeUrl = computed(() =>
: '',
)
const nextRecurrence = computed(() =>
props.item.rrule
? formatNextRecurrence(props.item.nextDueAt, props.item.repeatFromCompletion, props.item.done)
: null,
)
const strings = {
viewImage: t('pantry', 'View image'),
quantity: t('pantry', 'Quantity'),
category: t('pantry', 'Category'),
recurrence: t('pantry', 'Recurrence'),
nextRecurrence: t('pantry', 'Next recurrence'),
status: t('pantry', 'Status'),
done: t('pantry', 'Done'),
editItem: t('pantry', 'Edit item'),

View File

@@ -1,3 +1,4 @@
import { t } from '@nextcloud/l10n'
import { RRule } from 'rrule'
export function formatRrule(rrule: string): string {
@@ -8,3 +9,27 @@ export function formatRrule(rrule: string): string {
return rrule
}
}
/**
* Return a human-readable "next recurrence" string for a checklist item.
*/
export function formatNextRecurrence(
nextDueAt: number | null,
repeatFromCompletion: boolean,
done: boolean,
): string | null {
if (nextDueAt) {
const date = new Date(nextDueAt * 1000)
return date.toLocaleDateString(undefined, {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
})
}
if (repeatFromCompletion && !done) {
return t('pantry', 'Starts after completion')
}
return null
}