react-os-shell 0.7.4 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/apps/Email.tsx"],"names":[],"mappings":"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","file":"Email-ZUDCRZKB.js","sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport useMailAuth from '../hooks/useMailAuth';\nimport { setEmailUnreadCount } from '../hooks/useEmailUnread';\nimport { getMailClient } from '../api/mailClient';\nimport toast from '../shell/toast';\nimport Modal, { ModalActions } from '../shell/Modal';\nimport { formatDate, formatDateTime } from '../utils/date';\n\ninterface Folder {\n path: string;\n name: string;\n delimiter: string;\n specialUse: 'inbox' | 'sent' | 'drafts' | 'trash' | 'junk' | 'archive' | 'flagged' | null;\n subscribed: boolean;\n unreadCount: number;\n totalCount: number;\n}\n\ninterface Address { name: string; address: string }\n\ninterface MessageListItem {\n uid: number;\n threadId: string;\n from: Address;\n to: Address[];\n subject: string;\n snippet: string;\n date: string;\n flags: string[];\n hasAttachments: boolean;\n inReplyTo: string | null;\n references: string[];\n}\n\ninterface AttachmentInfo {\n partId: string;\n filename: string;\n contentType: string;\n size: number;\n contentId: string | null;\n}\n\ninterface MessageDetail extends Omit<MessageListItem, 'snippet' | 'hasAttachments'> {\n cc: Address[];\n text: string | null;\n html: string | null;\n attachments: AttachmentInfo[];\n}\n\nconst SMART_VIEWS: Array<{ key: string; label: string; icon: string }> = [\n { key: '__inbox__', label: 'Inbox', icon: '📥' },\n { key: '__starred__', label: 'Starred', icon: '⭐' },\n { key: '__unread__', label: 'Unread', icon: '●' },\n { key: '__drafts__', label: 'Drafts', icon: '📝' },\n { key: '__sent__', label: 'Sent', icon: '📤' },\n { key: '__trash__', label: 'Trash', icon: '🗑' },\n { key: '__junk__', label: 'Spam', icon: '⚠' },\n];\n\nfunction resolveSmartView(key: string, folders: Folder[]): string {\n if (key === '__inbox__') return folders.find(f => f.specialUse === 'inbox')?.path || 'INBOX';\n if (key === '__sent__') return folders.find(f => f.specialUse === 'sent')?.path || 'Sent';\n if (key === '__drafts__') return folders.find(f => f.specialUse === 'drafts')?.path || 'Drafts';\n if (key === '__trash__') return folders.find(f => f.specialUse === 'trash')?.path || 'Trash';\n if (key === '__junk__') return folders.find(f => f.specialUse === 'junk')?.path || 'Junk';\n return key; // __starred__, __unread__ → handled server-side\n}\n\nexport default function Email() {\n const { isConnected, serverReachable } = useMailAuth();\n\n const [folders, setFolders] = useState<Folder[]>([]);\n const [selectedKey, setSelectedKey] = useState<string>('__inbox__');\n const [messages, setMessages] = useState<MessageListItem[]>([]);\n const [selectedUid, setSelectedUid] = useState<number | null>(null);\n const [detail, setDetail] = useState<MessageDetail | null>(null);\n const [loadingFolders, setLoadingFolders] = useState(false);\n const [loadingList, setLoadingList] = useState(false);\n const [loadingDetail, setLoadingDetail] = useState(false);\n const [composeOpen, setComposeOpen] = useState(false);\n const [composeDraft, setComposeDraft] = useState<DraftState | null>(null);\n const [serverError, setServerError] = useState<string | null>(null);\n\n const selectedFolderPath = useMemo(() => resolveSmartView(selectedKey, folders), [selectedKey, folders]);\n\n const refreshFolders = useCallback(async () => {\n if (!isConnected) return;\n setLoadingFolders(true);\n setServerError(null);\n try {\n const res = await getMailClient().get<{ folders: Folder[] }>('/api/mail/folders');\n setFolders(res.data.folders);\n } catch (err) {\n setServerError(extractError(err));\n } finally {\n setLoadingFolders(false);\n }\n }, [isConnected]);\n\n const refreshList = useCallback(async () => {\n if (!isConnected) return;\n setLoadingList(true);\n setServerError(null);\n try {\n const res = await getMailClient().get<{ messages: MessageListItem[] }>('/api/mail/messages', {\n params: { folder: selectedFolderPath, page: 0, pageSize: 50 },\n });\n setMessages(res.data.messages);\n } catch (err) {\n setServerError(extractError(err));\n } finally {\n setLoadingList(false);\n }\n }, [isConnected, selectedFolderPath]);\n\n useEffect(() => {\n refreshFolders();\n }, [refreshFolders]);\n\n useEffect(() => {\n refreshList();\n setDetail(null);\n setSelectedUid(null);\n }, [refreshList]);\n\n // Poll unread counts every 30s and push to the badge.\n const unreadPollRef = useRef<number | null>(null);\n useEffect(() => {\n if (!isConnected) return;\n async function tick() {\n try {\n const res = await getMailClient().get<{ counts: Record<string, number> }>('/api/mail/unread-counts');\n const inboxFolder = folders.find(f => f.specialUse === 'inbox')?.path || 'INBOX';\n setEmailUnreadCount(res.data.counts[inboxFolder] || 0);\n setFolders(prev =>\n prev.map(f => ({ ...f, unreadCount: res.data.counts[f.path] ?? f.unreadCount }))\n );\n } catch {\n /* ignore polling errors */\n }\n }\n tick();\n unreadPollRef.current = window.setInterval(tick, 30_000) as unknown as number;\n return () => {\n if (unreadPollRef.current) window.clearInterval(unreadPollRef.current);\n };\n }, [isConnected, folders]);\n\n const openMessage = useCallback(async (item: MessageListItem) => {\n setSelectedUid(item.uid);\n setLoadingDetail(true);\n try {\n const res = await getMailClient().get<MessageDetail>(\n `/api/mail/messages/${encodeURIComponent(selectedFolderPath)}/${item.uid}`\n );\n setDetail(res.data);\n if (!item.flags.includes('\\\\Seen')) {\n await getMailClient().post(\n `/api/mail/messages/${encodeURIComponent(selectedFolderPath)}/${item.uid}/flags`,\n { add: ['\\\\Seen'] }\n );\n setMessages(prev =>\n prev.map(m => (m.uid === item.uid ? { ...m, flags: [...m.flags, '\\\\Seen'] } : m))\n );\n }\n } catch (err) {\n toast.error(extractError(err));\n } finally {\n setLoadingDetail(false);\n }\n }, [selectedFolderPath]);\n\n const toggleStar = useCallback(async (item: MessageListItem) => {\n const isFlagged = item.flags.includes('\\\\Flagged');\n try {\n await getMailClient().post(\n `/api/mail/messages/${encodeURIComponent(selectedFolderPath)}/${item.uid}/flags`,\n isFlagged ? { remove: ['\\\\Flagged'] } : { add: ['\\\\Flagged'] }\n );\n setMessages(prev =>\n prev.map(m =>\n m.uid === item.uid\n ? {\n ...m,\n flags: isFlagged ? m.flags.filter(f => f !== '\\\\Flagged') : [...m.flags, '\\\\Flagged'],\n }\n : m\n )\n );\n } catch (err) {\n toast.error(extractError(err));\n }\n }, [selectedFolderPath]);\n\n const trashMessage = useCallback(async (uid: number) => {\n try {\n await getMailClient().delete(`/api/mail/messages/${encodeURIComponent(selectedFolderPath)}/${uid}`);\n setMessages(prev => prev.filter(m => m.uid !== uid));\n if (selectedUid === uid) {\n setDetail(null);\n setSelectedUid(null);\n }\n } catch (err) {\n toast.error(extractError(err));\n }\n }, [selectedFolderPath, selectedUid]);\n\n function openCompose(initial?: DraftState) {\n setComposeDraft(initial ?? { to: '', cc: '', subject: '', body: '' });\n setComposeOpen(true);\n }\n\n if (serverReachable === false) {\n return (\n <EmptyState\n title=\"Mail server unreachable\"\n body=\"The bridge server is not responding. Start it with `npm run server:dev`, then retry.\"\n action={<button onClick={() => window.location.reload()} className=\"px-4 py-2 bg-gray-900 text-white rounded text-sm\">Retry</button>}\n />\n );\n }\n\n if (!isConnected) {\n return (\n <EmptyState\n title=\"Connect your mail account\"\n body=\"Open the Mail & Calendar button in the taskbar to connect via IMAP/SMTP/CalDAV.\"\n />\n );\n }\n\n return (\n <div className=\"flex h-full text-sm\">\n {/* Sidebar */}\n <aside className=\"w-56 shrink-0 border-r border-gray-200 overflow-y-auto bg-gray-50/60\">\n <div className=\"p-3\">\n <button\n onClick={() => openCompose()}\n className=\"w-full bg-gray-900 text-white rounded-lg px-3 py-2 text-sm font-medium hover:bg-gray-800\"\n >\n Compose\n </button>\n </div>\n <div className=\"px-2\">\n {SMART_VIEWS.map(view => {\n const folder = view.key === '__inbox__'\n ? folders.find(f => f.specialUse === 'inbox')\n : view.key === '__sent__'\n ? folders.find(f => f.specialUse === 'sent')\n : view.key === '__drafts__'\n ? folders.find(f => f.specialUse === 'drafts')\n : view.key === '__trash__'\n ? folders.find(f => f.specialUse === 'trash')\n : view.key === '__junk__'\n ? folders.find(f => f.specialUse === 'junk')\n : null;\n const unread = folder?.unreadCount ?? 0;\n const active = selectedKey === view.key;\n return (\n <button\n key={view.key}\n onClick={() => setSelectedKey(view.key)}\n className={`w-full flex items-center gap-2 px-2 py-1.5 rounded text-left text-sm ${active ? 'bg-gray-200 font-medium' : 'hover:bg-gray-100'}`}\n >\n <span className=\"w-5 text-center text-base leading-none\">{view.icon}</span>\n <span className=\"flex-1 truncate\">{view.label}</span>\n {unread > 0 && <span className=\"text-[10px] bg-blue-500 text-white rounded-full px-1.5\">{unread}</span>}\n </button>\n );\n })}\n </div>\n <div className=\"px-3 mt-4 mb-1 text-[10px] uppercase tracking-wider text-gray-500\">Folders</div>\n <div className=\"px-2 pb-3\">\n {folders\n .filter(f => !f.specialUse || f.specialUse === 'archive' || f.specialUse === 'flagged')\n .filter(f => f.path.toUpperCase() !== 'INBOX')\n .map(f => {\n const active = selectedKey === f.path;\n return (\n <button\n key={f.path}\n onClick={() => setSelectedKey(f.path)}\n className={`w-full flex items-center gap-2 px-2 py-1.5 rounded text-left text-sm ${active ? 'bg-gray-200 font-medium' : 'hover:bg-gray-100'}`}\n title={f.path}\n >\n <span className=\"w-5 text-center text-base leading-none\">📁</span>\n <span className=\"flex-1 truncate\">{f.name}</span>\n {f.unreadCount > 0 && <span className=\"text-[10px] bg-gray-300 text-gray-800 rounded-full px-1.5\">{f.unreadCount}</span>}\n </button>\n );\n })}\n </div>\n </aside>\n\n {/* Message list */}\n <section className=\"w-80 shrink-0 border-r border-gray-200 flex flex-col\">\n <header className=\"px-3 py-2 border-b border-gray-200 flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold\">\n {SMART_VIEWS.find(v => v.key === selectedKey)?.label || selectedKey}\n </h2>\n <button\n onClick={() => { refreshList(); refreshFolders(); }}\n className=\"text-xs text-gray-600 hover:text-gray-900\"\n disabled={loadingList || loadingFolders}\n >\n {loadingList || loadingFolders ? '…' : 'Refresh'}\n </button>\n </header>\n <div className=\"flex-1 overflow-y-auto\">\n {loadingList && messages.length === 0 ? (\n <div className=\"p-4 text-center text-xs text-gray-500\">Loading…</div>\n ) : messages.length === 0 ? (\n <div className=\"p-4 text-center text-xs text-gray-500\">No messages</div>\n ) : (\n messages.map(msg => (\n <MessageRow\n key={msg.uid}\n msg={msg}\n active={selectedUid === msg.uid}\n onOpen={() => openMessage(msg)}\n onStar={() => toggleStar(msg)}\n />\n ))\n )}\n </div>\n </section>\n\n {/* Detail */}\n <section className=\"flex-1 overflow-y-auto\">\n {detail ? (\n <MessageDetailView\n detail={detail}\n folderPath={selectedFolderPath}\n loading={loadingDetail}\n onReply={() => openCompose({\n to: detail.from.address,\n cc: '',\n subject: detail.subject.startsWith('Re:') ? detail.subject : `Re: ${detail.subject}`,\n body: '',\n inReplyTo: detail.threadId,\n references: detail.references,\n })}\n onTrash={() => trashMessage(detail.uid)}\n />\n ) : (\n <div className=\"h-full grid place-items-center text-xs text-gray-400\">\n Select a message\n </div>\n )}\n </section>\n\n {composeOpen && composeDraft && (\n <ComposeModal\n open={composeOpen}\n initial={composeDraft}\n onClose={() => setComposeOpen(false)}\n onSent={() => {\n setComposeOpen(false);\n toast.success('Message sent');\n refreshList();\n }}\n />\n )}\n\n {serverError && (\n <div className=\"absolute bottom-3 left-1/2 -translate-x-1/2 bg-red-50 border border-red-200 text-red-800 px-3 py-1 text-xs rounded\">\n {serverError}\n </div>\n )}\n </div>\n );\n}\n\nfunction MessageRow({ msg, active, onOpen, onStar }: {\n msg: MessageListItem;\n active: boolean;\n onOpen: () => void;\n onStar: () => void;\n}) {\n const unread = !msg.flags.includes('\\\\Seen');\n const starred = msg.flags.includes('\\\\Flagged');\n return (\n <div\n onClick={onOpen}\n className={`px-3 py-2 border-b border-gray-100 cursor-pointer ${active ? 'bg-blue-50' : 'hover:bg-gray-50'}`}\n >\n <div className=\"flex items-center gap-2 mb-0.5\">\n <button\n onClick={(e) => { e.stopPropagation(); onStar(); }}\n className={`text-xs ${starred ? 'text-yellow-500' : 'text-gray-300 hover:text-gray-500'}`}\n title={starred ? 'Unstar' : 'Star'}\n >\n ★\n </button>\n <p className={`text-xs flex-1 truncate ${unread ? 'font-semibold text-gray-900' : 'text-gray-700'}`}>\n {msg.from.name || msg.from.address}\n </p>\n <span className=\"text-[10px] text-gray-400 shrink-0\">{formatDate(msg.date)}</span>\n </div>\n <p className={`text-xs truncate ${unread ? 'font-medium text-gray-900' : 'text-gray-600'}`}>\n {msg.subject || '(no subject)'}\n </p>\n {msg.hasAttachments && <span className=\"text-[10px] text-gray-400\">📎 attachment</span>}\n </div>\n );\n}\n\nfunction MessageDetailView({\n detail,\n folderPath,\n loading,\n onReply,\n onTrash,\n}: {\n detail: MessageDetail;\n folderPath: string;\n loading: boolean;\n onReply: () => void;\n onTrash: () => void;\n}) {\n const baseUrl = `/api/mail/messages/${encodeURIComponent(folderPath)}/${detail.uid}/attachments`;\n return (\n <div>\n <header className=\"px-6 py-4 border-b border-gray-200\">\n <h1 className=\"text-lg font-semibold mb-2\">{detail.subject || '(no subject)'}</h1>\n <div className=\"flex items-center justify-between text-xs text-gray-600\">\n <div>\n <div><strong>{detail.from.name || detail.from.address}</strong> &lt;{detail.from.address}&gt;</div>\n <div>to {detail.to.map(t => t.address).join(', ')}</div>\n {detail.cc.length > 0 && <div>cc {detail.cc.map(t => t.address).join(', ')}</div>}\n <div className=\"text-gray-400 mt-1\">{formatDateTime(detail.date)}</div>\n </div>\n <div className=\"flex gap-2\">\n <button onClick={onReply} className=\"px-3 py-1 text-xs border border-gray-300 rounded hover:bg-gray-50\">Reply</button>\n <button onClick={onTrash} className=\"px-3 py-1 text-xs border border-red-200 text-red-700 rounded hover:bg-red-50\">Trash</button>\n </div>\n </div>\n </header>\n <article className=\"px-6 py-4\">\n {loading ? (\n <div className=\"text-xs text-gray-500\">Loading…</div>\n ) : detail.html ? (\n <div className=\"prose prose-sm max-w-none\" dangerouslySetInnerHTML={{ __html: detail.html }} />\n ) : (\n <pre className=\"whitespace-pre-wrap text-sm font-sans\">{detail.text || '(empty)'}</pre>\n )}\n </article>\n {detail.attachments.length > 0 && (\n <section className=\"px-6 pb-6\">\n <h3 className=\"text-xs font-semibold text-gray-700 mb-2\">Attachments</h3>\n <div className=\"grid grid-cols-2 gap-2\">\n {detail.attachments.map(att => (\n <a\n key={att.partId}\n href={`${getMailClient().defaults.baseURL}${baseUrl}/${encodeURIComponent(att.partId)}`}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"flex items-center gap-2 border border-gray-200 rounded px-3 py-2 text-xs hover:bg-gray-50\"\n >\n <span>📎</span>\n <span className=\"flex-1 truncate\">{att.filename}</span>\n <span className=\"text-gray-400\">{(att.size / 1024).toFixed(1)}KB</span>\n </a>\n ))}\n </div>\n </section>\n )}\n </div>\n );\n}\n\ninterface DraftState {\n to: string;\n cc: string;\n subject: string;\n body: string;\n inReplyTo?: string;\n references?: string[];\n}\n\nfunction ComposeModal({\n open,\n initial,\n onClose,\n onSent,\n}: {\n open: boolean;\n initial: DraftState;\n onClose: () => void;\n onSent: () => void;\n}) {\n const [draft, setDraft] = useState<DraftState>(initial);\n const [sending, setSending] = useState(false);\n\n async function send() {\n setSending(true);\n try {\n const toList = draft.to.split(',').map(s => s.trim()).filter(Boolean);\n const ccList = draft.cc.split(',').map(s => s.trim()).filter(Boolean);\n if (toList.length === 0) {\n toast.error('At least one recipient required');\n return;\n }\n await getMailClient().post('/api/mail/send', {\n to: toList,\n cc: ccList.length ? ccList : undefined,\n subject: draft.subject,\n text: draft.body,\n inReplyTo: draft.inReplyTo,\n references: draft.references,\n saveToSent: true,\n });\n onSent();\n } catch (err) {\n toast.error(extractError(err));\n } finally {\n setSending(false);\n }\n }\n\n return (\n <Modal open={open} onClose={onClose} title=\"New message\" size=\"lg\">\n <div className=\"space-y-3\">\n <input\n type=\"text\"\n placeholder=\"To\"\n value={draft.to}\n onChange={e => setDraft({ ...draft, to: e.target.value })}\n className=\"w-full border border-gray-300 rounded px-3 py-2 text-sm\"\n />\n <input\n type=\"text\"\n placeholder=\"Cc (optional)\"\n value={draft.cc}\n onChange={e => setDraft({ ...draft, cc: e.target.value })}\n className=\"w-full border border-gray-300 rounded px-3 py-2 text-sm\"\n />\n <input\n type=\"text\"\n placeholder=\"Subject\"\n value={draft.subject}\n onChange={e => setDraft({ ...draft, subject: e.target.value })}\n className=\"w-full border border-gray-300 rounded px-3 py-2 text-sm\"\n />\n <textarea\n rows={12}\n placeholder=\"Write your message…\"\n value={draft.body}\n onChange={e => setDraft({ ...draft, body: e.target.value })}\n className=\"w-full border border-gray-300 rounded px-3 py-2 text-sm font-mono\"\n />\n </div>\n <ModalActions>\n <button\n onClick={send}\n disabled={sending}\n className=\"bg-gray-900 text-white rounded-lg px-5 py-2 text-sm font-medium hover:bg-gray-800 disabled:opacity-50\"\n >\n {sending ? 'Sending…' : 'Send'}\n </button>\n </ModalActions>\n </Modal>\n );\n}\n\nfunction EmptyState({ title, body, action }: { title: string; body: string; action?: React.ReactNode }) {\n return (\n <div className=\"h-full grid place-items-center p-8 text-center\">\n <div className=\"max-w-sm\">\n <h2 className=\"text-lg font-semibold text-gray-900 mb-1\">{title}</h2>\n <p className=\"text-sm text-gray-600\">{body}</p>\n {action && <div className=\"mt-4\">{action}</div>}\n </div>\n </div>\n );\n}\n\nfunction extractError(err: unknown): string {\n const response = (err as { response?: { data?: { error?: string } } }).response;\n if (response?.data?.error) return response.data.error;\n if (err instanceof Error) return err.message;\n return 'Unknown error';\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/apps/TodoList.tsx"],"names":[],"mappings":"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","file":"TodoList-PI4SGVGI.js","sourcesContent":["import { useMemo, useState } from 'react';\nimport { useTodoTasks } from './_todoStore';\nimport type { TodoTask } from './_todoTypes';\nimport { confirm } from '../shell/ConfirmDialog';\n\ntype Filter = 'today' | 'upcoming' | 'all' | 'done';\n\nconst FILTERS: { id: Filter; label: string }[] = [\n { id: 'today', label: 'Today' },\n { id: 'upcoming', label: 'Upcoming' },\n { id: 'all', label: 'All' },\n { id: 'done', label: 'Done' },\n];\n\nfunction todayStr(): string {\n return new Date().toISOString().slice(0, 10);\n}\n\nfunction fmtDueLabel(due: string): string {\n const d = new Date(due + 'T00:00:00');\n const today = new Date(); today.setHours(0, 0, 0, 0);\n const diffDays = Math.round((d.getTime() - today.getTime()) / (24 * 3600 * 1000));\n if (diffDays === 0) return 'Today';\n if (diffDays === 1) return 'Tomorrow';\n if (diffDays === -1) return 'Yesterday';\n if (diffDays > 0 && diffDays < 7) return d.toLocaleDateString(undefined, { weekday: 'short' });\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n}\n\nfunction isOverdue(t: TodoTask): boolean {\n return !t.done && !!t.dueDate && t.dueDate < todayStr();\n}\n\nexport default function TodoList() {\n const { tasks, addTask, updateTask, removeTask, toggleDone } = useTodoTasks();\n const [filter, setFilter] = useState<Filter>('today');\n const [editingId, setEditingId] = useState<string | null>(null);\n const [adding, setAdding] = useState(false);\n\n // ── Filtered view ──\n const today = todayStr();\n const visible = useMemo(() => {\n const sorted = [...tasks].sort((a, b) => {\n // Done tasks always sink to the bottom.\n if (a.done !== b.done) return a.done ? 1 : -1;\n // Overdue first, then today, then by due date, then by createdAt.\n const aOver = isOverdue(a), bOver = isOverdue(b);\n if (aOver !== bOver) return aOver ? -1 : 1;\n if (a.dueDate && b.dueDate && a.dueDate !== b.dueDate) return a.dueDate < b.dueDate ? -1 : 1;\n if (!!a.dueDate !== !!b.dueDate) return a.dueDate ? -1 : 1;\n return a.createdAt.localeCompare(b.createdAt);\n });\n if (filter === 'today') return sorted.filter(t => !t.done && (t.dueDate === today || isOverdue(t)));\n if (filter === 'upcoming') return sorted.filter(t => !t.done && t.dueDate && t.dueDate > today);\n if (filter === 'done') return sorted.filter(t => t.done);\n return sorted;\n }, [tasks, filter, today]);\n\n const counts = useMemo(() => ({\n today: tasks.filter(t => !t.done && (t.dueDate === today || isOverdue(t))).length,\n upcoming: tasks.filter(t => !t.done && t.dueDate && t.dueDate > today).length,\n all: tasks.filter(t => !t.done).length,\n done: tasks.filter(t => t.done).length,\n }), [tasks, today]);\n\n // ── Action handlers ──\n const handleAdd = (input: { name: string; dueDate?: string; estimated?: number }) => {\n addTask(input);\n setAdding(false);\n };\n\n const handleToggle = (id: string) => {\n toggleDone(id);\n };\n\n const handleEdit = (id: string, patch: Partial<TodoTask>) => {\n updateTask(id, patch);\n };\n\n const handleDelete = async (id: string) => {\n const t = tasks.find(x => x.id === id);\n if (!t) return;\n const ok = await confirm({\n title: 'Delete this task?',\n message: `“${t.name}” will be removed from the Todo List and the Pomodoro widget. This can't be undone.`,\n confirmLabel: 'Delete',\n variant: 'danger',\n });\n if (!ok) return;\n removeTask(id);\n setEditingId(null);\n };\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* Header — filter pills + sync chip + add button */}\n <div className=\"flex items-center justify-between gap-3 px-4 py-2 border-b border-gray-200 shrink-0\">\n <div className=\"flex items-center gap-1\">\n {FILTERS.map(f => {\n const count = counts[f.id];\n const active = filter === f.id;\n return (\n <button key={f.id} onClick={() => setFilter(f.id)}\n className={`px-2.5 py-1 text-xs font-medium rounded-md transition-colors flex items-center gap-1.5 ${active ? 'bg-blue-600 text-white' : 'text-gray-600 hover:bg-gray-100'}`}>\n <span>{f.label}</span>\n <span className={`text-[10px] tabular-nums ${active ? 'text-white/80' : 'text-gray-400'}`}>{count}</span>\n </button>\n );\n })}\n </div>\n <div className=\"flex items-center gap-2\">\n <button onClick={() => setAdding(a => !a)}\n className=\"flex items-center gap-1 px-2.5 py-1 text-xs font-medium rounded-md bg-blue-600 text-white hover:bg-blue-700\">\n <svg className=\"h-3.5 w-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2.5}>\n <path strokeLinecap=\"round\" d=\"M12 5v14M5 12h14\" />\n </svg>\n <span>Add</span>\n </button>\n </div>\n </div>\n\n {/* List */}\n <div className=\"flex-1 overflow-y-auto\">\n {adding && (\n <AddTaskRow onSubmit={handleAdd} onCancel={() => setAdding(false)} />\n )}\n {visible.length === 0 && !adding && (\n <div className=\"flex flex-col items-center justify-center h-full text-center px-6 text-gray-400\">\n <svg className=\"h-10 w-10 mb-2 text-gray-300\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.5}>\n <rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"2\" />\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9 12l2 2 4-4\" />\n </svg>\n <p className=\"text-sm\">{filter === 'done' ? 'No completed tasks yet.' : 'Nothing here. Add a task to get started.'}</p>\n </div>\n )}\n {visible.map(task => (\n <TaskRow\n key={task.id}\n task={task}\n editing={editingId === task.id}\n onToggle={() => handleToggle(task.id)}\n onClick={() => setEditingId(editingId === task.id ? null : task.id)}\n onSave={(patch) => { handleEdit(task.id, patch); setEditingId(null); }}\n onDelete={() => handleDelete(task.id)}\n onCancelEdit={() => setEditingId(null)}\n />\n ))}\n </div>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────\n// Row + add form\n// ─────────────────────────────────────────────────────────────────────\n\nfunction TaskRow({ task, editing, onToggle, onClick, onSave, onDelete, onCancelEdit }: {\n task: TodoTask;\n editing: boolean;\n onToggle: () => void;\n onClick: () => void;\n onSave: (patch: Partial<TodoTask>) => void;\n onDelete: () => void;\n onCancelEdit: () => void;\n}) {\n if (editing) {\n return <EditDrawer task={task} onSave={onSave} onCancel={onCancelEdit} onDelete={onDelete} />;\n }\n const dueLabel = task.dueDate ? fmtDueLabel(task.dueDate) : null;\n const overdue = isOverdue(task);\n const pomos = (task.estimated || task.completed)\n ? `${task.completed ?? 0}/${task.estimated ?? '?'}`\n : null;\n return (\n <div\n onClick={onClick}\n className=\"flex items-center gap-3 px-4 py-2.5 border-b border-gray-200 cursor-pointer hover:bg-gray-50 transition-colors\">\n <button onClick={(e) => { e.stopPropagation(); onToggle(); }}\n className=\"shrink-0\">\n {task.done ? (\n <svg className=\"h-5 w-5 text-blue-600\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path d=\"M10 0a10 10 0 100 20 10 10 0 000-20zm-1 14.5l-4.5-4.5 1.4-1.4 3.1 3.1 6.1-6.1 1.4 1.4z\" />\n </svg>\n ) : (\n <svg className=\"h-5 w-5 text-gray-300 hover:text-gray-500\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n </svg>\n )}\n </button>\n <span className={`flex-1 text-sm truncate ${task.done ? 'line-through text-gray-400' : 'text-gray-800'}`}>\n {task.name || <span className=\"italic text-gray-400\">(untitled)</span>}\n </span>\n {pomos && (\n <span className=\"shrink-0 text-[11px] tabular-nums text-gray-500\" title=\"Pomodoros completed / estimated\">\n 🍅 {pomos}\n </span>\n )}\n {dueLabel && (\n <span className={`shrink-0 text-[11px] font-medium px-1.5 py-0.5 rounded ${overdue ? 'bg-red-100 text-red-700' : task.dueDate === todayStr() ? 'bg-blue-100 text-blue-700' : 'bg-gray-100 text-gray-600'}`}>\n {dueLabel}\n </span>\n )}\n </div>\n );\n}\n\nfunction EditDrawer({ task, onSave, onCancel, onDelete }: {\n task: TodoTask;\n onSave: (patch: Partial<TodoTask>) => void;\n onCancel: () => void;\n onDelete: () => void;\n}) {\n const [name, setName] = useState(task.name);\n const [dueDate, setDueDate] = useState(task.dueDate || '');\n const [estimated, setEstimated] = useState(task.estimated ?? 0);\n const [notes, setNotes] = useState(task.notes || '');\n\n const submit = () => onSave({\n name: name.trim(),\n dueDate: dueDate || undefined,\n estimated: estimated > 0 ? estimated : undefined,\n notes: notes.trim() || undefined,\n });\n\n return (\n <div className=\"px-4 py-3 border-b border-gray-200 bg-gray-50\">\n <input autoFocus value={name} onChange={e => setName(e.target.value)}\n onKeyDown={e => { if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) submit(); if (e.key === 'Escape') onCancel(); }}\n placeholder=\"Task name\"\n className=\"w-full text-sm font-medium bg-white border border-gray-200 rounded px-2 py-1.5 focus:outline-none focus:ring-1 focus:ring-blue-500\" />\n <div className=\"grid grid-cols-2 gap-2 mt-2\">\n <label className=\"flex flex-col text-[10px] font-semibold text-gray-500 uppercase tracking-wide\">\n Due\n <input type=\"date\" value={dueDate} onChange={e => setDueDate(e.target.value)}\n className=\"mt-0.5 text-sm bg-white border border-gray-200 rounded px-2 py-1 text-gray-800 focus:outline-none focus:ring-1 focus:ring-blue-500\" />\n </label>\n <label className=\"flex flex-col text-[10px] font-semibold text-gray-500 uppercase tracking-wide\">\n Est. pomos\n <input type=\"number\" min={0} max={20} value={estimated}\n onChange={e => setEstimated(Math.max(0, Math.min(20, parseInt(e.target.value, 10) || 0)))}\n className=\"mt-0.5 text-sm bg-white border border-gray-200 rounded px-2 py-1 text-gray-800 focus:outline-none focus:ring-1 focus:ring-blue-500\" />\n </label>\n </div>\n <textarea value={notes} onChange={e => setNotes(e.target.value)}\n placeholder=\"Notes (optional)\"\n rows={2}\n className=\"mt-2 w-full text-xs bg-white border border-gray-200 rounded px-2 py-1.5 text-gray-700 focus:outline-none focus:ring-1 focus:ring-blue-500 resize-none\" />\n <div className=\"flex items-center justify-between mt-2\">\n <button onClick={onDelete} className=\"text-xs text-red-600 hover:text-red-700\">\n Delete\n </button>\n <div className=\"flex gap-2\">\n <button onClick={onCancel} className=\"px-3 py-1 text-xs text-gray-600 hover:bg-gray-100 rounded\">Cancel</button>\n <button onClick={submit} className=\"px-3 py-1 text-xs font-semibold bg-blue-600 text-white rounded hover:bg-blue-700\">Save</button>\n </div>\n </div>\n </div>\n );\n}\n\nfunction AddTaskRow({ onSubmit, onCancel }: {\n onSubmit: (input: { name: string; dueDate?: string; estimated?: number }) => void;\n onCancel: () => void;\n}) {\n const [name, setName] = useState('');\n const [dueDate, setDueDate] = useState('');\n const [estimated, setEstimated] = useState(0);\n\n const submit = () => {\n const trimmed = name.trim();\n if (!trimmed) return;\n onSubmit({\n name: trimmed,\n dueDate: dueDate || undefined,\n estimated: estimated > 0 ? estimated : undefined,\n });\n };\n\n return (\n <div className=\"px-4 py-3 border-b border-gray-200 bg-blue-50/40\">\n <input autoFocus value={name} onChange={e => setName(e.target.value)}\n onKeyDown={e => { if (e.key === 'Enter') submit(); if (e.key === 'Escape') onCancel(); }}\n placeholder=\"What do you need to do?\"\n className=\"w-full text-sm font-medium bg-white border border-gray-200 rounded px-2 py-1.5 focus:outline-none focus:ring-1 focus:ring-blue-500\" />\n <div className=\"flex items-center gap-2 mt-2\">\n <label className=\"flex items-center gap-1.5 text-[10px] font-semibold text-gray-500 uppercase tracking-wide\">\n Due\n <input type=\"date\" value={dueDate} onChange={e => setDueDate(e.target.value)}\n className=\"text-xs bg-white border border-gray-200 rounded px-1.5 py-0.5 text-gray-800 focus:outline-none focus:ring-1 focus:ring-blue-500\" />\n </label>\n <label className=\"flex items-center gap-1.5 text-[10px] font-semibold text-gray-500 uppercase tracking-wide\">\n Est. pomos\n <input type=\"number\" min={0} max={20} value={estimated}\n onChange={e => setEstimated(Math.max(0, Math.min(20, parseInt(e.target.value, 10) || 0)))}\n className=\"w-12 text-xs bg-white border border-gray-200 rounded px-1.5 py-0.5 text-right text-gray-800 focus:outline-none focus:ring-1 focus:ring-blue-500\" />\n </label>\n <div className=\"flex-1\" />\n <button onClick={onCancel} className=\"px-3 py-1 text-xs text-gray-600 hover:bg-gray-100 rounded\">Cancel</button>\n <button onClick={submit} className=\"px-3 py-1 text-xs font-semibold bg-blue-600 text-white rounded hover:bg-blue-700\">Add</button>\n </div>\n </div>\n );\n}\n"]}
@@ -1,90 +0,0 @@
1
- import { useShellPrefs } from './chunk-36VM54SC.js';
2
- import { useMemo, useCallback } from 'react';
3
-
4
- var POMODORO_LEGACY_KEY = "pomodoro_tasks";
5
- var POMODORO_LEGACY_MIGRATED_FLAG = "pomodoro_tasks_migrated";
6
- function uid() {
7
- return Math.random().toString(36).slice(2, 11);
8
- }
9
- function nowIso() {
10
- return (/* @__PURE__ */ new Date()).toISOString();
11
- }
12
- function useTodoTasks() {
13
- const { prefs, save } = useShellPrefs();
14
- const tasks = useMemo(() => {
15
- const raw = prefs.todo_tasks;
16
- return Array.isArray(raw) ? raw : [];
17
- }, [prefs.todo_tasks]);
18
- const writeTasks = useCallback((next) => {
19
- save({ todo_tasks: next });
20
- }, [save]);
21
- const addTask = useCallback((input) => {
22
- const id = uid();
23
- const ts = nowIso();
24
- const task = {
25
- done: false,
26
- ...input,
27
- // Ensure name is trimmed and id/timestamps overwrite anything the
28
- // caller might have passed in.
29
- name: input.name.trim(),
30
- id,
31
- createdAt: ts,
32
- updatedAt: ts
33
- };
34
- writeTasks([...tasks, task]);
35
- return id;
36
- }, [tasks, writeTasks]);
37
- const updateTask = useCallback((id, patch) => {
38
- const next = tasks.map((t) => t.id === id ? { ...t, ...patch, id: t.id, updatedAt: nowIso() } : t);
39
- writeTasks(next);
40
- }, [tasks, writeTasks]);
41
- const removeTask = useCallback((id) => {
42
- writeTasks(tasks.filter((t) => t.id !== id));
43
- }, [tasks, writeTasks]);
44
- const toggleDone = useCallback((id) => {
45
- const target = tasks.find((t) => t.id === id);
46
- if (!target) return;
47
- updateTask(id, { done: !target.done });
48
- }, [tasks, updateTask]);
49
- return { tasks, addTask, updateTask, removeTask, toggleDone, setAllTasks: writeTasks };
50
- }
51
- function migratePomodoroTasksOnce(currentTasks, setAllTasks) {
52
- try {
53
- if (localStorage.getItem(POMODORO_LEGACY_MIGRATED_FLAG)) return;
54
- const raw = localStorage.getItem(POMODORO_LEGACY_KEY);
55
- if (!raw) {
56
- localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, "1");
57
- return;
58
- }
59
- const legacy = JSON.parse(raw);
60
- if (!Array.isArray(legacy) || legacy.length === 0) {
61
- localStorage.removeItem(POMODORO_LEGACY_KEY);
62
- localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, "1");
63
- return;
64
- }
65
- const ts = nowIso();
66
- const migrated = legacy.filter((t) => typeof t?.name === "string").map((t) => ({
67
- id: t.id || uid(),
68
- name: String(t.name),
69
- done: !!t.done,
70
- estimated: typeof t.estimated === "number" ? t.estimated : void 0,
71
- completed: typeof t.completed === "number" ? t.completed : void 0,
72
- createdAt: ts,
73
- updatedAt: ts
74
- }));
75
- const existingIds = new Set(currentTasks.map((t) => t.id));
76
- const additions = migrated.filter((t) => !existingIds.has(t.id));
77
- setAllTasks([...additions, ...currentTasks]);
78
- localStorage.removeItem(POMODORO_LEGACY_KEY);
79
- localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, "1");
80
- } catch {
81
- try {
82
- localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, "1");
83
- } catch {
84
- }
85
- }
86
- }
87
-
88
- export { migratePomodoroTasksOnce, useTodoTasks };
89
- //# sourceMappingURL=chunk-25L4DIKH.js.map
90
- //# sourceMappingURL=chunk-25L4DIKH.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/apps/_todoStore.ts"],"names":[],"mappings":"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","file":"chunk-25L4DIKH.js","sourcesContent":["/**\n * Shared task store — wraps `useShellPrefs()` so the Todo List app, the\n * Pomodoro widget, and the Calendar app all read/write the same array\n * at `prefs.todo_tasks`. Mutations bump `updatedAt` so Google-Tasks\n * sync (when enabled) can use last-write-wins conflict resolution.\n *\n * `migratePomodoroTasksOnce()` is a one-shot escape hatch: when the\n * Pomodoro widget mounts the first time after this refactor, it copies\n * any existing tasks from the legacy `localStorage.pomodoro_tasks` key\n * into the shared store and removes the old key. After that mount it's\n * a no-op.\n */\n\nimport { useCallback, useMemo } from 'react';\nimport { useShellPrefs } from '../shell/ShellPrefs';\nimport type { TodoTask } from './_todoTypes';\n\nconst POMODORO_LEGACY_KEY = 'pomodoro_tasks';\nconst POMODORO_LEGACY_MIGRATED_FLAG = 'pomodoro_tasks_migrated';\n\nfunction uid(): string {\n return Math.random().toString(36).slice(2, 11);\n}\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\nexport interface UseTodoTasks {\n tasks: TodoTask[];\n /** Add a new task. Returns the id of the freshly-added task. */\n addTask: (input: Partial<Omit<TodoTask, 'id' | 'createdAt' | 'updatedAt'>> & { name: string }) => string;\n /** Patch any subset of fields on a task by id. `updatedAt` is auto-bumped. */\n updateTask: (id: string, patch: Partial<TodoTask>) => void;\n /** Remove a task by id. Used by both Pomodoro's kebab menu and TodoList's delete action. */\n removeTask: (id: string) => void;\n /** Flip `done`. Same as `updateTask(id, { done: !done })` but faster to type at call sites. */\n toggleDone: (id: string) => void;\n /** Replace the entire list. Used by Google Tasks sync after a pull. */\n setAllTasks: (tasks: TodoTask[]) => void;\n}\n\nexport function useTodoTasks(): UseTodoTasks {\n const { prefs, save } = useShellPrefs();\n const tasks: TodoTask[] = useMemo(() => {\n const raw = prefs.todo_tasks;\n return Array.isArray(raw) ? (raw as TodoTask[]) : [];\n }, [prefs.todo_tasks]);\n\n const writeTasks = useCallback((next: TodoTask[]) => {\n save({ todo_tasks: next });\n }, [save]);\n\n const addTask = useCallback<UseTodoTasks['addTask']>((input) => {\n const id = uid();\n const ts = nowIso();\n const task: TodoTask = {\n done: false,\n ...input,\n // Ensure name is trimmed and id/timestamps overwrite anything the\n // caller might have passed in.\n name: input.name.trim(),\n id,\n createdAt: ts,\n updatedAt: ts,\n };\n writeTasks([...tasks, task]);\n return id;\n }, [tasks, writeTasks]);\n\n const updateTask = useCallback<UseTodoTasks['updateTask']>((id, patch) => {\n const next = tasks.map(t => t.id === id ? { ...t, ...patch, id: t.id, updatedAt: nowIso() } : t);\n writeTasks(next);\n }, [tasks, writeTasks]);\n\n const removeTask = useCallback<UseTodoTasks['removeTask']>((id) => {\n writeTasks(tasks.filter(t => t.id !== id));\n }, [tasks, writeTasks]);\n\n const toggleDone = useCallback<UseTodoTasks['toggleDone']>((id) => {\n const target = tasks.find(t => t.id === id);\n if (!target) return;\n updateTask(id, { done: !target.done });\n }, [tasks, updateTask]);\n\n return { tasks, addTask, updateTask, removeTask, toggleDone, setAllTasks: writeTasks };\n}\n\n/**\n * One-time migration: pull any tasks the Pomodoro widget previously\n * persisted to `localStorage.pomodoro_tasks` into the shared store.\n * Called from PomodoroTimer's mount effect — safe to invoke on every\n * mount, since the migrated flag stays set after the first run.\n *\n * Pass `setAllTasks` from `useTodoTasks()` so the migration can fold\n * the legacy entries in alongside any tasks the user has already added\n * elsewhere (i.e. via the new TodoList app).\n */\nexport function migratePomodoroTasksOnce(\n currentTasks: TodoTask[],\n setAllTasks: (next: TodoTask[]) => void,\n): void {\n try {\n if (localStorage.getItem(POMODORO_LEGACY_MIGRATED_FLAG)) return;\n const raw = localStorage.getItem(POMODORO_LEGACY_KEY);\n if (!raw) {\n localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1');\n return;\n }\n const legacy: Array<{ id?: string; name?: string; estimated?: number; completed?: number; done?: boolean }>\n = JSON.parse(raw);\n if (!Array.isArray(legacy) || legacy.length === 0) {\n localStorage.removeItem(POMODORO_LEGACY_KEY);\n localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1');\n return;\n }\n const ts = nowIso();\n const migrated: TodoTask[] = legacy\n .filter(t => typeof t?.name === 'string')\n .map(t => ({\n id: t.id || uid(),\n name: String(t.name),\n done: !!t.done,\n estimated: typeof t.estimated === 'number' ? t.estimated : undefined,\n completed: typeof t.completed === 'number' ? t.completed : undefined,\n createdAt: ts,\n updatedAt: ts,\n }));\n // Fold migrated tasks in first so the legacy list keeps its position\n // ahead of anything the user added via the new app.\n const existingIds = new Set(currentTasks.map(t => t.id));\n const additions = migrated.filter(t => !existingIds.has(t.id));\n setAllTasks([...additions, ...currentTasks]);\n localStorage.removeItem(POMODORO_LEGACY_KEY);\n localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1');\n } catch {\n // Don't block startup on corrupt localStorage — just mark it migrated.\n try { localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1'); } catch {}\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/date.ts"],"names":[],"mappings":";AAwBO,SAAS,iBAAA,GAAmC;AACjD,EAAA,OAAQ,YAAA,CAAa,OAAA,CAAQ,kBAAkB,CAAA,IAAuB,YAAA;AACxE;AAUO,SAAS,WAAW,KAAA,EAA0C;AACnE,EAAA,IAAI,CAAC,OAAO,OAAO,QAAA;AAEnB,EAAA,MAAM,OAAA,GAAU,KAAA,CAAM,QAAA,CAAS,GAAG,CAAA,GAAI,MAAM,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,GAAI,KAAA;AAC5D,EAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,GAAI,QAAQ,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA;AAC/C,EAAA,IAAI,CAAC,CAAA,IAAK,CAAC,CAAA,IAAK,CAAC,GAAG,OAAO,KAAA;AAE3B,EAAA,MAAM,KAAK,MAAA,CAAO,CAAC,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AACpC,EAAA,MAAM,KAAK,MAAA,CAAO,CAAC,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AACpC,EAAA,MAAM,IAAA,GAAO,OAAO,CAAC,CAAA;AAErB,EAAA,MAAM,MAAM,iBAAA,EAAkB;AAC9B,EAAA,QAAQ,GAAA;AAAK,IACX,KAAK,YAAA;AAAc,MAAA,OAAO,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,IAAI,IAAI,CAAA,CAAA;AAAA,IAC7C,KAAK,YAAA;AAAc,MAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,EAAE,IAAI,EAAE,CAAA,CAAA;AAAA,IAC7C,KAAK,YAAA;AAAc,MAAA,OAAO,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,IAAI,IAAI,CAAA,CAAA;AAAA,IAC7C,KAAK,YAAA;AAAc,MAAA,OAAO,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,IAAI,IAAI,CAAA,CAAA;AAAA,IAC7C,KAAK,YAAA;AAAA,IACL;AAAmB,MAAA,OAAO,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,IAAI,IAAI,CAAA,CAAA;AAAA;AAEjD;AAMO,SAAS,eAAe,KAAA,EAA0C;AACvE,EAAA,IAAI,CAAC,OAAO,OAAO,QAAA;AACnB,EAAA,MAAM,EAAA,GAAK,IAAI,IAAA,CAAK,KAAK,CAAA;AACzB,EAAA,IAAI,KAAA,CAAM,EAAA,CAAG,OAAA,EAAS,GAAG,OAAO,KAAA;AAChC,EAAA,MAAM,OAAA,GAAU,CAAA,EAAG,EAAA,CAAG,WAAA,EAAa,IAAI,MAAA,CAAO,EAAA,CAAG,QAAA,EAAS,GAAI,CAAC,CAAA,CAAE,SAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA,EAAI,MAAA,CAAO,EAAA,CAAG,OAAA,EAAS,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AAC1H,EAAA,MAAM,IAAA,GAAO,GAAG,kBAAA,CAAmB,MAAA,EAAW,EAAE,IAAA,EAAM,SAAA,EAAW,MAAA,EAAQ,SAAA,EAAW,CAAA;AACpF,EAAA,OAAO,CAAA,EAAG,UAAA,CAAW,OAAO,CAAC,KAAK,IAAI,CAAA,CAAA;AACxC","file":"chunk-NSU7OHPC.js","sourcesContent":["/**\n * Shared date formatting utility.\n *\n * Reads the user's preferred date format from localStorage (`user_date_format`)\n * and formats all dates consistently across the app.\n *\n * Supported formats:\n * 'DD/MM/YYYY' — 24/04/2026\n * 'MM/DD/YYYY' — 04/24/2026\n * 'YYYY-MM-DD' — 2026-04-24\n * 'DD-MM-YYYY' — 24-04-2026\n * 'DD.MM.YYYY' — 24.04.2026\n */\n\nexport type DateFormatKey = 'DD/MM/YYYY' | 'MM/DD/YYYY' | 'YYYY-MM-DD' | 'DD-MM-YYYY' | 'DD.MM.YYYY';\n\nexport const DATE_FORMAT_OPTIONS: { key: DateFormatKey; example: string }[] = [\n { key: 'DD/MM/YYYY', example: '24/04/2026' },\n { key: 'MM/DD/YYYY', example: '04/24/2026' },\n { key: 'YYYY-MM-DD', example: '2026-04-24' },\n { key: 'DD-MM-YYYY', example: '24-04-2026' },\n { key: 'DD.MM.YYYY', example: '24.04.2026' },\n];\n\nexport function getUserDateFormat(): DateFormatKey {\n return (localStorage.getItem('user_date_format') as DateFormatKey) || 'DD/MM/YYYY';\n}\n\nexport function setUserDateFormat(fmt: DateFormatKey) {\n localStorage.setItem('user_date_format', fmt);\n}\n\n/**\n * Format a date string (YYYY-MM-DD or ISO timestamp) for display.\n * Returns '—' for null/empty values.\n */\nexport function formatDate(value: string | null | undefined): string {\n if (!value) return '—';\n // Parse — handle both \"YYYY-MM-DD\" and ISO timestamps\n const dateStr = value.includes('T') ? value.split('T')[0] : value;\n const [y, m, d] = dateStr.split('-').map(Number);\n if (!y || !m || !d) return value; // fallback if unparseable\n\n const dd = String(d).padStart(2, '0');\n const mm = String(m).padStart(2, '0');\n const yyyy = String(y);\n\n const fmt = getUserDateFormat();\n switch (fmt) {\n case 'MM/DD/YYYY': return `${mm}/${dd}/${yyyy}`;\n case 'YYYY-MM-DD': return `${yyyy}-${mm}-${dd}`;\n case 'DD-MM-YYYY': return `${dd}-${mm}-${yyyy}`;\n case 'DD.MM.YYYY': return `${dd}.${mm}.${yyyy}`;\n case 'DD/MM/YYYY':\n default: return `${dd}/${mm}/${yyyy}`;\n }\n}\n\n/**\n * Format a datetime string (ISO timestamp) for display, including time.\n * Returns '—' for null/empty values.\n */\nexport function formatDateTime(value: string | null | undefined): string {\n if (!value) return '—';\n const dt = new Date(value);\n if (isNaN(dt.getTime())) return value;\n const dateStr = `${dt.getFullYear()}-${String(dt.getMonth() + 1).padStart(2, '0')}-${String(dt.getDate()).padStart(2, '0')}`;\n const time = dt.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n return `${formatDate(dateStr)}, ${time}`;\n}\n"]}
@@ -1,24 +0,0 @@
1
- import { useState, useEffect } from 'react';
2
-
3
- // src/hooks/useEmailUnread.ts
4
- var _count = 0;
5
- var _listeners = /* @__PURE__ */ new Set();
6
- function setEmailUnreadCount(n) {
7
- if (_count === n) return;
8
- _count = n;
9
- _listeners.forEach((fn) => fn(n));
10
- }
11
- function useEmailUnreadCount() {
12
- const [count, setCount] = useState(_count);
13
- useEffect(() => {
14
- _listeners.add(setCount);
15
- return () => {
16
- _listeners.delete(setCount);
17
- };
18
- }, []);
19
- return count;
20
- }
21
-
22
- export { setEmailUnreadCount, useEmailUnreadCount };
23
- //# sourceMappingURL=chunk-PDFQNHW7.js.map
24
- //# sourceMappingURL=chunk-PDFQNHW7.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/useEmailUnread.ts"],"names":[],"mappings":";;;AAEA,IAAI,MAAA,GAAS,CAAA;AACb,IAAM,UAAA,uBAAiB,GAAA,EAAyB;AAEzC,SAAS,oBAAoB,CAAA,EAAW;AAC7C,EAAA,IAAI,WAAW,CAAA,EAAG;AAClB,EAAA,MAAA,GAAS,CAAA;AACT,EAAA,UAAA,CAAW,OAAA,CAAQ,CAAA,EAAA,KAAM,EAAA,CAAG,CAAC,CAAC,CAAA;AAChC;AAEO,SAAS,mBAAA,GAA8B;AAC5C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAS,MAAM,CAAA;AACzC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,UAAA,CAAW,IAAI,QAAQ,CAAA;AACvB,IAAA,OAAO,MAAM;AAAE,MAAA,UAAA,CAAW,OAAO,QAAQ,CAAA;AAAA,IAAG,CAAA;AAAA,EAC9C,CAAA,EAAG,EAAE,CAAA;AACL,EAAA,OAAO,KAAA;AACT","file":"chunk-PDFQNHW7.js","sourcesContent":["import { useState, useEffect } from 'react';\n\nlet _count = 0;\nconst _listeners = new Set<(n: number) => void>();\n\nexport function setEmailUnreadCount(n: number) {\n if (_count === n) return;\n _count = n;\n _listeners.forEach(fn => fn(n));\n}\n\nexport function useEmailUnreadCount(): number {\n const [count, setCount] = useState(_count);\n useEffect(() => {\n _listeners.add(setCount);\n return () => { _listeners.delete(setCount); };\n }, []);\n return count;\n}\n"]}
@@ -1,129 +0,0 @@
1
- import { useState, useEffect, useCallback } from 'react';
2
-
3
- // src/api/mailClient.ts
4
- var DEFAULT_BASE_URL = "http://localhost:3001";
5
- var _client = null;
6
- var _baseUrl = DEFAULT_BASE_URL;
7
- var _axiosPromise = null;
8
- function loadAxios() {
9
- if (!_axiosPromise) _axiosPromise = import('axios').then((m) => m.default);
10
- return _axiosPromise;
11
- }
12
- async function setShellMailServer(input) {
13
- if (typeof input === "string") {
14
- _baseUrl = input;
15
- const axios = await loadAxios();
16
- _client = axios.create({ baseURL: input, withCredentials: true, timeout: 6e4 });
17
- } else {
18
- _client = input;
19
- }
20
- }
21
- function getMailClient() {
22
- if (_client) return _client;
23
- const proxy = new Proxy({}, {
24
- get(_t, prop) {
25
- if (typeof prop !== "string") return void 0;
26
- return (...args) => loadAxios().then((axios) => {
27
- if (!_client) {
28
- _client = axios.create({ baseURL: _baseUrl, withCredentials: true, timeout: 6e4 });
29
- }
30
- const fn = _client[prop];
31
- return typeof fn === "function" ? fn.apply(_client, args) : fn;
32
- });
33
- }
34
- });
35
- return proxy;
36
- }
37
- var SESSION_FLAG = "mail_session_known";
38
- var listeners = /* @__PURE__ */ new Set();
39
- var cached = {
40
- user: null,
41
- capabilities: null,
42
- checked: false,
43
- serverReachable: null
44
- };
45
- function broadcast() {
46
- listeners.forEach((fn) => fn());
47
- }
48
- async function fetchMe() {
49
- const client = getMailClient();
50
- try {
51
- const res = await client.get("/api/auth/me");
52
- cached = { user: res.data.user, capabilities: res.data.capabilities, checked: true, serverReachable: true };
53
- } catch (err) {
54
- const status = err?.response?.status;
55
- if (status === 401) {
56
- localStorage.removeItem(SESSION_FLAG);
57
- cached = { user: null, capabilities: null, checked: true, serverReachable: true };
58
- } else {
59
- cached = { user: null, capabilities: null, checked: true, serverReachable: false };
60
- }
61
- }
62
- broadcast();
63
- }
64
- function useMailAuth() {
65
- const [, force] = useState(0);
66
- const [loading, setLoading] = useState(false);
67
- const [error, setError] = useState(null);
68
- useEffect(() => {
69
- const sub = () => force((n) => n + 1);
70
- listeners.add(sub);
71
- if (!cached.checked && localStorage.getItem(SESSION_FLAG) === "true") {
72
- fetchMe();
73
- } else if (!cached.checked) {
74
- cached.checked = true;
75
- cached.serverReachable = null;
76
- broadcast();
77
- }
78
- return () => {
79
- listeners.delete(sub);
80
- };
81
- }, []);
82
- const login = useCallback(async (payload) => {
83
- setLoading(true);
84
- setError(null);
85
- try {
86
- const client = getMailClient();
87
- const res = await client.post("/api/auth/login", payload);
88
- localStorage.setItem(SESSION_FLAG, "true");
89
- cached = { user: res.data.user, capabilities: res.data.capabilities, checked: true, serverReachable: true };
90
- broadcast();
91
- } catch (err) {
92
- const msg = err?.response?.data?.error || err?.message || "Login failed";
93
- setError(msg);
94
- throw err;
95
- } finally {
96
- setLoading(false);
97
- }
98
- }, []);
99
- const logout = useCallback(async () => {
100
- setLoading(true);
101
- try {
102
- const client = getMailClient();
103
- await client.post("/api/auth/logout").catch(() => void 0);
104
- } finally {
105
- localStorage.removeItem(SESSION_FLAG);
106
- cached = { user: null, capabilities: null, checked: true, serverReachable: cached.serverReachable };
107
- setLoading(false);
108
- broadcast();
109
- }
110
- }, []);
111
- const refresh = useCallback(async () => {
112
- await fetchMe();
113
- }, []);
114
- return {
115
- loading,
116
- serverReachable: cached.serverReachable,
117
- isConnected: !!cached.user,
118
- user: cached.user,
119
- capabilities: cached.capabilities,
120
- error,
121
- login,
122
- logout,
123
- refresh
124
- };
125
- }
126
-
127
- export { getMailClient, setShellMailServer, useMailAuth };
128
- //# sourceMappingURL=chunk-VBFB3ZIN.js.map
129
- //# sourceMappingURL=chunk-VBFB3ZIN.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api/mailClient.ts","../src/hooks/useMailAuth.ts"],"names":[],"mappings":"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","file":"chunk-VBFB3ZIN.js","sourcesContent":["// Mail bridge client.\n//\n// Axios is imported dynamically (via `import('axios')`) so the shell's static\n// module graph never references it. Consumers (e.g. admin-portal) bundle\n// their own axios for their own API client — when both the shell and the\n// host statically reference axios, rolldown puts it in a shared chunk and\n// occasionally orders that chunk after the consumer's `client.ts` chunk,\n// surfacing as `Cannot read properties of undefined (reading 'create')`\n// during module evaluation (see 0.3.0 → 0.3.1 prod incident). Keeping the\n// runtime import here lazy avoids that entire chunk-graph by design.\n//\n// `getMailClient()` keeps its synchronous signature by returning a Proxy\n// that resolves axios on first method call; existing callers that already\n// `await client.get(...)` keep working unchanged because the proxied method\n// returns the same Promise shape.\n\nimport type { AxiosInstance } from 'axios';\n\nconst DEFAULT_BASE_URL = 'http://localhost:3001';\nlet _client: AxiosInstance | null = null;\nlet _baseUrl: string = DEFAULT_BASE_URL;\nlet _axiosPromise: Promise<typeof import('axios').default> | null = null;\n\nfunction loadAxios(): Promise<typeof import('axios').default> {\n if (!_axiosPromise) _axiosPromise = import('axios').then((m) => m.default);\n return _axiosPromise;\n}\n\nexport async function setShellMailServer(input: string | AxiosInstance): Promise<void> {\n if (typeof input === 'string') {\n _baseUrl = input;\n const axios = await loadAxios();\n _client = axios.create({ baseURL: input, withCredentials: true, timeout: 60_000 });\n } else {\n _client = input;\n }\n}\n\nexport function getMailClient(): AxiosInstance {\n if (_client) return _client;\n\n // Lazy proxy: resolves axios + creates the instance on first method call.\n // Methods that return promises (the entire AxiosInstance surface) keep\n // their normal signature — callers `await client.get(...)` exactly as\n // before. Non-method property access returns undefined.\n const proxy = new Proxy({} as AxiosInstance, {\n get(_t, prop) {\n if (typeof prop !== 'string') return undefined;\n return (...args: unknown[]) =>\n loadAxios().then((axios) => {\n if (!_client) {\n _client = axios.create({ baseURL: _baseUrl, withCredentials: true, timeout: 60_000 });\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const fn = (_client as any)[prop];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return typeof fn === 'function' ? fn.apply(_client, args) : fn;\n });\n },\n });\n return proxy;\n}\n\nexport function getMailServerBaseUrl(): string {\n return _baseUrl;\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { getMailClient } from '../api/mailClient';\n\nconst SESSION_FLAG = 'mail_session_known';\n\nexport interface MailUser {\n email: string;\n displayName: string;\n}\n\nexport interface MailCapabilities {\n imap: { thread: boolean; condstore: boolean; idle: boolean };\n smtp: boolean;\n caldav: boolean;\n}\n\nexport interface LoginPayload {\n imap: { host: string; port: number; secure: boolean; user: string; pass: string };\n smtp: { host: string; port: number; secure: boolean; user: string; pass: string };\n caldav?: { serverUrl: string; user: string; pass: string };\n}\n\ninterface MailAuthState {\n loading: boolean;\n serverReachable: boolean | null;\n isConnected: boolean;\n user: MailUser | null;\n capabilities: MailCapabilities | null;\n error: string | null;\n login: (payload: LoginPayload) => Promise<void>;\n logout: () => Promise<void>;\n refresh: () => Promise<void>;\n}\n\nconst listeners = new Set<() => void>();\nlet cached: { user: MailUser | null; capabilities: MailCapabilities | null; checked: boolean; serverReachable: boolean | null } = {\n user: null,\n capabilities: null,\n checked: false,\n serverReachable: null,\n};\n\nfunction broadcast(): void {\n listeners.forEach(fn => fn());\n}\n\nasync function fetchMe(): Promise<void> {\n const client = getMailClient();\n try {\n const res = await client.get('/api/auth/me');\n cached = { user: res.data.user, capabilities: res.data.capabilities, checked: true, serverReachable: true };\n } catch (err) {\n const status = (err as { response?: { status?: number } })?.response?.status;\n if (status === 401) {\n localStorage.removeItem(SESSION_FLAG);\n cached = { user: null, capabilities: null, checked: true, serverReachable: true };\n } else {\n cached = { user: null, capabilities: null, checked: true, serverReachable: false };\n }\n }\n broadcast();\n}\n\nexport default function useMailAuth(): MailAuthState {\n const [, force] = useState(0);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const sub = () => force(n => n + 1);\n listeners.add(sub);\n if (!cached.checked && localStorage.getItem(SESSION_FLAG) === 'true') {\n fetchMe();\n } else if (!cached.checked) {\n cached.checked = true;\n cached.serverReachable = null;\n broadcast();\n }\n return () => {\n listeners.delete(sub);\n };\n }, []);\n\n const login = useCallback(async (payload: LoginPayload) => {\n setLoading(true);\n setError(null);\n try {\n const client = getMailClient();\n const res = await client.post('/api/auth/login', payload);\n localStorage.setItem(SESSION_FLAG, 'true');\n cached = { user: res.data.user, capabilities: res.data.capabilities, checked: true, serverReachable: true };\n broadcast();\n } catch (err) {\n const msg = (err as { response?: { data?: { error?: string } }; message?: string })?.response?.data?.error\n || (err as { message?: string })?.message\n || 'Login failed';\n setError(msg);\n throw err;\n } finally {\n setLoading(false);\n }\n }, []);\n\n const logout = useCallback(async () => {\n setLoading(true);\n try {\n const client = getMailClient();\n await client.post('/api/auth/logout').catch(() => undefined);\n } finally {\n localStorage.removeItem(SESSION_FLAG);\n cached = { user: null, capabilities: null, checked: true, serverReachable: cached.serverReachable };\n setLoading(false);\n broadcast();\n }\n }, []);\n\n const refresh = useCallback(async () => {\n await fetchMe();\n }, []);\n\n return {\n loading,\n serverReachable: cached.serverReachable,\n isConnected: !!cached.user,\n user: cached.user,\n capabilities: cached.capabilities,\n error,\n login,\n logout,\n refresh,\n };\n}\n"]}