diff --git a/src/utils/ChoreCardHelpers.jsx b/src/utils/ChoreCardHelpers.jsx new file mode 100644 index 0000000..ca87966 --- /dev/null +++ b/src/utils/ChoreCardHelpers.jsx @@ -0,0 +1,62 @@ +import moment from 'moment' + +/** + * Get the text to display for a chore's due date + * @param {string|null} nextDueDate - The next due date of the chore + * @param {Object} chore - The chore object (needed for nextDueDate null check) + * @returns {string} The formatted due date text + */ +export const getDueDateChipText = (nextDueDate, chore) => { + if (chore?.nextDueDate === null || nextDueDate === null) return 'No Due Date' + + const dueDate = moment(nextDueDate) + const diff = moment(nextDueDate).diff(moment(), 'hours') + + // if seconds and minutes set to 59, treat as no time (date only) + if (dueDate.seconds() === 59 && dueDate.minutes() === 59) { + if (diff < 0) { + // For overdue dates, show calendar format for recent dates + const absDiff = Math.abs(diff) + if (absDiff <= 48) { + return ( + 'Overdue ' + + moment(nextDueDate).calendar().split(' at ')[0].toLowerCase() + ) + } + return 'Overdue ' + dueDate.fromNow() + } + // if due in next 48 hours, show calendar format without time (e.g., "Tomorrow") + if (diff < 48 && diff > 0) { + return moment(nextDueDate).calendar().split(' at ')[0] + } + // if due date is after 48 hours, show it in format: Due in 3 days + return 'Due ' + dueDate.fromNow() + } + + // if due in next 48 hours, we should show it in this format: Tomorrow 11:00 AM + if (diff < 48 && diff > 0) { + return moment(nextDueDate).calendar().replace(' at', '') + } + return 'Due ' + moment(nextDueDate).fromNow() +} + +/** + * Get the color to use for a chore's due date chip + * @param {string|null} nextDueDate - The next due date of the chore + * @param {Object} chore - The chore object (needed for nextDueDate null check) + * @returns {string} The color name for the chip + */ +export const getDueDateChipColor = (nextDueDate, chore) => { + if (chore?.nextDueDate === null || nextDueDate === null) return 'neutral' + + const diff = moment(nextDueDate).diff(moment(), 'hours') + + if (diff < 48 && diff > 0) { + return 'warning' + } + if (diff < 0) { + return 'danger' + } + + return 'neutral' +} diff --git a/src/views/Chores/ChoreCard.jsx b/src/views/Chores/ChoreCard.jsx index 0da767c..c7c2b9d 100644 --- a/src/views/Chores/ChoreCard.jsx +++ b/src/views/Chores/ChoreCard.jsx @@ -23,6 +23,10 @@ import { import moment from 'moment' import { useImpersonateUser } from '../../contexts/ImpersonateUserContext.jsx' import { useUserProfile } from '../../queries/UserQueries.jsx' +import { + getDueDateChipColor, + getDueDateChipText, +} from '../../utils/ChoreCardHelpers.jsx' import { notInCompletionWindow } from '../../utils/Chores.jsx' import { getTextColorFromBackgroundColor } from '../../utils/Colors.jsx' import Priorities from '../../utils/Priorities' @@ -62,28 +66,6 @@ const ChoreCard = ({ ) } - const getDueDateChipText = nextDueDate => { - if (chore.nextDueDate === null) return 'No Due Date' - // if due in next 48 hours, we should it in this format : Tomorrow 11:00 AM - const diff = moment(nextDueDate).diff(moment(), 'hours') - if (diff < 48 && diff > 0) { - return moment(nextDueDate).calendar().replace(' at', '') - } - return 'Due ' + moment(nextDueDate).fromNow() - } - const getDueDateChipColor = nextDueDate => { - if (chore.nextDueDate === null) return 'neutral' - const diff = moment(nextDueDate).diff(moment(), 'hours') - if (diff < 48 && diff > 0) { - return 'warning' - } - if (diff < 0) { - return 'danger' - } - - return 'neutral' - } - const getRecurrentChipText = chore => { // if chore.frequencyMetadata is type string then parse it otherwise assigned to the metadata: const metadata = @@ -216,9 +198,9 @@ const ChoreCard = ({ zIndex: 3, left: 10, }} - color={getDueDateChipColor(chore.nextDueDate)} + color={getDueDateChipColor(chore.nextDueDate, chore)} > - {getDueDateChipText(chore.nextDueDate)} + {getDueDateChipText(chore.nextDueDate, chore)} { - if (chore.nextDueDate === null) return 'No Due Date' - // if due in next 48 hours, we should it in this format : Tomorrow 11:00 AM - const diff = moment(nextDueDate).diff(moment(), 'hours') - if (diff < 48 && diff > 0) { - return moment(nextDueDate).calendar().replace(' at', '') - } - - return moment(nextDueDate).fromNow() - } - - const getDueDateColor = nextDueDate => { - if (chore.nextDueDate === null) return 'neutral' - const diff = moment(nextDueDate).diff(moment(), 'hours') - if (diff < 48 && diff > 0) { - return 'warning' - } - if (diff < 0) { - return 'danger' - } - return 'neutral' - } const getRecurrentText = chore => { // if chore.frequencyMetadata is type string then parse it otherwise assigned to the metadata: @@ -509,7 +491,7 @@ const CompactChoreCard = ({ - {getDueDateText(chore.nextDueDate)} + {getDueDateChipText(chore.nextDueDate, chore)}