11import clsx from 'clsx' ;
2- import { MAX_POLL_OPTIONS } from '../constants' ;
3- import { nanoid } from 'nanoid' ;
42import React , { useCallback } from 'react' ;
53import { FieldError } from '../../Form/FieldError' ;
64import { DragAndDropContainer } from '../../DragAndDrop/DragAndDropContainer' ;
75import { useTranslationContext } from '../../../context' ;
8- import type { OptionErrors , PollFormState , PollOptionFormData } from './types' ;
6+ import { useMessageComposer } from '../../MessageInput/hooks/messageComposer/useMessageComposer' ;
7+ import { useStateStore } from '../../../store' ;
8+ import type { PollComposerState } from 'stream-chat' ;
99
10- const VALIDATION_ERRORS = { 'Option already exists' : true } as const as Record <
11- string ,
12- boolean
13- > ;
10+ const pollComposerStateSelector = ( state : PollComposerState ) => ( {
11+ errors : state . errors . options ,
12+ options : state . data . options ,
13+ } ) ;
1414
15- export type OptionFieldSetProps = {
16- errors : OptionErrors ;
17- options : PollFormState [ 'options' ] ;
18- setErrors : ( fn : ( prev : OptionErrors ) => OptionErrors ) => void ;
19- setState : ( fn : ( prev : PollFormState ) => PollFormState ) => void ;
20- } ;
21-
22- export const OptionFieldSet = ( {
23- errors,
24- options,
25- setErrors,
26- setState,
27- } : OptionFieldSetProps ) => {
15+ export const OptionFieldSet = ( ) => {
16+ const { pollComposer } = useMessageComposer ( ) ;
17+ const { errors, options } = useStateStore (
18+ pollComposer . state ,
19+ pollComposerStateSelector ,
20+ ) ;
2821 const { t } = useTranslationContext ( 'OptionFieldSet' ) ;
2922
30- const findOptionDuplicate = ( sourceOption : PollOptionFormData ) => {
31- const isDuplicateFilter = ( option : PollOptionFormData ) =>
32- ! ! sourceOption . text . trim ( ) && // do not include empty options into consideration
33- option . id !== sourceOption . id &&
34- option . text . trim ( ) === sourceOption . text . trim ( ) ;
35-
36- return options . find ( isDuplicateFilter ) ;
37- } ;
38-
3923 const onSetNewOrder = useCallback (
4024 ( newOrder : number [ ] ) => {
41- setState ( ( prev ) => ( {
42- ...prev ,
43- options : newOrder . map ( ( index ) => prev . options [ index ] ) ,
44- } ) ) ;
25+ const prevOptions = pollComposer . options ;
26+ pollComposer . updateFields ( { options : newOrder . map ( ( index ) => prevOptions [ index ] ) } ) ;
4527 } ,
46- [ setState ] ,
28+ [ pollComposer ] ,
4729 ) ;
4830
4931 const draggable = options . length > 1 ;
@@ -56,83 +38,47 @@ export const OptionFieldSet = ({
5638 draggable = { draggable }
5739 onSetNewOrder = { onSetNewOrder }
5840 >
59- { options . map ( ( option , i ) => (
60- < div
61- className = { clsx ( 'str-chat__form__input-field' , {
62- 'str-chat__form__input-field--draggable' : draggable ,
63- 'str-chat__form__input-field--has-error' : errors [ option . id ] ,
64- } ) }
65- key = { `new-poll-option-${ i } ` }
66- >
67- < div className = 'str-chat__form__input-field__value' >
68- < FieldError
69- className = 'str-chat__form__input-field__error'
70- data-testid = { 'poll-option-input-field-error' }
71- text = { errors [ option . id ] }
72- />
73- < input
74- id = { option . id }
75- onBlur = { ( e ) => {
76- if ( findOptionDuplicate ( { id : e . target . id , text : e . target . value } ) ) {
77- setErrors ( ( prev ) => ( {
78- ...prev ,
79- [ e . target . id ] : t < string > ( 'Option already exists' ) ,
80- } ) ) ;
81- }
82- } }
83- onChange = { ( e ) => {
84- setState ( ( prev ) => {
85- const shouldAddEmptyOption =
86- prev . options . length < MAX_POLL_OPTIONS &&
87- ( ! prev . options ||
88- ( prev . options . slice ( i + 1 ) . length === 0 && ! ! e . target . value ) ) ;
89- const shouldRemoveOption =
90- prev . options &&
91- prev . options . slice ( i + 1 ) . length > 0 &&
92- ! e . target . value ;
93-
94- const optionListHead = prev . options ? prev . options . slice ( 0 , i ) : [ ] ;
95- const optionListTail = shouldAddEmptyOption
96- ? [ { id : nanoid ( ) , text : '' } ]
97- : ( prev . options || [ ] ) . slice ( i + 1 ) ;
98-
99- if (
100- ( errors [ option . id ] && ! e . target . value ) ||
101- ( VALIDATION_ERRORS [ errors [ option . id ] ] &&
102- ! findOptionDuplicate ( { id : e . target . id , text : e . target . value } ) )
103- ) {
104- setErrors ( ( prev ) => {
105- delete prev [ option . id ] ;
106- return prev ;
107- } ) ;
41+ { options . map ( ( option , i ) => {
42+ const error = errors ?. [ option . id ] ;
43+ return (
44+ < div
45+ className = { clsx ( 'str-chat__form__input-field' , {
46+ 'str-chat__form__input-field--draggable' : draggable ,
47+ 'str-chat__form__input-field--has-error' : error ,
48+ } ) }
49+ key = { `new-poll-option-${ i } ` }
50+ >
51+ < div className = 'str-chat__form__input-field__value' >
52+ < FieldError
53+ className = 'str-chat__form__input-field__error'
54+ data-testid = { 'poll-option-input-field-error' }
55+ text = { error && t ( error ) }
56+ />
57+ < input
58+ id = { option . id }
59+ onBlur = { ( ) => {
60+ pollComposer . handleFieldBlur ( 'options' ) ;
61+ } }
62+ onChange = { ( e ) => {
63+ pollComposer . updateFields ( {
64+ options : { index : i , text : e . target . value } ,
65+ } ) ;
66+ } }
67+ onKeyUp = { ( event ) => {
68+ if ( event . key === 'Enter' ) {
69+ const nextInputId = options [ i + 1 ] . id ;
70+ document . getElementById ( nextInputId ) ?. focus ( ) ;
10871 }
109-
110- return {
111- ...prev ,
112- options : [
113- ...optionListHead ,
114- ...( shouldRemoveOption
115- ? [ ]
116- : [ { ...option , text : e . target . value } ] ) ,
117- ...optionListTail ,
118- ] ,
119- } ;
120- } ) ;
121- } }
122- onKeyUp = { ( event ) => {
123- if ( event . key === 'Enter' ) {
124- const nextInputId = options [ i + 1 ] . id ;
125- document . getElementById ( nextInputId ) ?. focus ( ) ;
126- }
127- } }
128- placeholder = { t < string > ( 'Add an option' ) }
129- type = 'text'
130- value = { option . text }
131- />
72+ } }
73+ placeholder = { t < string > ( 'Add an option' ) }
74+ type = 'text'
75+ value = { option . text }
76+ />
77+ </ div >
78+ { draggable && < div className = 'str-chat__drag-handle' /> }
13279 </ div >
133- { draggable && < div className = 'str-chat__drag-handle' /> }
134- </ div >
135- ) ) }
80+ ) ;
81+ } ) }
13682 </ DragAndDropContainer >
13783 </ fieldset >
13884 ) ;
0 commit comments