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

[#163591901,#163591918,#163591935] Messages Inbox/Deadlines/Archive Tabs (v2) #823

Merged
merged 11 commits into from
Feb 15, 2019
2 changes: 2 additions & 0 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,8 @@ messages:
fetchCalendars: Error fetching calendars
unknownSender: Unknown sender
noContent: Content not available
agenda:
sectionDate: "dddd D MMMM"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this date format is not specific of the agenda view, it should be under the global namespace

messageDetails:
headerTitle: Message
emptyMessage: No content
Expand Down
2 changes: 2 additions & 0 deletions locales/it/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,8 @@ messages:
fetchCalendars: Errore durante il recupero dei calendari
unknownSender: Mittente sconosciuto
noContent: Contenuto non disponibile
agenda:
sectionDate: "dddd D MMMM"
messageDetails:
headerTitle: Messaggio
emptyMessage: Nessun contenuto
Expand Down
12 changes: 8 additions & 4 deletions ts/components/messages/MessageAgenda.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
StyleSheet
} from "react-native";

import I18n from "../../i18n";
import customVariables from "../../theme/variables";
import { MessageWithContentAndDueDatePO } from "../../types/MessageWithContentAndDueDatePO";
import H5 from "../ui/H5";
Expand Down Expand Up @@ -38,7 +39,7 @@ type Props = {
// typescript definition.
// tslint:disable-next-line:readonly-array
sections: MessageAgendaSection[];
refreshing: boolean;
isRefreshing: boolean;
onRefresh: () => void;
onPressItem: (id: string) => void;
};
Expand All @@ -48,15 +49,15 @@ type Props = {
*/
class MessageAgenda extends React.PureComponent<Props> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agenda has a slightly different meaning than in Italian (it means ordine del giorno, like a meeting agenda) - perhaps MessageCalendar ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reference @matteodesanti gave me was the Agenda view of the Android Calendar app and is called "Agenda" also in the english version:
https://android.googlesource.com/platform/packages/apps/Calendar/+/master/res/values-en-rGB/strings.xml#53

public render() {
const { sections, refreshing, onRefresh } = this.props;
const { sections, isRefreshing, onRefresh } = this.props;
return (
<SectionList
sections={sections}
keyExtractor={keyExtractor}
stickySectionHeadersEnabled={true}
alwaysBounceVertical={false}
ItemSeparatorComponent={ItemSeparatorComponent}
refreshing={refreshing}
refreshing={isRefreshing}
onRefresh={onRefresh}
renderSectionHeader={this.renderSectionHeader}
renderItem={this.renderItem}
Expand All @@ -67,7 +68,10 @@ class MessageAgenda extends React.PureComponent<Props> {
private renderSectionHeader = (info: { section: MessageAgendaSection }) => {
return (
<H5 style={styles.sectionHeader}>
{format(info.section.title, "dddd D MMMM").toUpperCase()}
{format(
info.section.title,
I18n.t("messages.agenda.sectionDate")
).toUpperCase()}
</H5>
);
};
Expand Down
4 changes: 4 additions & 0 deletions ts/components/messages/MessageAgendaItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ type Props = {
onPress: (id: string) => void;
};

/**
* A component to render a single Agenda item.
* Extends PureComponent to avoid unnecessary re-renders.
*/
class MessageAgendaItem extends React.PureComponent<Props> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add comment

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be an SFC

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It must be a PureComponent to avoid unnecessary rerender.

public render() {
const { subject, due_date } = this.props;
Expand Down
34 changes: 16 additions & 18 deletions ts/components/messages/MessagesArchive.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React, { ComponentProps } from "react";
import { StyleSheet } from "react-native";

import I18n from "../../i18n";
import { lexicallyOrderedMessagesStateInfoSelector } from "../../store/reducers/entities/messages";
import { lexicallyOrderedMessagesStateSelector } from "../../store/reducers/entities/messages";
import { MessageState } from "../../store/reducers/entities/messages/messagesById";
import {
InjectedWithMessagesSelectionProps,
Expand Down Expand Up @@ -35,9 +35,7 @@ const styles = StyleSheet.create({
});

type OwnProps = {
messagesStateInfo: ReturnType<
typeof lexicallyOrderedMessagesStateInfoSelector
>;
messagesState: ReturnType<typeof lexicallyOrderedMessagesStateSelector>;
navigateToMessageDetail: (id: string) => void;
setMessagesArchivedState: (
ids: ReadonlyArray<string>,
Expand All @@ -53,14 +51,14 @@ type Props = Pick<
InjectedWithMessagesSelectionProps;

type State = {
lastMessageStatesUpdate: number;
filteredMessageStates: ReturnType<typeof generateFilteredMessagesState>;
lastMessagesState: ReturnType<typeof lexicallyOrderedMessagesStateSelector>;
filteredMessageStates: ReturnType<typeof generateMessagesStateArchivedArray>;
};

/**
* Filter only the messages that are not archived.
* Filter only the messages that are archived.
*/
const generateFilteredMessagesState = (
const generateMessagesStateArchivedArray = (
potMessagesState: pot.Pot<ReadonlyArray<MessageState>, string>
): ReadonlyArray<MessageState> =>
pot.getOrElse(
Expand All @@ -77,22 +75,22 @@ const generateFilteredMessagesState = (
*/
class MessagesArchive extends React.PureComponent<Props, State> {
/**
* The function is used to update the filteredMessageStates only when necessary.
* Updates the filteredMessageStates only when necessary.
*/
public static getDerivedStateFromProps(
nextProps: Props,
prevState: State
): Partial<State> | null {
const { lastMessageStatesUpdate } = prevState;
const { lastMessagesState } = prevState;

if (lastMessageStatesUpdate !== nextProps.messagesStateInfo.lastUpdate) {
if (lastMessagesState !== nextProps.messagesState) {
// The list was updated, we need to re-apply the filter and
// save the result in the state.
return {
filteredMessageStates: generateFilteredMessagesState(
nextProps.messagesStateInfo.potMessagesState
filteredMessageStates: generateMessagesStateArchivedArray(
nextProps.messagesState
),
lastMessageStatesUpdate: nextProps.messagesStateInfo.lastUpdate
lastMessagesState: nextProps.messagesState
};
}

Expand All @@ -103,15 +101,13 @@ class MessagesArchive extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
lastMessageStatesUpdate: 0,
lastMessagesState: pot.none,
filteredMessageStates: []
};
}

public render() {
const isLoading = pot.isLoading(
this.props.messagesStateInfo.potMessagesState
);
const isLoading = pot.isLoading(this.props.messagesState);
const { selectedMessageIds, resetSelection } = this.props;

return (
Expand Down Expand Up @@ -144,6 +140,8 @@ class MessagesArchive extends React.PureComponent<Props, State> {

private handleOnPressItem = (id: string) => {
if (this.props.selectedMessageIds.isSome()) {
// Is the selection mode is active a simple "press" must act as
// a "longPress" (select the item).
this.handleOnLongPressItem(id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be handleOnPressItem ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to add a comment here. If we are in selection mode a "press" need act like the "longPress" (select the item).

} else {
this.props.navigateToMessageDetail(id);
Expand Down
14 changes: 6 additions & 8 deletions ts/components/messages/MessagesDeadlines.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { View } from "native-base";
import React, { ComponentProps } from "react";
import { StyleSheet } from "react-native";

import { lexicallyOrderedMessagesStateInfoSelector } from "../../store/reducers/entities/messages";
import { lexicallyOrderedMessagesStateSelector } from "../../store/reducers/entities/messages";
import { MessageState } from "../../store/reducers/entities/messages/messagesById";
import {
isMessageWithContentAndDueDatePO,
Expand Down Expand Up @@ -36,9 +36,7 @@ const styles = StyleSheet.create({
});

type OwnProps = {
messagesStateInfo: ReturnType<
typeof lexicallyOrderedMessagesStateInfoSelector
>;
messagesState: ReturnType<typeof lexicallyOrderedMessagesStateSelector>;
navigateToMessageDetail: (id: string) => void;
};

Expand Down Expand Up @@ -131,16 +129,16 @@ const generateSections = (
*/
class MessagesDeadlines extends React.PureComponent<Props, never> {
public render() {
const { messagesStateInfo, onRefresh } = this.props;
const isLoading = pot.isLoading(messagesStateInfo.potMessagesState);
const { messagesState, onRefresh } = this.props;
const isLoading = pot.isLoading(messagesState);

const sections = generateSections(messagesStateInfo.potMessagesState);
const sections = generateSections(messagesState);

return (
<View style={styles.listWrapper}>
<MessageAgenda
sections={sections}
refreshing={isLoading}
isRefreshing={isLoading}
onRefresh={onRefresh}
onPressItem={this.handleOnPressItem}
/>
Expand Down
34 changes: 17 additions & 17 deletions ts/components/messages/MessagesInbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React, { ComponentProps } from "react";
import { StyleSheet } from "react-native";

import I18n from "../../i18n";
import { lexicallyOrderedMessagesStateInfoSelector } from "../../store/reducers/entities/messages";
import { lexicallyOrderedMessagesStateSelector } from "../../store/reducers/entities/messages";
import { MessageState } from "../../store/reducers/entities/messages/messagesById";
import {
InjectedWithMessagesSelectionProps,
Expand Down Expand Up @@ -35,9 +35,7 @@ const styles = StyleSheet.create({
});

type OwnProps = {
messagesStateInfo: ReturnType<
typeof lexicallyOrderedMessagesStateInfoSelector
>;
messagesState: ReturnType<typeof lexicallyOrderedMessagesStateSelector>;
navigateToMessageDetail: (id: string) => void;
setMessagesArchivedState: (
ids: ReadonlyArray<string>,
Expand All @@ -53,14 +51,16 @@ type Props = Pick<
InjectedWithMessagesSelectionProps;

type State = {
lastMessageStatesUpdate: number;
filteredMessageStates: ReturnType<typeof generateFilteredMessagesState>;
lastMessagesState: ReturnType<typeof lexicallyOrderedMessagesStateSelector>;
filteredMessageStates: ReturnType<
typeof generateMessagesStateNotArchivedArray
>;
};

/**
* Filter only the messages that are not archived.
*/
const generateFilteredMessagesState = (
const generateMessagesStateNotArchivedArray = (
potMessagesState: pot.Pot<ReadonlyArray<MessageState>, string>
): ReadonlyArray<MessageState> =>
pot.getOrElse(
Expand All @@ -77,22 +77,22 @@ const generateFilteredMessagesState = (
*/
class MessagesInbox extends React.PureComponent<Props, State> {
/**
* The function is used to update the filteredMessageStates only when necessary.
* Updates the filteredMessageStates only when necessary.
*/
public static getDerivedStateFromProps(
nextProps: Props,
prevState: State
): Partial<State> | null {
const { lastMessageStatesUpdate } = prevState;
const { lastMessagesState } = prevState;

if (lastMessageStatesUpdate !== nextProps.messagesStateInfo.lastUpdate) {
if (lastMessagesState !== nextProps.messagesState) {
// The list was updated, we need to re-apply the filter and
// save the result in the state.
return {
filteredMessageStates: generateFilteredMessagesState(
nextProps.messagesStateInfo.potMessagesState
filteredMessageStates: generateMessagesStateNotArchivedArray(
nextProps.messagesState
),
lastMessageStatesUpdate: nextProps.messagesStateInfo.lastUpdate
lastMessagesState: nextProps.messagesState
};
}

Expand All @@ -103,15 +103,13 @@ class MessagesInbox extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
lastMessageStatesUpdate: 0,
lastMessagesState: pot.none,
filteredMessageStates: []
};
}

public render() {
const isLoading = pot.isLoading(
this.props.messagesStateInfo.potMessagesState
);
const isLoading = pot.isLoading(this.props.messagesState);
const { selectedMessageIds, resetSelection } = this.props;

return (
Expand Down Expand Up @@ -144,6 +142,8 @@ class MessagesInbox extends React.PureComponent<Props, State> {

private handleOnPressItem = (id: string) => {
if (this.props.selectedMessageIds.isSome()) {
// Is the selection mode is active a simple "press" must act as
// a "longPress" (select the item).
this.handleOnLongPressItem(id);
} else {
this.props.navigateToMessageDetail(id);
Expand Down
Loading