Skip to content

Commit

Permalink
add messageForm
Browse files Browse the repository at this point in the history
  • Loading branch information
Tatyana-js committed Jan 13, 2025
1 parent a459eb2 commit 0730852
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 41 deletions.
55 changes: 50 additions & 5 deletions frontend/src/api/chatApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

export const chatApi = createApi({
reducerPath: 'chatApi',
tagTypes: ['Channels', 'Messages'],
baseQuery: fetchBaseQuery({
baseUrl: '/api/v1',
prepareHeaders: (headers) => {
Expand All @@ -13,16 +14,60 @@ export const chatApi = createApi({
}
}),
endpoints: (builder) => ({
getChannels: builder.query({
query: () => 'channels',
getChannels: builder.query({ // Каналы
query: () => '/channels',
providesTags: ['Channels'],
}),
addChannel: builder.mutation ({
query: (channel) => ({
url: '/channels',
method: 'POST',
body: channel,
}),
invalidatesTags: ['Channels'],
}),
renameChannel: builder.mutation ({
query: ({ id, name }) => ({
url: `/channels/${id}`,
method: 'PATCH',
body: { name },
}),
invalidatesTags: ['Channels', 'Messages'],
}),
removeChannel: builder.mutation ({
query: (id) => ({
url: `/channels/${id}`,
method: 'DELETE',
}),
invalidatesTags: ['Channels', 'Messages'],
}),
getMessages: builder.query({ // Сообщения
query: () => '/messages',
providesTags: ['Messages'],
}),
addMessage: builder.mutation ({
query: (newMessege) => ({
url: 'messages',
method: 'POST',
body: newMessege,
}),
invalidatesTags: ['Messages'],
}),
removeMessage: builder.mutation ({
query: (id) => ({
url: `/messages/${id}`,
method: 'DELETE',
}),
invalidatesTags: ['Messages'],
}),
getMessages: builder.query({
query: () => 'messages',
})
}),
});

export const {
useGetChannelsQuery,
useGetMessagesQuery,
useAddChannelMutation,
useAddMessageMutation,
useRemoveChannelMutation,
useRemoveMessageMutation,
} = chatApi;
32 changes: 23 additions & 9 deletions frontend/src/components/MessageField.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { useSelector, useDispatch } from 'react-redux';
import { useRef } from 'react';
import { useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { activeChannelSelector } from '../store/activeChannelSlice.js';
import MessageForm from './MessageForm.jsx';
import { useGetMessagesQuery } from '../api/chatApi.js';
import useAuth from '../hooks/index.jsx';
import { useGetMessagesQuery, useAddMessageMutation } from '../api/chatApi.js';

const MessageField = () => {
const { t } = useTranslation();
const { data, error, isLoading, refetch } = useGetMessagesQuery();
const { t } = useTranslation();
const { data: messages = [], error, isLoading, refetch } = useGetMessagesQuery();
const [ addMessage ] = useAddMessageMutation();
const activeChannel = useSelector(activeChannelSelector);
const dispatch = useDispatch();
const messages = data;
const messagesEl = useRef(null);
const { username } = useAuth();
const countMessages = messages?.length || 0;
console.log(messages)
console.log(messages);

return (
<div className="d-flex flex-column h-100">
Expand All @@ -23,8 +26,19 @@ const MessageField = () => {
{t('countMessages.messages', { count: countMessages })}
</span>
</div>
<div id="messages-box" className="chat-messages overflow-auto px-5 ">{messages}</div>
<MessageForm />
<div id="messages-box" className="chat-messages overflow-auto px-5 "ref={messagesEl}>
{messages?.map(({ id, username, body}) => (
<div key={id} className='text-break mb-2'>
<b>{username}</b>
{`: ${body}`}
</div>
))}
</div>
<MessageForm
activeChannelId={activeChannel.id}
username={username}
addMessage={addMessage}
/>
</div>
);
};
Expand Down
48 changes: 38 additions & 10 deletions frontend/src/components/MessageForm.jsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,51 @@
import { Button, Form } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
import { useRef } from 'react';
import { useFormik } from 'formik';

const MessageForm = () => {
const MessageForm = ({ activeChannelId, username, addMessage }) => {
const { t } = useTranslation();
const formControlEl = useRef(null);
const formik = useFormik({
initialValues: {
body: '',
},
onSubmit: async (values, { setFieldValue }) => {
try {
const newMessege = { body: values.body, channelId: activeChannelId, username };
console.log(newMessege)
await addMessage(newMessege);
setFieldValue('body', newMessege.body);
formik.resetForm();
} catch (error) {

}
},
});
return (
<div className="mt-auto px-5 py-3">
<Form className="py-1 border rounded-2">
<Form.Group className="input-group">
<Form className="py-1 border rounded-2" onSubmit={formik.handleSubmit} noValidate>
<Form.Group className="input-group has-validation" >
<Form.Control
type="text"
placeholder="Введите сообщение..."
name="body"
required
aria-label={t('formMesseges.input')}
placeholder={t('formMesseges.placeholder')}
className="border-0 p-0 ps-2"
value=""
// onChange={handleChange}
value={formik.values.body}
ref={formControlEl}
onChange={formik.handleChange}
/>
<Button type="submit" variant="outline-secondary" disabled readOnly className="btn-group-vertical">
<Button
type="submit"
disabled={!formik.values.body}
className="btn-group-vertical"
variant="light">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="20" height="20" fill="currentColor">
<path fillRule="evenodd" d="M15 2a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1zM0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm4.5 5.5a.5.5 0 0 0 0 1h5.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3a.5.5 0 0 0 0-.708l-3-3a.5.5 0 1 0-.708.708L10.293 7.5z">
</path>
<path fillRule="evenodd" d="M15 2a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1zM0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm4.5 5.5a.5.5 0 0 0 0 1h5.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3a.5.5 0 0 0 0-.708l-3-3a.5.5 0 1 0-.708.708L10.293 7.5z" />
</svg>
<span className="visually-hidden">Отправить</span>
<span className="visually-hidden">{t('formMesseges.button')}</span>
</Button>

</Form.Group>
Expand Down
36 changes: 23 additions & 13 deletions frontend/src/components/Сhannels.jsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import { Nav, Button } from 'react-bootstrap';
import { Nav, Button, Spinner } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
import { useGetChannelsQuery } from '../api/chatApi.js';
import { useRef, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { selectActiveTab, activeChannelSelector } from '../store/activeChannelSlice.js';

const Channels = () => {
const { data, error, isLoading, refetch } = useGetChannelsQuery();
const { data: channels = [], error, isLoading, refetch } = useGetChannelsQuery();
const { t } = useTranslation();
const dispatch = useDispatch();
const channels = data;
const channelsRef = useRef(null);
const activeChannel = useSelector(activeChannelSelector);
useEffect(() => {
try {
if (isLoading) {

}
} catch (err) {
console.log(err);
}
}, []);
// useEffect(() => {
// try {
// if (isLoading) {
// return (
// <Spinner animation="border" role="status">
// <span className="visually-hidden">Loading...</span>
// </Spinner>
// );
// }
// } catch (error) {
// console.log(error.messege);
// }
// }, []);

return (
<Nav
Expand All @@ -27,7 +32,12 @@ return (
className="flex-column nav-pills nav-fill px-2 mb-3 overflow-auto h-100 d-block"
ref={channelsRef}
>
{channels?.map((channel) => {
{isLoading && (
<Spinner animation="border" role="status">
<span className="visually-hidden">{t('loading')}</span>
</Spinner>
)}
{channels.map((channel) => {
return (
<Nav.Item as="li" key={channel.id} className="w-100">
<Button
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/context/AuthProvider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const AuthProvider = ({ children }) => {
const [loggedIn, setLoggedIn] = useState(!!localStorage.getItem('token'));

const token = localStorage.getItem('token');

const username = localStorage.getItem('username');

const logIn = (token, username) => {
localStorage.setItem('token', token);
localStorage.setItem('username', username);
Expand All @@ -29,7 +30,7 @@ const AuthProvider = ({ children }) => {
}, []);

return (
<AuthContext.Provider value={{ loggedIn, logIn, logOut, token }}>
<AuthContext.Provider value={{ loggedIn, logIn, logOut, token, username }}>
{children}
</AuthContext.Provider>
);
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/locales/ru.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ export default {
messages_one: '{{count}} сообщение',
messages_fwe: '{{count}} сообщения',
messages_many: '{{count}} сообщений',
},
loading: 'Loading...',
formMesseges: {
placeholder: 'Введите сообщение...',
button: 'Отправить',
input: 'Новое сообщение',
}
// singUpForm: {
// username: ''
Expand Down
1 change: 0 additions & 1 deletion frontend/src/store/activeChannelSlice.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ const activeChannelSlice = createSlice({
reducers: {
selectActiveTab: (state, { payload }) => {
state.currentChannel = payload;
// console.log(payload);
},
},
});
Expand Down
1 change: 0 additions & 1 deletion frontend/src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import activeChannelReducer from './activeChannelSlice.js';
const rootReducer = combineReducers({
[chatApi.reducerPath]: chatApi.reducer,
activeChannel: activeChannelReducer,
// messages: mesagesReducer,
});

const store = configureStore ({
Expand Down

0 comments on commit 0730852

Please sign in to comment.