Skip to content

Commit

Permalink
feat(messaging): messageChannel conversations (#26)
Browse files Browse the repository at this point in the history
* feat(messaging): messageChannel conversations

Co-authored-by: Kuruyia <[email protected]>

---------

Signed-off-by: Mauran <[email protected]>
Co-authored-by: Kuruyia <[email protected]>
  • Loading branch information
thomas-mauran and Kuruyia authored Dec 8, 2023
1 parent 6ff3721 commit cc6de79
Show file tree
Hide file tree
Showing 16 changed files with 514 additions and 28 deletions.
3 changes: 2 additions & 1 deletion front/assets/translations/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
},
"messaging": {
"info": {
"messageChannel": "Messages"
"messageChannel": "Messages",
"textInputPlaceholer": "Your message"
}
},
"profile": {
Expand Down
3 changes: 2 additions & 1 deletion front/assets/translations/fr_FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
},
"messaging": {
"info": {
"messageChannel": "Messages"
"messageChannel": "Messages",
"textInputPlaceholer": "Votre message"
}
},
"profile": {
Expand Down
64 changes: 64 additions & 0 deletions front/src/components/messaging/MessageBubble.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { FC } from 'react';
import { StyleSheet, View } from 'react-native';
import { Text, useTheme } from 'react-native-paper';

import { Message, MessageDirection } from '@/models/entities/message';

/**
* The styles for the MessageBubble component.
*/
const styles = StyleSheet.create({
message: {
borderRadius: 10,
padding: 10,
},
});

/**
* The props for the MessageBubble component.
*/
type MessageBubbleProps = {
/**
* The message to display.
*/
message: Message;
};

/**
* Displays a message sent by a worker.
* @constructor
*/
const MessageBubble: FC<MessageBubbleProps> = ({ message }) => {
const theme = useTheme();

const backgroundColor =
message?.direction == MessageDirection.WorkerToEmployer
? theme.colors.primary
: theme.colors.tertiary;
const textAlign =
message?.direction == MessageDirection.EmployerToWorker ? 'left' : 'right';
const alignSelf =
message?.direction == MessageDirection.EmployerToWorker
? 'flex-start'
: 'flex-end';

return (
<View style={{ alignSelf }}>
<Text
variant='labelLarge'
style={[
styles.message,
{
backgroundColor,
color: theme.colors.onPrimary,
textAlign,
},
]}
>
{message.content}
</Text>
</View>
);
};

export default MessageBubble;
51 changes: 51 additions & 0 deletions front/src/components/messaging/MessageChannelContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { FC } from 'react';
import { StyleSheet, View } from 'react-native';

import { Message } from '@/models/entities/message';
import { MessageChannel } from '@/models/entities/messageChannel';

import MessageList from './MessageList';
import MessageTextInput from './MessageTextInput';

/**
* The styles for the MessageChannelContent component.
*/
const styles = StyleSheet.create({
container: {
flex: 1,
gap: 16,
},
});

/**
* The props for the MessageChannelContent component.
*/
type MessageChannelContentProps = {
/**
* The message channel to display.
*/
messageChannel: MessageChannel;

/**
* The messages of the message channel.
*/
messages: Message[];
};

/**
* Displays the the conversation of a message channel.
* @constructor
*/
const MessageChannelContent: FC<MessageChannelContentProps> = ({
messageChannel,
messages,
}) => {
return (
<View style={styles.container}>
<MessageList messages={messages} />
<MessageTextInput messageChannelId={messageChannel.id} />
</View>
);
};

export default MessageChannelContent;
36 changes: 36 additions & 0 deletions front/src/components/messaging/MessageList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { FC } from 'react';
import { ScrollView, StyleSheet, View } from 'react-native';

import { Message } from '@/models/entities/message';

import MessageBubble from './MessageBubble';

/**
* The styles for the MessageList component.
*/
const styles = StyleSheet.create({
container: {
gap: 30,
},
});

type MessageListProps = {
/**
* The list of messages of a message channels to display.
*/
messages: Message[];
};

const MessageList: FC<MessageListProps> = ({ messages }) => {
return (
<ScrollView contentContainerStyle={styles.container}>
{messages?.map((message) => (
<View key={message.id}>
<MessageBubble message={message} />
</View>
))}
</ScrollView>
);
};

export default MessageList;
62 changes: 62 additions & 0 deletions front/src/components/messaging/MessageTextInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { FC, useState } from 'react';
import { StyleSheet, View } from 'react-native';
import { IconButton, TextInput, useTheme } from 'react-native-paper';

import { usePostMessageMutation } from '@/store/api/messagingApiSlice';
import i18n from '@/utils/i18n';

/**
* The styles for the MessageTextInput component.
*/
const styles = StyleSheet.create({
container: {
alignItems: 'center',
flexDirection: 'row',
gap: 10,
},
textInput: {
flex: 1,
},
});

/**
* The props for the MessageTextInput component.
*/
type MessageTextInputProps = {
/**
* The messages channel id.
*/
messageChannelId: string;
};

const MessageTextInput: FC<MessageTextInputProps> = ({ messageChannelId }) => {
const theme = useTheme();
// API calls
const [content, setContent] = useState('');
const [postMessage] = usePostMessageMutation();

// Callbacks
const onSendPress = () => {
postMessage({ id: messageChannelId, content });
setContent('');
};
return (
<View style={styles.container}>
<TextInput
style={styles.textInput}
placeholder={i18n.t('messaging.info.textInputPlaceholer')}
value={content}
onChangeText={setContent}
mode={'outlined'}
/>
<IconButton
icon='send-outline'
onPress={onSendPress}
style={{ backgroundColor: theme.colors.primary }}
iconColor={theme.colors.onPrimary}
/>
</View>
);
};

export default MessageTextInput;
14 changes: 14 additions & 0 deletions front/src/models/dtos/messaging/createMessageDto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* DTO for creating a new message in a message channel.
*/
export type CreateMessageDto = {
/**
* The channel id.
*/
id: string;

/**
* The content of the message.
*/
content: string;
};
42 changes: 42 additions & 0 deletions front/src/models/entities/message.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* The direction of a message.
*/
export enum MessageDirection {
WorkerToEmployer = 0,
EmployerToWorker = 1,
}

/**
* Message channel.
*/
export type Message = {
/**
* The id of the message.
*/
id: string;

/**
* The id of the message channel the message was sent in.
*/
channelId: string;

/**
* The id of the employer.
*/
employerId: string;

/**
* The direction of the message.
*/
direction: MessageDirection;

/**
* The timestamp of the message.
*/
sentAt: string;

/**
* The content of the message.
*/
content: string;
};
16 changes: 14 additions & 2 deletions front/src/pages/messaging/MessageChannelListPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { FC, useCallback } from 'react';
import { ScrollView, StyleSheet } from 'react-native';

import MessagingList from '@/components/messaging/MessageChannelList';
import { MessageChannel } from '@/models/entities/messageChannel';
import { useGetMessageChannelsQuery } from '@/store/api/messagingApiSlice';

import { MessagingStackParamList } from './MessagingNav';
Expand Down Expand Up @@ -34,11 +35,19 @@ type MessagingListPageProps = NativeStackScreenProps<
* Displays the page of message channels for the current user.
* @constructor
*/
const MessageChannelListPage: FC<MessagingListPageProps> = () => {
const MessageChannelListPage: FC<MessagingListPageProps> = ({ navigation }) => {
// API calls
const { data: messageChannels, refetch: refetchMessageChannels } =
useGetMessageChannelsQuery();

// Callbacks
const handleMessageChannelPress = useCallback(
(messageChannel: MessageChannel) => {
navigation.navigate('MessageChannel', { id: messageChannel.id });
},
[navigation],
);

// Fetch data from the API when the page is focused
useFocusEffect(
useCallback(() => {
Expand All @@ -55,7 +64,10 @@ const MessageChannelListPage: FC<MessagingListPageProps> = () => {
style={styles.container}
contentContainerStyle={styles.contentContainer}
>
<MessagingList messageChannels={messageChannels} />
<MessagingList
onItemPress={handleMessageChannelPress}
messageChannels={messageChannels}
/>
</ScrollView>
);
};
Expand Down
Loading

0 comments on commit cc6de79

Please sign in to comment.