Skip to content

Commit 29a107e

Browse files
authored
Merge branch 'master' into fix/duplicate-content
2 parents e501475 + 8ae8659 commit 29a107e

4 files changed

Lines changed: 38 additions & 2 deletions

File tree

apps/web/core/hooks/use-request-to-be-editor.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import { useCallback } from 'react';
77

88
import { Effect, Either } from 'effect';
99

10+
import { normalizeSpaceId } from '~/core/access/space-access';
1011
import { usePersonalSpaceId } from '~/core/hooks/use-personal-space-id';
1112
import { useSmartAccount } from '~/core/hooks/use-smart-account';
1213
import { useSmartAccountTransaction } from '~/core/hooks/use-smart-account-transaction';
14+
import { getIsEditorOfSpace } from '~/core/io/queries';
1315
import { useStatusBar } from '~/core/state/status-bar-store';
1416
import { runEffectEither } from '~/core/telemetry/effect-runtime';
1517
import { SPACE_REGISTRY_ADDRESS } from '~/core/utils/contracts/space-registry';
@@ -47,6 +49,17 @@ export function useRequestToBeEditor({ spaceId }: UseRequestToBeEditorArgs) {
4749
throw new Error('Invalid target space ID');
4850
}
4951

52+
// Existing editors already belong to the space; a duplicate editor request errors on vote.
53+
// Check at submit time rather than via reactive access-control state, which reads false
54+
// while still hydrating and would let a fast click through. Fail open if the check errors.
55+
const access = await runEffectEither(
56+
getIsEditorOfSpace(normalizeSpaceId(spaceId), normalizeSpaceId(personalSpaceId))
57+
);
58+
if (Either.isRight(access) && access.right) {
59+
dispatch({ type: 'ERROR', payload: 'You are already an editor of this space' });
60+
throw new Error('User is already an editor of the space');
61+
}
62+
5063
console.log('Requesting to be editor', {
5164
authorSpaceId: personalSpaceId,
5265
spaceId,

apps/web/core/hooks/use-request-to-be-member.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import { useCallback } from 'react';
77

88
import { Effect, Either } from 'effect';
99

10+
import { normalizeSpaceId } from '~/core/access/space-access';
1011
import { usePersonalSpaceId } from '~/core/hooks/use-personal-space-id';
1112
import { useSmartAccount } from '~/core/hooks/use-smart-account';
1213
import { useSmartAccountTransaction } from '~/core/hooks/use-smart-account-transaction';
14+
import { getIsEditorOfSpace, getIsMemberOfSpace } from '~/core/io/queries';
1315
import { useStatusBar } from '~/core/state/status-bar-store';
1416
import { runEffectEither } from '~/core/telemetry/effect-runtime';
1517
import { SPACE_REGISTRY_ADDRESS } from '~/core/utils/contracts/space-registry';
@@ -47,6 +49,22 @@ export function useRequestToBeMember({ spaceId }: UseRequestToBeMemberArgs) {
4749
throw new Error('Invalid target space ID');
4850
}
4951

52+
// Members/editors already belong to the space; a duplicate join request errors on vote.
53+
// Check at submit time rather than via reactive access-control state, which reads false
54+
// while still hydrating and would let a fast click through. Fail open if the check errors.
55+
const normalizedSpaceId = normalizeSpaceId(spaceId);
56+
const normalizedPersonalSpaceId = normalizeSpaceId(personalSpaceId);
57+
const access = await runEffectEither(
58+
Effect.all([
59+
getIsMemberOfSpace(normalizedSpaceId, normalizedPersonalSpaceId),
60+
getIsEditorOfSpace(normalizedSpaceId, normalizedPersonalSpaceId),
61+
])
62+
);
63+
if (Either.isRight(access) && (access.right[0] || access.right[1])) {
64+
dispatch({ type: 'ERROR', payload: 'You are already a member of this space' });
65+
throw new Error('User is already a member or editor of the space');
66+
}
67+
5068
console.log('Requesting to be member', {
5169
authorSpaceId: personalSpaceId,
5270
spaceId,

apps/web/partials/space-page/space-members-popover-content.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ interface Props {
1818
spaceId: string;
1919
isPublicSpace: boolean;
2020
isMember: boolean;
21+
isEditor: boolean;
2122
hasRequestedSpaceMembership: boolean;
2223
connectedAddress: string | null;
2324
}
@@ -26,6 +27,7 @@ export function SpaceMembersContent({
2627
spaceId,
2728
isPublicSpace,
2829
isMember,
30+
isEditor,
2931
hasRequestedSpaceMembership,
3032
connectedAddress,
3133
}: Props) {
@@ -59,7 +61,7 @@ export function SpaceMembersContent({
5961
<button className="text-smallButton text-grey-04 transition-colors duration-75 hover:text-text">
6062
{connectedAddress ? 'Leave space' : 'Sign in to join'}
6163
</button>
62-
) : connectedAddress ? (
64+
) : isEditor ? null : connectedAddress ? (
6365
<SpaceMembersPopoverMemberRequestButton
6466
spaceId={spaceId}
6567
hasRequestedSpaceMembership={hasRequestedSpaceMembership}

apps/web/partials/space-page/space-members.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,15 @@ export async function SpaceMembers({ spaceId }: Props) {
4646
spaceId={spaceId}
4747
isPublicSpace={isPublicSpace}
4848
isMember={isMember}
49+
isEditor={isEditor}
4950
hasRequestedSpaceMembership={hasRequestedSpaceMembership}
5051
connectedAddress={connectedAddress ?? null}
5152
/>
5253
);
5354

54-
if (isMember) {
55+
// Editors aren't always in the members list, but they already belong to the space — treat
56+
// them as joined so they don't see (and can't fire) a duplicate membership request.
57+
if (isMember || isEditor) {
5558
return (
5659
<div className="flex h-6 items-center gap-1.5 rounded border border-grey-02 pr-2 pl-1.5 text-metadata shadow-button transition-colors duration-150 focus-within:border-text">
5760
<SpaceMembersPopover trigger={<SpaceMembersChip spaceId={spaceId} />} content={popoverContent} />

0 commit comments

Comments
 (0)