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], + ) +}