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:
@@ -49,6 +49,10 @@ interface EventModalProps {
|
||||
onPreviewChange?: (preview: PendingEventPreview | null) => void;
|
||||
currentUserEmails?: string[];
|
||||
isMobile?: boolean;
|
||||
prefillTitle?: string;
|
||||
prefillDescription?: string;
|
||||
prefillParticipants?: { name?: string; email: string }[];
|
||||
prefillDate?: string;
|
||||
}
|
||||
|
||||
function formatDateInput(d: Date): string {
|
||||
@@ -178,6 +182,10 @@ export function EventModal({
|
||||
onPreviewChange,
|
||||
currentUserEmails = [],
|
||||
isMobile = false,
|
||||
prefillTitle,
|
||||
prefillDescription,
|
||||
prefillParticipants,
|
||||
prefillDate,
|
||||
}: EventModalProps) {
|
||||
const t = useTranslations("calendar");
|
||||
const locale = useLocale();
|
||||
@@ -228,6 +236,10 @@ export function EventModal({
|
||||
d.setHours(now.getHours() + 1, 0, 0, 0);
|
||||
return d;
|
||||
}
|
||||
if (prefillDate) {
|
||||
const d = new Date(prefillDate);
|
||||
if (!isNaN(d.getTime())) return d;
|
||||
}
|
||||
const d = new Date();
|
||||
d.setHours(d.getHours() + 1, 0, 0, 0);
|
||||
return d;
|
||||
@@ -244,8 +256,8 @@ export function EventModal({
|
||||
return addHours(getInitialStart(), 1);
|
||||
};
|
||||
|
||||
const [title, setTitle] = useState(event?.title || "");
|
||||
const [description, setDescription] = useState(event?.description || "");
|
||||
const [title, setTitle] = useState(event?.title || prefillTitle || "");
|
||||
const [description, setDescription] = useState(event?.description || prefillDescription || "");
|
||||
const [location, setLocation] = useState(
|
||||
event?.locations ? Object.values(event.locations)[0]?.name || "" : ""
|
||||
);
|
||||
@@ -328,7 +340,12 @@ export function EventModal({
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const [attendees, setAttendees] = useState<{ name: string; email: string }[]>(() => {
|
||||
if (!event?.participants) return [];
|
||||
if (!event?.participants) {
|
||||
if (prefillParticipants && prefillParticipants.length > 0) {
|
||||
return prefillParticipants.map(p => ({ name: p.name || "", email: p.email }));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
return existingParticipants
|
||||
.filter(p => !p.isOrganizer)
|
||||
.map(p => ({ name: p.name, email: p.email }));
|
||||
|
||||
Reference in New Issue
Block a user