diff --git a/src/components/ChecklistItemRow/ChecklistItemRow.test.ts b/src/components/ChecklistItemRow/ChecklistItemRow.test.ts index 0e166f5..489c48f 100644 --- a/src/components/ChecklistItemRow/ChecklistItemRow.test.ts +++ b/src/components/ChecklistItemRow/ChecklistItemRow.test.ts @@ -57,6 +57,7 @@ vi.mock('@/api/images', () => ({ vi.mock('@/utils/rrule', () => ({ formatRrule: (rrule: string) => rrule, + formatNextRecurrence: () => null, })) import ChecklistItemRow from './ChecklistItemRow.vue' diff --git a/src/components/ChecklistItemRow/ChecklistItemRow.vue b/src/components/ChecklistItemRow/ChecklistItemRow.vue index 6bdfb6a..306dbbd 100644 --- a/src/components/ChecklistItemRow/ChecklistItemRow.vue +++ b/src/components/ChecklistItemRow/ChecklistItemRow.vue @@ -24,7 +24,7 @@
× {{ item.quantity }} - + {{ formatRrule(item.rrule) }} @@ -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'), diff --git a/src/components/ChecklistItemViewDialog/ChecklistItemViewDialog.test.ts b/src/components/ChecklistItemViewDialog/ChecklistItemViewDialog.test.ts index 5854c9f..54c7dc9 100644 --- a/src/components/ChecklistItemViewDialog/ChecklistItemViewDialog.test.ts +++ b/src/components/ChecklistItemViewDialog/ChecklistItemViewDialog.test.ts @@ -45,6 +45,7 @@ vi.mock('@/api/images', () => ({ vi.mock('@/utils/rrule', () => ({ formatRrule: (rrule: string) => rrule, + formatNextRecurrence: () => null, })) import ChecklistItemViewDialog from './ChecklistItemViewDialog.vue' diff --git a/src/components/ChecklistItemViewDialog/ChecklistItemViewDialog.vue b/src/components/ChecklistItemViewDialog/ChecklistItemViewDialog.vue index 6b64899..9b2be47 100644 --- a/src/components/ChecklistItemViewDialog/ChecklistItemViewDialog.vue +++ b/src/components/ChecklistItemViewDialog/ChecklistItemViewDialog.vue @@ -40,6 +40,10 @@ {{ formatRrule(item.rrule) }}
+
+ {{ strings.nextRecurrence }}: + {{ nextRecurrence }} +
{{ strings.status }}: {{ strings.done }} @@ -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'), diff --git a/src/utils/rrule.ts b/src/utils/rrule.ts index f02b1f0..09819e0 100644 --- a/src/utils/rrule.ts +++ b/src/utils/rrule.ts @@ -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 +}