mirror of
https://github.com/chenasraf/nextcloud-pantry.git
synced 2026-05-17 17:28:01 +00:00
feat: show next due date for items
This commit is contained in:
@@ -57,6 +57,7 @@ vi.mock('@/api/images', () => ({
|
|||||||
|
|
||||||
vi.mock('@/utils/rrule', () => ({
|
vi.mock('@/utils/rrule', () => ({
|
||||||
formatRrule: (rrule: string) => rrule,
|
formatRrule: (rrule: string) => rrule,
|
||||||
|
formatNextRecurrence: () => null,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
import ChecklistItemRow from './ChecklistItemRow.vue'
|
import ChecklistItemRow from './ChecklistItemRow.vue'
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
</NcCheckboxRadioSwitch>
|
</NcCheckboxRadioSwitch>
|
||||||
<div class="checklist-row__meta">
|
<div class="checklist-row__meta">
|
||||||
<span v-if="item.quantity" class="checklist-row__quantity">× {{ item.quantity }}</span>
|
<span v-if="item.quantity" class="checklist-row__quantity">× {{ 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" />
|
<RepeatIcon :size="14" />
|
||||||
{{ formatRrule(item.rrule) }}
|
{{ formatRrule(item.rrule) }}
|
||||||
</span>
|
</span>
|
||||||
@@ -77,7 +77,7 @@ import DeleteIcon from '@icons/Delete.vue'
|
|||||||
import ArrowRightIcon from '@icons/ArrowRight.vue'
|
import ArrowRightIcon from '@icons/ArrowRight.vue'
|
||||||
import { categoryIconComponent } from '@/components/CategoryPicker'
|
import { categoryIconComponent } from '@/components/CategoryPicker'
|
||||||
import { itemImagePreviewUrl } from '@/api/images'
|
import { itemImagePreviewUrl } from '@/api/images'
|
||||||
import { formatRrule } from '@/utils/rrule'
|
import { formatRrule, formatNextRecurrence } from '@/utils/rrule'
|
||||||
import type { ChecklistItem, Category } from '@/api/types'
|
import type { ChecklistItem, Category } from '@/api/types'
|
||||||
|
|
||||||
const props = withDefaults(
|
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 = {
|
const strings = {
|
||||||
viewImage: t('pantry', 'View image'),
|
viewImage: t('pantry', 'View image'),
|
||||||
viewItem: t('pantry', 'View item'),
|
viewItem: t('pantry', 'View item'),
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ vi.mock('@/api/images', () => ({
|
|||||||
|
|
||||||
vi.mock('@/utils/rrule', () => ({
|
vi.mock('@/utils/rrule', () => ({
|
||||||
formatRrule: (rrule: string) => rrule,
|
formatRrule: (rrule: string) => rrule,
|
||||||
|
formatNextRecurrence: () => null,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
import ChecklistItemViewDialog from './ChecklistItemViewDialog.vue'
|
import ChecklistItemViewDialog from './ChecklistItemViewDialog.vue'
|
||||||
|
|||||||
@@ -40,6 +40,10 @@
|
|||||||
{{ formatRrule(item.rrule) }}
|
{{ formatRrule(item.rrule) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</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">
|
<div v-if="item.done" class="item-view__row">
|
||||||
<span class="item-view__label">{{ strings.status }}:</span>
|
<span class="item-view__label">{{ strings.status }}:</span>
|
||||||
<span>{{ strings.done }}</span>
|
<span>{{ strings.done }}</span>
|
||||||
@@ -67,7 +71,7 @@ import RepeatIcon from '@icons/Repeat.vue'
|
|||||||
import PencilIcon from '@icons/Pencil.vue'
|
import PencilIcon from '@icons/Pencil.vue'
|
||||||
import { categoryIconComponent } from '@/components/CategoryPicker'
|
import { categoryIconComponent } from '@/components/CategoryPicker'
|
||||||
import { itemImagePreviewUrl } from '@/api/images'
|
import { itemImagePreviewUrl } from '@/api/images'
|
||||||
import { formatRrule } from '@/utils/rrule'
|
import { formatRrule, formatNextRecurrence } from '@/utils/rrule'
|
||||||
import type { ChecklistItem, Category } from '@/api/types'
|
import type { ChecklistItem, Category } from '@/api/types'
|
||||||
|
|
||||||
const props = defineProps<{
|
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 = {
|
const strings = {
|
||||||
viewImage: t('pantry', 'View image'),
|
viewImage: t('pantry', 'View image'),
|
||||||
quantity: t('pantry', 'Quantity'),
|
quantity: t('pantry', 'Quantity'),
|
||||||
category: t('pantry', 'Category'),
|
category: t('pantry', 'Category'),
|
||||||
recurrence: t('pantry', 'Recurrence'),
|
recurrence: t('pantry', 'Recurrence'),
|
||||||
|
nextRecurrence: t('pantry', 'Next recurrence'),
|
||||||
status: t('pantry', 'Status'),
|
status: t('pantry', 'Status'),
|
||||||
done: t('pantry', 'Done'),
|
done: t('pantry', 'Done'),
|
||||||
editItem: t('pantry', 'Edit item'),
|
editItem: t('pantry', 'Edit item'),
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { t } from '@nextcloud/l10n'
|
||||||
import { RRule } from 'rrule'
|
import { RRule } from 'rrule'
|
||||||
|
|
||||||
export function formatRrule(rrule: string): string {
|
export function formatRrule(rrule: string): string {
|
||||||
@@ -8,3 +9,27 @@ export function formatRrule(rrule: string): string {
|
|||||||
return rrule
|
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
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user