From 343a70ef5d7e77b30b7b993b7755e24432088394 Mon Sep 17 00:00:00 2001 From: sajjad isvand Date: Fri, 26 Dec 2025 13:41:19 +0330 Subject: [PATCH 1/4] fix: implement temporary todo handling and improve UI feedback during sync operations --- src/context/todo.context.tsx | 45 ++++-- src/layouts/widgets/todos/todo.item.tsx | 196 ++++++++++++++---------- 2 files changed, 145 insertions(+), 96 deletions(-) diff --git a/src/context/todo.context.tsx b/src/context/todo.context.tsx index 721aebda..5340c24b 100644 --- a/src/context/todo.context.tsx +++ b/src/context/todo.context.tsx @@ -14,6 +14,7 @@ import { useUpdateTodo } from '@/services/hooks/todo/update-todo.hook' import { useGetTodos } from '@/services/hooks/todo/get-todos.hook' import type { FetchedTodo, Todo } from '@/services/hooks/todo/todo.interface' import { playAlarm } from '@/common/playAlarm' +import { sleep } from '@/common/utils/timeout' export enum TodoViewType { Day = 'day', @@ -159,17 +160,21 @@ export function TodoProvider({ children }: { children: React.ReactNode }) { ? Math.max(...sameDateTodos.map((t) => t.order || 0)) : 0 - const [err, _] = await safeAwait( - addTodoAsync({ - text: input.text, - completed: false, - date: input.date, - priority: input.priority || TodoPriority.Low, - category: input.category || '', - order: maxOrder + 1, - description: input.notes || '', - }) - ) + const item: any = { + text: input.text, + completed: false, + date: input.date, + priority: input.priority || TodoPriority.Low, + category: input.category || '', + order: maxOrder + 1, + description: input.notes || '', + } + const id = `temp-${Date.now()}` + old.unshift({ ...item, order: 0, id }) + setTodos(() => old) + + await sleep(3000) + const [err, _] = await safeAwait(addTodoAsync(item)) if (err) { const content = translateError(err) if (typeof content === 'string') { @@ -201,6 +206,20 @@ export function TodoProvider({ children }: { children: React.ReactNode }) { ) } const isCompleted = !current.completed + + setTodos((prev) => { + if (!prev) return prev + return prev.map((todo) => { + if (todo.id === id || todo.onlineId === id) { + return { + ...todo, + completed: isCompleted, + } + } + return todo + }) + }) + const [err, _] = await safeAwait( updateTodoAsync({ id: onlineId, @@ -214,9 +233,9 @@ export function TodoProvider({ children }: { children: React.ReactNode }) { showToast(translateError(err) as string, 'error') return } - refetch() - Analytics.event('todo_toggled') + if (isCompleted) playAlarm('done_todo') + Analytics.event('todo_toggled') } const updateTodo = async (id: string, updates: Partial>) => { diff --git a/src/layouts/widgets/todos/todo.item.tsx b/src/layouts/widgets/todos/todo.item.tsx index ec78aa1e..9e9f1245 100644 --- a/src/layouts/widgets/todos/todo.item.tsx +++ b/src/layouts/widgets/todos/todo.item.tsx @@ -44,8 +44,17 @@ export function TodoItem({ const [showEditModal, setShowEditModal] = useState(false) const isUpdating = useIsMutating({ mutationKey: ['updateTodo'] }) > 0 const { mutateAsync, isPending } = useRemoveTodo(todo.onlineId || todo.id) + const [isSyncing, setIsSyncing] = useState(todo.id.startsWith('temp-') || false) + const isTemp = todo.id.startsWith('temp-') const handleDelete = (e: React.MouseEvent) => { + if (isTemp) { + return showToast( + 'این وظیفه هنوز همگام‌سازی نشده است و نمی‌توان آن را حذف کرد.', + 'error' + ) + } + e.stopPropagation() if (isPending) return if (!isAuthenticated) return showToast('برای حذف وظیفه باید وارد شوید', 'error') @@ -54,19 +63,21 @@ export function TodoItem({ } const handleEdit = (e: React.MouseEvent) => { + if (isTemp) { + return showToast( + 'این وظیفه هنوز همگام‌سازی نشده است و نمی‌توان آن را ویرایش کرد.', + 'error' + ) + } + e.stopPropagation() if (!isAuthenticated) return showToast('برای ویرایش وظیفه باید وارد شوید', 'error') setShowEditModal(true) } - const handleExpand = (e: React.MouseEvent) => { - e.stopPropagation() - setExpanded(!expanded) - } - const onConfirmDelete = async () => { - if (isPending) return + if (isPending || isSyncing) return const onlineId = todo.onlineId || todo.id if (validate(onlineId)) { @@ -92,67 +103,24 @@ export function TodoItem({ refetchTodos() } - const getBorderStyle = () => { - switch (todo.priority) { - case 'high': - return '!border-error' - case 'medium': - return '!border-warning' - case 'low': - return '!border-success' - default: - return '!border-primary' - } - } - - const getCheckedCheckboxStyle = () => { - switch (todo.priority) { - case 'high': - return '!border-error !bg-error' - case 'medium': - return '!border-warning !bg-warning' - case 'low': - return '!border-success !bg-success' - default: - return '!border-primary !bg-primary' - } - } - - const getUnCheckedCheckboxStyle = () => { - switch (todo.priority) { - case 'high': - return '!border-error' - case 'medium': - return '!border-warning' - case 'low': - return '!border-success' - default: - return '!border-primary' - } - } - - const getPriorityColor = () => { - switch (todo.priority) { - case 'high': - return 'bg-error/10 text-error' - case 'medium': - return 'bg-warning/10 text-warning' - case 'low': - return 'bg-success/10 text-success' - default: - return 'bg-primary text-primary-content' - } - } - - const onToggleClick = (e: React.MouseEvent) => { + const onToggleClick = async (e: React.MouseEvent) => { e.stopPropagation() - if (isUpdating) return + if (isUpdating || isSyncing) return if (!isAuthenticated) { return showToast('برای تغییر وضعیت وظیفه باید وارد شوید', 'error') } + setIsSyncing(true) + try { + await toggleTodo(todo.id) + } finally { + setIsSyncing(false) + } + } - toggleTodo(todo.id) + const handleExpand = (e: React.MouseEvent) => { + e.stopPropagation() + setExpanded(!expanded) } return ( @@ -172,10 +140,14 @@ export function TodoItem({
onToggleClick(e)} />
@@ -189,22 +161,28 @@ export function TodoItem({ {/* Actions */}
- - + {isSyncing ? ( + + ) : ( + <> + + + + )} + ))} +
+ + ) +} - , + }, + { + label: 'گوگل‌کلندر', + value: 'google', + icon: ( + Google Calendar + ), + }, +] +const CalendarLayout: React.FC = () => { + const { currentDate, selectedDate, setCurrentDate, setSelectedDate, goToToday } = + useDate() + const [activeTab, setActiveTab] = useState('calendar') + + const onSetActiveTab = (tab: string) => { + setActiveTab(tab) + Analytics.event(`calendar_tab_switch_to_${tab}`) + } -
- + return ( + +
+ {activeTab === 'calendar' ? ( + <> + +
+ +
+ + ) : ( + + )}
+ +
) } diff --git a/src/layouts/widgets/calendar/components/calendar-grid.tsx b/src/layouts/widgets/calendar/components/calendar-grid.tsx index b6c00cd8..e73695d2 100644 --- a/src/layouts/widgets/calendar/components/calendar-grid.tsx +++ b/src/layouts/widgets/calendar/components/calendar-grid.tsx @@ -1,6 +1,5 @@ import { useAuth } from '@/context/auth.context' import { useGeneralSetting } from '@/context/general-setting.context' -import { useTodoStore } from '@/context/todo.context' import { useGetEvents } from '@/services/hooks/date/getEvents.hook' import type React from 'react' import { useState } from 'react' @@ -30,6 +29,12 @@ export const CalendarGrid: React.FC = ({ const { data: events } = useGetEvents() + const eventsForCalendar = events || { + gregorianEvents: [], + hijriEvents: [], + shamsiEvents: [], + } + const { data: calendarData, refetch } = useGetCalendarData( isAuthenticated, currentDate.clone().doAsGregorian().startOf('jMonth').format('YYYY-MM-DD'), @@ -75,7 +80,7 @@ export const CalendarGrid: React.FC = ({ key={`day-${i}`} currentDate={currentDate} day={i + 1} - events={events} + events={eventsForCalendar} googleEvents={calendarData?.googleEvents || []} selectedDateStr={selectedDateStr} setSelectedDate={setSelectedDate} @@ -107,7 +112,7 @@ export const CalendarGrid: React.FC = ({ triggerRef={{ current: clickedElement }} content={ refetch()} diff --git a/src/layouts/widgets/calendar/components/google-calendar/google-calendar-view.tsx b/src/layouts/widgets/calendar/components/google-calendar/google-calendar-view.tsx new file mode 100644 index 00000000..d5f8e45f --- /dev/null +++ b/src/layouts/widgets/calendar/components/google-calendar/google-calendar-view.tsx @@ -0,0 +1,202 @@ +import Analytics from '@/analytics' +import { HiChevronLeft, HiChevronRight } from 'react-icons/hi2' +import { useGetGoogleCalendarEvents } from '@/services/hooks/date/getGoogleCalendarEvents.hook' +import { useDate } from '@/context/date.context' +import { CalendarEvent } from './google-event.item' +import { useAuth } from '@/context/auth.context' +import { Button } from '@/components/button/button' +import { callEvent } from '@/common/utils/call-event' + +const HOUR_HEIGHT = 80 +export const GoogleCalendarView: React.FC = () => { + const { user, isAuthenticated } = useAuth() + const { selectedDate, isToday, setSelectedDate, currentDate } = useDate() + const containerRef = useRef(null) + const [currentTime, setCurrentTime] = useState(new Date()) + + const isCalendarConnected = user?.connections?.includes('google') || false + + useEffect(() => { + const timer = setInterval(() => setCurrentTime(new Date()), 60000) + return () => clearInterval(timer) + }, []) + + useEffect(() => { + if (containerRef.current && isToday(selectedDate)) { + const now = new Date() + const scrollPos = + ((now.getHours() * 60 + now.getMinutes()) / 60) * HOUR_HEIGHT - 100 + containerRef.current.scrollTo({ top: scrollPos, behavior: 'smooth' }) + } + }, [selectedDate]) + + const { data: events } = useGetGoogleCalendarEvents( + isCalendarConnected, + selectedDate.clone().startOf('day').toDate(), + selectedDate.clone().endOf('day').toDate() + ) + + const handleEventClick = (event: any) => { + Analytics.event('google_calendar_event_click') + if (event.hangoutLink) { + window.open(event.hangoutLink, '_blank') + } else if (event.location) { + window.open( + `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(event.location)}`, + '_blank' + ) + } + } + + const onNextDay = () => { + setSelectedDate(selectedDate.clone().add(1, 'jD')) + Analytics.event('google_calendar_next_day') + } + + const onPrevDay = () => { + setSelectedDate(selectedDate.clone().add(-1, 'jD')) + Analytics.event('google_calendar_prev_day') + } + + const onGoToToday = () => { + setSelectedDate(currentDate.clone()) + Analytics.event('google_calendar_go_to_today') + } + + const getInitials = (email: string) => + email.split('@')[0].substring(0, 2).toUpperCase() + + const hours = Array.from({ length: 24 }, (_, i) => i) + + const nextEvent = events?.find((e) => new Date(e.start.dateTime) > currentTime) + + if (!isCalendarConnected) { + return ( +
+

+ {isAuthenticated + ? 'برای مشاهده رویدادهای گوگل، لطفاً حساب گوگل خود را متصل کنید.' + : 'برای مشاهده رویدادهای گوگل، لطفاً وارد حساب کاربری خود شوید.'} +

+ +
+ ) + } + + return ( +
+
+
+ {events?.length || 0} رویداد +
+ {nextEvent && ( +
+ بعدی: {new Date(nextEvent.start.dateTime).getHours()}: + {new Date(nextEvent.start.dateTime) + .getMinutes() + .toString() + .padStart(2, '0')}{' '} + - {nextEvent.summary} +
+ )} +
+ +
+
+ {hours.map((hour) => { + const isPast = + isToday(selectedDate) && currentTime.getHours() > hour + return ( +
+
+ {hour === 0 ? '۱۲' : hour <= 12 ? hour : hour - 12} + + {hour < 12 ? 'ق.ظ' : 'ب.ظ'} + +
+
+
+ ) + })} + + {isToday(selectedDate) && ( +
+
+
+
+ )} + + {events?.map((event) => ( + + ))} +
+
+ +
+ + + + + +
+
+ ) +} diff --git a/src/layouts/widgets/calendar/components/google-calendar/google-event.item.tsx b/src/layouts/widgets/calendar/components/google-calendar/google-event.item.tsx new file mode 100644 index 00000000..436d0a8c --- /dev/null +++ b/src/layouts/widgets/calendar/components/google-calendar/google-event.item.tsx @@ -0,0 +1,118 @@ +import Tooltip from '@/components/toolTip' +import { HiOutlineMapPin, HiOutlineVideoCamera } from 'react-icons/hi2' + +interface CalendarEventProps { + event: any + isToday: boolean + currentTime: Date + hourHeight: number + onEventClick: (event: any) => void + getInitials: (email: string) => string +} + +export const CalendarEvent = ({ + event, + isToday, + currentTime, + onEventClick, + getInitials, + hourHeight, +}: CalendarEventProps) => { + const start = new Date(event.start.dateTime) + const end = new Date(event.end.dateTime) + const isNow = isToday && currentTime >= start && currentTime <= end + const duration = (end.getTime() - start.getTime()) / 60000 + const isShort = duration <= 45 + const hasAction = !!(event.hangoutLink || event.location) + const isEnd = end <= currentTime + const getEventStyle = (event: any) => { + const start = new Date(event.start.dateTime) + const end = new Date(event.end.dateTime) + const startMinutes = start.getHours() * 60 + start.getMinutes() + const duration = (end.getTime() - start.getTime()) / 60000 + + return { + top: `${(startMinutes / 60) * hourHeight + 2}px`, + right: '38px', + left: '10px', + height: `${Math.max((duration / 60) * hourHeight - 4, 42)}px`, + } + } + + return ( +
onEventClick(event)} + className={`absolute z-20 px-3 py-2 overflow-hidden transition-all border-r-2 rounded-xl shadow-sm + ${hasAction ? 'cursor-pointer hover:shadow-md active:scale-[0.98]' : 'cursor-default'} + ${isNow ? 'bg-primary/15 border-primary backdrop-blur-md ring-1 ring-primary/30' : 'bg-base-300/90 hover:bg-base-300 border-primary/40'} + ${isEnd && 'opacity-60! border-r!'} + `} + style={getEventStyle(event)} + > +
+
+

+ {event.summary} +

+ {!isShort && event.hangoutLink && ( +
+ + میت +
+ )} +
+ +
+
+ + {start.toLocaleTimeString('fa-IR', { + hour: '2-digit', + minute: '2-digit', + })}{' '} + {' - '}{' '} + {end.toLocaleTimeString('fa-IR', { + hour: '2-digit', + minute: '2-digit', + })} + +
+ {event.location && !isShort && ( +
+ + + {event.location} + +
+ )} +
+ + {!isShort && event.attendees && ( +
+
+ {event.attendees + .slice(0, 3) + .map((attendee: any, idx: number) => ( + +
+ {getInitials(attendee.email)} +
+
+ ))} + {event.attendees.length > 3 && ( +
+ +{event.attendees.length - 3} +
+ )} +
+
+ )} +
+
+ ) +} diff --git a/src/layouts/widgets/wigiPad/date-display/dates/jalali.date.tsx b/src/layouts/widgets/wigiPad/date-display/dates/jalali.date.tsx index e1b8272e..83ce8c67 100644 --- a/src/layouts/widgets/wigiPad/date-display/dates/jalali.date.tsx +++ b/src/layouts/widgets/wigiPad/date-display/dates/jalali.date.tsx @@ -6,7 +6,12 @@ import { HolidayBadge } from '../components/holiday.badge' export function JalaliDate() { const { today, todayIsHoliday } = useDate() const { data: events } = useGetEvents() - const sortedEvents = combineAndSortEvents(events, today.clone(), []) + const eventsForCalendar = events || { + gregorianEvents: [], + hijriEvents: [], + shamsiEvents: [], + } + const sortedEvents = combineAndSortEvents(eventsForCalendar, today.clone(), []) const isHoliday = sortedEvents.some((event) => event.isHoliday) || todayIsHoliday const textColor = 'text-content drop-shadow-md' diff --git a/src/layouts/widgets/wigiPad/info-panel/info-panel.tsx b/src/layouts/widgets/wigiPad/info-panel/info-panel.tsx index 6ea90077..ab4a26e3 100644 --- a/src/layouts/widgets/wigiPad/info-panel/info-panel.tsx +++ b/src/layouts/widgets/wigiPad/info-panel/info-panel.tsx @@ -2,7 +2,7 @@ import { useRef, useState } from 'react' import { NotificationItem } from './components/ann-item' import { useInfoPanelData } from './hooks/useInfoPanelData' import { BirthdayTab } from './tabs/birthday/birthday-tab' -import { GoogleTab } from './tabs/google/google.tab' +import { BsFillCalendar2WeekFill } from 'react-icons/bs' export function InfoPanel() { const [activeSection, setActiveSection] = useState('all') @@ -10,12 +10,12 @@ export function InfoPanel() { const tabContainerRef = useRef(null) const sections = [ { id: 'all', label: 'ویجی تب', icon: '📋' }, + { id: 'birthdays', label: 'تولدها', icon: '🎂' }, { id: 'google-meetings', label: 'گوگل کلندر', icon: '📅', }, - { id: 'birthdays', label: 'تولدها', icon: '🎂' }, ] const handleSectionClick = ( @@ -45,7 +45,14 @@ export function InfoPanel() { case 'birthdays': return case 'google-meetings': - return + return ( +
+ +

+ این قسمت رو به ویجت تقویم انتقال دادیم 🪄 +

+
+ ) default: return ( @@ -72,7 +79,8 @@ export function InfoPanel() { activeSection === section.id ? 'bg-primary text-white' : 'text-muted bg-base-300/70 border border-base-300/70' - }`} + } + ${section.id === 'google-meetings' ? 'line-through' : ''}`} > {section.icon} {section.label} diff --git a/src/layouts/widgets/wigiPad/info-panel/tabs/google/google-meeting-item.tsx b/src/layouts/widgets/wigiPad/info-panel/tabs/google/google-meeting-item.tsx deleted file mode 100644 index 4a49eeb9..00000000 --- a/src/layouts/widgets/wigiPad/info-panel/tabs/google/google-meeting-item.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import moment from 'jalali-moment' -import { CgMediaLive } from 'react-icons/cg' -import { MdDateRange, MdLocationOn } from 'react-icons/md' -import GoogleCalendar from '@/assets/google-calendar.png' -import Tooltip from '@/components/toolTip' -import { getCurrentDate } from '@/layouts/widgets/calendar/utils' -import type { GoogleCalendarEvent } from '@/services/hooks/date/getGoogleCalendarEvents.hook' - -interface GoogleEventItemProps { - meeting: GoogleCalendarEvent - timezone: string -} - -function formatEventTime(dateTimeStr: string) { - if (!dateTimeStr) return null - const date = new Date(dateTimeStr) - return date.toLocaleTimeString('fa-IR', { hour: '2-digit', minute: '2-digit' }) -} - -export function GoogleMeetingItem({ meeting, timezone }: GoogleEventItemProps) { - const handleJoinMeeting = () => { - const meetLink = - meeting.hangoutLink || - meeting.conferenceData?.entryPoints?.find( - (ep: any) => ep.entryPointType === 'video' - )?.uri || - meeting.htmlLink - - if (meetLink) { - window.open(meetLink, '_blank') - } - } - - const isPastEvent = () => { - if (!meeting.end || !meeting.end.dateTime) return false - const endDate = new Date(meeting.end.dateTime) - const now = getCurrentDate(timezone).toDate() - return endDate < now - } - - const isCurrentEvent = () => { - if ( - !meeting.start || - !meeting.start.dateTime || - !meeting.end || - !meeting.end.dateTime - ) - return false - const startDate = new Date(meeting.start.dateTime) - const endDate = new Date(meeting.end.dateTime) - const now = getCurrentDate(timezone).toDate() - return startDate <= now && endDate >= now - } - - return ( -
- {isPastEvent() && ( -
-
- اتمام یافته -
-
- )} - {isCurrentEvent() && ( -
- - - -
- )} -
-
- Gmail -
{' '} -
-

- {meeting.summary} -

-

- - {moment(meeting.start.dateTime) - .locale('fa') - .format('dddd، jD jMMMM jYYYY') || 'نامشخص'} -

-

- {formatEventTime(meeting.start.dateTime) || 'نامشخص'} -{' '} - {formatEventTime(meeting.end.dateTime) || 'نامشخص'} -

- {meeting.location && ( -

- - {meeting.location} -

- )} -
-
-
- ) -} diff --git a/src/layouts/widgets/wigiPad/info-panel/tabs/google/google.tab.tsx b/src/layouts/widgets/wigiPad/info-panel/tabs/google/google.tab.tsx deleted file mode 100644 index c81f2578..00000000 --- a/src/layouts/widgets/wigiPad/info-panel/tabs/google/google.tab.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { LuLockKeyhole } from 'react-icons/lu' -import { MdEvent } from 'react-icons/md' -import { useAuth } from '@/context/auth.context' -import { useDate } from '@/context/date.context' -import { useGeneralSetting } from '@/context/general-setting.context' -import { useGetGoogleCalendarEvents } from '@/services/hooks/date/getGoogleCalendarEvents.hook' -import { GoogleMeetingItem } from './google-meeting-item' - -const LoadingSkeleton = () => ( -
- {[...Array(3)].map((_, index) => ( -
-
-
-
-
-
-
-
-
-
- ))} -
-) - -export function GoogleTab() { - const { today } = useDate() - const { selected_timezone } = useGeneralSetting() - const { isAuthenticated } = useAuth() - const { blurMode } = useGeneralSetting() - const { data: googleEvents, isLoading } = useGetGoogleCalendarEvents( - isAuthenticated, - today.clone().toDate(), - today.clone().add(30, 'day').toDate() - ) - - return ( -
- {!isAuthenticated ? ( -
- -

- برای مشاهده رویدادهای گوگل، لطفاً وارد حساب کاربری خود شوید. -

-
- ) : isLoading ? ( - - ) : googleEvents && googleEvents.length > 0 ? ( - googleEvents.map((event) => ( - - )) - ) : ( -
-
- -
-

- هیچ مناسبت/جلسه گوگل امروز نیست -

-
- )} -
- ) -} diff --git a/src/services/hooks/calendar/get-calendarData.hook.ts b/src/services/hooks/calendar/get-calendarData.hook.ts index b0107801..d4b254f9 100644 --- a/src/services/hooks/calendar/get-calendarData.hook.ts +++ b/src/services/hooks/calendar/get-calendarData.hook.ts @@ -18,10 +18,8 @@ export const useGetCalendarData = (enabled: boolean, start: string, end: string) queryFn: async () => getCalendarData(start, end), retry: 0, enabled: enabled && !!start && !!end, - initialData: { - moods: [], - googleEvents: [], - }, + staleTime: 5 * 60 * 1000, + gcTime: 10 * 60 * 1000, refetchOnWindowFocus: false, }) } diff --git a/src/services/hooks/date/getEvents.hook.ts b/src/services/hooks/date/getEvents.hook.ts index e440aa97..8ce34ab2 100644 --- a/src/services/hooks/date/getEvents.hook.ts +++ b/src/services/hooks/date/getEvents.hook.ts @@ -19,11 +19,7 @@ export const useGetEvents = () => { queryKey: ['get-events'], queryFn: async () => getEvents(), retry: 0, - initialData: { - shamsiEvents: [], - gregorianEvents: [], - hijriEvents: [], - }, + staleTime: 10 * 60 * 1000, }) } diff --git a/src/services/hooks/date/getGoogleCalendarEvents.hook.ts b/src/services/hooks/date/getGoogleCalendarEvents.hook.ts index f20bfa41..a364a3ae 100644 --- a/src/services/hooks/date/getGoogleCalendarEvents.hook.ts +++ b/src/services/hooks/date/getGoogleCalendarEvents.hook.ts @@ -82,7 +82,7 @@ export const useGetGoogleCalendarEvents = ( const cacheKey = `${startParam}-${endParam}` return useQuery({ - queryKey: ['google-calendar-events', startParam, endParam], + queryKey: ['google-calendar-events', cacheKey], queryFn: async () => { if (cache.has(cacheKey)) { return cache.get(cacheKey) || [] @@ -93,7 +93,6 @@ export const useGetGoogleCalendarEvents = ( return events }, retry: 1, - // initialData: cache.get(cacheKey) || [], enabled: enabled, }) } diff --git a/src/styles/theme/esteghlal.css b/src/styles/theme/esteghlal.css index ae419e61..c16866ee 100644 --- a/src/styles/theme/esteghlal.css +++ b/src/styles/theme/esteghlal.css @@ -1,34 +1,34 @@ @plugin "daisyui/theme" { name: "esteghlal"; default: false; - prefersdark: false; + prefersdark: true; color-scheme: "dark"; --color-base-100: oklch(28% 0.091 267.935); - --color-base-200: oklch(37% 0.146 265.522); - --color-base-300: oklch(42% 0.199 265.638); - --color-base-content: oklch(93% 0.032 255.585); - --color-primary: oklch(68% 0.169 237.323); - --color-primary-content: oklch(27% 0.072 132.109); - --color-secondary: oklch(80% 0.105 251.813); - --color-secondary-content: oklch(28% 0.091 267.935); - --color-accent: oklch(83% 0.145 321.434); - --color-accent-content: oklch(29% 0.136 325.661); - --color-neutral: oklch(54% 0.245 262.881); - --color-neutral-content: oklch(97% 0.014 254.604); - --color-info: oklch(71% 0.143 215.221); - --color-info-content: oklch(98% 0.019 200.873); - --color-success: oklch(72% 0.219 149.579); - --color-success-content: oklch(98% 0.018 155.826); - --color-warning: oklch(79% 0.184 86.047); - --color-warning-content: oklch(98% 0.026 102.212); - --color-error: oklch(63% 0.237 25.331); - --color-error-content: oklch(97% 0.013 17.38); - --radius-selector: 1rem; - --radius-field: 0rem; - --radius-box: 0.25rem; + --color-base-200: oklch(35% 0.12 265.522); + --color-base-300: oklch(40% 0.15 265.638); + --color-base-content: oklch(95% 0.02 260); + --color-primary: oklch(65% 0.22 260); + --color-primary-content: oklch(100% 0 0); + --color-secondary: oklch(75% 0.15 251.813); + --color-secondary-content: oklch(20% 0.08 267.935); + --color-accent: oklch(80% 0.12 210); + --color-accent-content: oklch(20% 0.08 267.935); + --color-neutral: oklch(20% 0.06 267.935); + --color-neutral-content: oklch(90% 0.02 267.935); + --color-info: oklch(70% 0.16 245); + --color-info-content: oklch(100% 0 0); + --color-success: oklch(75% 0.18 150); + --color-success-content: oklch(20% 0.1 150); + --color-warning: oklch(82% 0.18 90); + --color-warning-content: oklch(20% 0.1 90); + --color-error: oklch(65% 0.22 25); + --color-error-content: oklch(100% 0 0); + --radius-selector: 0.5rem; + --radius-field: 0.25rem; + --radius-box: 0.5rem; --size-selector: 0.25rem; --size-field: 0.25rem; --border: 1px; - --depth: 0; - --noise: 1; + --depth: 1; + --noise: 0; } \ No newline at end of file From ef96ffa5f8167fa17578eebc964ce2f23f1ccad3 Mon Sep 17 00:00:00 2001 From: sajjad isvand Date: Fri, 26 Dec 2025 21:47:56 +0330 Subject: [PATCH 4/4] fix: remove Google Calendar events handling from CalendarDayDetails and DayItem components for simplification --- .../calendar/components/calendar-grid.tsx | 1 - .../widgets/calendar/components/day/day.tsx | 23 +-------------- .../components/day/toolTipContent.tsx | 29 +------------------ 3 files changed, 2 insertions(+), 51 deletions(-) diff --git a/src/layouts/widgets/calendar/components/calendar-grid.tsx b/src/layouts/widgets/calendar/components/calendar-grid.tsx index e73695d2..2edc774a 100644 --- a/src/layouts/widgets/calendar/components/calendar-grid.tsx +++ b/src/layouts/widgets/calendar/components/calendar-grid.tsx @@ -113,7 +113,6 @@ export const CalendarGrid: React.FC = ({ content={ refetch()} /> diff --git a/src/layouts/widgets/calendar/components/day/day.tsx b/src/layouts/widgets/calendar/components/day/day.tsx index 95ce5dc2..c92c2501 100644 --- a/src/layouts/widgets/calendar/components/day/day.tsx +++ b/src/layouts/widgets/calendar/components/day/day.tsx @@ -29,7 +29,6 @@ export function DayItem({ day, currentDate, events, - googleEvents = [], selectedDateStr, setSelectedDate, timezone, @@ -43,10 +42,7 @@ export function DayItem({ const todayHijriEvents = getHijriEvents(events, cellDate) const todayGregorianEvents = getGregorianEvents(events, cellDate) - const googleEventsForDay = filterGoogleEventsByDate(googleEvents, cellDate) - const hasGoogleEvents = googleEventsForDay.length > 0 - - const hasEvent = todayShamsiEvents.length || hasGoogleEvents + const hasEvent = todayShamsiEvents.length const eventIcons = [ ...todayGregorianEvents.filter((event) => event.icon).map((event) => event.icon), ...todayShamsiEvents.filter((event) => event.icon).map((event) => event.icon), @@ -174,20 +170,3 @@ const isToday = (date: jalaliMoment.Moment, timezone: string) => { date.jYear() === today.jYear() ) } - -const filterGoogleEventsByDate = ( - googleEvents: GoogleCalendarEvent[], - date: jalaliMoment.Moment -) => { - return googleEvents.filter((event) => { - if (event.eventType !== 'birthday') { - const eventDate = jalaliMoment(event.start.dateTime) - return ( - eventDate.jDate() === date.jDate() && - eventDate.jMonth() === date.jMonth() && - eventDate.jYear() === date.jYear() - ) - } - return undefined - }) -} diff --git a/src/layouts/widgets/calendar/components/day/toolTipContent.tsx b/src/layouts/widgets/calendar/components/day/toolTipContent.tsx index 47b53972..3c54b1a5 100644 --- a/src/layouts/widgets/calendar/components/day/toolTipContent.tsx +++ b/src/layouts/widgets/calendar/components/day/toolTipContent.tsx @@ -1,5 +1,3 @@ -import moment from 'jalali-moment' -import { AiOutlineGoogle } from 'react-icons/ai' import { FaGlobeAsia } from 'react-icons/fa' import { FaMoon } from 'react-icons/fa6' import { HiSparkles } from 'react-icons/hi2' @@ -7,13 +5,11 @@ import { useState } from 'react' import type { FetchedAllEvents } from '@/services/hooks/date/getEvents.hook' import { convertShamsiToHijri, - filterGoogleEventsByDate, getGregorianEvents, getHijriEvents, getShamsiEvents, } from '../../utils' import { useDate } from '@/context/date.context' -import type { GoogleCalendarEvent } from '@/services/hooks/date/getGoogleCalendarEvents.hook' import type React from 'react' import { useAuth } from '@/context/auth.context' import { @@ -30,7 +26,6 @@ import Analytics from '@/analytics' interface CalendarDayDetailsProps { events: FetchedAllEvents - googleEvents: GoogleCalendarEvent[] eventIcon?: string moods: MoodEntry[] onMoodChange?: (mood: MoodType) => void @@ -69,7 +64,6 @@ export const moodOptions = [ export const CalendarDayDetails: React.FC = ({ events, - googleEvents, moods, onMoodChange, }) => { @@ -159,8 +153,7 @@ export const CalendarDayDetails: React.FC = ({ const jalali = selectedDate.format('jYYYY/jMM/jD') const jalaliDay = selectedDate.format('dddd') - const dayGoogleEvents = filterGoogleEventsByDate(googleEvents, selectedDate) - const totalEvents = dayEvent.length + dayGoogleEvents.length + const totalEvents = dayEvent.length const holidayStyle = isHoliday ? 'from-orange-600 to-red-700' : 'from-sky-500 to-blue-700' @@ -234,26 +227,6 @@ export const CalendarDayDetails: React.FC = ({ {totalEvents > 0 && (
- {dayGoogleEvents.map((event, idx) => ( -
- -
-
- {event.summary} -
-
- {moment(event.start.dateTime).format('HH:mm')} -
-
-
- ))} - {dayEvent.map((event, idx) => (