diff --git a/src/components/[guild]/crm/CrmRoleAccessIndicator/CrmRoleAccessIndicator.tsx b/src/components/[guild]/crm/CrmRoleAccessIndicator/CrmRoleAccessIndicator.tsx
new file mode 100644
index 0000000000..16d94b634a
--- /dev/null
+++ b/src/components/[guild]/crm/CrmRoleAccessIndicator/CrmRoleAccessIndicator.tsx
@@ -0,0 +1,30 @@
+import { PopoverHeader } from "@chakra-ui/react"
+import { POPOVER_HEADER_STYLES } from "components/[guild]/Requirements/components/RequiementAccessIndicator"
+import { Check, X } from "phosphor-react"
+import { CrmRole } from "../useMembers"
+import CrmRoleAccessIndicatorUI from "./components/CrmRoleAccessIndicatorUI"
+
+type Props = {
+ memberRole: CrmRole
+}
+
+const CrmRoleAccessIndicator = ({ memberRole }: Props) => {
+ if (!memberRole)
+ return (
+
+ Role not satisfied
+
+ )
+
+ return (
+
+ Role satisfied
+
+ )
+}
+
+export default CrmRoleAccessIndicator
diff --git a/src/components/[guild]/crm/CrmRoleAccessIndicator/components/CrmRoleAccessIndicatorUI.tsx b/src/components/[guild]/crm/CrmRoleAccessIndicator/components/CrmRoleAccessIndicatorUI.tsx
new file mode 100644
index 0000000000..a2a621bf45
--- /dev/null
+++ b/src/components/[guild]/crm/CrmRoleAccessIndicator/components/CrmRoleAccessIndicatorUI.tsx
@@ -0,0 +1,44 @@
+import {
+ Center,
+ Icon,
+ Popover,
+ PopoverArrow,
+ PopoverContent,
+ PopoverTrigger,
+ Portal,
+ Tag,
+ Text,
+} from "@chakra-ui/react"
+import { FC, PropsWithChildren } from "react"
+
+type Props = {
+ colorScheme: string
+ icon: FC
+ amount?: number
+}
+
+const CrmRoleAccessIndicatorUI = ({
+ colorScheme,
+ icon,
+ amount,
+ children,
+}: PropsWithChildren) => (
+
+
+
+
+
+ {amount && {amount.toFixed(2)}}
+
+
+
+
+ {children}
+
+
+
+
+
+)
+
+export default CrmRoleAccessIndicatorUI
diff --git a/src/components/[guild]/crm/CrmRoleAccessIndicator/index.ts b/src/components/[guild]/crm/CrmRoleAccessIndicator/index.ts
new file mode 100644
index 0000000000..2ae2b54303
--- /dev/null
+++ b/src/components/[guild]/crm/CrmRoleAccessIndicator/index.ts
@@ -0,0 +1,3 @@
+import CrmRoleAccessIndicator from "./CrmRoleAccessIndicator"
+
+export default CrmRoleAccessIndicator
diff --git a/src/components/[guild]/crm/CustomizeViewModal.tsx b/src/components/[guild]/crm/CustomizeViewModal.tsx
index 7b868d33e6..4eed0390d0 100644
--- a/src/components/[guild]/crm/CustomizeViewModal.tsx
+++ b/src/components/[guild]/crm/CustomizeViewModal.tsx
@@ -11,10 +11,12 @@ import {
useColorModeValue,
} from "@chakra-ui/react"
import { Column, Table } from "@tanstack/react-table"
+import SimpleRoleTag from "components/analytics/MembersChart/components/SimpleRoleTag"
import { Modal } from "components/common/Modal"
import { Reorder } from "framer-motion"
import { DotsSixVertical } from "phosphor-react"
-import { useState } from "react"
+import { useEffect, useState } from "react"
+import useGuild from "../hooks/useGuild"
import { Member } from "./useMembers"
type Props = {
@@ -35,6 +37,10 @@ const CustomizeViewModal = ({ isOpen, onClose, table }: Props) => {
const columns = table.getAllColumns()
const [localOrder, setLocalOrder] = useState(() => transformToLocalOrder(table))
+ useEffect(() => {
+ setLocalOrder(transformToLocalOrder(table))
+ }, [columns])
+
const setTableOrder = () => {
const newOrder = transformToTableOrder(localOrder)
/**
@@ -47,7 +53,7 @@ const CustomizeViewModal = ({ isOpen, onClose, table }: Props) => {
}
return (
-
+
Customize shown columns
@@ -65,7 +71,14 @@ const CustomizeViewModal = ({ isOpen, onClose, table }: Props) => {
onDragEnd={setTableOrder}
style={{ position: "relative" }} // needed for the auto-applied zIndex to work
>
- col.id === colId)} />
+ {colId.startsWith("role_") ? (
+ col.id === colId)}
+ roleId={parseInt(colId.split("_")[1])}
+ />
+ ) : (
+ col.id === colId)} />
+ )}
))}
@@ -87,6 +100,7 @@ const ColumnSelector = ({ column, isDisabled }: SelectorProps) => {
mb="2"
bg={bg}
borderRadius="xl"
+ boxShadow={"xs"}
cursor={!isDisabled && "grab"}
>
@@ -135,10 +149,41 @@ const ColumnSelector = ({ column, isDisabled }: SelectorProps) => {
)
}
+type RoleSelectorProps = { column: Column; roleId: number }
+
+const RoleColumnSelector = ({ column, roleId }: RoleSelectorProps) => {
+ const bg = useColorModeValue("white", "#343437")
+ const { roles } = useGuild()
+
+ const role = roles.find((r) => r.id === roleId)
+
+ return (
+
+
+
+
+
+
+
+
+ )
+}
+
const transformToLocalOrder = (table) => {
- const columnOrder = table.getState().columnOrder
+ const res = [...table.getState().columnOrder]
const columnIds = table.getAllLeafColumns().map((col) => col.id)
- const res = columnOrder.length ? columnOrder : columnIds
+ columnIds.forEach((colId) => !res.includes(colId) && res.push(colId))
// remove 'select' and 'identity'
res.splice(0, 2)
diff --git a/src/components/[guild]/crm/RoleTags.tsx b/src/components/[guild]/crm/RoleTags.tsx
index 3bb78e2855..136e476135 100644
--- a/src/components/[guild]/crm/RoleTags.tsx
+++ b/src/components/[guild]/crm/RoleTags.tsx
@@ -16,7 +16,9 @@ import {
} from "@chakra-ui/react"
import { Column } from "@tanstack/react-table"
import Button from "components/common/Button"
-import { Funnel } from "phosphor-react"
+import { useAtom } from "jotai"
+import { shownRoleColumnsAtom } from "pages/[guild]/members"
+import { ArrowFatRight, Funnel, X } from "phosphor-react"
import { Visibility } from "types"
import pluralize from "utils/pluralize"
import ClickableTagPopover from "../activity/ActivityLogAction/components/ClickableTagPopover"
@@ -176,6 +178,7 @@ export const ClickableCrmRoleTag = ({
+
>
}
>
@@ -206,4 +209,31 @@ const FilterByCrmRole = ({ roleId, column, onFilter }) => {
)
}
+const MoveRoleToColumn = ({ roleId }) => {
+ const [shownRoleColumns, setShownRoleColumnsAtom] = useAtom(shownRoleColumnsAtom)
+
+ const isAlreadyColumn = shownRoleColumns.includes(roleId)
+
+ const onClick = () => {
+ setShownRoleColumnsAtom((prevValue) =>
+ isAlreadyColumn
+ ? prevValue.filter((id) => id !== roleId)
+ : [...prevValue, roleId]
+ )
+ }
+
+ return (
+ : }
+ size="sm"
+ borderRadius={0}
+ onClick={onClick}
+ justifyContent="start"
+ >
+ {isAlreadyColumn ? "Remove column" : "Move to column"}
+
+ )
+}
+
export default RoleTags
diff --git a/src/pages/[guild]/members.tsx b/src/pages/[guild]/members.tsx
index f98a14e924..b5b9d5fff5 100644
--- a/src/pages/[guild]/members.tsx
+++ b/src/pages/[guild]/members.tsx
@@ -11,6 +11,7 @@ import CrmTableWrapper from "components/[guild]/crm/CRMTable/CrmTableWrapper"
import CrmTbody from "components/[guild]/crm/CRMTable/CrmTbody"
import CrmThead from "components/[guild]/crm/CRMTable/CrmThead"
import CrmMenu from "components/[guild]/crm/CrmMenu"
+import CrmRoleAccessIndicator from "components/[guild]/crm/CrmRoleAccessIndicator"
import FilterByRoles from "components/[guild]/crm/FilterByRoles"
import Identities from "components/[guild]/crm/Identities"
import IdentitiesExpansionToggle from "components/[guild]/crm/IdentitiesExpansionToggle"
@@ -22,10 +23,11 @@ import {
parseFiltersFromQuery,
parseSortingFromQuery,
} from "components/[guild]/crm/transformTableStateToAndFromQuery"
-import useMembers, { Member } from "components/[guild]/crm/useMembers"
+import useMembers, { CrmRole, Member } from "components/[guild]/crm/useMembers"
import useGuild from "components/[guild]/hooks/useGuild"
import GuildLogo from "components/common/GuildLogo"
import Layout from "components/common/Layout"
+import { atom, useAtom } from "jotai"
import Head from "next/head"
import { useRouter } from "next/router"
import ErrorPage from "pages/_error"
@@ -124,9 +126,26 @@ const columns = [
}),
]
+export const shownRoleColumnsAtom = atom([])
+
const GuildPage = (): JSX.Element => {
const { textColor, localThemeColor, localBackgroundImage } = useThemeContext()
const { name, roles, imageUrl } = useGuild()
+ const [shownRoleColumns] = useAtom(shownRoleColumnsAtom)
+
+ const roleColumns = useMemo(
+ () =>
+ shownRoleColumns.map((roleId) => ({
+ accessorKey: `role_${roleId}`,
+ accessorFn: (row) =>
+ Object.values(row.roles)
+ .flat()
+ .find((role: CrmRole) => role.roleId === roleId),
+ header: () => roles.find((role) => role.id === roleId)?.name,
+ cell: (info) => ,
+ })),
+ [shownRoleColumns]
+ )
const router = useRouter()
const [columnFilters, setColumnFilters] = useState(() =>
@@ -166,7 +185,7 @@ const GuildPage = (): JSX.Element => {
const table = useReactTable({
data: useMemo(() => data ?? [], [data]),
- columns,
+ columns: useMemo(() => [...columns, ...roleColumns], [roleColumns]),
state: {
columnFilters,
sorting,