Skip to content

Commit

Permalink
fix: correctly store newly created tags, refactor custom throttle rxj…
Browse files Browse the repository at this point in the history
…s operator
  • Loading branch information
robinpyon committed Jan 5, 2021
1 parent 66e620a commit 93010a1
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 65 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
"cz-conventional-changelog": "3.3.0",
"date-fns": "2.16.1",
"filesize": "6.1.0",
"groq": "1.149.16",
"immer": "5.0.0",
"groq": "2.0.9",
"immer": "8.0.0",
"pluralize": "8.0.0",
"react-hook-form": "6.14.0",
"react-redux": "7.2.2",
Expand Down
24 changes: 5 additions & 19 deletions src/components/FormFieldInputTags/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import {AddIcon, ChevronDownIcon, CloseIcon} from '@sanity/icons'
import {Box, Card, Flex, Text, studioTheme} from '@sanity/ui'
// import groq from 'groq'
// import client from 'part:@sanity/base/client'
import React, {forwardRef, useState} from 'react'
import React, {forwardRef} from 'react'
import {Controller, FieldError} from 'react-hook-form'
import {useDispatch} from 'react-redux'
import {components} from 'react-select'
import CreatableSelect from 'react-select/creatable'
// import AsyncCreatableSelect from 'react-select/async-creatable'

import useTypedSelector from '../../hooks/useTypedSelector'
import {tagsCreate} from '../../modules/tags'
Expand Down Expand Up @@ -92,13 +89,11 @@ const Option = (props: any) => {
const FormFieldInputTags = forwardRef<Ref, Props>((props: Props, ref) => {
const {control, description, disabled, error, label, name, placeholder, value} = props

// State
const [isCreating, setIsCreating] = useState(false)

// Redux
const dispatch = useDispatch()
const allIds = useTypedSelector(state => state.tags.allIds)
const byIds = useTypedSelector(state => state.tags.byIds)
const creating = useTypedSelector(state => state.tags.creating)

const selectTags = allIds.map(id => {
const tag = byIds[id].tag
Expand All @@ -108,7 +103,6 @@ const FormFieldInputTags = forwardRef<Ref, Props>((props: Props, ref) => {
value: tag.name
}
})
console.log('>>> selectTags', selectTags)

// Callbacks
const handleChange = (newValue: any, actionMeta: any) => {
Expand All @@ -119,14 +113,8 @@ const FormFieldInputTags = forwardRef<Ref, Props>((props: Props, ref) => {
}

const handleCreate = (value: string) => {
console.log('create....')
console.log('value', value)
setIsCreating(true)

// TODO: dispatch action to create new tag
// Dispatch action to create new tag
dispatch(tagsCreate(value))

// TODO: how do we determine if a tag has been successfully created?
}

return (
Expand All @@ -151,11 +139,9 @@ const FormFieldInputTags = forwardRef<Ref, Props>((props: Props, ref) => {
defaultOptions
instanceId="tags"
isClearable={false} // TODO: re-enable when we're able to correctly (manually) re-validate on clear
isDisabled={isCreating || disabled}
isDisabled={creating || disabled}
isMulti
isLoading={isCreating}
// menuPortalTarget={document.body}
// menuPortalTarget={refContainer.current}
isLoading={creating}
name={name}
onChange={handleChange}
onCreateOption={handleCreate}
Expand Down
8 changes: 4 additions & 4 deletions src/modules/assets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {isOfType} from 'typesafe-actions'

import {BROWSER_SELECT} from '../../config'
import {SEARCH_FACET_OPERATORS} from '../../constants'
import {debugThrottle} from '../utils'
import debugThrottle from '../../operators/debugThrottle'
import {
AssetsActions,
AssetsClearAction,
Expand Down Expand Up @@ -644,7 +644,7 @@ export const assetsDeleteEpic = (
mergeMap(([action, state]) => {
const {asset} = action.payload
return of(action).pipe(
debugThrottle(action, state.debug.badConnection),
debugThrottle(state.debug.badConnection),
mergeMap(() => from(client.delete(asset._id))),
mergeMap(() => of(assetsDeleteComplete(asset._id))),
catchError(error => of(assetsDeleteError(asset, error)))
Expand Down Expand Up @@ -698,7 +698,7 @@ export const assetsFetchEpic = (
const query = action.payload?.query

return of(action).pipe(
debugThrottle(action, state.debug.badConnection),
debugThrottle(state.debug.badConnection),
mergeMap(() => from(client.fetch(query, params))),
mergeMap((result: any) => {
const {
Expand Down Expand Up @@ -850,7 +850,7 @@ export const assetsUpdateEpic = (
const {asset, formData, options} = action.payload

return of(action).pipe(
debugThrottle(action, state.debug.badConnection),
debugThrottle(state.debug.badConnection),
mergeMap(() => from(client.patch(asset._id).set(formData).commit())),
mergeMap((updatedAsset: any) => {
return of(assetsUpdateComplete(updatedAsset, options))
Expand Down
64 changes: 53 additions & 11 deletions src/modules/tags/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
TagsListenerUpdateAction,
TagsReducerState
} from './types'
import {debugThrottle} from '../utils'
import debugThrottle from '../../operators/debugThrottle'
import {RootReducerState} from '../types'

/***********
Expand Down Expand Up @@ -55,6 +55,8 @@ export enum TagsActionTypes {
export const initialState: TagsReducerState = {
allIds: [],
byIds: {},
creating: false,
creatingError: null,
fetchCount: -1,
fetching: false,
fetchingError: null
Expand All @@ -68,20 +70,52 @@ export default function tagsReducerState(
return produce(state, draft => {
// eslint-disable-next-line default-case
switch (action.type) {
case TagsActionTypes.CREATE_COMPLETE:
/**
* A tag has been successfully created via the client.
* - Add tag from the redux store (both the normalised object and ordered tag id).
*/
case TagsActionTypes.CREATE_COMPLETE: {
const tag = action.payload.tag
draft.creating = false

// Add normalised tag item
draft.byIds[tag._id] = {
picked: false,
tag,
updating: false
}

// Add tag ID and re-order by name (asc)
draft.allIds = [...draft.allIds, tag._id].sort((a, b) => {
const tagA = draft.byIds[a].tag
const tagB = draft.byIds[b].tag

if (tagA.name < tagB.name) {
return -1
} else if (tagA.name > tagB.name) {
return 1
} else {
return 1
}
})

break
}

/**
* A tag was unable to be created via the client.
*/
case TagsActionTypes.CREATE_ERROR:
// TODO: store error on root tags reducer? (can we ever create multiple tags at once?)
draft.creating = false
draft.creatingError = action.payload.error
break

/**
* A request to delete a tag has been made (and not yet completed).
* A request to create a tag has been made (and not yet completed).
*/
case TagsActionTypes.CREATE_REQUEST:
draft.creating = true
draft.creatingError = null
break

/**
Expand Down Expand Up @@ -209,8 +243,8 @@ export const tagsCreate = (name: string): TagsCreateRequestAction => ({
})

// Create success
export const tagsCreateComplete = (name: string): TagsCreateCompleteAction => ({
payload: {name},
export const tagsCreateComplete = (tag: Tag): TagsCreateCompleteAction => ({
payload: {tag},
type: TagsActionTypes.CREATE_COMPLETE
})

Expand Down Expand Up @@ -255,7 +289,7 @@ export const tagsFetch = (): TagsFetchRequestAction => {
_rev,
_type,
'name': name.current
} | order(_updatedAt desc),
} | order(name.current asc),
}
`

Expand Down Expand Up @@ -307,8 +341,9 @@ export const tagsCreateEpic = (
withLatestFrom(state$),
mergeMap(([action, state]) => {
const {name} = action.payload

return of(action).pipe(
debugThrottle(action, state.debug.badConnection),
debugThrottle(state.debug.badConnection),
mergeMap(() =>
from(
client.create({
Expand All @@ -320,7 +355,14 @@ export const tagsCreateEpic = (
})
)
),
mergeMap(() => of(tagsCreateComplete(name))),
// TODO: type correctly
mergeMap((result: any) => {
const tag = {
...result,
name: result?.name?.current
}
return of(tagsCreateComplete(tag))
}),
catchError(error => of(tagsCreateError(name, error)))
)
})
Expand All @@ -341,7 +383,7 @@ export const tagsDeleteEpic = (
mergeMap(([action, state]) => {
const {tag} = action.payload
return of(action).pipe(
debugThrottle(action, state.debug.badConnection),
debugThrottle(state.debug.badConnection),
mergeMap(() => from(client.delete(tag._id))),
mergeMap(() => of(tagsDeleteComplete(tag._id))),
catchError(error => of(tagsDeleteError(tag, error)))
Expand All @@ -367,7 +409,7 @@ export const tagsFetchEpic = (
const query = action.payload?.query

return of(action).pipe(
debugThrottle(action, state.debug.badConnection),
debugThrottle(state.debug.badConnection),
mergeMap(() => from(client.fetch(query, params))),
mergeMap((result: any) => {
const {
Expand Down
4 changes: 3 additions & 1 deletion src/modules/tags/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {TagsActionTypes} from './index'
export type TagsReducerState = {
allIds: string[]
byIds: Record<string, TagItem>
creating: boolean
creatingError: any
fetchCount: number
fetching: boolean
fetchingError: any
Expand All @@ -15,7 +17,7 @@ export type TagsReducerState = {
// Actions

export type TagsCreateCompleteAction = {
payload: {name: string}
payload: {tag: Tag}
type: TagsActionTypes.CREATE_COMPLETE
}

Expand Down
20 changes: 0 additions & 20 deletions src/modules/utils.ts

This file was deleted.

22 changes: 22 additions & 0 deletions src/operators/debugThrottle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {iif, Observable, of, throwError} from 'rxjs'
import {delay, mergeMap} from 'rxjs/operators'

const debugThrottle = (throttled?: boolean) => {
return function <T>(source: Observable<T>): Observable<T> {
return iif(
() => !!throttled,
source.pipe(
delay(3000),
mergeMap(source => {
if (Math.random() > 0.5) {
return throwError('Test error')
}
return of(source)
})
),
source
)
}
}

export default debugThrottle
16 changes: 8 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3478,10 +3478,10 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0:
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==

groq@1.149.16:
version "1.149.16"
resolved "https://registry.yarnpkg.com/groq/-/groq-1.149.16.tgz#dd889e287fa97ff4160dd96a9d8bb332e7aba8f6"
integrity sha512-+3HQr0I3FtKzeSIlfHqhUJLFPFdsDNwqIVS28IBaCPF7FeGBVUBTGqtiEd8QQjVEK3PlZTxEtfy6A/nOAevb3Q==
groq@2.0.9:
version "2.0.9"
resolved "https://registry.yarnpkg.com/groq/-/groq-2.0.9.tgz#c7edaf56ce1b045299c5391cc14aca013852b28b"
integrity sha512-Ed9YFs4B7DMmVAzAwDMnC/6FjRnwrIbpNpBbAep2zWR5L+4hcXgRV5C/2L6DDaEqYfrJUdRKf6jRipVnDzIaQA==

gud@^1.0.0:
version "1.0.0"
Expand Down Expand Up @@ -3672,10 +3672,10 @@ ignore@^5.1.4:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==

immer@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/immer/-/immer-5.0.0.tgz#07f462b7d95f7e86c214a861ecacd766d42b8c0a"
integrity sha512-G7gRqKbi9NE025XVyqyTV98dxUOtdKvu/P1QRaVZfA55aEcXgjbxPdm+TlWdcSMNPKijlaHNz61DGPyelouRlA==
immer@8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.0.tgz#08763549ba9dd7d5e2eb4bec504a8315bd9440c2"
integrity sha512-jm87NNBAIG4fHwouilCHIecFXp5rMGkiFrAuhVO685UnMAlOneEAnOyzPt8OnP47TC11q/E7vpzZe0WvwepFTg==

immer@^5.0.0:
version "5.3.6"
Expand Down

0 comments on commit 93010a1

Please sign in to comment.