diff --git a/packages/sanity/src/core/releases/tool/overview/ReleaseCalendarFilter.tsx b/packages/sanity/src/core/releases/tool/overview/ReleaseCalendarFilter.tsx
new file mode 100644
index 00000000000..651629dc7d9
--- /dev/null
+++ b/packages/sanity/src/core/releases/tool/overview/ReleaseCalendarFilter.tsx
@@ -0,0 +1,76 @@
+import {CloseIcon} from '@sanity/icons'
+import {format} from 'date-fns'
+import {AnimatePresence, motion} from 'framer-motion'
+import {useMemo, useState} from 'react'
+
+import {Button} from '../../../../ui-components'
+import {CalendarDay} from '../../../../ui-components/inputs/DateFilters/calendar/CalendarDay'
+import {type CalendarProps} from '../../../../ui-components/inputs/DateFilters/calendar/CalendarFilter'
+import {useReleases} from '../../store/useReleases'
+import {useTimezoneAdjustedDateTimeRange} from './useTimezoneAdjustedDateTimeRange'
+
+export const ReleaseCalendarFilterDay: CalendarProps['renderCalendarDay'] = (props) => {
+ const {data: releases} = useReleases()
+ const getTimezoneAdjustedDateTimeRange = useTimezoneAdjustedDateTimeRange()
+
+ const {date} = props
+
+ const [startOfDayForTimeZone, endOfDayForTimeZone] = getTimezoneAdjustedDateTimeRange(date)
+
+ const dayHasReleases = releases?.some((release) => {
+ const releasePublishAt = release.publishAt || release.metadata.intendedPublishAt
+ if (!releasePublishAt) return false
+
+ const publishDateUTC = new Date(releasePublishAt)
+
+ return (
+ release.metadata.releaseType === 'scheduled' &&
+ publishDateUTC >= startOfDayForTimeZone &&
+ publishDateUTC <= endOfDayForTimeZone
+ )
+ })
+
+ return
+}
+
+const MotionButton = motion(Button)
+
+export const DateFilterButton = ({
+ filterDate,
+ onClear,
+}: {
+ filterDate: Date
+ onClear: () => void
+}) => {
+ const [isExiting, setIsExiting] = useState(false)
+
+ const handleOnExitComplete = useMemo(
+ () => () => {
+ setIsExiting(false)
+ onClear()
+ },
+ [onClear],
+ )
+
+ if (!filterDate) return null
+
+ return (
+
+ {!isExiting && (
+ setIsExiting(true)}
+ padding={2}
+ selected
+ text={format(filterDate, 'PPP')}
+ />
+ )}
+
+ )
+}
diff --git a/packages/sanity/src/core/releases/tool/overview/ReleasesOverview.tsx b/packages/sanity/src/core/releases/tool/overview/ReleasesOverview.tsx
index f751e126c03..017de253144 100644
--- a/packages/sanity/src/core/releases/tool/overview/ReleasesOverview.tsx
+++ b/packages/sanity/src/core/releases/tool/overview/ReleasesOverview.tsx
@@ -1,16 +1,13 @@
-import {AddIcon, ChevronDownIcon, CloseIcon, EarthGlobeIcon} from '@sanity/icons'
-import {Box, type ButtonMode, Card, Container, Flex, Stack, Text} from '@sanity/ui'
-import {endOfDay, format, isSameDay, startOfDay} from 'date-fns'
+import {AddIcon, ChevronDownIcon, EarthGlobeIcon} from '@sanity/icons'
+// eslint-disable-next-line no-restricted-imports
+import {Box, Button, type ButtonMode, Card, Container, Flex, Stack, Text} from '@sanity/ui'
+import {format, isSameDay} from 'date-fns'
import {AnimatePresence, motion} from 'framer-motion'
import {type MouseEventHandler, useCallback, useEffect, useMemo, useRef, useState} from 'react'
-import {type RouterContextValue, type SearchParam, useRouter} from 'sanity/router'
+import {type SearchParam, useRouter} from 'sanity/router'
-import {Button, Button as StudioButton} from '../../../../ui-components'
-import {CalendarDay} from '../../../../ui-components/inputs/DateFilters/calendar/CalendarDay'
-import {
- CalendarFilter,
- type CalendarProps,
-} from '../../../../ui-components/inputs/DateFilters/calendar/CalendarFilter'
+import {Button as StudioButton, Tooltip} from '../../../../ui-components'
+import {CalendarFilter} from '../../../../ui-components/inputs/DateFilters/calendar/CalendarFilter'
import {useTranslation} from '../../../i18n'
import useDialogTimeZone from '../../../scheduledPublishing/hooks/useDialogTimeZone'
import useTimeZone from '../../../scheduledPublishing/hooks/useTimeZone'
@@ -24,107 +21,29 @@ import {getReleaseTone} from '../../util/getReleaseTone'
import {ReleaseMenuButton} from '../components/ReleaseMenuButton/ReleaseMenuButton'
import {Table, type TableRowProps} from '../components/Table/Table'
import {type TableSort} from '../components/Table/TableProvider'
+import {
+ DATE_SEARCH_PARAM_KEY,
+ getInitialFilterDate,
+ getInitialReleaseGroupMode,
+ GROUP_SEARCH_PARAM_KEY,
+ type Mode,
+} from './queryParamUtils'
+import {DateFilterButton, ReleaseCalendarFilterDay} from './ReleaseCalendarFilter'
import {releasesOverviewColumnDefs} from './ReleasesOverviewColumnDefs'
+import {useTimezoneAdjustedDateTimeRange} from './useTimezoneAdjustedDateTimeRange'
-type Mode = 'open' | 'archived'
-
-const MotionButton = motion(Button)
const MotionStudioButton = motion(StudioButton)
+const MotionUiButton = motion(Button)
-const DateFilterButton = ({filterDate, onClear}: {filterDate: Date; onClear: () => void}) => {
- const [isExiting, setIsExiting] = useState(false)
-
- const handleOnExitComplete = useMemo(
- () => () => {
- setIsExiting(false)
- onClear()
- },
- [onClear],
- )
-
- if (!filterDate) return null
-
- return (
-
- {!isExiting && (
- setIsExiting(true)}
- padding={2}
- selected
- text={format(filterDate, 'PPP')}
- />
- )}
-
- )
-}
-
-const DATE_SEARCH_PARAM_KEY = 'date'
const DATE_SEARCH_PARAM_VALUE_FORMAT = 'yyyy-MM-dd'
-const GROUP_SEARCH_PARAM_KEY = 'group'
export interface TableRelease extends ReleaseDocument {
documentsMetadata?: ReleasesMetadata
isDeleted?: boolean
}
-const useTimezoneAdjustedDateTimeRange = () => {
- const {zoneDateToUtc} = useTimeZone()
-
- return useCallback(
- (date: Date) => [startOfDay(date), endOfDay(date)].map(zoneDateToUtc),
- [zoneDateToUtc],
- )
-}
-
-const ReleaseCalendarDay: CalendarProps['renderCalendarDay'] = (props) => {
- const {data: releases} = useReleases()
- const getTimezoneAdjustedDateTimeRange = useTimezoneAdjustedDateTimeRange()
-
- const {date} = props
-
- const [startOfDayForTimeZone, endOfDayForTimeZone] = getTimezoneAdjustedDateTimeRange(date)
-
- const dayHasReleases = releases?.some((release) => {
- const releasePublishAt = release.publishAt || release.metadata.intendedPublishAt
- if (!releasePublishAt) return false
-
- const publishDateUTC = new Date(releasePublishAt)
-
- return (
- release.metadata.releaseType === 'scheduled' &&
- publishDateUTC >= startOfDayForTimeZone &&
- publishDateUTC <= endOfDayForTimeZone
- )
- })
-
- return
-}
-
const DEFAULT_RELEASES_OVERVIEW_SORT: TableSort = {column: 'publishAt', direction: 'asc'}
-const getInitialFilterDate = (router: RouterContextValue) => () => {
- const activeFilterDate = new URLSearchParams(router.state._searchParams).get(
- DATE_SEARCH_PARAM_KEY,
- )
-
- return activeFilterDate ? new Date(activeFilterDate) : undefined
-}
-
-const getInitialReleaseGroupMode = (router: RouterContextValue) => () => {
- const activeGroupMode = new URLSearchParams(router.state._searchParams).get(
- GROUP_SEARCH_PARAM_KEY,
- )
-
- return activeGroupMode === 'archived' ? 'archived' : 'open'
-}
-
export function ReleasesOverview() {
const {data: releases, archivedReleases, loading: loadingReleases} = useReleases()
const router = useRouter()
@@ -241,7 +160,7 @@ export function ReleasesOverview() {
}
return (
-
- {/* StudioButton supports tooltip when button is disabled */}
-
+
+
+
+
+
)
}, [
@@ -343,7 +264,7 @@ export function ReleasesOverview() {
diff --git a/packages/sanity/src/core/releases/tool/overview/queryParamUtils.ts b/packages/sanity/src/core/releases/tool/overview/queryParamUtils.ts
new file mode 100644
index 00000000000..75145249a08
--- /dev/null
+++ b/packages/sanity/src/core/releases/tool/overview/queryParamUtils.ts
@@ -0,0 +1,22 @@
+import {type RouterContextValue} from 'sanity/router'
+
+export type Mode = 'open' | 'archived'
+
+export const DATE_SEARCH_PARAM_KEY = 'date'
+export const GROUP_SEARCH_PARAM_KEY = 'group'
+
+export const getInitialFilterDate = (router: RouterContextValue) => () => {
+ const activeFilterDate = new URLSearchParams(router.state._searchParams).get(
+ DATE_SEARCH_PARAM_KEY,
+ )
+
+ return activeFilterDate ? new Date(activeFilterDate) : undefined
+}
+
+export const getInitialReleaseGroupMode = (router: RouterContextValue) => (): Mode => {
+ const activeGroupMode = new URLSearchParams(router.state._searchParams).get(
+ GROUP_SEARCH_PARAM_KEY,
+ )
+
+ return activeGroupMode === 'archived' ? 'archived' : 'open'
+}
diff --git a/packages/sanity/src/core/releases/tool/overview/useTimezoneAdjustedDateTimeRange.ts b/packages/sanity/src/core/releases/tool/overview/useTimezoneAdjustedDateTimeRange.ts
new file mode 100644
index 00000000000..3cace08c147
--- /dev/null
+++ b/packages/sanity/src/core/releases/tool/overview/useTimezoneAdjustedDateTimeRange.ts
@@ -0,0 +1,13 @@
+import {endOfDay, startOfDay} from 'date-fns'
+import {useCallback} from 'react'
+
+import useTimeZone from '../../../scheduledPublishing/hooks/useTimeZone'
+
+export const useTimezoneAdjustedDateTimeRange = () => {
+ const {zoneDateToUtc} = useTimeZone()
+
+ return useCallback(
+ (date: Date) => [startOfDay(date), endOfDay(date)].map(zoneDateToUtc),
+ [zoneDateToUtc],
+ )
+}