Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pr-topic-edit-modal #5510

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/ZulipMobile.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import AppEventHandlers from './boot/AppEventHandlers';
import { initializeSentry } from './sentry';
import ZulipSafeAreaProvider from './boot/ZulipSafeAreaProvider';
import { OfflineNoticeProvider } from './boot/OfflineNoticeProvider';
import TopicEditModalProvider from './boot/TopicEditModalProvider';

initializeSentry();

Expand Down Expand Up @@ -79,9 +80,11 @@ export default function ZulipMobile(): Node {
<TranslationProvider>
<ThemeProvider>
<OfflineNoticeProvider>
<ActionSheetProvider>
<ZulipNavigationContainer />
</ActionSheetProvider>
<TopicEditModalProvider>
<ActionSheetProvider>
<ZulipNavigationContainer />
</ActionSheetProvider>
</TopicEditModalProvider>
</OfflineNoticeProvider>
</ThemeProvider>
</TranslationProvider>
Expand Down
21 changes: 20 additions & 1 deletion src/action-sheets/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ type TopicArgs = {
zulipFeatureLevel: number,
dispatch: Dispatch,
_: GetText,
startEditTopic: (streamId: number, topic: string) => void,
...
};

Expand Down Expand Up @@ -171,6 +172,14 @@ const deleteMessage = {
},
};

const editTopic = {
title: 'Edit topic',
errorMessage: 'Failed to edit topic',
action: ({ streamId, topic, startEditTopic }) => {
startEditTopic(streamId, topic);
},
};

const markTopicAsRead = {
title: 'Mark topic as read',
errorMessage: 'Failed to mark topic as read',
Expand Down Expand Up @@ -532,9 +541,18 @@ export const constructTopicActionButtons = (args: {|

const buttons = [];
const unreadCount = getUnreadCountForTopic(unread, streamId, topic);
const isAdmin = roleIsAtLeast(ownUserRole, Role.Admin);
if (unreadCount > 0) {
buttons.push(markTopicAsRead);
}
// At present, the permissions for editing the topic of a message are highly complex.
// Until we move to a better set of policy options, we'll only display the edit topic
// button to admins.
// Issue: https://github.com/zulip/zulip/issues/21739
// Relevant comment: https://github.com/zulip/zulip-mobile/issues/5365#issuecomment-1197093294
if (isAdmin) {
buttons.push(editTopic);
}
if (isTopicMuted(streamId, topic, mute)) {
buttons.push(unmuteTopic);
} else {
Expand All @@ -545,7 +563,7 @@ export const constructTopicActionButtons = (args: {|
} else {
buttons.push(unresolveTopic);
}
if (roleIsAtLeast(ownUserRole, Role.Admin)) {
if (isAdmin) {
buttons.push(deleteTopic);
}
const sub = subscriptions.get(streamId);
Expand Down Expand Up @@ -705,6 +723,7 @@ export const showTopicActionSheet = (args: {|
showActionSheetWithOptions: ShowActionSheetWithOptions,
callbacks: {|
dispatch: Dispatch,
startEditTopic: (streamId: number, topic: string) => void,
_: GetText,
|},
backgroundData: $ReadOnly<{
Expand Down
57 changes: 57 additions & 0 deletions src/boot/TopicEditModalProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* @flow strict-local */
import React, { createContext, useState, useCallback, useContext } from 'react';
import type { Context, Node } from 'react';

import TopicEditModal from '../topics/TopicEditModal';

type Props = $ReadOnly<{|
children: Node,
|}>;

export type TopicEditProviderStateType = {
streamId: number,
oldTopic: string,
};

type StartEditTopicContext = (streamId: number, oldTopic: string) => void;

const TopicEditModalContext: Context<StartEditTopicContext> = createContext(() => {
throw new Error(
'Tried to open the edit-topic UI from a component without TopicEditModalProvider above it in the tree.',
);
});

export const useStartEditTopic = (): StartEditTopicContext => useContext(TopicEditModalContext);

export default function TopicEditModalProvider(props: Props): Node {
const { children } = props;

const [topicModalProviderState, setTopicModalProviderState] =
useState<TopicEditProviderStateType | null>(null);

const startEditTopic = useCallback(
(streamIdArg, oldTopicArg) => {
if (!topicModalProviderState) {
setTopicModalProviderState({
streamId: streamIdArg,
oldTopic: oldTopicArg,
});
}
},
[topicModalProviderState],
);

const closeEditTopicModal = () => {
setTopicModalProviderState(null);
};

return (
<TopicEditModalContext.Provider value={startEditTopic}>
<TopicEditModal
topicModalProviderState={topicModalProviderState}
closeEditTopicModal={closeEditTopicModal}
/>
{children}
</TopicEditModalContext.Provider>
);
}
3 changes: 3 additions & 0 deletions src/chat/ChatScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { showErrorAlert } from '../utils/info';
import { TranslationContext } from '../boot/TranslationProvider';
import * as api from '../api';
import { useConditionalEffect } from '../reactUtils';
import { useStartEditTopic } from '../boot/TopicEditModalProvider';

type Props = $ReadOnly<{|
navigation: AppNavigationProp<'chat'>,
Expand Down Expand Up @@ -132,6 +133,7 @@ export default function ChatScreen(props: Props): Node {
(value: EditMessage | null) => navigation.setParams({ editMessage: value }),
[navigation],
);
const startEditTopic = useStartEditTopic();

const isNarrowValid = useSelector(state => getIsNarrowValid(state, narrow));
const draft = useSelector(state => getDraftForNarrow(state, narrow));
Expand Down Expand Up @@ -219,6 +221,7 @@ export default function ChatScreen(props: Props): Node {
}
showMessagePlaceholders={showMessagePlaceholders}
startEditMessage={setEditMessage}
startEditTopic={startEditTopic}
/>
);
}
Expand Down
3 changes: 3 additions & 0 deletions src/search/SearchMessagesCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { createStyleSheet } from '../styles';
import LoadingIndicator from '../common/LoadingIndicator';
import SearchEmptyState from '../common/SearchEmptyState';
import MessageList from '../webview/MessageList';
import { useStartEditTopic } from '../boot/TopicEditModalProvider';

const styles = createStyleSheet({
results: {
Expand All @@ -24,6 +25,7 @@ type Props = $ReadOnly<{|

export default function SearchMessagesCard(props: Props): Node {
const { narrow, isFetching, messages } = props;
const startEditTopic = useStartEditTopic();

if (isFetching) {
// Display loading indicator only if there are no messages to
Expand Down Expand Up @@ -55,6 +57,7 @@ export default function SearchMessagesCard(props: Props): Node {
// TODO: handle editing a message from the search results,
// or make this prop optional
startEditMessage={() => undefined}
startEditTopic={startEditTopic}
/>
</View>
);
Expand Down
4 changes: 3 additions & 1 deletion src/streams/TopicItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
import { getMute } from '../mute/muteModel';
import { getUnread } from '../unread/unreadModel';
import { getOwnUserRole } from '../permissionSelectors';
import { useStartEditTopic } from '../boot/TopicEditModalProvider';

const componentStyles = createStyleSheet({
selectedRow: {
Expand Down Expand Up @@ -70,6 +71,7 @@ export default function TopicItem(props: Props): Node {
useActionSheet().showActionSheetWithOptions;
const _ = useContext(TranslationContext);
const dispatch = useDispatch();
const startEditTopic = useStartEditTopic();
const backgroundData = useSelector(state => ({
auth: getAuth(state),
mute: getMute(state),
Expand All @@ -88,7 +90,7 @@ export default function TopicItem(props: Props): Node {
onLongPress={() => {
showTopicActionSheet({
showActionSheetWithOptions,
callbacks: { dispatch, _ },
callbacks: { dispatch, startEditTopic, _ },
backgroundData,
streamId,
topic: name,
Expand Down
4 changes: 3 additions & 1 deletion src/title/TitleStream.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { showStreamActionSheet, showTopicActionSheet } from '../action-sheets';
import type { ShowActionSheetWithOptions } from '../action-sheets';
import { getUnread } from '../unread/unreadModel';
import { getOwnUserRole } from '../permissionSelectors';
import { useStartEditTopic } from '../boot/TopicEditModalProvider';

type Props = $ReadOnly<{|
narrow: Narrow,
Expand All @@ -51,6 +52,7 @@ export default function TitleStream(props: Props): Node {
const { narrow, color } = props;
const dispatch = useDispatch();
const stream = useSelector(state => getStreamInNarrow(state, narrow));
const startEditTopic = useStartEditTopic();
const backgroundData = useSelector(state => ({
auth: getAuth(state),
mute: getMute(state),
Expand All @@ -75,7 +77,7 @@ export default function TitleStream(props: Props): Node {
? () => {
showTopicActionSheet({
showActionSheetWithOptions,
callbacks: { dispatch, _ },
callbacks: { dispatch, startEditTopic, _ },
backgroundData,
streamId: stream.stream_id,
topic: topicOfNarrow(narrow),
Expand Down
Loading