feat: P2.2 Create Appointment from Email + P2.4 Calendar Dashlet + P2.12 Action Wheel + P2.14 Share Files
- P2.2: 'Create Appointment' button in email viewer → pre-fills event modal with subject, body, participants, date. calendar-store newEventPrefill state. - P2.4: MiniCalendarDashlet in sidebar bottom — month grid with event dots, day click navigates to calendar. Collapsible, respect firstDayOfWeek. - P2.12: Custom radial menu (components/ui/radial-menu.tsx) — circular SVG menu with keyboard nav, animations. Wired into email-list, contact-list, file-browser, calendar-month-view right-click handlers. - P2.14: 'Send as Attachment' button in file browser — opens compose tab with selected files pre-attached via Pro tab store.
This commit is contained in:
@@ -11,6 +11,7 @@ import { useAuthStore, redirectToLogin } from "@/stores/auth-store";
|
||||
import { useAccountStore } from "@/stores/account-store";
|
||||
import { useEmailStore } from "@/stores/email-store";
|
||||
import { useFileStore } from "@/stores/file-store";
|
||||
import { useProTabStore } from "@/stores/pro-tab-store";
|
||||
import { toast } from "@/stores/toast-store";
|
||||
import { cn, formatFileSize } from "@/lib/utils";
|
||||
import { NavigationRail } from "@/components/layout/navigation-rail";
|
||||
@@ -411,6 +412,31 @@ export default function FilesPage() {
|
||||
await shareResource(id, principalId, rights);
|
||||
}, [shareResource]);
|
||||
|
||||
const handleSendAsAttachment = useCallback((names: string[]) => {
|
||||
const store = useFileStore.getState();
|
||||
const fileAtts = names
|
||||
.map((name) => {
|
||||
const r = store.resources.find((res) => res.name === name);
|
||||
if (!r || r.isDirectory || !r.blobId) return null;
|
||||
return {
|
||||
blobId: r.blobId,
|
||||
name: r.name,
|
||||
type: r.contentType || "application/octet-stream",
|
||||
size: r.contentLength,
|
||||
};
|
||||
})
|
||||
.filter(Boolean) as Array<{ blobId: string; name: string; type: string; size: number }>;
|
||||
|
||||
if (fileAtts.length === 0) return;
|
||||
|
||||
useProTabStore.getState().openComposeTab({
|
||||
sessionId: Date.now(),
|
||||
mode: "compose",
|
||||
replyTo: { attachments: fileAtts },
|
||||
title: fileAtts.length === 1 ? fileAtts[0].name : `${fileAtts.length} attachments`,
|
||||
});
|
||||
}, []);
|
||||
|
||||
// Pro shell only: all connected accounts are equal top-level entries at
|
||||
// the root. The root path "/" itself is a cross-account picker - no
|
||||
// account's files are shown until the user enters one.
|
||||
@@ -554,6 +580,7 @@ export default function FilesPage() {
|
||||
ownAccountId={filesAccountId}
|
||||
sharingEnabled={sharingEnabled}
|
||||
onShare={handleShare}
|
||||
onSendAsAttachment={handleSendAsAttachment}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user