1+ import Message from "Models/Message" ;
12import React , { useEffect , useState } from "react" ;
23import Async from "react-select/async" ;
34import { get } from "../gateway" ;
@@ -7,19 +8,40 @@ import Icon from "./icons";
78import Textarea from "./Textarea" ;
89import TextInput from "./TextInput" ;
910
10- const groupOption = ( d ) => {
11- const id = d [ Group . model . id ] ;
11+ type GroupOption = {
12+ id : number ;
13+ type : "group" ;
14+ label : string ;
15+ value : string ;
16+ }
17+
18+ const groupOption = ( d : Group ) : GroupOption => {
19+ const id = d . id ;
1220 const type = "group" ;
1321 return {
14- id,
22+ id : id ! ,
1523 type,
1624 label : `Grupp: ${ d . title } ` ,
1725 value : type + id ,
1826 } ;
1927} ;
2028
21- const memberOption = ( d ) => {
22- const id = d [ Member . model . id ] ;
29+ type MemberOption = {
30+ id : number ;
31+ type : "member" ;
32+ label : string ;
33+ value : string ;
34+ }
35+
36+ type CombinedOption = {
37+ type : "combined" ,
38+ label : string ,
39+ value : string ,
40+ inner : ( MemberOption | GroupOption ) [ ] ,
41+ }
42+
43+ const memberOption = ( d : Member ) : MemberOption => {
44+ const id = d . member_id ;
2345 const type = "member" ;
2446 const lastname = d . lastname || "" ;
2547 return {
@@ -30,15 +52,25 @@ const memberOption = (d) => {
3052 } ;
3153} ;
3254
33- const MessageForm = ( { message, onSave, recipientSelect } ) => {
55+ const MessageForm = ( { message, onSave, recipientSelect } : { message : Message , onSave : ( ) => void , recipientSelect : boolean } ) => {
3456 const [ sendDisabled , setSendDisabled ] = useState ( true ) ;
35- const [ recipients , setRecipients ] = useState ( [ ] ) ;
57+ const [ recipients , setRecipients ] = useState < ( MemberOption | GroupOption ) [ ] > ( [ ] ) ;
3658 const [ bodyLength , setBodyLength ] = useState ( message . body . length ) ;
59+ const memberCache = React . useRef ( new Map < number , Member > ( ) ) . current ;
60+
61+ const getMember = async ( id : number ) : Promise < Member > => {
62+ if ( memberCache . has ( id ) ) {
63+ return memberCache . get ( id ) ! ;
64+ }
65+ const { data } = await get ( { url : `/membership/member/${ id } ` } ) ;
66+ memberCache . set ( id , data ) ;
67+ return data ;
68+ } ;
3769
3870 useEffect ( ( ) => {
3971 const unsubscribe = message . subscribe ( ( ) => {
4072 setSendDisabled ( ! message . canSave ( ) ) ;
41- setRecipients ( message . recipients ) ;
73+ setRecipients ( message . recipients as any as ( MemberOption | GroupOption ) [ ] ) ;
4274 setBodyLength ( message . body . length ) ;
4375 } ) ;
4476
@@ -47,7 +79,29 @@ const MessageForm = ({ message, onSave, recipientSelect }) => {
4779 } ;
4880 } , [ message ] ) ;
4981
50- const loadOptions = ( inputValue , callback ) => {
82+ const loadOptions = ( inputValue : string , callback : ( options : ( MemberOption | GroupOption | CombinedOption ) [ ] ) => void ) => {
83+ const intListMatch = inputValue . match ( / ^ ( \d + [ \s , ] * ) + $ / ) ;
84+ if ( intListMatch ) {
85+ const ids = inputValue
86+ . split ( / [ \s , ] + / )
87+ . map ( ( v ) => parseInt ( v , 10 ) )
88+ . filter ( ( v ) => ! isNaN ( v ) ) ;
89+ if ( ids . length > 0 ) {
90+ Promise . all ( ids . map ( getMember ) ) . then ( members => {
91+ const options = members . map ( memberOption ) ;
92+ callback ( [
93+ {
94+ type : "combined" ,
95+ label : `${ options . map ( o => o . label ) . join ( ", " ) } ` ,
96+ value : "combined-" + ids . join ( "-" ) ,
97+ inner : options ,
98+ } ,
99+ ] ) ;
100+ } ) ;
101+ return ;
102+ }
103+ }
104+
51105 Promise . all ( [
52106 get ( {
53107 url : "/membership/group" ,
@@ -65,16 +119,16 @@ const MessageForm = ({ message, onSave, recipientSelect }) => {
65119 sort_order : "asc" ,
66120 } ,
67121 } ) ,
68- ] ) . then ( ( [ { data : groups } , { data : members } ] ) =>
122+ ] ) . then ( ( [ { data : groups } , { data : members } ] : [ { data : Group [ ] } , { data : Member [ ] } ] ) =>
69123 callback (
70124 groups
71- . map ( ( d ) => groupOption ( d ) )
125+ . map ( ( d ) => groupOption ( d ) as GroupOption | MemberOption )
72126 . concat ( members . map ( ( d ) => memberOption ( d ) ) ) ,
73127 ) ,
74128 ) ;
75129 } ;
76130
77- const handleSubmit = ( e ) => {
131+ const handleSubmit = ( e : React . FormEvent < HTMLFormElement > ) => {
78132 e . preventDefault ( ) ;
79133 onSave ( ) ;
80134 } ;
@@ -87,18 +141,20 @@ const MessageForm = ({ message, onSave, recipientSelect }) => {
87141 Mottagare
88142 </ label >
89143 < div className = "uk-form-controls" >
90- < Async
144+ < Async < ( MemberOption | GroupOption | CombinedOption ) , true >
91145 name = "recipients"
92146 isMulti
93- cache = { false }
94147 placeholder = "Type to search for member or group"
95148 getOptionValue = { ( e ) => e . value }
96149 getOptionLabel = { ( e ) => e . label }
97150 loadOptions = { loadOptions }
98151 value = { recipients }
99152 onChange = { ( values ) => {
100- message . recipients = values ;
101- setRecipients ( values ) ;
153+ const flattened = values . flatMap ( ( v ) =>
154+ v . type === "combined" ? v . inner : v
155+ ) ;
156+ message . recipients = flattened ;
157+ setRecipients ( flattened ) ;
102158 } }
103159 />
104160 </ div >
0 commit comments