Skip to content

Commit 43bcc22

Browse files
committed
Add ellipsis menu to event page and add copy link
1 parent 0e9f53a commit 43bcc22

5 files changed

Lines changed: 187 additions & 121 deletions

File tree

app/web/features/communities/events/CancelEventDialog.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,20 @@ export default function CancelEventDialog({
5050
</DialogContent>
5151
<DialogActions>
5252
<Button
53-
onClick={handleCancelEvent}
54-
loading={cancelEventMutation.isPending}
55-
>
56-
{t("global:yes")}
57-
</Button>
58-
<Button
53+
variant="outlined"
5954
onClick={() =>
6055
props.onClose ? props.onClose({}, "escapeKeyDown") : null
6156
}
6257
loading={cancelEventMutation.isPending}
6358
>
6459
{t("global:no")}
6560
</Button>
61+
<Button
62+
onClick={handleCancelEvent}
63+
loading={cancelEventMutation.isPending}
64+
>
65+
{t("global:yes")}
66+
</Button>
6667
</DialogActions>
6768
</Dialog>
6869
);

app/web/features/communities/events/EditEventPage.tsx

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,50 @@
1+
import { styled } from "@mui/material";
12
import { useMutation, useQueryClient } from "@tanstack/react-query";
23
import Alert from "components/Alert";
34
import Button from "components/Button";
45
import CenteredSpinner from "components/CenteredSpinner/CenteredSpinner";
6+
import HeaderButton from "components/HeaderButton";
57
import HtmlMeta from "components/HtmlMeta";
8+
import { BackIcon } from "components/Icons";
69
import NotFoundPage from "features/NotFoundPage";
710
import { RpcError } from "grpc-web";
811
import { useTranslation } from "i18n";
912
import { COMMUNITIES, GLOBAL, PROFILE } from "i18n/namespaces";
1013
import { useRouter } from "next/router";
1114
import { service } from "service";
1215
import type { UpdateEventInput } from "service/events";
16+
import { theme } from "theme";
1317
import dayjs from "utils/dayjs";
18+
import { sendNativeBack, useIsNativeEmbed } from "utils/nativeLink";
1419

1520
import { Event } from "../../../proto/events_pb";
16-
import { routeToEvent } from "../../../routes";
21+
import { eventsRoute, routeToEvent } from "../../../routes";
1722
import { communityEventsBaseKey, eventKey } from "../../queryKeys";
1823
import EventForm, { CreateEventVariables } from "./EventForm";
1924
import { useEvent } from "./hooks";
2025

26+
const StyledBackButton = styled(HeaderButton)(() => ({
27+
width: "2.5rem",
28+
height: "2.5rem",
29+
marginTop: theme.spacing(2),
30+
}));
31+
2132
export default function EditEventPage({ eventId }: { eventId: number }) {
2233
const { t } = useTranslation([GLOBAL, COMMUNITIES, PROFILE]);
2334
const router = useRouter();
35+
const isNativeEmbed = useIsNativeEmbed();
36+
37+
const handleBackClick = () => {
38+
if (isNativeEmbed) {
39+
sendNativeBack();
40+
return;
41+
}
42+
if (window.history.length > 1) {
43+
router.back();
44+
} else {
45+
router.push(eventsRoute);
46+
}
47+
};
2448

2549
const {
2650
data: event,
@@ -117,6 +141,12 @@ export default function EditEventPage({ eventId }: { eventId: number }) {
117141
) : (
118142
<>
119143
<HtmlMeta title={t("communities:edit_event")} />
144+
<StyledBackButton
145+
onClick={handleBackClick}
146+
aria-label={t("communities:previous_page")}
147+
>
148+
<BackIcon />
149+
</StyledBackButton>
120150
<EventForm
121151
error={error}
122152
event={event}

app/web/features/communities/events/EventPage.test.tsx

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -209,16 +209,24 @@ describe("Event page", () => {
209209
getEventMock.mockResolvedValue({ ...firstEvent, canEdit: true });
210210
renderEventPage();
211211

212+
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
213+
await user.click(await screen.findByTestId("event-page-more-options"));
214+
212215
expect(
213-
await screen.findByRole("button", { name: t("communities:edit_event") }),
216+
await screen.findByRole("menuitem", {
217+
name: t("communities:edit_event"),
218+
}),
214219
).toBeVisible();
215220
});
216221

217222
it("does not show the 'edit event' button if the user does not have edit permission", async () => {
218223
renderEventPage();
219224

225+
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
226+
await user.click(await screen.findByTestId("event-page-more-options"));
227+
220228
expect(
221-
await screen.queryByRole("button", { name: t("communities:edit_event") }),
229+
screen.queryByRole("menuitem", { name: t("communities:edit_event") }),
222230
).not.toBeInTheDocument();
223231
});
224232

@@ -227,8 +235,11 @@ describe("Event page", () => {
227235
getEventMock.mockResolvedValue({ ...firstEvent, creatorUserId: 1 });
228236
renderEventPage();
229237

238+
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
239+
await user.click(await screen.findByTestId("event-page-more-options"));
240+
230241
expect(
231-
await screen.findByRole("button", {
242+
await screen.findByRole("menuitem", {
232243
name: t("communities:duplicate_event"),
233244
}),
234245
).toBeVisible();
@@ -239,28 +250,32 @@ describe("Event page", () => {
239250
getEventMock.mockResolvedValue({ ...firstEvent, creatorUserId: 2 });
240251
renderEventPage();
241252

242-
await screen.findByRole("heading", { name: firstEvent.title });
253+
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
254+
await user.click(await screen.findByTestId("event-page-more-options"));
243255

244256
expect(
245-
screen.queryByRole("button", {
257+
screen.queryByRole("menuitem", {
246258
name: t("communities:duplicate_event"),
247259
}),
248260
).not.toBeInTheDocument();
249261
});
250262

251-
it("disables the 'duplicate event' button for cancelled events", async () => {
263+
it("hides the 'duplicate event' item for cancelled events", async () => {
252264
getEventMock.mockResolvedValue({
253265
...firstEvent,
254266
creatorUserId: 1,
255267
isCancelled: true,
256268
});
257269
renderEventPage();
258270

259-
const duplicateButton = await screen.findByRole("button", {
260-
name: t("communities:duplicate_event"),
261-
});
262-
expect(duplicateButton).toBeDisabled();
263-
expect(duplicateButton).toHaveAttribute("tabIndex", "-1");
271+
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
272+
await user.click(await screen.findByTestId("event-page-more-options"));
273+
274+
expect(
275+
screen.queryByRole("menuitem", {
276+
name: t("communities:duplicate_event"),
277+
}),
278+
).not.toBeInTheDocument();
264279
});
265280

266281
it("allows duplicating past events", async () => {
@@ -272,11 +287,14 @@ describe("Event page", () => {
272287
getEventMock.mockResolvedValue(pastEvent);
273288
renderEventPage();
274289

275-
const duplicateButton = await screen.findByRole("button", {
276-
name: t("communities:duplicate_event"),
277-
});
278-
expect(duplicateButton).toBeEnabled();
279-
expect(duplicateButton).not.toHaveAttribute("tabIndex", "-1");
290+
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
291+
await user.click(await screen.findByTestId("event-page-more-options"));
292+
293+
expect(
294+
await screen.findByRole("menuitem", {
295+
name: t("communities:duplicate_event"),
296+
}),
297+
).toBeVisible();
280298
});
281299

282300
it("navigates to create event page with duplicate query param when clicked", async () => {
@@ -285,11 +303,13 @@ describe("Event page", () => {
285303
renderEventPage();
286304

287305
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
306+
await user.click(await screen.findByTestId("event-page-more-options"));
288307

289-
const duplicateButton = await screen.findByRole("button", {
290-
name: t("communities:duplicate_event"),
291-
});
292-
await user.click(duplicateButton);
308+
await user.click(
309+
await screen.findByRole("menuitem", {
310+
name: t("communities:duplicate_event"),
311+
}),
312+
);
293313

294314
await waitFor(() =>
295315
expect(mockRouter.push).toHaveBeenCalledWith(
@@ -302,15 +322,14 @@ describe("Event page", () => {
302322
getEventMock.mockResolvedValue({ ...firstEvent, creatorUserId: 1 });
303323
renderEventPage();
304324

305-
const duplicateButton = await screen.findByRole("button", {
325+
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
326+
await user.click(await screen.findByTestId("event-page-more-options"));
327+
328+
const duplicateItem = await screen.findByRole("menuitem", {
306329
name: t("communities:duplicate_event"),
307330
});
308-
expect(duplicateButton).toHaveAttribute(
309-
"aria-label",
310-
t("communities:duplicate_event"),
311-
);
312-
expect(duplicateButton).toHaveAttribute("tabIndex", "0");
313-
expect(duplicateButton).not.toBeDisabled();
331+
expect(duplicateItem).toBeVisible();
332+
expect(duplicateItem).not.toHaveAttribute("aria-disabled", "true");
314333
});
315334

316335
it("shows the not found page if the user tries to find an event with an invalid ID in the URL", async () => {

0 commit comments

Comments
 (0)