Files
donetick/src/views/components/CalendarDual.jsx
Mo Tarbin fc91894336 Refactor localization handling across components
- 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.
2026-03-08 23:08:37 -04:00

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