Skip to content

Commit 2eccea6

Browse files
committed
fixes in notifications, updates to gitignore
1 parent 8985b57 commit 2eccea6

File tree

5 files changed

+57
-10
lines changed

5 files changed

+57
-10
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,4 +262,6 @@ gows.db
262262
# YoYo AI version control directory
263263
.yoyo/
264264
settings.local.json
265-
settings.json
265+
settings.json
266+
src/server/celerybeat-schedule-shm
267+
src/server/celerybeat-schedule-wal

src/client/components/NotificationsOverlay.js

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client"
22

3-
import React, { useState, useEffect, useCallback } from "react"
3+
import React, { useState, useEffect, useCallback } from "react" // eslint-disable-line
44
import toast from "react-hot-toast"
55
import { useRouter } from "next/navigation"
66
import { motion } from "framer-motion"
@@ -13,11 +13,33 @@ import {
1313
} from "@tabler/icons-react"
1414
import { formatDistanceToNow, parseISO } from "date-fns"
1515

16-
const NotificationItem = ({ notification, onDelete, onClick }) => {
17-
const formattedTimestamp = formatDistanceToNow(
18-
parseISO(notification.timestamp),
19-
{ addSuffix: true }
20-
)
16+
const NotificationItem = ({
17+
notification,
18+
onDelete,
19+
onClick,
20+
userTimezone
21+
}) => {
22+
let formattedTimestamp = "..." // Placeholder while timezone is loading
23+
24+
try {
25+
const date = parseISO(notification.timestamp)
26+
if (typeof userTimezone === "string") {
27+
// If timezone is available, format to an absolute time string
28+
formattedTimestamp = new Intl.DateTimeFormat(undefined, {
29+
month: "short",
30+
day: "numeric",
31+
hour: "numeric",
32+
minute: "2-digit",
33+
hour12: true,
34+
timeZone: userTimezone
35+
}).format(date)
36+
} else if (userTimezone === null) {
37+
// Fallback to relative time if timezone fetch completes but is not set
38+
formattedTimestamp = formatDistanceToNow(date, { addSuffix: true })
39+
}
40+
} catch (e) {
41+
formattedTimestamp = "Recently" // Fallback for invalid date
42+
}
2143

2244
return (
2345
<motion.div
@@ -59,6 +81,7 @@ const NotificationsOverlay = ({ onClose }) => {
5981
const [notifications, setNotifications] = useState([])
6082
const [isLoading, setIsLoading] = useState(true)
6183
const [error, setError] = useState(null)
84+
const [userTimezone, setUserTimezone] = useState(undefined) // undefined: loading, null: not found, string: found
6285
const router = useRouter()
6386

6487
const fetchNotifications = useCallback(async () => {
@@ -93,9 +116,28 @@ const NotificationsOverlay = ({ onClose }) => {
93116
}
94117
}, [])
95118

119+
const fetchUserData = useCallback(async () => {
120+
try {
121+
const response = await fetch("/api/user/data")
122+
if (!response.ok) {
123+
throw new Error("Failed to fetch user data")
124+
}
125+
const result = await response.json()
126+
const timezone = result?.data?.personalInfo?.timezone
127+
setUserTimezone(timezone || null) // Set to null if not found
128+
} catch (err) {
129+
console.error(
130+
"NotificationsOverlay: Failed to fetch user timezone",
131+
err
132+
)
133+
setUserTimezone(null) // Set to null on error to trigger fallback
134+
}
135+
}, [])
136+
96137
useEffect(() => {
97138
fetchNotifications()
98-
}, [fetchNotifications])
139+
fetchUserData()
140+
}, [fetchNotifications, fetchUserData])
99141

100142
const handleDelete = async (e, notificationId) => {
101143
if (e && e.stopPropagation) e.stopPropagation()
@@ -220,6 +262,7 @@ const NotificationsOverlay = ({ onClose }) => {
220262
<NotificationItem
221263
key={notif.id}
222264
notification={notif}
265+
userTimezone={userTimezone}
223266
onDelete={(id) => handleDelete(null, id)}
224267
onClick={(n) =>
225268
handleNotificationClick(null, n)

src/server/celerybeat-schedule-shm

-32 KB
Binary file not shown.

src/server/celerybeat-schedule-wal

-628 KB
Binary file not shown.

src/server/main/db.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ async def update_user_last_active(self, user_id: str) -> bool:
145145
# --- Notification Methods ---
146146
async def get_notifications(self, user_id: str) -> List[Dict]:
147147
if not user_id: return []
148-
user_doc = await self.notifications_collection.find_one(
148+
user_doc = await self.notifications_collection.find_one( # noqa: E501
149149
{"user_id": user_id}, {"notifications": 1}
150150
)
151151
notifications_list = user_doc.get("notifications", []) if user_doc else []
@@ -158,7 +158,9 @@ async def get_notifications(self, user_id: str) -> List[Dict]:
158158

159159
async def add_notification(self, user_id: str, notification_data: Dict) -> Optional[Dict]:
160160
if not user_id or not notification_data: return None
161-
notification_data["timestamp"] = datetime.datetime.now(datetime.timezone.utc)
161+
# Store timestamp as an ISO 8601 string to ensure timezone correctness
162+
# across all database and application layers.
163+
notification_data["timestamp"] = datetime.datetime.now(datetime.timezone.utc).isoformat()
162164
notification_data["id"] = str(uuid.uuid4())
163165
result = await self.notifications_collection.update_one(
164166
{"user_id": user_id},

0 commit comments

Comments
 (0)