Skip to content

Commit

Permalink
feat: add pending state to banner button
Browse files Browse the repository at this point in the history
  • Loading branch information
drewlyton committed Sep 29, 2024
1 parent d9e356f commit 56c7578
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './RequestPermissionDialog'
export * from './useRoleRequestsStatus'
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import {addWeeks, isAfter, isBefore} from 'date-fns'
import {useEffect, useState} from 'react'
import {from, of} from 'rxjs'
import {catchError, map} from 'rxjs/operators'
import {useClient, useProjectId} from 'sanity'

import {type AccessRequest} from '../../../core/studio/screens'

export const useRoleRequestsStatus = () => {
const client = useClient()
const projectId = useProjectId()
const [status, setStatus] = useState<string>()

useEffect(() => {
const checkRoleRequests$ = () => {
if (!client || !projectId) {
return of()
}

return from(
client.request<AccessRequest[] | null>({
url: `/access/requests/me`,
}),
).pipe(
map((requests) => {
if (requests && requests.length) {
// Filter requests for the specific project and where type is 'role'
const projectRequests = requests.filter(
(request) => request.resourceId === projectId && request.type === 'role',
)

const declinedRequest = projectRequests.find((request) => request.status === 'declined')
if (declinedRequest) {
return 'denied'
}

const pendingRequest = projectRequests.find(
(request) =>
request.status === 'pending' &&
isAfter(addWeeks(new Date(request.createdAt), 2), new Date()),
)
if (pendingRequest) {
return 'pending'
}

const oldPendingRequest = projectRequests.find(
(request) =>
request.status === 'pending' &&
isBefore(addWeeks(new Date(request.createdAt), 2), new Date()),
)
if (oldPendingRequest) {
return 'expired'
}
}
return 'none' // No relevant requests found
}),
catchError((error) => {
console.error(error)
return of('error') // Return 'error' status on request failure
}),
)
}

const subscription = checkRoleRequests$().subscribe({
next: (value) => setStatus(value),
error: (err) => console.error(err),
})

return () => {
subscription.unsubscribe() // Cleanup on component unmount
}
}, [client, projectId])

return status
}
2 changes: 2 additions & 0 deletions packages/sanity/src/structure/i18n/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ const structureLocaleStrings = defineLocalesResources('structure', {
/** The text for the permission check banner if the user only has multiple roles, but they do not allow updating this document */
'banners.permission-check-banner.missing-permission_update_other':
'Your roles <Roles/> do not have permissions to edit this document.',
/** The pending text for the request permission button that appears for viewer roles */
'banners.permission-check-banner.request-permission-button.sent': 'Request sent',
/** The text for the request permission button that appears for viewer roles */
'banners.permission-check-banner.request-permission-button.text': 'Ask to edit',
/** The text for the reload button */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ interface BannerProps {
onClick?: () => void
text: string
tone?: ButtonTone
disabled?: boolean
}
content: ReactNode
icon?: ComponentType
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import {Text} from '@sanity/ui'
import {useState} from 'react'
import {Translate, useCurrentUser, useListFormat, useTranslation} from 'sanity'

import {RequestPermissionDialog} from '../../../../components/requestPermissionDialog/RequestPermissionDialog'
import {
RequestPermissionDialog,
useRoleRequestsStatus,
} from '../../../../components/requestPermissionDialog'
import {structureLocaleNamespace} from '../../../../i18n'
import {Banner} from './Banner'

Expand All @@ -15,6 +18,7 @@ interface PermissionCheckBannerProps {
export function PermissionCheckBanner({granted, requiredPermission}: PermissionCheckBannerProps) {
const currentUser = useCurrentUser()

const roleRequestStatus = useRoleRequestsStatus()
const currentUserRoles = currentUser?.roles || []
const isOnlyViewer = currentUserRoles.length === 1 && currentUserRoles[0].name === 'viewer'
const [showRequestPermissionDialog, setShowRequestPermissionDialog] = useState(false)
Expand Down Expand Up @@ -47,11 +51,18 @@ export function PermissionCheckBanner({granted, requiredPermission}: PermissionC
}
center
action={
isOnlyViewer
isOnlyViewer && roleRequestStatus
? {
onClick: () => setShowRequestPermissionDialog(true),
text: t('banners.permission-check-banner.request-permission-button.text'),
tone: 'primary',
onClick:
roleRequestStatus === 'none'
? () => setShowRequestPermissionDialog(true)
: undefined,
text:
roleRequestStatus === 'none'
? t('banners.permission-check-banner.request-permission-button.text')
: t('banners.permission-check-banner.request-permission-button.sent'),
tone: roleRequestStatus === 'none' ? 'primary' : 'default',
disabled: roleRequestStatus !== 'none',
// mode: 'bleed',
}
: undefined
Expand Down

0 comments on commit 56c7578

Please sign in to comment.