Skip to content

Commit

Permalink
feat: Implement editable OOO events feature (#15932)
Browse files Browse the repository at this point in the history
* feat: Implement edit ooo feature

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* refactor: Refactor button text and gap between buttons

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* fix: Fix entry create and edit edge cases

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* chore: Change "edit ooo event" modal title

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* chore: Add tooltips to entry eidt and delete buttons

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* feat: Reset form on form close event

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* refactor: Refactor reset-form function

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* chore: Rename create or edit OOO as suggested

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* refactor: Refactor component and function names

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* feat: Improve ooo events email notifications

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* fix: Fix email templates

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* feat: Add e2e test for ooo event edit functionality

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* refactor: Create separate test for edit ooo event

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* fix: Remove extra user from redirect user configuration test

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* chore: code refactor

* remove log

* chore: Update ooo-input-schema uuid data type

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* fix: Address feedbacks

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>

* chore: code splitting and refactor

---------

Signed-off-by: Souptik Datta <souptikdatta2001@gmail.com>
Co-authored-by: Amit Sharma <74371312+Amit91848@users.noreply.github.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
  • Loading branch information
3 people authored and zomars committed Sep 4, 2024
1 parent ec98706 commit a0c55e7
Show file tree
Hide file tree
Showing 10 changed files with 714 additions and 380 deletions.
372 changes: 22 additions & 350 deletions apps/web/pages/settings/my-account/out-of-office/index.tsx

Large diffs are not rendered by default.

95 changes: 93 additions & 2 deletions apps/web/playwright/out-of-office.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@ test.describe("Out of office", () => {
await user.apiLogin();

await page.goto("/settings/my-account/out-of-office");
await page.waitForLoadState("networkidle");

await page.getByTestId("add_entry_ooo").click();
await page.waitForLoadState("networkidle");
await page.getByTestId("reason_select").click();

await page.getByTestId("select-option-4").click();

await page.getByTestId("notes_input").click();
await page.getByTestId("notes_input").fill("Demo notes");
await page.getByTestId("create-entry-ooo-redirect").click();
await page.getByTestId("create-or-edit-entry-ooo-redirect").click();

await expect(page.locator(`data-testid=table-redirect-n-a`)).toBeVisible();
});
Expand Down Expand Up @@ -62,8 +64,10 @@ test.describe("Out of office", () => {
await user.apiLogin();

await page.goto(`/settings/my-account/out-of-office`);
await page.waitForLoadState("networkidle");

await page.getByTestId("add_entry_ooo").click();
await page.waitForLoadState("networkidle");
await page.getByTestId("reason_select").click();

await page.getByTestId("select-option-4").click();
Expand All @@ -79,12 +83,98 @@ test.describe("Out of office", () => {
await page.locator("#react-select-3-input").press("Enter");

// send request
await page.getByTestId("create-entry-ooo-redirect").click();
await page.getByTestId("create-or-edit-entry-ooo-redirect").click();

// expect table-redirect-toUserId to be visible
await expect(page.locator(`data-testid=table-redirect-${userTo.username}`)).toBeVisible();
});

test("User can edit out of office entry", async ({ page, users }) => {
const user = await users.create({ name: "userOne" });
const userTo = await users.create({ name: "userTwo" });
const userToSecond = await users.create({ name: "userThree" });

const team = await prisma.team.create({
data: {
name: "test-insights",
slug: `test-insights-${Date.now()}-${randomString(5)}}`,
},
});

// create memberships
await prisma.membership.createMany({
data: [
{
userId: user.id,
teamId: team.id,
accepted: true,
role: "ADMIN",
},
{
userId: userTo.id,
teamId: team.id,
accepted: true,
role: "ADMIN",
},
{
userId: userToSecond.id,
teamId: team.id,
accepted: true,
role: "ADMIN",
},
],
});

// Skip creating the ooo entry through front-end as we can assume that it has already been tested above.
const uuid = uuidv4();
await prisma.outOfOfficeEntry.create({
data: {
start: dayjs().startOf("day").toDate(),
end: dayjs().startOf("day").add(1, "w").toDate(),
uuid,
user: { connect: { id: user.id } },
toUser: { connect: { id: userTo.id } },
createdAt: new Date(),
reason: {
connect: {
id: 1,
},
},
},
});

await user.apiLogin();

await page.goto(`/settings/my-account/out-of-office`);
await page.waitForLoadState("networkidle");

// expect table-redirect-toUserId to be visible
await expect(page.locator(`data-testid=table-redirect-${userTo.username}`)).toBeVisible();

// Open the edit modal and change redirect user and note.
await page.getByTestId(`ooo-edit-${userTo.username}`).click();

await page.getByTestId("notes_input").click();
await page.getByTestId("notes_input").fill("Changed notes");

await page.getByTestId("team_username_select").click();

await page.locator("#react-select-3-input").fill("userThree");
await page.locator("#react-select-3-input").press("Enter");

// send request
await page.getByTestId("create-or-edit-entry-ooo-redirect").click();

// expect entry with new username exist.
await expect(page.locator(`data-testid=table-redirect-${userToSecond.username}`)).toBeVisible();

// expect new note to be present.
await expect(page.locator(`data-testid=ooo-entry-note-${userToSecond.username}`)).toBeVisible();
await expect(page.locator(`data-testid=ooo-entry-note-${userToSecond.username}`)).toContainText(
"Changed notes"
);
});

test("Profile redirection", async ({ page, users }) => {
const user = await users.create({ name: "userOne" });
const userTo = await users.create({ name: "userTwo" });
Expand All @@ -106,6 +196,7 @@ test.describe("Out of office", () => {
});

await page.goto(`/${user.username}`);
await page.waitForLoadState("networkidle");

const eventTypeLink = page.locator('[data-testid="event-type-link"]').first();
await eventTypeLink.click();
Expand Down
10 changes: 9 additions & 1 deletion apps/web/public/static/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -2348,7 +2348,13 @@
"success_entry_created": "Successfully created a new entry",
"booking_redirect_email_subject": "Booking redirect notification",
"booking_redirect_email_title": "Booking Redirect Notification",
"booking_redirect_email_description": "You have received a booking redirection from {{toName}} so their profile links will be redirect to yours for the time interval: ",
"booking_redirect_email_description": "You have received a booking redirection from {{eventOwner}} so their profile links will be redirect to yours for the time interval: \"{{dates}}\"",
"booking_redirect_updated_email_subject": "Booking redirect edit notification",
"booking_redirect_updated_email_title": "Booking Redirect Edit Notification",
"booking_redirect_updated_email_description": "Your booking redirection from {{eventOwner}} for interval \"{{oldDates}}\" have been udpated. New time interval for the redirection is: \"{{dates}}\"",
"booking_redirect_cancelled_email_subject": "Booking redirect cancel notification",
"booking_redirect_cancelled_email_title": "Booking Redirect Cancel Notification",
"booking_redirect_cancelled_email_description": "Your booking redirection from {{eventOwner}}, for time interval \"{{dates}}\" have been cancelled.",
"success_accept_booking_redirect": "You have accepted this booking redirect request.",
"success_reject_booking_redirect": "You have rejected this booking redirect request.",
"copy_link_booking_redirect_request": "Copy link to share request",
Expand All @@ -2359,6 +2365,7 @@
"redirect_team_disabled": "Provide a link to a team member when OOO (Team plan required)",
"out_of_office_unavailable_list": "Out of office unavailability list",
"success_deleted_entry_out_of_office": "Successfully deleted entry",
"success_edited_entry_out_of_office": "Successfully edited entry",
"temporarily_out_of_office": "Temporarily Out-Of-Office?",
"add_a_redirect": "Add a redirect",
"create_entry": "Create entry",
Expand Down Expand Up @@ -2486,6 +2493,7 @@
"ooo_create_entry_modal": "Go Out of Office",
"ooo_select_reason": "Select reason",
"create_an_out_of_office": "Go Out of Office",
"edit_an_out_of_office": "Edit Out of Office Entry",
"submit_feedback": "Submit Feedback",
"host_no_show": "Your host didn't show up",
"no_show_description": "You can reschedule another meeting with them",
Expand Down
32 changes: 26 additions & 6 deletions packages/emails/src/templates/BookingRedirectEmailNotification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,39 @@ export const BookingRedirectEmailNotification = (
) => {
return (
<BaseEmailHtml
subject={props.language("booking_redirect_email_subject")}
title={props.language("booking_redirect_email_title")}>
subject={props.language(
{
add: "booking_redirect_email_subject",
update: "booking_redirect_updated_email_subject",
cancel: "booking_redirect_cancelled_email_subject",
}[props.action]
)}
title={props.language(
{
add: "booking_redirect_email_title",
update: "booking_redirect_updated_email_title",
cancel: "booking_redirect_cancelled_email_title",
}[props.action]
)}>
<p
style={{
color: "black",
fontSize: "16px",
lineHeight: "24px",
fontWeight: "400",
}}>
{props.language("booking_redirect_email_description", {
toName: props.toName,
})}
{props.dates}
{props.language(
{
add: "booking_redirect_email_description",
update: "booking_redirect_updated_email_description",
cancel: "booking_redirect_cancelled_email_description",
}[props.action],
{
eventOwner: props.eventOwner,
dates: props.dates,
oldDates: props.oldDates ?? "",
}
)}
<br />
<div
style={{
Expand Down
11 changes: 10 additions & 1 deletion packages/emails/templates/booking-redirect-notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ import BaseEmail from "./_base-email";
export interface IBookingRedirect {
language: TFunction;
fromEmail: string;
eventOwner: string;
toEmail: string;
toName: string;
oldDates?: string;
dates: string;
action: "add" | "update" | "cancel";
}

export default class BookingRedirectNotification extends BaseEmail {
Expand All @@ -26,7 +29,13 @@ export default class BookingRedirectNotification extends BaseEmail {
return {
to: `${this.bookingRedirect.toName} <${this.bookingRedirect.toEmail}>`,
from: `${EMAIL_FROM_NAME} <${this.getMailerOptions().from}>`,
subject: this.bookingRedirect.language("booking_redirect_email_subject"),
subject: this.bookingRedirect.language(
{
add: "booking_redirect_email_subject",
update: "booking_redirect_updated_email_subject",
cancel: "booking_redirect_cancelled_email_subject",
}[this.bookingRedirect.action]
),
html: await renderEmail("BookingRedirectEmailNotification", {
...this.bookingRedirect,
}),
Expand Down
Loading

0 comments on commit a0c55e7

Please sign in to comment.