From bd0dbb70338b7bf7343a118cb2fa6a4d8a3bec53 Mon Sep 17 00:00:00 2001 From: MananTank Date: Wed, 9 Oct 2024 22:46:09 +0000 Subject: [PATCH] Team Member Settings Page updates (#4978) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem solved Short description of the bug fixed or feature added --- ## PR-Codex overview This PR focuses on enhancing the `TeamMembersSettingsPage` by adding an alert for unavailable features, updating the logic for invite permissions, and refining member management with improved filtering and sorting functionalities. ### Detailed summary - Added an `Alert` component in `TeamMembersSettingsPage` to notify users about feature availability. - Changed the condition for `inviteEnabled` in `InviteSection` to check for non-free plans. - Updated member management logic to filter and sort members based on roles. - Modified the `ManageMembersSection` to use filtered member lists for display and actions. - Adjusted the `createMemberStub` function to accept a `createdHours` parameter. - Updated storybook examples to reflect changes in team plans and permissions. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- apps/dashboard/src/@/api/team-members.ts | 15 ++- .../~/settings/members/InviteSection.tsx | 8 +- .../settings/members/ManageMembersSection.tsx | 91 +++++++++++++++---- .../TeamMembersSettingsPage.stories.tsx | 66 +++++--------- .../members/TeamMembersSettingsPage.tsx | 13 +++ .../(team)/~/settings/members/page.tsx | 15 ++- 6 files changed, 129 insertions(+), 79 deletions(-) diff --git a/apps/dashboard/src/@/api/team-members.ts b/apps/dashboard/src/@/api/team-members.ts index ba38805a089..a1f7eff7c1d 100644 --- a/apps/dashboard/src/@/api/team-members.ts +++ b/apps/dashboard/src/@/api/team-members.ts @@ -1,7 +1,6 @@ import "server-only"; -import { COOKIE_ACTIVE_ACCOUNT, COOKIE_PREFIX_TOKEN } from "@/constants/cookie"; import { API_SERVER_URL } from "@/constants/env"; -import { cookies } from "next/headers"; +import { getAuthToken } from "../../app/api/lib/getAuthToken"; const TeamAccountRole = { OWNER: "OWNER", @@ -26,14 +25,10 @@ export type TeamMember = { }; export async function getMembers(teamSlug: string) { - const cookiesManager = cookies(); - const activeAccount = cookiesManager.get(COOKIE_ACTIVE_ACCOUNT)?.value; - const token = activeAccount - ? cookiesManager.get(COOKIE_PREFIX_TOKEN + activeAccount)?.value - : null; + const token = getAuthToken(); if (!token) { - return []; + return undefined; } const teamsRes = await fetch( @@ -44,8 +39,10 @@ export async function getMembers(teamSlug: string) { }, }, ); + if (teamsRes.ok) { return (await teamsRes.json())?.result as TeamMember[]; } - return []; + + return undefined; } diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/InviteSection.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/InviteSection.tsx index a4075962242..2208d21fa36 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/InviteSection.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/InviteSection.tsx @@ -25,19 +25,19 @@ export function InviteSection(props: { }) { const teamPlan = getValidTeamPlan(props.team); let bottomSection: React.ReactNode = null; - const inviteEnabled = teamPlan === "pro" && props.userHasEditPermission; + const inviteEnabled = teamPlan !== "free" && props.userHasEditPermission; - if (teamPlan !== "pro") { + if (teamPlan === "free") { bottomSection = (

- This feature is only available on the{" "} + This feature is not available on the Free Plan.{" "} - Pro plan + View plans

diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/ManageMembersSection.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/ManageMembersSection.tsx index d4c15718f41..b6c1ed94784 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/ManageMembersSection.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/ManageMembersSection.tsx @@ -14,7 +14,9 @@ import { SelectValue, } from "@/components/ui/select"; import { EllipsisIcon, SearchIcon } from "lucide-react"; -import { useState } from "react"; +import { useMemo, useState } from "react"; + +type RoleFilterValue = "ALL ROLES" | TeamAccountRole; export function ManageMembersSection(props: { team: Team; @@ -23,6 +25,36 @@ export function ManageMembersSection(props: { }) { let topSection: React.ReactNode = null; + const [role, setRole] = useState("ALL ROLES"); + const [sortBy, setSortBy] = useState("date"); + + const membersToShow = useMemo(() => { + let value = props.members; + if (role !== "ALL ROLES") { + value = value.filter((m) => m.role === role); + } + + switch (sortBy) { + case "date": + value = value.sort( + (a, b) => a.createdAt.getTime() - b.createdAt.getTime(), + ); + break; + case "a-z": + value = value.sort((a, b) => + a.account.name.localeCompare(b.account.name), + ); + break; + case "z-a": + value = value.sort((a, b) => + b.account.name.localeCompare(a.account.name), + ); + break; + } + + return value; + }, [role, props.members, sortBy]); + if (!props.userHasEditPermission) { topSection = (
@@ -39,14 +71,14 @@ export function ManageMembersSection(props: { id="select-all" className="border-muted-foreground data-[state=checked]:border-inverted" disabled={ - !props.userHasEditPermission || props.members.length === 0 + !props.userHasEditPermission || membersToShow.length === 0 } />
@@ -54,7 +86,7 @@ export function ManageMembersSection(props: { size="icon" variant="ghost" className="!h-auto !w-auto p-1.5" - disabled={!props.userHasEditPermission || props.members.length === 0} + disabled={!props.userHasEditPermission || membersToShow.length === 0} > @@ -68,7 +100,14 @@ export function ManageMembersSection(props: {
- +
@@ -77,11 +116,14 @@ export function ManageMembersSection(props: { {/* Top section */} {topSection} - {props.members.length > 0 && ( + {membersToShow.length > 0 && (
    - {props.members.map((member) => { + {membersToShow.map((member) => { return ( -
  • +
  • No Members Found

@@ -108,7 +150,7 @@ function MemberRow(props: { userHasEditPermission: boolean; }) { return ( -
+
{/* Checkbox */} void; + setSortBy: (sortBy: MemberSortId) => void; + sortBy: MemberSortId; }) { + const { role, setRole, setSortBy, sortBy } = props; return (
{/* Search */} @@ -164,8 +211,12 @@ function FiltersSection(props: {
- - + +
); @@ -175,8 +226,10 @@ type MemberSortId = "date" | "a-z" | "z-a"; function SortMembersBy(props: { disabled?: boolean; + setSortBy: (sortBy: MemberSortId) => void; + sortBy: MemberSortId; }) { - const [sortBy, setSortBy] = useState("date"); + const { sortBy, setSortBy } = props; const valueToLabel: Record = { date: "Date", "a-z": "Name (A-Z)", @@ -211,19 +264,17 @@ function SortMembersBy(props: { function RoleSelector(props: { disabled?: boolean; + role: RoleFilterValue; + setRole: (role: RoleFilterValue) => void; }) { - const roles: (TeamAccountRole | "ALL ROLES")[] = [ - "OWNER", - "MEMBER", - "ALL ROLES", - ]; - const [role, setRole] = useState("ALL ROLES"); + const { role, setRole } = props; + const roles: RoleFilterValue[] = ["OWNER", "MEMBER", "ALL ROLES"]; return (