Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/components/GroupView/GroupViewPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from '../../types';
import Calendar from '../selectCalendarComponents/CalendarApp';
import { useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import {
getEventObjectForGCal,
getParticipantIndex,
Expand All @@ -24,6 +25,7 @@ import {
getChosenLocation,
getEmailAdmin,
setEmailAdmin,
wrappedSaveDeclinedParticipantDetails,
} from '../../backend/events';
import LocationChart from './LocationChart';
import UserChart from './UserChart';
Expand Down Expand Up @@ -115,6 +117,7 @@ export default function GroupViewPage({
userHasFilled: boolean;
setUserHasFilled: Dispatch<SetStateAction<boolean>>;
}) {
const navigate = useNavigate();
const [showUserChart, setShowUserChart] = useState(false);
const [showParticipantFilter, setShowParticipantFilter] = useState(false);
const [participantToggleClicked, setParticipantToggleClicked] =
Expand Down Expand Up @@ -317,7 +320,15 @@ export default function GroupViewPage({
>
{eventName}
</div>
{isAdmin && <EventOptionsMenu eventCode={code} />}
<EventOptionsMenu
eventCode={code}
isAdmin={isAdmin}
userHasFilled={userHasFilled}
onCancel={async () => {
await wrappedSaveDeclinedParticipantDetails();
navigate('/');
}}
/>
</div>
{eventDescription && (
<div
Expand Down
17 changes: 14 additions & 3 deletions src/components/SideBySideView/SharedSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ interface SharedSidebarProps {
userHasSignedIn: boolean;
onUserSignIn: () => void;

userHasFilled: boolean;
onDecline: () => void;
}

Expand Down Expand Up @@ -106,6 +107,7 @@ export default function SharedSidebar({
setSelectedLocations,
userHasSignedIn,
onUserSignIn,
userHasFilled,
onDecline,
}: SharedSidebarProps) {
const navigate = useNavigate();
Expand Down Expand Up @@ -218,7 +220,16 @@ export default function SharedSidebar({
>
{eventName}
</div>
{isAdmin && <EventOptionsMenu eventCode={code} />}
<EventOptionsMenu
eventCode={code}
isAdmin={isAdmin}
userHasFilled={userHasFilled}
onCancel={async () => {
await wrappedSaveDeclinedParticipantDetails();
onDecline();
navigate('/');
}}
/>
</div>
{eventDescription && (
<div
Expand Down Expand Up @@ -382,8 +393,8 @@ export default function SharedSidebar({
</div>
)}

{/* Decline Button */}
{!chartedUsers?.hovering && !isAdmin && userHasSignedIn && getAccountId() !== '' && (
{/* Decline Button - only shown when user hasnt filled availability yet. once filled it moves to the dropdown */}
{!chartedUsers?.hovering && !isAdmin && userHasSignedIn && getAccountId() !== '' && !userHasFilled && (
<div>
<div className="text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-2 flex items-center justify-between cursor-pointer">
Decline Invitation{' '}
Expand Down
3 changes: 3 additions & 0 deletions src/components/SideBySideView/SideBySideView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ interface SideBySideViewProps {
onSave: () => Promise<void>;
onDecline: () => void;
isSaving: boolean;
userHasFilled: boolean;

// Unsaved changes tracking
hasUnsavedChanges: boolean;
Expand Down Expand Up @@ -128,6 +129,7 @@ export default function SideBySideView({
onSave,
onDecline,
isSaving,
userHasFilled,
hasUnsavedChanges,
setHasUnsavedChanges,
}: SideBySideViewProps) {
Expand Down Expand Up @@ -436,6 +438,7 @@ export default function SideBySideView({
setSelectedLocations={wrappedSetSelectedLocations}
userHasSignedIn={userHasSignedIn}
onUserSignIn={() => setUserHasSignedIn(true)}
userHasFilled={userHasFilled}
onDecline={onDecline}
/>
</div>
Expand Down
13 changes: 12 additions & 1 deletion src/components/TimeSelect/TimeSelectPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import LocationSelectionComponent from './LocationSelectionComponent';
import { calendar_v3, google } from 'googleapis';
import { useState, useEffect, Dispatch, SetStateAction } from 'react';
import { useNavigate } from 'react-router-dom';
import { DateTime } from 'luxon';
import {
calanderState,
Expand Down Expand Up @@ -28,6 +29,7 @@ import {
setUserSelectedCalendarIDs,
workingEvent,
checkIfAdmin,
wrappedSaveDeclinedParticipantDetails,
} from '../../backend/events';
import { notifyAdminOfNewResponse } from '../../emails/sendEmailHelpers';
import Calendar from '../selectCalendarComponents/CalendarApp';
Expand Down Expand Up @@ -105,6 +107,7 @@ function TimeSelectPage({
hasAvailability: boolean;
setHasAvailability: Dispatch<SetStateAction<boolean>>;
}) {
const navigate = useNavigate();
const [isGcalPopupOpen, setGcalPopupOpen] = useState(false);

const [isSaving, setIsSaving] = useState(false);
Expand Down Expand Up @@ -591,7 +594,15 @@ function TimeSelectPage({
>
{eventName}
</div>
{checkIfAdmin() && <EventOptionsMenu eventCode={code} />}
<EventOptionsMenu
eventCode={code}
isAdmin={checkIfAdmin()}
userHasFilled={hasAvailability}
onCancel={async () => {
await wrappedSaveDeclinedParticipantDetails();
navigate('/');
}}
/>
</div>
{eventDescription && (
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ export default function UnifiedAvailabilityPage() {
onSave={handleSideBySideSave}
onDecline={() => fetchData(false)}
isSaving={isSaving}
userHasFilled={userHasFilled}
hasUnsavedChanges={hasUnsavedChanges}
setHasUnsavedChanges={setHasUnsavedChanges}
/>
Expand Down
83 changes: 60 additions & 23 deletions src/components/utils/components/EventOptionsMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { IconDotsVertical, IconPencil, IconTrash } from '@tabler/icons-react';
import { IconDotsVertical, IconPencil, IconTrash, IconX } from '@tabler/icons-react';
import { deleteEvent } from '../../../backend/events';
import DeletePopup from './DeletePopup';

interface EventOptionsMenuProps {
eventCode: string | undefined;
isAdmin: boolean;
userHasFilled?: boolean;
onCancel?: () => Promise<void>;
}

export default function EventOptionsMenu({ eventCode }: EventOptionsMenuProps) {
export default function EventOptionsMenu({ eventCode, isAdmin, userHasFilled, onCancel }: EventOptionsMenuProps) {
const [isMenuOpen, setIsMenuOpen] = useState(false);
const [showDeletePopup, setShowDeletePopup] = useState(false);
const [showCancelPopup, setShowCancelPopup] = useState(false);
const nav = useNavigate();

const showMenu = isAdmin || (!!userHasFilled && !!onCancel);

// Close menu when clicking outside
useEffect(() => {
if (isMenuOpen) {
Expand All @@ -39,6 +45,8 @@ export default function EventOptionsMenu({ eventCode }: EventOptionsMenuProps) {
}
};

if (!showMenu) return null;

return (
<>
<div className="relative flex-shrink-0">
Expand All @@ -53,28 +61,44 @@ export default function EventOptionsMenu({ eventCode }: EventOptionsMenuProps) {
{isMenuOpen && (
<div
id="event-menu-dropdown"
className="absolute right-0 mt-1 w-40 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 z-50 overflow-hidden"
className="absolute right-0 mt-1 w-44 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 z-50 overflow-hidden"
>
<button
onClick={() => {
setIsMenuOpen(false);
nav(`/edit/${eventCode}`);
}}
className="w-full px-4 py-2.5 text-left text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 flex items-center gap-2 transition-colors"
>
<IconPencil size={16} />
Edit Event
</button>
<button
onClick={() => {
setIsMenuOpen(false);
setShowDeletePopup(true);
}}
className="w-full px-4 py-2.5 text-left text-sm text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 flex items-center gap-2 transition-colors"
>
<IconTrash size={16} />
Delete Event
</button>
{isAdmin && (
<>
<button
onClick={() => {
setIsMenuOpen(false);
nav(`/edit/${eventCode}`);
}}
className="w-full px-4 py-2.5 text-left text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 flex items-center gap-2 transition-colors"
>
<IconPencil size={16} />
Edit Event
</button>
<button
onClick={() => {
setIsMenuOpen(false);
setShowDeletePopup(true);
}}
className="w-full px-4 py-2.5 text-left text-sm text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 flex items-center gap-2 transition-colors"
>
<IconTrash size={16} />
Delete Event
</button>
</>
)}
{!isAdmin && userHasFilled && onCancel && (
<button
onClick={() => {
setIsMenuOpen(false);
setShowCancelPopup(true);
}}
className="w-full px-4 py-2.5 text-left text-sm text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 flex items-center gap-2 transition-colors"
>
<IconX size={16} />
Decline Event
</button>
)}
</div>
)}
</div>
Expand All @@ -86,6 +110,19 @@ export default function EventOptionsMenu({ eventCode }: EventOptionsMenuProps) {
onConfirm={handleDeleteEvent}
onCancel={() => setShowDeletePopup(false)}
/>

<DeletePopup
title="Decline Event"
message="Are you sure you want to decline this event? This will remove your availability and mark you as declined for this event."
isOpen={showCancelPopup}
onConfirm={async () => {
setShowCancelPopup(false);
if (onCancel) await onCancel();
}}
onCancel={() => setShowCancelPopup(false)}
confirmText="Yes, decline event"
cancelText="No"
/>
</>
);
}
Loading