|  | 
|  | 1 | +// @flow strict-local | 
|  | 2 | +import React, { useState, useContext, useEffect } from 'react'; | 
|  | 3 | +import { Modal, View } from 'react-native'; | 
|  | 4 | +import type { Node } from 'react'; | 
|  | 5 | +import styles, { ThemeContext, BRAND_COLOR, createStyleSheet } from '../styles'; | 
|  | 6 | +import { updateMessage } from '../api'; | 
|  | 7 | +import type { Auth, GetText, Stream } from '../types'; | 
|  | 8 | +import { fetchSomeMessageIdForConversation } from '../message/fetchActions'; | 
|  | 9 | +import ZulipTextIntl from '../common/ZulipTextIntl'; | 
|  | 10 | +import ZulipTextButton from '../common/ZulipTextButton'; | 
|  | 11 | +import Input from '../common/Input'; | 
|  | 12 | + | 
|  | 13 | +type Props = $ReadOnly<{| | 
|  | 14 | +  topicModalProviderState: { | 
|  | 15 | +    visible: boolean, | 
|  | 16 | +    topic: string, | 
|  | 17 | +    streamId: number, | 
|  | 18 | +  }, | 
|  | 19 | +  auth: Auth, | 
|  | 20 | +  zulipFeatureLevel: number, | 
|  | 21 | +  streamsById: Map<number, Stream>, | 
|  | 22 | +  _: GetText, | 
|  | 23 | +  closeEditTopicModal: () => void, | 
|  | 24 | +|}>; | 
|  | 25 | + | 
|  | 26 | +export default function TopicEditModal(props: Props): Node { | 
|  | 27 | +  const { topicModalProviderState, closeEditTopicModal, auth, zulipFeatureLevel, streamsById, _ } = | 
|  | 28 | +    props; | 
|  | 29 | + | 
|  | 30 | +  const { visible, topic, streamId } = topicModalProviderState; | 
|  | 31 | + | 
|  | 32 | +  const [topicName, onChangeTopicName] = useState(); | 
|  | 33 | + | 
|  | 34 | +  useEffect(() => { | 
|  | 35 | +    onChangeTopicName(topic); | 
|  | 36 | +  }, [topic]); | 
|  | 37 | + | 
|  | 38 | +  const { backgroundColor } = useContext(ThemeContext); | 
|  | 39 | + | 
|  | 40 | +  const modalStyles = createStyleSheet({ | 
|  | 41 | +    wrapper: { | 
|  | 42 | +      flex: 1, | 
|  | 43 | +      justifyContent: 'center', | 
|  | 44 | +      alignItems: 'center', | 
|  | 45 | +    }, | 
|  | 46 | +    modal: { | 
|  | 47 | +      justifyContent: 'flex-start', | 
|  | 48 | +      backgroundColor, | 
|  | 49 | +      padding: 15, | 
|  | 50 | +      shadowOpacity: 0.5, | 
|  | 51 | +      shadowColor: 'gray', | 
|  | 52 | +      shadowOffset: { | 
|  | 53 | +        height: 5, | 
|  | 54 | +        width: 5, | 
|  | 55 | +      }, | 
|  | 56 | +      shadowRadius: 5, | 
|  | 57 | +      borderRadius: 5, | 
|  | 58 | +      width: '90%', | 
|  | 59 | +    }, | 
|  | 60 | +    buttonContainer: { | 
|  | 61 | +      flexDirection: 'row', | 
|  | 62 | +      justifyContent: 'flex-end', | 
|  | 63 | +    }, | 
|  | 64 | +    titleText: { | 
|  | 65 | +      fontSize: 18, | 
|  | 66 | +      lineHeight: 21, | 
|  | 67 | +      color: BRAND_COLOR, | 
|  | 68 | +      marginBottom: 10, | 
|  | 69 | +      fontWeight: 'bold', | 
|  | 70 | +    }, | 
|  | 71 | +  }); | 
|  | 72 | + | 
|  | 73 | +  const handleSubmit = async () => { | 
|  | 74 | +    if (topicName === '') { | 
|  | 75 | +      return; | 
|  | 76 | +    } | 
|  | 77 | +    const messageId = await fetchSomeMessageIdForConversation( | 
|  | 78 | +      auth, | 
|  | 79 | +      streamId, | 
|  | 80 | +      topic, | 
|  | 81 | +      streamsById, | 
|  | 82 | +      zulipFeatureLevel, | 
|  | 83 | +    ); | 
|  | 84 | +    if (messageId == null) { | 
|  | 85 | +      throw new Error( | 
|  | 86 | +        _('No messages in topic: {streamAndTopic}', { | 
|  | 87 | +          streamAndTopic: `#${streamsById.get(streamId)?.name ?? 'unknown'} > ${topic}`, | 
|  | 88 | +        }), | 
|  | 89 | +      ); | 
|  | 90 | +    } | 
|  | 91 | +    await updateMessage(auth, messageId, { | 
|  | 92 | +      propagate_mode: 'change_all', | 
|  | 93 | +      subject: topicName, | 
|  | 94 | +      ...(zulipFeatureLevel >= 9 && { | 
|  | 95 | +        send_notification_to_old_thread: true, | 
|  | 96 | +        send_notification_to_new_thread: true, | 
|  | 97 | +      }), | 
|  | 98 | +    }); | 
|  | 99 | +    closeEditTopicModal(); | 
|  | 100 | +  }; | 
|  | 101 | +  return ( | 
|  | 102 | +    <Modal | 
|  | 103 | +      transparent | 
|  | 104 | +      visible={visible} | 
|  | 105 | +      animationType="slide" | 
|  | 106 | +      onRequestClose={closeEditTopicModal} | 
|  | 107 | +      supportedOrientations={['portrait', 'landscape', 'landscape-left', 'landscape-right']} | 
|  | 108 | +    > | 
|  | 109 | +      <View style={modalStyles.wrapper}> | 
|  | 110 | +        <View style={modalStyles.modal}> | 
|  | 111 | +          <ZulipTextIntl style={modalStyles.titleText} text="Edit topic" /> | 
|  | 112 | +          <Input | 
|  | 113 | +            style={styles.marginBottom} | 
|  | 114 | +            defaultValue={topicName} | 
|  | 115 | +            placeholder="Please enter a new topic name." | 
|  | 116 | +            onChangeText={onChangeTopicName} | 
|  | 117 | +            maxLength={60} | 
|  | 118 | +            autoFocus | 
|  | 119 | +            selectTextOnFocus | 
|  | 120 | +          /> | 
|  | 121 | +          <View style={modalStyles.buttonContainer}> | 
|  | 122 | +            <ZulipTextButton label="Cancel" onPress={closeEditTopicModal} /> | 
|  | 123 | +            <ZulipTextButton | 
|  | 124 | +              label="Submit" | 
|  | 125 | +              onPress={handleSubmit} | 
|  | 126 | +              disabled={topicName === ''} | 
|  | 127 | +            /> | 
|  | 128 | +          </View> | 
|  | 129 | +        </View> | 
|  | 130 | +      </View> | 
|  | 131 | +    </Modal> | 
|  | 132 | +  ); | 
|  | 133 | +} | 
0 commit comments