-
Notifications
You must be signed in to change notification settings - Fork 17
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
feat: add members space page #971
base: master
Are you sure you want to change the base?
Changes from all commits
f910024
0c3e3f9
5cc5563
d8738d3
707bc7d
58a8eba
0060899
d5ca893
b65c7f4
cf5db05
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ import IHCog from '~icons/heroicons-outline/cog'; | |
import IHGlobeAlt from '~icons/heroicons-outline/globe-alt'; | ||
import IHGlobe from '~icons/heroicons-outline/globe-americas'; | ||
import IHHome from '~icons/heroicons-outline/home'; | ||
import IHIdentification from '~icons/heroicons-outline/identification'; | ||
import IHLightningBolt from '~icons/heroicons-outline/lightning-bolt'; | ||
import IHNewspaper from '~icons/heroicons-outline/newspaper'; | ||
import IHStop from '~icons/heroicons-outline/stop'; | ||
|
@@ -42,15 +43,17 @@ const space = computed(() => | |
: null | ||
); | ||
|
||
const isController = computedAsync(async () => { | ||
if (!networkId.value || !space.value) return false; | ||
|
||
const { account } = web3.value; | ||
const controller = computedAsync(async () => { | ||
if (!networkId.value || !space.value) return null; | ||
|
||
const network = getNetwork(networkId.value); | ||
const controller = await network.helpers.getSpaceController(space.value); | ||
return await network.helpers.getSpaceController(space.value); | ||
}); | ||
|
||
return compareAddresses(controller, account); | ||
const isController = computed(() => { | ||
const { account } = web3.value; | ||
|
||
return compareAddresses(controller.value ?? '', account); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit. I'd just check if it's undefined as separate case to avoid calling |
||
}); | ||
|
||
const canSeeSettings = computed(() => { | ||
|
@@ -63,6 +66,18 @@ const canSeeSettings = computed(() => { | |
|
||
return admins.includes(web3.value.account.toLowerCase()); | ||
} | ||
return false; | ||
}); | ||
|
||
const canSeeMembers = computed(() => { | ||
const data = space.value?.additionalRawData; | ||
|
||
return ( | ||
controller.value || | ||
(data?.admins?.length ?? 0) > 0 || | ||
(data?.moderators?.length ?? 0) > 0 || | ||
(data?.members?.length ?? 0) > 0 | ||
); | ||
Comment on lines
+72
to
+80
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This makes this section visible on Snapshot onchain spaces, original issue includes this:
Might be confusing though (Snapshot spaces = Snapshot offchain spaces, SX = Snapshot onchain spaces). |
||
}); | ||
|
||
const navigationConfig = computed< | ||
|
@@ -81,6 +96,14 @@ const navigationConfig = computed< | |
name: 'Leaderboard', | ||
icon: IHUserGroup | ||
}, | ||
...(canSeeMembers.value | ||
? { | ||
members: { | ||
name: 'Members', | ||
icon: IHIdentification | ||
} | ||
} | ||
: undefined), | ||
...(space.value?.delegations && space.value.delegations.length > 0 | ||
? { | ||
delegates: { | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -360,3 +360,18 @@ export const STRATEGY_QUERY = gql` | |||||
} | ||||||
${STRATEGY_FRAGMENT} | ||||||
`; | ||||||
|
||||||
export const STATEMENTS_AND_USERS_QUERY = gql` | ||||||
query ($where: StatementsWhere, $userIds: [String!]) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This way it's clearer when we execute query as to what |
||||||
statements(where: $where) { | ||||||
delegate | ||||||
space | ||||||
network | ||||||
statement | ||||||
} | ||||||
users(where: { id_in: $userIds }) { | ||||||
id | ||||||
about | ||||||
} | ||||||
} | ||||||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
<script setup lang="ts"> | ||
import removeMarkdown from 'remove-markdown'; | ||
import { getNames } from '@/helpers/stamp'; | ||
import { shorten } from '@/helpers/utils'; | ||
import { getNetwork } from '@/networks'; | ||
import { Space } from '@/types'; | ||
|
||
const props = defineProps<{ space: Space }>(); | ||
|
||
const { addNotification } = useUiStore(); | ||
const { setTitle } = useTitle(); | ||
|
||
const loaded = ref(false); | ||
const roles = ref<{ data: string[]; label: string }[]>([]); | ||
const names = ref<Record<string, string>>({}); | ||
const statements = ref<Record<string, string>>({}); | ||
const abouts = ref<Record<string, string>>({}); | ||
const network = computed(() => getNetwork(props.space.network)); | ||
|
||
const admins = props.space.additionalRawData?.admins || []; | ||
const moderators = props.space.additionalRawData?.moderators || []; | ||
const authors = props.space.additionalRawData?.members || []; | ||
|
||
async function loadMembersData() { | ||
try { | ||
const controller = await network.value.helpers | ||
.getSpaceController(props.space) | ||
.then(c => c.toLowerCase()); | ||
|
||
const allUsers = [controller, ...admins, ...moderators, ...authors].map(u => | ||
u.toLowerCase() | ||
); | ||
|
||
names.value = await getNames(allUsers); | ||
|
||
const { statements: userStatements, users } = | ||
await network.value.api.loadStatementsAndUsers( | ||
props.space.network, | ||
props.space.id, | ||
allUsers | ||
); | ||
|
||
statements.value = userStatements.reduce( | ||
(acc, statement) => { | ||
acc[statement.delegate.toLowerCase()] = statement.statement; | ||
return acc; | ||
}, | ||
{} as Record<string, string> | ||
); | ||
|
||
abouts.value = users.reduce( | ||
(acc, user) => { | ||
acc[user.id.toLowerCase()] = user.about || ''; | ||
return acc; | ||
}, | ||
{} as Record<string, string> | ||
); | ||
|
||
roles.value = [ | ||
{ data: [controller], label: 'Controller' }, | ||
{ data: admins, label: 'Admin(s)' }, | ||
{ data: moderators, label: 'Moderator(s)' }, | ||
{ data: authors, label: 'Authors(s)' } | ||
] as const; | ||
|
||
loaded.value = true; | ||
} catch (e) { | ||
addNotification('error', 'Failed to load members data.'); | ||
loaded.value = true; | ||
} | ||
} | ||
watchEffect(() => setTitle(`Members - ${props.space.name}`)); | ||
|
||
onMounted(loadMembersData); | ||
</script> | ||
|
||
<template> | ||
<div v-if="!loaded" class="px-4 py-4 block"> | ||
<UiLoading class="block" /> | ||
</div> | ||
<template v-for="role in roles" v-else :key="role.label"> | ||
<UiLabel v-if="role.data?.length" :label="role.label" /> | ||
<div class="text-left table-fixed w-full"> | ||
<div | ||
v-for="(user, i) in role.data" | ||
:key="`${role.label}-${i}`" | ||
class="border-b flex space-x-1" | ||
> | ||
<div | ||
class="flex items-center pl-4 py-3 gap-x-3 leading-[22px] min-w-[220px] truncate" | ||
> | ||
<UiStamp :id="user" :size="32" /> | ||
<AppLink | ||
:to="{ | ||
name: 'space-user-statement', | ||
params: { space: `${space.network}:${space.id}`, user: user } | ||
}" | ||
class="overflow-hidden" | ||
> | ||
<h4 | ||
class="text-skin-link truncate" | ||
v-text="names[user] || shorten(user)" | ||
/> | ||
<div | ||
class="text-[17px] text-skin-text truncate" | ||
v-text="shorten(user)" | ||
/> | ||
</AppLink> | ||
</div> | ||
<div | ||
class="hidden sm:flex items-center grow text-[17px] px-4 overflow-hidden leading-[22px] text-skin-text" | ||
> | ||
<span | ||
v-if="statements[user] || abouts[user]" | ||
class="line-clamp-2 max-h-[44px]" | ||
> | ||
{{ shorten(removeMarkdown(statements[user] || abouts[user]), 250) }} | ||
</span> | ||
</div> | ||
</div> | ||
</div> | ||
</template> | ||
</template> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
await
there does nothing.