-
Notifications
You must be signed in to change notification settings - Fork 427
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(corel): integrate bundles store (#7040)
* feat(corel): add bundles store
- Loading branch information
1 parent
8ee5853
commit 0b9b5e6
Showing
8 changed files
with
578 additions
and
0 deletions.
There are no files selected for viewing
110 changes: 110 additions & 0 deletions
110
packages/sanity/src/core/store/bundles/__workshop__/BundlesStoreStory.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import {Card, Flex, Stack, Text} from '@sanity/ui' | ||
import {type ComponentType, type FormEvent, useCallback, useState} from 'react' | ||
|
||
import {Button} from '../../../../ui-components' | ||
import {LoadingBlock} from '../../../components/loadingBlock/LoadingBlock' | ||
import {AddonDatasetProvider} from '../../../studio/addonDataset/AddonDatasetProvider' | ||
import {type BundleDocument} from '../types' | ||
import {useBundleOperations} from '../useBundleOperations' | ||
import {useBundlesStore} from '../useBundlesStore' | ||
import {ReleaseForm} from './ReleaseForm' | ||
|
||
const WithAddonDatasetProvider = <P extends object>(Component: ComponentType<P>): React.FC<P> => { | ||
const WrappedComponent: React.FC<P> = (props) => ( | ||
<AddonDatasetProvider> | ||
<Component {...props} /> | ||
</AddonDatasetProvider> | ||
) | ||
WrappedComponent.displayName = `WithAddonDatasetProvider(${Component.displayName || Component.name || 'Component'})` | ||
|
||
return WrappedComponent | ||
} | ||
|
||
const initialValue = {name: '', title: '', tone: undefined, publishAt: undefined} | ||
const BundlesStoreStory = () => { | ||
const {data, loading} = useBundlesStore() | ||
const {createBundle, deleteBundle} = useBundleOperations() | ||
const [creating, setCreating] = useState(false) | ||
const [deleting, setDeleting] = useState<string | null>(null) | ||
const [value, setValue] = useState<Partial<BundleDocument>>(initialValue) | ||
const handleCreateBundle = useCallback( | ||
async (event: FormEvent<HTMLFormElement>) => { | ||
try { | ||
event.preventDefault() | ||
setCreating(true) | ||
await createBundle(value) | ||
setValue(initialValue) | ||
} catch (err) { | ||
console.error(err) | ||
} finally { | ||
setCreating(false) | ||
} | ||
}, | ||
[createBundle, value], | ||
) | ||
|
||
const handleDeleteBundle = useCallback( | ||
async (id: string) => { | ||
try { | ||
setDeleting(id) | ||
await deleteBundle(id) | ||
} catch (err) { | ||
console.error(err) | ||
} finally { | ||
setDeleting(null) | ||
} | ||
}, | ||
[deleteBundle], | ||
) | ||
|
||
return ( | ||
<Stack space={3}> | ||
<Flex gap={2}> | ||
<Card margin={3} padding={3} border> | ||
<form onSubmit={handleCreateBundle}> | ||
<Stack space={4}> | ||
<Text weight="medium">Create a new release</Text> | ||
<ReleaseForm onChange={setValue} value={value} /> | ||
<Flex justify="flex-end"> | ||
<Button | ||
text="Create" | ||
tone="primary" | ||
type="submit" | ||
disabled={creating} | ||
loading={creating} | ||
/> | ||
</Flex> | ||
</Stack> | ||
</form> | ||
</Card> | ||
<Card margin={3} border padding={3}> | ||
<div style={{maxHeight: '400px', overflow: 'scroll'}}> | ||
<Text>Data</Text> | ||
{loading ? <LoadingBlock /> : <pre>{JSON.stringify(data, null, 2)}</pre>} | ||
</div> | ||
</Card> | ||
</Flex> | ||
<Card margin={3} border padding={3}> | ||
<Stack space={3}> | ||
{data?.map((bundle) => ( | ||
<Card key={bundle._id} padding={3} border radius={3}> | ||
<Flex align="center" gap={3} justify={'space-between'}> | ||
<Text>{bundle.name}</Text> | ||
<Button | ||
text="Delete" | ||
tone="critical" | ||
// eslint-disable-next-line react/jsx-no-bind | ||
onClick={() => handleDeleteBundle(bundle._id)} | ||
disabled={deleting === bundle._id} | ||
loading={deleting === bundle._id} | ||
/> | ||
</Flex> | ||
</Card> | ||
))} | ||
</Stack> | ||
</Card> | ||
</Stack> | ||
) | ||
} | ||
|
||
export default WithAddonDatasetProvider(BundlesStoreStory) |
133 changes: 133 additions & 0 deletions
133
packages/sanity/src/core/store/bundles/__workshop__/ReleaseForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import {COLOR_HUES} from '@sanity/color' | ||
import {CalendarIcon} from '@sanity/icons' | ||
import { | ||
Box, | ||
type ButtonTone, | ||
Card, | ||
Flex, | ||
Select, | ||
Stack, | ||
Text, | ||
TextArea, | ||
TextInput, | ||
} from '@sanity/ui' | ||
import speakingurl from 'speakingurl' | ||
|
||
import {Button} from '../../../../ui-components/button' | ||
import {type BundleDocument} from '../types' | ||
|
||
function toSlug(value: string): string { | ||
return speakingurl(value, {truncate: 200, symbols: true}) | ||
} | ||
|
||
/** | ||
* Copy from Prototype, not a final or complete working implementation. | ||
*/ | ||
export function ReleaseForm(props: { | ||
onChange: (params: Partial<BundleDocument>) => void | ||
value: Partial<BundleDocument> | ||
}) { | ||
const {onChange, value} = props | ||
|
||
const handleReleaseTitleChange = (event: React.ChangeEvent<HTMLInputElement>) => { | ||
const v = event.target.value | ||
|
||
onChange({...value, title: v, name: toSlug(v)}) | ||
} | ||
|
||
const handleReleaseDescriptionChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => { | ||
const v = event.target.value | ||
|
||
onChange({...value, description: v || undefined}) | ||
} | ||
|
||
const handleReleaseToneChange = (event: React.ChangeEvent<HTMLSelectElement>) => { | ||
onChange({...value, tone: (event.target.value || undefined) as ButtonTone | undefined}) | ||
} | ||
|
||
const handleReleasePublishAtChange = (event: React.ChangeEvent<HTMLInputElement>) => { | ||
const v = event.target.value | ||
|
||
onChange({...value, publishAt: v}) | ||
} | ||
|
||
return ( | ||
<Stack space={5}> | ||
<Stack space={3}> | ||
<Text size={1} weight="medium"> | ||
Title | ||
</Text> | ||
<TextInput fontSize={3} onChange={handleReleaseTitleChange} value={value.title} /> | ||
</Stack> | ||
|
||
<Stack space={3}> | ||
<Text size={1} weight="medium"> | ||
Description | ||
</Text> | ||
<TextArea onChange={handleReleaseDescriptionChange} value={value.description} /> | ||
</Stack> | ||
|
||
<Stack hidden space={3}> | ||
<Text size={1} weight="medium"> | ||
Schedule for publishing at | ||
</Text> | ||
<TextInput | ||
onChange={handleReleasePublishAtChange} | ||
suffix={ | ||
<Box padding={1} style={{border: '1px solid transparent'}}> | ||
<Button icon={CalendarIcon} mode="bleed" /> | ||
</Box> | ||
} | ||
value={value.publishAt || ''} | ||
/> | ||
</Stack> | ||
|
||
<Stack space={3}> | ||
<Text size={1} weight="medium"> | ||
Color | ||
</Text> | ||
<Flex> | ||
<Card | ||
borderTop | ||
borderLeft | ||
borderBottom | ||
flex="none" | ||
radius={2} | ||
padding={2} | ||
style={{ | ||
borderTopRightRadius: 0, | ||
borderBottomRightRadius: 0, | ||
}} | ||
> | ||
<div | ||
style={{ | ||
borderRadius: 1, | ||
width: 17, | ||
height: 17, | ||
backgroundColor: `var(--card-avatar-${value.tone || 'gray'}-bg-color)`, | ||
}} | ||
> | ||
| ||
</div> | ||
</Card> | ||
<Stack flex={1}> | ||
<Select | ||
onChange={handleReleaseToneChange} | ||
style={{ | ||
borderTopLeftRadius: 0, | ||
borderBottomLeftRadius: 0, | ||
}} | ||
value={value.tone || ''} | ||
> | ||
{COLOR_HUES.map((hue) => ( | ||
<option key={hue} value={hue === 'gray' ? '' : hue}> | ||
{hue} | ||
</option> | ||
))} | ||
</Select> | ||
</Stack> | ||
</Flex> | ||
</Stack> | ||
</Stack> | ||
) | ||
} |
14 changes: 14 additions & 0 deletions
14
packages/sanity/src/core/store/bundles/__workshop__/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import {defineScope} from '@sanity/ui-workshop' | ||
import {lazy} from 'react' | ||
|
||
export default defineScope({ | ||
name: 'core/bundles', | ||
title: 'bundles', | ||
stories: [ | ||
{ | ||
name: 'bundles-store', | ||
title: 'BundlesStore', | ||
component: lazy(() => import('./BundlesStoreStory')), | ||
}, | ||
], | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './useBundlesStore' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import {type BundleDocument} from './types' | ||
|
||
interface BundleAddedAction { | ||
payload: BundleDocument | ||
type: 'BUNDLE_ADDED' | ||
} | ||
|
||
interface BundleDeletedAction { | ||
id: string | ||
type: 'BUNDLE_DELETED' | ||
} | ||
|
||
interface BundleUpdatedAction { | ||
payload: BundleDocument | ||
type: 'BUNDLE_UPDATED' | ||
} | ||
|
||
interface BundlesSetAction { | ||
payload: BundleDocument[] | ||
type: 'BUNDLES_SET' | ||
} | ||
|
||
interface BundleReceivedAction { | ||
payload: BundleDocument | ||
type: 'BUNDLE_RECEIVED' | ||
} | ||
|
||
export type bundlesReducerAction = | ||
| BundleAddedAction | ||
| BundleDeletedAction | ||
| BundleUpdatedAction | ||
| BundlesSetAction | ||
| BundleReceivedAction | ||
|
||
export interface bundlesReducerState { | ||
bundles: Map<string, BundleDocument> | ||
} | ||
|
||
function createBundlesSet(bundles: BundleDocument[]) { | ||
const bundlesById = bundles.reduce((acc, bundle) => { | ||
acc.set(bundle._id, bundle) | ||
return acc | ||
}, new Map<string, BundleDocument>()) | ||
return bundlesById | ||
} | ||
|
||
export function bundlesReducer( | ||
state: bundlesReducerState, | ||
action: bundlesReducerAction, | ||
): bundlesReducerState { | ||
switch (action.type) { | ||
case 'BUNDLES_SET': { | ||
// Create an object with the BUNDLE id as key | ||
const bundlesById = createBundlesSet(action.payload) | ||
|
||
return { | ||
...state, | ||
bundles: bundlesById, | ||
} | ||
} | ||
|
||
case 'BUNDLE_ADDED': { | ||
const addedBundle = action.payload as BundleDocument | ||
const currentBundles = new Map(state.bundles) | ||
currentBundles.set(addedBundle._id, addedBundle) | ||
|
||
return { | ||
...state, | ||
bundles: currentBundles, | ||
} | ||
} | ||
|
||
case 'BUNDLE_RECEIVED': { | ||
const receivedBundle = action.payload as BundleDocument | ||
const currentBundles = new Map(state.bundles) | ||
currentBundles.set(receivedBundle._id, receivedBundle) | ||
|
||
return { | ||
...state, | ||
bundles: currentBundles, | ||
} | ||
} | ||
|
||
case 'BUNDLE_DELETED': { | ||
const currentBundles = new Map(state.bundles) | ||
currentBundles.delete(action.id) | ||
|
||
return { | ||
...state, | ||
bundles: currentBundles, | ||
} | ||
} | ||
|
||
case 'BUNDLE_UPDATED': { | ||
const updatedBundle = action.payload | ||
const id = updatedBundle._id as string | ||
const currentBundles = new Map(state.bundles) | ||
currentBundles.set(id, updatedBundle) | ||
|
||
return { | ||
...state, | ||
bundles: currentBundles, | ||
} | ||
} | ||
|
||
default: | ||
return state | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import {type SanityDocument} from '@sanity/types' | ||
import {type ButtonTone} from '@sanity/ui' | ||
|
||
export interface BundleDocument extends SanityDocument { | ||
_type: 'bundle' | ||
title: string | ||
name: string | ||
description?: string | ||
tone?: ButtonTone | ||
icon?: string | ||
authorId: string | ||
} |
Oops, something went wrong.