Skip to content

Commit

Permalink
feat(sanity): supporting editing bundle metadata (#7180)
Browse files Browse the repository at this point in the history
* feat: supporting editing bundle metadata

* test(sanity): updating tests for Bundle form

* fix(releases): fixing issue with mocked imports on ReleasesOverview

* refactor(core): bundle detail dialog form computes action from initial value rather than passing as a prop

* refactor(core): bundle detail dialog form computes action from initial value rather than passing as a prop

* refactor(core): only passing diff when editing bundle details
  • Loading branch information
jordanl17 authored and bjoerge committed Jul 30, 2024
1 parent 3f8ff0f commit a1db92d
Show file tree
Hide file tree
Showing 12 changed files with 486 additions and 260 deletions.
3 changes: 2 additions & 1 deletion packages/sanity/src/core/bundles/components/BundleBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export function BundleBadge(
<Flex
gap={padding}
padding={padding}
data-testid={`bundle-badge-color-${hue}`}
style={
{
'--card-bg-color': rgba(hues[hue][color._dark ? 700 : 300].hex, 0.2),
Expand All @@ -40,7 +41,7 @@ export function BundleBadge(
{icon && (
<Box flex="none">
<Text size={1}>
<Icon symbol={icon} />
<Icon data-testid={`bundle-badge-icon-${icon.toString()}`} symbol={icon} />
</Text>
</Box>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import {ArrowRightIcon} from '@sanity/icons'
import {Box, Button, Dialog, Flex} from '@sanity/ui'
import {type FormEvent, useCallback, useState} from 'react'

import {type BundleDocument} from '../../../store/bundles/types'
import {useBundleOperations} from '../../../store/bundles/useBundleOperations'
import {usePerspective} from '../../hooks/usePerspective'
import {BundleForm} from './BundleForm'

interface BundleDetailsDialogProps {
onCancel: () => void
onSubmit: () => void
bundle?: BundleDocument
}

export function BundleDetailsDialog(props: BundleDetailsDialogProps): JSX.Element {
const {onCancel, onSubmit, bundle} = props
const {createBundle, updateBundle} = useBundleOperations()
const [hasErrors, setHasErrors] = useState(false)
const formAction = bundle ? 'edit' : 'create'

const [value, setValue] = useState<Partial<BundleDocument>>(() => {
if (bundle) {
return {
slug: bundle.slug,
title: bundle.title,
description: bundle.description,
hue: bundle.hue,
icon: bundle.icon,
}
}

return {
slug: '',
title: '',
hue: 'gray',
icon: 'cube',
//publishAt: undefined,
}
})
const [isSubmitting, setIsSubmitting] = useState(false)

// TODO MAKE SURE THIS IS HOW WE WANT TO DO THIS
const {setPerspective} = usePerspective()

const bundleOperation = useCallback(
(formValue: Partial<BundleDocument>) => {
if (formAction === 'edit' && bundle?._id) {
const updatedBundle: Partial<BundleDocument> = {
...formValue,
_id: bundle._id,
}

return updateBundle(updatedBundle)
}
return createBundle(formValue)
},
[bundle?._id, createBundle, formAction, updateBundle],
)

const handleOnSubmit = useCallback(
async (event: FormEvent<HTMLFormElement>) => {
if (value.slug) {
try {
event.preventDefault()
setIsSubmitting(true)
await bundleOperation(value)
setValue(value)
} catch (err) {
console.error(err)
} finally {
setIsSubmitting(false)
if (formAction === 'create') {
setPerspective(value.slug)
}
onSubmit()
}
}
},
[bundleOperation, formAction, onSubmit, setPerspective, value],
)

const handleOnChange = useCallback((changedValue: Partial<BundleDocument>) => {
setValue(changedValue)
}, [])

const handleOnError = useCallback((errorsExist: boolean) => {
setHasErrors(errorsExist)
}, [])

const dialogTitle = formAction === 'edit' ? 'Edit release' : 'Create release'

return (
<Dialog
animate
header={dialogTitle}
id="create-bundle-dialog"
onClose={onCancel}
zOffset={5000}
width={1}
>
<form onSubmit={handleOnSubmit}>
<Box padding={6}>
<BundleForm onChange={handleOnChange} onError={handleOnError} value={value} />
</Box>
<Flex justify="flex-end" padding={3}>
<Button
disabled={!value.title || isSubmitting || hasErrors}
iconRight={ArrowRightIcon}
type="submit"
// localize Text
text={dialogTitle}
loading={isSubmitting}
data-testid="submit-release-button"
/>
</Flex>
</form>
</Dialog>
)
}
25 changes: 21 additions & 4 deletions packages/sanity/src/core/bundles/components/dialog/BundleForm.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable i18next/no-literal-string */
//import {CalendarIcon} from '@sanity/icons'
import {Flex, Stack, Text, TextArea, TextInput} from '@sanity/ui'
import {useCallback, useMemo, useState} from 'react'
import {useCallback, useMemo, useRef, useState} from 'react'
import {
FormFieldHeaderText,
type FormNodeValidation,
Expand All @@ -24,6 +24,10 @@ export function BundleForm(props: {
}): JSX.Element {
const {onChange, onError, value} = props
const {title, description, icon, hue /*, publishAt*/} = value
// derive the action from whether the initial value prop has a slug
// only editing existing bundles will provide a value.slug
const {current: action} = useRef(value.slug ? 'edit' : 'create')
const isEditing = action === 'edit'

//const dateFormatter = useDateTimeFormat()

Expand Down Expand Up @@ -52,11 +56,24 @@ export function BundleForm(props: {
[icon, hue],
)

const generateSlugFromTitle = useCallback(
(pickedTitle: string) => {
if (isEditing && value.slug) {
const slug = value.slug
return {slug, slugExists: false}
}
const newSlug = speakingurl(pickedTitle)
const slugExists = Boolean(data && data.find((bundle) => bundle.slug === newSlug))

return {slug: newSlug, slugExists}
},
[isEditing, value, data],
)

const handleBundleTitleChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
const pickedTitle = event.target.value
const newSlug = speakingurl(pickedTitle)
const slugExists = data && data.find((bundle) => bundle.slug === newSlug)
const {slug: newSlug, slugExists} = generateSlugFromTitle(pickedTitle)
const isEmptyTitle = pickedTitle.trim() === '' && !isInitialRender

if (isDraftOrPublished(pickedTitle) || slugExists || (isEmptyTitle && !isInitialRender)) {
Expand Down Expand Up @@ -88,7 +105,7 @@ export function BundleForm(props: {
setIsInitialRender(false)
onChange({...value, title: pickedTitle, slug: newSlug})
},
[data, isInitialRender, onChange, onError, value],
[generateSlugFromTitle, isInitialRender, onChange, onError, value],
)

const handleBundleDescriptionChange = useCallback(
Expand Down

This file was deleted.

Loading

0 comments on commit a1db92d

Please sign in to comment.