Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New account and apps users structure #524

Merged
merged 3 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 14 additions & 31 deletions app/models/portal/queries.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,13 @@ query getUserAccount(
id
name
planType
users {
userID
owner
accountUsers {
accountUserID
email
portalAppRoles {
owner
portalApps {
portalAppID
roleName
}
portalAppsAccepted {
portalAppID
accepted
}
}
Expand Down Expand Up @@ -158,8 +155,8 @@ query getUserAccounts(
id
name
}
users {
userID
accountUsers {
accountUserID
owner
}
}
Expand All @@ -172,18 +169,11 @@ query getUserPortalApp($portalAppID: ID!) {
accountID
appEmoji
description
users {
userID
owner
portalAppUsers {
portalAppUserID
email
portalAppRoles {
portalAppID
roleName
}
portalAppsAccepted {
portalAppID
accepted
}
roleName
accepted
}
settings {
appID
Expand Down Expand Up @@ -264,18 +254,11 @@ query getUserPortalApps(
accountID
appEmoji
description
users {
userID
owner
portalAppUsers {
portalAppUserID
email
portalAppRoles {
portalAppID
roleName
}
portalAppsAccepted {
portalAppID
accepted
}
roleName
accepted
}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { ActionIcon, Flex, Menu, Text } from "@pokt-foundation/pocket-blocks"
import React, { useMemo } from "react"
import { LuMinusCircle, LuMoreHorizontal, LuSend } from "react-icons/lu"
import { AccountUserAccess, PortalApp, RoleNameV2, User } from "~/models/portal/sdk"
import { PortalApp, PortalAppUser, RoleNameV2, User } from "~/models/portal/sdk"
import useTeamModals from "~/routes/account.$accountId.$appId.team/hooks/useTeamModals"
import useCommonStyles from "~/styles/commonStyles"

type TeamMemberActionProps = {
app: PortalApp
userRole: RoleNameV2 | null
user?: User
teamMember: AccountUserAccess & { accepted: boolean; roleName: RoleNameV2 | null }
teamMember: PortalAppUser
status: Boolean
}

Expand All @@ -30,13 +30,14 @@ const TeamMemberAction = ({

switch (userRole) {
case RoleNameV2.Owner:
if (teamMember.userID === user?.portalUserID) {
if (teamMember.portalAppUserID === user?.portalUserID) {
// OWNER --CANNOT-- LEAVE THEIR OWN APP
} else {
// OWNER --CAN--REMOVE OTHER USERS
items.push({
icon: <LuMinusCircle size={18} />,
onClick: () => openRemoveUserModal(teamMember.email, teamMember.userID),
onClick: () =>
openRemoveUserModal(teamMember.email, teamMember.portalAppUserID),
label: "Remove",
})
if (!status) {
Expand All @@ -50,18 +51,20 @@ const TeamMemberAction = ({
}
break
case RoleNameV2.Admin:
if (teamMember.userID === user?.portalUserID) {
if (teamMember.portalAppUserID === user?.portalUserID) {
// ADMIN --CAN--REMOVE THEMSELVES
items.push({
icon: <LuMinusCircle size={18} />,
onClick: () => openRemoveUserModal(teamMember.email, teamMember.userID),
onClick: () =>
openRemoveUserModal(teamMember.email, teamMember.portalAppUserID),
label: "Remove",
})
} else {
// ADMIN --CAN--REMOVE OTHER USERS
items.push({
icon: <LuMinusCircle size={18} />,
onClick: () => openRemoveUserModal(teamMember.email, teamMember.userID),
onClick: () =>
openRemoveUserModal(teamMember.email, teamMember.portalAppUserID),
label: "Remove",
})
if (!status) {
Expand All @@ -76,11 +79,12 @@ const TeamMemberAction = ({
break
case RoleNameV2.Member:
default:
if (teamMember.userID === user?.portalUserID) {
if (teamMember.portalAppUserID === user?.portalUserID) {
// MEMEBER --CAN-- LEAVE APP THEMSELVES
items.push({
icon: <LuMinusCircle size={18} />,
onClick: () => openLeaveTeamModal(teamMember.email, teamMember.userID),
onClick: () =>
openLeaveTeamModal(teamMember.email, teamMember.portalAppUserID),
label: "Leave",
})
} else {
Expand All @@ -92,7 +96,7 @@ const TeamMemberAction = ({
return items
}, [
userRole,
teamMember.userID,
teamMember.portalAppUserID,
teamMember.email,
user?.portalUserID,
status,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import Identicon from "~/components/Identicon"
import { PortalApp, RoleName, RoleNameV2, User } from "~/models/portal/sdk"
import TeamMemberAction from "~/routes/account.$accountId.$appId.team/components/TeamMemberAction"
import useTeamModals from "~/routes/account.$accountId.$appId.team/hooks/useTeamModals"
import { getAppAcceptedValue, getUserRole } from "~/utils/applicationUtils"

type TeamMembersTableProps = {
app: PortalApp
Expand All @@ -22,26 +21,22 @@ type TeamMembersTableProps = {
const TeamMembersTable = ({ app, userRole, user }: TeamMembersTableProps) => {
const { openChangeRoleModal } = useTeamModals({ app })

const teamData = app.users
.map((user) => ({
...user,
roleName: getUserRole(app, user.userID),
accepted: getAppAcceptedValue(app, user.userID),
}))
.sort((a, b) => Number(b.owner) - Number(a.owner))
const teamData = app.portalAppUsers.sort(
(a, b) => Number(b.roleName === "OWNER") - Number(a.roleName === "OWNER"),
)

return (
<DataTable
columns={["Member", "Roles", "Status", ""]}
data={teamData.map(({ email, roleName, accepted, userID }, index) => {
data={teamData.map(({ email, roleName, accepted, portalAppUserID }, index) => {
return {
member: {
element: (
<Group>
<Avatar radius="xl">
<Identicon
alt={`${userID} profile picture`}
seed={userID}
alt={`${portalAppUserID} profile picture`}
seed={portalAppUserID}
size="md"
type="user"
/>
Expand Down Expand Up @@ -71,7 +66,7 @@ const TeamMembersTable = ({ app, userRole, user }: TeamMembersTableProps) => {
disabled={!accepted}
onChange={(value) =>
value !== roleName &&
openChangeRoleModal(email, userID, value as RoleName)
openChangeRoleModal(email, portalAppUserID, value as RoleName)
}
/>
</Flex>
Expand Down
5 changes: 3 additions & 2 deletions app/routes/account.$accountId.$appId/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import useActionNotification from "~/hooks/useActionNotification"
import { initPortalClient } from "~/models/portal/portal.server"
import { Blockchain, PortalApp, RoleNameV2 } from "~/models/portal/sdk"
import { DataStruct } from "~/types/global"
import { getUserRole } from "~/utils/applicationUtils"
import { getErrorMessage } from "~/utils/catchError"
import { seo_title_append } from "~/utils/seo"
import { requireUser } from "~/utils/user.server"
Expand Down Expand Up @@ -126,7 +127,7 @@ export type AppIdOutletContext = AppIdLoaderData & {

export default function AppIdLayout() {
const { data, error, message } = useLoaderData() as DataStruct<AppIdLoaderData>
const { userRoles } = useOutletContext<AccountIdLoaderData>()
const { user } = useOutletContext<AccountIdLoaderData>()
const actionData = useActionData() as DataStruct<AppIdActionData>

// handle all notifications at the layout level
Expand All @@ -137,7 +138,7 @@ export default function AppIdLayout() {
}

const { app, blockchains } = data
const userRole = userRoles.find((r) => r.portalAppID === app.id)?.roleName as RoleNameV2
const userRole = getUserRole(app.portalAppUsers, user.portalUserID) as RoleNameV2

return (
<AppIdLayoutView app={app} userRole={userRole}>
Expand Down
12 changes: 4 additions & 8 deletions app/routes/account.$accountId/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
GetUserAccountQuery,
GetUserAccountsQuery,
PortalApp,
PortalAppRole,
User,
} from "~/models/portal/sdk"
import { DataStruct } from "~/types/global"
Expand All @@ -21,7 +20,6 @@ export type AccountIdLoaderData = {
accounts: GetUserAccountsQuery["getUserAccounts"]
user: User
hasPendingInvites: boolean
userRoles: PortalAppRole[]
}

export const loader: LoaderFunction = async ({ request, params }) => {
Expand Down Expand Up @@ -53,9 +51,6 @@ export const loader: LoaderFunction = async ({ request, params }) => {
accounts: userAccounts.getUserAccounts,
user: user.user,
hasPendingInvites: userPendingApps.getUserPortalApps.length > 0,
userRoles: account.getUserAccount.users.filter(
(u) => u.userID === user.user.portalUserID,
)[0].portalAppRoles,
},
error: false,
})
Expand All @@ -67,7 +62,8 @@ export const loader: LoaderFunction = async ({ request, params }) => {

let ownerAccount = userAccounts?.getUserAccounts?.find(
(account) =>
account?.users?.find((u) => u.userID === user.user.portalUserID)?.owner,
account?.accountUsers?.find((u) => u.accountUserID === user.user.portalUserID)
?.owner,
)

if (accountId !== ownerAccount?.id) {
Expand All @@ -89,7 +85,7 @@ export default function AccountId() {
return <ErrorView message={message} />
}

const { account, accounts, user, userRoles, hasPendingInvites } = data
const { account, accounts, user, hasPendingInvites } = data

return (
<RootAppShell
Expand All @@ -98,7 +94,7 @@ export default function AccountId() {
hasPendingInvites={hasPendingInvites}
user={user}
>
<Outlet context={{ account, accounts, user, userRoles }} />
<Outlet context={{ account, accounts, user }} />
</RootAppShell>
)
}
2 changes: 1 addition & 1 deletion app/routes/account_.$accountId.$appId.update/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const loader: LoaderFunction = async ({ request, params }) => {

const isUserMember =
getUserRole(
getUserPortalAppResponse.getUserPortalApp as PortalApp,
getUserPortalAppResponse.getUserPortalApp.portalAppUsers,
user.user.portalUserID,
) === "MEMBER"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const AccountsTable = ({ accounts, user }: AccountsTableProps) => {

const sortedAccounts = useMemo(() => {
const ownedAccount = accounts.find((account) =>
account.users.find((u) => u.userID === user.portalUserID && u.owner),
account?.accountUsers.find((u) => u.accountUserID === user.portalUserID && u.owner),
)
const filteredAccounts = accounts.filter(({ id }) => id !== ownedAccount?.id)
return [
Expand Down Expand Up @@ -56,8 +56,8 @@ const AccountsTable = ({ accounts, user }: AccountsTableProps) => {
members: {
element: (
<Text>
{account?.users?.length} Member
{account?.users?.length > 1 ? "s" : ""}
{account?.accountUsers?.length} Member
{account?.accountUsers?.length > 1 ? "s" : ""}
</Text>
),
},
Expand Down
4 changes: 2 additions & 2 deletions app/routes/user.invited-apps/view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ export const UserInvitedApps = ({ apps, user }: UserInvitedAppsProps) => {
return apps
.map((app) => ({
...app,
accepted: getAppAcceptedValue(app, user.portalUserID),
role: getUserRole(app, user.portalUserID),
accepted: getAppAcceptedValue(app.portalAppUsers, user.portalUserID),
role: getUserRole(app.portalAppUsers, user.portalUserID),
}))
.sort((a, b) => Number(a.accepted) - Number(b.accepted))
.filter((app) => app.role !== RoleNameV2.Owner)
Expand Down
32 changes: 7 additions & 25 deletions app/utils/applicationUtils.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,11 @@
import { PortalApp } from "~/models/portal/sdk"
import { PortalAppUser } from "~/models/portal/sdk"

export const getAppAcceptedValue = (app: PortalApp, userId: string) => {
const user = app.users.find((user) => user.userID === userId)

if (user) {
const acceptedEntry = user.portalAppsAccepted.find(
(entry) => entry.portalAppID === app.id,
)

return acceptedEntry ? acceptedEntry.accepted : false
}

return false
export const getAppAcceptedValue = (portalAppUsers: PortalAppUser[], userId: string) => {
const user = portalAppUsers.find((user) => user.portalAppUserID === userId)
return user?.accepted ?? false
}

export const getUserRole = (app: PortalApp, userId: string) => {
const user = app.users.find((user) => user.userID === userId)

if (user) {
const role = user.portalAppRoles.find((role) => role.portalAppID === app.id)

if (role) {
return role.roleName
}
}

return null
export const getUserRole = (portalAppUsers: PortalAppUser[], userId: string) => {
const user = portalAppUsers.find((user) => user.portalAppUserID === userId)
return user?.roleName ?? null
}
4 changes: 3 additions & 1 deletion app/utils/user.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
}

export const requireUser = async (request: Request, defaultRedirect = "/") => {
const url = new URL(request.url)

Check warning on line 13 in app/utils/user.server.ts

View workflow job for this annotation

GitHub Actions / ⬣ Validate

'url' is assigned a value but never used
const user = await authenticator.isAuthenticated(request)

if (!user) {
Expand Down Expand Up @@ -103,7 +103,9 @@
let account = accounts.getUserAccounts[0] as Partial<Account>

let owner = accounts.getUserAccounts.find(
(account) => account?.users.find((u) => u.userID === user.user.portalUserID)?.owner,
(account) =>
account?.accountUsers.find((u) => u.accountUserID === user.user.portalUserID)
?.owner,
)

if (owner) {
Expand Down
4 changes: 3 additions & 1 deletion app/utils/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const isUserAccountOwner = ({
}) =>
accounts
.find(({ id }) => accountId === id)
?.users.some((u) => u.userID === user.portalUserID && u.owner) as boolean
?.accountUsers.some(
(u) => u.accountUserID === user.portalUserID && u.owner,
) as boolean

export default isUserAccountOwner
Loading