- Updated LocalizationContext to consolidate date and time formatting functions into a single `fmt` object. - Modified ChoreCardHelpers to accept a time format parameter for due date text. - Adjusted ChoreView, RepeatSection, TimePassedCard, and other components to utilize the new `fmt` object for date and time formatting. - Enhanced HistoryCard and TimerEditModal to use the new localization functions for consistent date and time display. - Refined Settings and CircleSettings to leverage the updated localization methods for subscription and member date displays. - Improved ThingsHistory and UserActivities to format dates and times using the new localization structure. - Ensured CalendarCard and CalendarDual components utilize the new formatting functions for better readability.
175 lines
5.2 KiB
JavaScript
175 lines
5.2 KiB
JavaScript
import { Box, Typography } from '@mui/joy'
|
|
import { useEffect, useState } from 'react'
|
|
import Calendar from 'react-calendar'
|
|
import { useNavigate } from 'react-router-dom'
|
|
import { useCircleMembers, useUserProfile } from '../../queries/UserQueries'
|
|
import { getPriorityColor, TASK_COLOR } from '../../utils/Colors'
|
|
import { useLocalization } from '../../contexts/LocalizationContext'
|
|
import styles from './CalendarDual.module.css'
|
|
|
|
const getAssigneeColor = (assignee, userProfile) => {
|
|
return assignee === userProfile.id
|
|
? TASK_COLOR.ASSIGNED_TO_ME
|
|
: TASK_COLOR.ASSIGNED_TO_OTHER
|
|
}
|
|
const CalendarDual = ({ chores, onDateChange }) => {
|
|
const { data: userProfile } = useUserProfile()
|
|
const { firstDayOfWeek, fmt } = useLocalization()
|
|
const calendarType =
|
|
firstDayOfWeek === 1 ? 'iso8601' : firstDayOfWeek === 6 ? 'islamic' : 'gregory'
|
|
|
|
const [selectedDate, setSeletedDate] = useState(null)
|
|
const [currentDate, setCurrentDate] = useState(new Date())
|
|
const [nextMonth, setNextMonth] = useState(() => {
|
|
const next = new Date()
|
|
next.setMonth(next.getMonth() + 1)
|
|
return next
|
|
})
|
|
const Navigate = useNavigate()
|
|
|
|
// Fetch circle members data to get assignee names
|
|
const { data: circleMembersData } = useCircleMembers()
|
|
const circleMembers = circleMembersData?.res || []
|
|
|
|
// Update next month whenever current date changes
|
|
useEffect(() => {
|
|
const next = new Date(currentDate.getTime())
|
|
next.setMonth(currentDate.getMonth() + 1)
|
|
setNextMonth(next)
|
|
}, [currentDate])
|
|
|
|
// Helper function to get assignee display name
|
|
const getAssigneeName = assignedTo => {
|
|
if (assignedTo === userProfile.id) {
|
|
return userProfile.displayName
|
|
}
|
|
const assignee = circleMembers.find(member => member.userId === assignedTo)
|
|
return assignee ? `${assignee.displayName}` : 'Assigned to other'
|
|
}
|
|
|
|
const tileContent = ({ date, view }) => {
|
|
if (view === 'month') {
|
|
const dayChores = chores.filter(chore => {
|
|
const choreDate = new Date(chore.nextDueDate).toLocaleDateString()
|
|
const tileDate = date.toLocaleDateString()
|
|
return choreDate === tileDate
|
|
})
|
|
if (dayChores.length === 0) {
|
|
return (
|
|
<div className={styles.dotContainer}>
|
|
<span className={styles.dotEmpty}></span>
|
|
</div>
|
|
)
|
|
}
|
|
if (dayChores.length > 3) {
|
|
return (
|
|
<div className={styles.dotContainer}>
|
|
<span
|
|
className={styles.dotWithLine}
|
|
style={{
|
|
backgroundColor: getPriorityColor(dayChores[0].priority),
|
|
}}
|
|
></span>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className={styles.dotContainer}>
|
|
{dayChores.map((chore, index) => {
|
|
return (
|
|
<span
|
|
key={index}
|
|
className={styles.dot}
|
|
style={{
|
|
backgroundColor: getPriorityColor(chore.priority),
|
|
}}
|
|
></span>
|
|
)
|
|
})}
|
|
</div>
|
|
)
|
|
}
|
|
return null
|
|
}
|
|
|
|
const renderSingleCalendar = (date, isSecondary = false) => (
|
|
<div
|
|
className={`${styles.reactCalendar} ${isSecondary ? styles.secondaryCalendar : ''}`}
|
|
>
|
|
{isSecondary && (
|
|
<div className={styles.secondaryCalendarHeader}>
|
|
<Typography level='title-md' sx={{ textAlign: 'center', mb: 1 }}>
|
|
{fmt.date(date, 'MMMM YYYY')}
|
|
</Typography>
|
|
</div>
|
|
)}
|
|
<Calendar
|
|
className={styles.reactCalendar}
|
|
tileContent={tileContent}
|
|
calendarType={calendarType}
|
|
onChange={d => {
|
|
let date = new Date(d)
|
|
setSeletedDate(date)
|
|
onDateChange(date)
|
|
}}
|
|
value={selectedDate}
|
|
activeStartDate={date}
|
|
// Don't show navigation on secondary calendar
|
|
showNavigation={!isSecondary}
|
|
// format the days from MON, TUE, WED, THU, FRI, SAT, SUN to first three letters:
|
|
formatShortWeekday={(locale, date) =>
|
|
['S', 'M', 'T', 'W', 'T', 'F', 'S'][date.getDay()]
|
|
}
|
|
onActiveStartDateChange={({ activeStartDate }) => {
|
|
if (!isSecondary) {
|
|
setCurrentDate(activeStartDate)
|
|
}
|
|
}}
|
|
/>
|
|
</div>
|
|
)
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
width: '100%',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
}}
|
|
>
|
|
{/* Responsive Calendar Layout */}
|
|
<Box
|
|
sx={{
|
|
width: '100%',
|
|
display: 'flex',
|
|
flexDirection: { xs: 'column', md: 'row' },
|
|
gap: { xs: 2, md: 4 },
|
|
justifyContent: 'center',
|
|
alignItems: { xs: 'center', md: 'flex-start' },
|
|
}}
|
|
>
|
|
{/* Primary Calendar */}
|
|
<Box sx={{ flex: 1, display: 'flex', justifyContent: 'center' }}>
|
|
{renderSingleCalendar(currentDate)}
|
|
</Box>
|
|
|
|
{/* Secondary Calendar - only show on desktop */}
|
|
<Box
|
|
sx={{
|
|
flex: 1,
|
|
display: { xs: 'none', md: 'flex' },
|
|
justifyContent: 'center',
|
|
}}
|
|
>
|
|
{renderSingleCalendar(nextMonth, true)}
|
|
</Box>
|
|
</Box>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default CalendarDual
|