Skip to content

Commit

Permalink
Merge branch 'master' into production
Browse files Browse the repository at this point in the history
  • Loading branch information
RuntimeTerror10 committed May 10, 2024
2 parents cd62b8f + 9d5ce60 commit 9b689ae
Show file tree
Hide file tree
Showing 23 changed files with 1,463 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@ import CreatableSelect from "react-select/creatable";
import { MultiValue } from "react-select";

interface Props {
autoFocus?: boolean;
onChange: (emails: string[]) => void;
transparentBackground?: boolean;
}

const EmailInputWithDomainBasedSuggestions: React.FC<Props> = ({ onChange, transparentBackground = false }) => {
const EmailInputWithDomainBasedSuggestions: React.FC<Props> = ({
onChange,
transparentBackground = false,
autoFocus = false,
}) => {
const user = useSelector(getUserAuthDetails);
const userEmail = user?.details?.profile?.email;

Expand Down Expand Up @@ -58,6 +63,7 @@ const EmailInputWithDomainBasedSuggestions: React.FC<Props> = ({ onChange, trans

return (
<CreatableSelect
autoFocus={autoFocus}
isMulti={true}
isClearable={false}
options={suggestionOptions}
Expand Down
5 changes: 5 additions & 0 deletions app/src/features/settings/analytics/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export const SETTINGS = {
APP_SETTINGS_VIEWED: "app_settings_viewed",
APP_SETTINGS_SIDEBAR_CLICKED: "app_settings_sidebar_clicked",

// TODO: Move these constants inside billin folder
BILLING: {
BILLING_TEAM_VIEWED: "billing_team_viewed",
BILLING_TEAM_NAVIGATED: "billing_team_navigated",
Expand All @@ -14,6 +15,10 @@ export const SETTINGS = {
REQUEST_BILLING_TEAM_ACCESS_MODAL_VIEWED: "request_billing_team_access_modal_viewed",
JOIN_BILLING_TEAM_REMINDER_VIEWED: "join_billing_team_reminder_viewed",
BILLING_TEAM_ACCESS_REQUEST_RESPONDED: "billing_team_access_request_responded",
BILLING_TEAM_INVITE_MEMBER_CLICKED: "billing_team_invite_member_clicked",
BILLING_TEAM_INVITE_MEMBER_EMAIL_ENTERRED: "billing_team_invite_member_email_enterred",
BILLING_TEAM_INVITE_SENT_SUCCESSFULLY: "billing_team_invite_sent_successfully",
BILLING_TEAM_INVITE_SENDING_FAILED: "billing_team_invite_sending_failed",
},

WORKSPACE: {
Expand Down
16 changes: 16 additions & 0 deletions app/src/features/settings/analytics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,19 @@ export const trackJoinBillingTeamReminderViewed = () => {
export const trackBillingTeamAccessRequestResponded = (action: string, status: string) => {
trackEvent(SETTINGS.BILLING.BILLING_TEAM_ACCESS_REQUEST_RESPONDED, { action, status });
};

export const trackBillingTeamInviteMemberClicked = (source: string) => {
trackEvent(SETTINGS.BILLING.BILLING_TEAM_INVITE_MEMBER_CLICKED, { source });
};

export const trackBillingTeamInviteMemberEmailEntered = () => {
trackEvent(SETTINGS.BILLING.BILLING_TEAM_INVITE_MEMBER_EMAIL_ENTERRED);
};

export const trackBillingTeamInviteSentSuccessfully = (hasExternalDomainUser: boolean) => {
trackEvent(SETTINGS.BILLING.BILLING_TEAM_INVITE_SENT_SUCCESSFULLY, { hasExternalDomainUser });
};

export const trackBillingTeamInviteSendingFailed = (status: string, hasExternalDomainUser: boolean) => {
trackEvent(SETTINGS.BILLING.BILLING_TEAM_INVITE_SENDING_FAILED, { status, hasExternalDomainUser });
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { useParams } from "react-router-dom";
import React, { useState } from "react";
import { IoMdClose } from "@react-icons/all-files/io/IoMdClose";
import { Col, Drawer, Row } from "antd";
import { AddMembersTable } from "./components/AddMembersTable/AddMembersTable";
import { useFetchOrgMembers } from "features/settings/components/OrgMembers/hooks/useFetchOrganizationMembers";
import { RQButton } from "lib/design-system/components";
import { MdArrowBack } from "@react-icons/all-files/md/MdArrowBack";
import { InviteMembersForm } from "./components/InviteMembersForm/InviteMembersForm";
import "./addMembersDrawer.scss";

interface AppMembersDrawerProps {
Expand All @@ -11,6 +16,9 @@ interface AppMembersDrawerProps {

export const AppMembersDrawer: React.FC<AppMembersDrawerProps> = ({ isOpen, onClose }) => {
const [searchValue, setSearchValue] = useState("");
const { isLoading, organizationMembers } = useFetchOrgMembers();
const [isInviteFormVisible, setIsInviteFormVisible] = useState(false);
const { billingId } = useParams();

return (
<Drawer
Expand All @@ -23,13 +31,42 @@ export const AppMembersDrawer: React.FC<AppMembersDrawerProps> = ({ isOpen, onCl
className="billing-team-members-drawer"
>
<Row className="billing-team-members-drawer-header w-full" justify="space-between" align="middle">
<Col className="billing-team-members-drawer-header_title">Add members in billing team</Col>
<Col className="billing-team-members-drawer-header_title">
{isInviteFormVisible ? (
<div className="display-flex items-center" style={{ gap: "6px" }}>
<RQButton
size="small"
type="text"
iconOnly
icon={<MdArrowBack className="billing-team-members-drawer-back-btn" />}
onClick={() => setIsInviteFormVisible(false)}
/>
Invite & add to billing team
</div>
) : (
"Add members in billing team"
)}
</Col>
<Col>
<IoMdClose onClick={onClose} />
</Col>
</Row>
<Col className="billing-team-members-drawer-body">
<AddMembersTable searchValue={searchValue} setSearchValue={setSearchValue} />
{isInviteFormVisible ? (
<InviteMembersForm
toggleInviteFormVisibility={() => setIsInviteFormVisible(!isInviteFormVisible)}
closeAddMembersDrawer={onClose}
billingId={billingId}
/>
) : (
<AddMembersTable
searchValue={searchValue}
setSearchValue={setSearchValue}
isLoading={isLoading}
members={organizationMembers}
toggleInviteFormVisibility={() => setIsInviteFormVisible(!isInviteFormVisible)}
/>
)}
</Col>
</Drawer>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
display: none;
}

svg.billing-team-members-drawer-back-btn {
font-size: 14px;
}

.ant-drawer-body {
background: var(--surface-0_5);
background: var(--requestly-color-surface-0);
padding: 0;
}

Expand All @@ -31,7 +35,6 @@
}

&-body {
padding: 1rem;
position: relative;
}

Expand All @@ -43,4 +46,13 @@
width: 100%;
padding: 0 1rem;
}

.org-member-table {
border: none;

.org-member-table-header {
padding: 1rem;
border-bottom: 0;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,63 @@ import React, { useMemo } from "react";
import { OrgMembersTable } from "features/settings/components/OrgMembers/components/OrgMembersTable/OrgMembersTable";
import { useSelector } from "react-redux";
import { getUserAuthDetails } from "store/selectors";
import { OrgMember } from "features/settings/components/OrgMembers/types";
import { EmptyMembersTableView } from "./components/EmptyMembersTableView/EmptyMembersTableView";
import { RQButton } from "lib/design-system/components";
import { MdOutlinePersonAdd } from "@react-icons/all-files/md/MdOutlinePersonAdd";
import { AddMembersTableActions } from "./components/AddMembersTableActions/AddMembersTableActions";
import { useFetchOrgMembers } from "features/settings/components/OrgMembers/hooks/useFetchOrganizationMembers";
import { trackBillingTeamInviteMemberClicked } from "features/settings/analytics";
import "./addMembersTable.scss";

interface AddMembersTableProps {
searchValue: string;
isLoading: boolean;
members: OrgMember[];
setSearchValue: (value: string) => void;
toggleInviteFormVisibility: () => void;
}

export const AddMembersTable: React.FC<AddMembersTableProps> = ({ searchValue, setSearchValue }) => {
export const AddMembersTable: React.FC<AddMembersTableProps> = ({
searchValue,
setSearchValue,
members,
isLoading,
toggleInviteFormVisibility,
}) => {
const user = useSelector(getUserAuthDetails);
const { isLoading, organizationMembers } = useFetchOrgMembers();

const searchedMembers = useMemo(() => {
if (!organizationMembers) return [];
return organizationMembers?.filter((member: any) => {
if (!members) return [];
return members?.filter((member: any) => {
return member?.email?.includes(searchValue) && member?.email !== user?.details?.profile?.email;
});
}, [organizationMembers, searchValue, user?.details?.profile?.email]);
}, [members, searchValue, user?.details?.profile?.email]);

return (
<OrgMembersTable
isLoading={isLoading}
searchValue={searchValue}
setSearchValue={setSearchValue}
members={searchedMembers}
actions={(member) => <AddMembersTableActions member={member} />}
/>
<div className="add-members-table-wrapper">
<OrgMembersTable
isLoading={isLoading}
searchValue={searchValue}
setSearchValue={setSearchValue}
members={searchedMembers}
memberActions={(member) => [<AddMembersTableActions member={member} />]}
tableActions={[
<RQButton
type="default"
className="invite-people-btn"
icon={<MdOutlinePersonAdd />}
onClick={() => {
toggleInviteFormVisibility();
trackBillingTeamInviteMemberClicked("header");
}}
>
Invite people
</RQButton>,
]}
emptyView={
<EmptyMembersTableView searchValue={searchValue} toggleInviteFormVisibility={toggleInviteFormVisibility} />
}
/>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.add-members-table-wrapper {
.org-member-table {
border: none;

.org-member-table-header {
padding: 1rem;
border-bottom: 0;
}

.ant-table-empty .ant-table-tbody > tr.ant-table-placeholder td {
border-bottom: none;
}
}

.invite-people-btn.ant-btn {
gap: 6px;
}

.org-members-table-count {
padding-top: 1rem;
}

.ant-spin-nested-loading > div > .ant-spin {
background: var(--requestly-color-surface-0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { toast } from "utils/Toast";
import { trackBillingTeamActionClicked, trackBillingTeamMemberAdded } from "features/settings/analytics";
import { addUsersToBillingTeam } from "backend/billing";
import { OrgMember } from "features/settings/components/OrgMembers/types";
import "./orgTableActions.scss";

export const AddMembersTableActions: React.FC<{ member: OrgMember }> = ({ member }) => {
const { billingId } = useParams();
Expand Down Expand Up @@ -56,7 +57,7 @@ export const AddMembersTableActions: React.FC<{ member: OrgMember }> = ({ member
{isUserAdmin && (
<Row justify="end">
<RQButton
type="default"
type="text"
icon={<IoMdAdd />}
className="billing-team-members-add-btn"
loading={isAddingUser}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.billing-team-members-add-btn.ant-btn {
gap: 8px;
color: var(--neutrals-gray-300);

&:hover,
&:focus,
&:active {
color: var(--white);
border-color: var(--surface-3);
}
}

.billing-team-members-added-label {
color: var(--neutrals-gray-300);
padding-right: 5px;

& svg {
position: relative;
top: 3px;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from "react";
import { RQButton } from "lib/design-system/components";
import EmptyIcon from "./assets/empty.svg";
import { trackBillingTeamInviteMemberClicked } from "features/settings/analytics";
import "./emptyMembersTableView.scss";

interface EmptyMembersTableViewProps {
searchValue: string;
toggleInviteFormVisibility: () => void;
}

export const EmptyMembersTableView: React.FC<EmptyMembersTableViewProps> = ({
searchValue,
toggleInviteFormVisibility,
}) => {
return (
<div className="empty-members-table-view">
<img src={EmptyIcon} alt="empty list" />
<div className="empty-members-table-title">
{searchValue.length
? `No user found with email “${searchValue}” in your billing team`
: "You are the first one from your organization"}
</div>
<div className="empty-members-table-description">
Please click the button below to invite and add members in your billing team.
</div>
<RQButton
className="mt-24"
type="primary"
onClick={() => {
toggleInviteFormVisibility();
trackBillingTeamInviteMemberClicked("member_not_found");
}}
>
Invite & add to billing team
</RQButton>
</div>
);
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.empty-members-table-view {
padding-top: 32px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;

.empty-members-table-title {
color: var(--requestly-color-text-default);
font-size: var(--requestly-font-size-lg);
font-weight: 500;
text-align: center;
margin-top: 24px;
}

.empty-members-table-description {
color: var(--requestly-color-text-subtle);
font-size: var(--requestly-font-size-xs);
margin-top: 8px;
text-align: center;
}
}
Loading

0 comments on commit 9b689ae

Please sign in to comment.