Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 79289457c9 | |||
| 5f386c0f4e | |||
| 33c8f863a1 | |||
|
|
dd16f42995 | ||
| f3e93bae19 | |||
| 07728cbbb0 | |||
| 17697d7f77 | |||
|
|
2829c11e4c | ||
|
|
0bcdb95b57 | ||
|
|
cabe02be57 | ||
|
|
59d4a44079 | ||
|
|
fde1f8ecfe | ||
|
|
9b4870995f | ||
|
|
2f447cef1a |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
node_modules
|
||||
.idea
|
||||
.idea
|
||||
coverage/
|
||||
1
__mocks__/fileMock.js
Normal file
1
__mocks__/fileMock.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = 'test-file-stub';
|
||||
11
__tests__/AccountButtons.test.tsx
Normal file
11
__tests__/AccountButtons.test.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import AccountButtons from '../src/components/account/AccountButtons.jsx';
|
||||
|
||||
describe('AccountButtons Component', () => {
|
||||
it('should render the Back link', () => {
|
||||
render(<AccountButtons registered={false} />);
|
||||
const backLinkElement = screen.getByRole('link', { name: /back/i });
|
||||
expect(backLinkElement).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
18
__tests__/ActionButton.test.tsx
Normal file
18
__tests__/ActionButton.test.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import ActionButton from '../src/components/account/ActionButton.jsx';
|
||||
|
||||
describe('ActionButton Component', () => {
|
||||
it('should render with the correct title and call the action when clicked', () => {
|
||||
const mockAction = jest.fn();
|
||||
const title = 'Click Me';
|
||||
|
||||
render(<ActionButton action={mockAction} title={title} />);
|
||||
|
||||
const buttonElement = screen.getByText(title);
|
||||
expect(buttonElement).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(buttonElement);
|
||||
expect(mockAction).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
23
__tests__/Card.test.tsx
Normal file
23
__tests__/Card.test.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import Card from '../src/components/home/Card.jsx';
|
||||
|
||||
describe('Card Component', () => {
|
||||
it('should render the Card component with the given ID', () => {
|
||||
const testId = '123';
|
||||
render(<Card id={testId} color={"FFA500FF"}/>);
|
||||
|
||||
const cardElement = screen.getByText(/123/i);
|
||||
expect(cardElement).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should store the ID in local storage when clicked', () => {
|
||||
const testId = '456';
|
||||
render(<Card id={testId} color={"FFA500FF"}/>);
|
||||
|
||||
const cardElement = screen.getByText(/456/i);
|
||||
fireEvent.click(cardElement);
|
||||
|
||||
expect(localStorage.setItem).toHaveBeenCalledWith('selectedId', testId);
|
||||
});
|
||||
});
|
||||
24
__tests__/Helloitem.test.tsx
Normal file
24
__tests__/Helloitem.test.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import HelloItem from '../src/components/account/HelloItem.jsx';
|
||||
|
||||
describe('HelloItem Component', () => {
|
||||
it('should display a personalized greeting when nickname is provided', () => {
|
||||
const nickname = 'JohnDoe';
|
||||
const id = '12345';
|
||||
|
||||
render(<HelloItem nickname={nickname} id={id} />);
|
||||
|
||||
const greetingElement = screen.getByText(`Hello, ${nickname}!`);
|
||||
const idElement = screen.getByText(`Your ID: ${id}`);
|
||||
expect(greetingElement).toBeInTheDocument();
|
||||
expect(idElement).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display a default message when nickname is not provided', () => {
|
||||
render(<HelloItem nickname="" id="12345" />);
|
||||
|
||||
const defaultMessage = screen.getByText("You don't have an account :(");
|
||||
expect(defaultMessage).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
60
__tests__/Home.test.jsx
Normal file
60
__tests__/Home.test.jsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { Provider } from "react-redux";
|
||||
import configureStore from "redux-mock-store";
|
||||
import Home from "src/pages/Home";
|
||||
import { useGetChatsQuery } from "src/backend/redux/api_slice";
|
||||
|
||||
// Mock Redux store
|
||||
const mockStore = configureStore([]);
|
||||
|
||||
// Mock the useGetChatsQuery hook
|
||||
jest.mock("src/backend/redux/api_slice", () => ({
|
||||
useGetChatsQuery: jest.fn(),
|
||||
}));
|
||||
|
||||
describe("Home Page", () => {
|
||||
let store;
|
||||
|
||||
beforeEach(() => {
|
||||
store = mockStore({});
|
||||
});
|
||||
|
||||
test("renders Home page with loading state", () => {
|
||||
useGetChatsQuery.mockReturnValue({ isLoading: true });
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<Home />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(/loading/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("renders Home page with chat data", () => {
|
||||
const chatsData = [{ id: 1, name: "Chat 1" }, { id: 2, name: "Chat 2" }];
|
||||
useGetChatsQuery.mockReturnValue({ data: chatsData, isLoading: false });
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<Home />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
expect(screen.getByText("Chat 1")).toBeInTheDocument();
|
||||
expect(screen.getByText("Chat 2")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("renders error message when fetching chats fails", () => {
|
||||
useGetChatsQuery.mockReturnValue({ error: true, isLoading: false });
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<Home />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
expect(screen.getByText(/error/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
41
__tests__/InputField.test.tsx
Normal file
41
__tests__/InputField.test.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import InputField from '../src/components/reg/InputField.jsx';
|
||||
|
||||
describe('InputField Component', () => {
|
||||
it('should render with the correct title and placeholder', () => {
|
||||
const title = 'Username';
|
||||
const placeholder = 'Enter your username';
|
||||
|
||||
render(<InputField title={title} placeholder={placeholder} value="" setValue={() => {}} />);
|
||||
|
||||
const titleElement = screen.getByText(title);
|
||||
const inputElement = screen.getByPlaceholderText(placeholder);
|
||||
|
||||
expect(titleElement).toBeInTheDocument();
|
||||
expect(inputElement).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call setValue on input change', () => {
|
||||
const mockSetValue = jest.fn();
|
||||
const newValue = 'testUser';
|
||||
|
||||
render(<InputField title="Username" value="" setValue={mockSetValue} />);
|
||||
|
||||
const inputElement = screen.getByRole('textbox');
|
||||
fireEvent.change(inputElement, { target: { value: newValue } });
|
||||
|
||||
expect(mockSetValue).toHaveBeenCalledWith(newValue);
|
||||
});
|
||||
|
||||
it('should call submit function when Enter key is pressed', () => {
|
||||
const mockSubmit = jest.fn();
|
||||
|
||||
render(<InputField title="Username" value="" setValue={() => {}} submit={mockSubmit} />);
|
||||
|
||||
const inputElement = screen.getByRole('textbox');
|
||||
fireEvent.keyDown(inputElement, { key: 'Enter', code: 'Enter' });
|
||||
|
||||
expect(mockSubmit).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
16
__tests__/NavButton.test.tsx
Normal file
16
__tests__/NavButton.test.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import NavButton from '../src/components/init/NavButton.jsx';
|
||||
|
||||
describe('NavButton Component', () => {
|
||||
it('should render the NavButton with the correct text and link', () => {
|
||||
const navLink = '/home';
|
||||
const buttonText = 'Go Home';
|
||||
|
||||
render(<NavButton nav={navLink} text={buttonText} />);
|
||||
|
||||
const linkElement = screen.getByText(buttonText);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
expect(linkElement.closest('a')).toHaveAttribute('href', navLink);
|
||||
});
|
||||
});
|
||||
23
__tests__/Search.test.tsx
Normal file
23
__tests__/Search.test.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import Search from '../src/components/home/Search.jsx';
|
||||
|
||||
describe('Search Component', () => {
|
||||
it('should render the Search button', () => {
|
||||
render(<Search search={() => {}} item="testItem" />);
|
||||
const searchButton = screen.getByText(/find/i);
|
||||
expect(searchButton).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call the search function with the correct item when clicked', () => {
|
||||
const mockSearch = jest.fn();
|
||||
const item = 'testItem';
|
||||
|
||||
render(<Search search={mockSearch} item={item} />);
|
||||
|
||||
const searchButton = screen.getByText(/find/i);
|
||||
fireEvent.click(searchButton);
|
||||
|
||||
expect(mockSearch).toHaveBeenCalledWith(item);
|
||||
});
|
||||
});
|
||||
52
__tests__/SignIn.test.jsx
Normal file
52
__tests__/SignIn.test.jsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import React from "react";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import SignIn from "src/pages/SignIn";
|
||||
import { displayMessage } from "src/backend/notifications/notifications";
|
||||
import { post } from "src/backend/api";
|
||||
|
||||
// Mock the displayMessage and post functions
|
||||
jest.mock("src/backend/notifications/notifications", () => ({
|
||||
displayMessage: jest.fn(),
|
||||
}));
|
||||
jest.mock("src/backend/api", () => ({
|
||||
post: jest.fn(),
|
||||
}));
|
||||
|
||||
describe("SignIn Page", () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test("renders SignIn form", () => {
|
||||
render(<SignIn />);
|
||||
expect(screen.getByLabelText(/username/i)).toBeInTheDocument();
|
||||
expect(screen.getByLabelText(/password/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/sign in/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("displays error message on failed login", async () => {
|
||||
post.mockResolvedValueOnce({ ok: false, data: { message: "Invalid credentials" } });
|
||||
|
||||
render(<SignIn />);
|
||||
fireEvent.change(screen.getByLabelText(/username/i), { target: { value: "user" } });
|
||||
fireEvent.change(screen.getByLabelText(/password/i), { target: { value: "password" } });
|
||||
fireEvent.click(screen.getByText(/sign in/i));
|
||||
|
||||
expect(await screen.findByText(/invalid credentials/i)).toBeInTheDocument();
|
||||
expect(displayMessage).toHaveBeenCalledWith("Invalid credentials", "error");
|
||||
});
|
||||
|
||||
test("displays additional info message after multiple login attempts", async () => {
|
||||
post.mockResolvedValueOnce({ ok: false, data: { message: "Invalid credentials" } });
|
||||
|
||||
render(<SignIn />);
|
||||
fireEvent.change(screen.getByLabelText(/username/i), { target: { value: "user" } });
|
||||
fireEvent.change(screen.getByLabelText(/password/i), { target: { value: "password" } });
|
||||
|
||||
// Simulate two failed login attempts
|
||||
fireEvent.click(screen.getByText(/sign in/i));
|
||||
fireEvent.click(screen.getByText(/sign in/i));
|
||||
|
||||
expect(displayMessage).toHaveBeenCalledWith("Note that you need to enter your ID name", "info");
|
||||
});
|
||||
});
|
||||
13
__tests__/helloworld.test.tsx.no
Normal file
13
__tests__/helloworld.test.tsx.no
Normal file
@@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
describe('Hello World Test', () => {
|
||||
it('should display hello world', () => {
|
||||
// Render a simple component
|
||||
render(<div>Hello World</div>);
|
||||
|
||||
// Check if "Hello World" is in the document
|
||||
const helloWorldElement = screen.getByText(/hello world/i);
|
||||
expect(helloWorldElement).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
7
babel.config.js
Normal file
7
babel.config.js
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@babel/preset-env',
|
||||
'@babel/preset-react',
|
||||
'@babel/preset-typescript'],
|
||||
};
|
||||
|
||||
28
jest.config.ts
Normal file
28
jest.config.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import type { Config } from 'jest';
|
||||
import { defaults } from 'jest-config';
|
||||
|
||||
const config: Config = {
|
||||
clearMocks: true,
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: [
|
||||
"src/components/**/*.{js,jsx,ts,tsx}", // Include all components
|
||||
"src/pages/**/*.{js,jsx,ts,tsx}",
|
||||
"!src/**/*.test.{js,jsx,ts,tsx}", // Exclude test files
|
||||
"!src/**/index.{js,jsx,ts,tsx}", // Optionally exclude index files
|
||||
],
|
||||
coverageDirectory: "coverage",
|
||||
coverageProvider: "v8",
|
||||
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
|
||||
testEnvironment: "jsdom",
|
||||
// transform: {
|
||||
// '^.+\\.(ts|tsx|js|jsx)$': 'babel-jest',
|
||||
// },
|
||||
moduleNameMapper: {
|
||||
"^@/src/(.*)$": "<rootDir>/src/$1", // Map '@/src' to the 'src' folder
|
||||
"^src/(.*)$": "<rootDir>/src/$1", // Map 'src' to the 'src' folder
|
||||
"\\.(svg|png|jpg|jpeg|gif)$": "<rootDir>/__mocks__/fileMock.js", // Add this line
|
||||
},
|
||||
moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts', 'tsx', 'js', 'jsx'],
|
||||
};
|
||||
|
||||
export default config;
|
||||
17
jest.setup.ts
Normal file
17
jest.setup.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { jest } from '@jest/globals';
|
||||
import '@testing-library/jest-dom';
|
||||
import mockedConfig from './bro.config.js'
|
||||
|
||||
jest.mock('@brojs/cli', () => {
|
||||
return {
|
||||
getNavigations() {
|
||||
return mockedConfig.navigations
|
||||
},
|
||||
getNavigationsValue(key) {
|
||||
return mockedConfig.navigations[key]
|
||||
},
|
||||
getConfigValue(key) {
|
||||
return mockedConfig.config[key]
|
||||
}
|
||||
}
|
||||
})
|
||||
5099
package-lock.json
generated
5099
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
23
package.json
23
package.json
@@ -3,6 +3,7 @@
|
||||
"@brojs/cli": "^1.0.0",
|
||||
"@brojs/create": "^1.0.0",
|
||||
"@ijl/cli": "^5.1.0",
|
||||
"@reduxjs/toolkit": "^2.3.0",
|
||||
"@types/react": "^18.3.5",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"dotenv": "^16.4.5",
|
||||
@@ -13,6 +14,7 @@
|
||||
"react-dom": "^18.3.1",
|
||||
"react-emoji-picker": "^1.0.13",
|
||||
"react-icons": "^5.3.0",
|
||||
"react-redux": "^9.1.2",
|
||||
"react-router-dom": "^6.26.1",
|
||||
"react-toastify": "^10.0.5",
|
||||
"socket.io": "^4.8.0",
|
||||
@@ -26,8 +28,25 @@
|
||||
"start": "brojs server --port=8099 --with-open-browser",
|
||||
"build": "npm run clean && brojs build --dev",
|
||||
"build:prod": "npm run clean && brojs build",
|
||||
"clean": "rimraf dist"
|
||||
"clean": "rimraf dist",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watchAll"
|
||||
},
|
||||
"name": "enterfront",
|
||||
"version": "0.5.1"
|
||||
"version": "0.5.4",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.8",
|
||||
"@babel/preset-env": "^7.25.8",
|
||||
"@babel/preset-react": "^7.25.7",
|
||||
"@babel/preset-typescript": "^7.25.7",
|
||||
"@testing-library/jest-dom": "^6.6.2",
|
||||
"@testing-library/react": "^16.0.1",
|
||||
"@types/jest": "^29.5.13",
|
||||
"babel-jest": "^29.7.0",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"redux-mock-store": "^1.5.4",
|
||||
"ts-jest": "^29.2.5",
|
||||
"ts-node": "^10.9.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@ import { Dashboard } from './dashboard';
|
||||
import {ToastContainer} from "react-toastify";
|
||||
import 'react-toastify/dist/ReactToastify.css';
|
||||
|
||||
import { Provider } from 'react-redux';
|
||||
import store from './backend/redux/store.js'; // Import your store
|
||||
|
||||
|
||||
import './index.css'
|
||||
import {displayMessage} from "./backend/notifications/notifications.js";
|
||||
@@ -26,13 +29,13 @@ const App = () => {
|
||||
}, []);
|
||||
|
||||
return(
|
||||
<div>
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<Dashboard />
|
||||
</BrowserRouter>
|
||||
|
||||
<ToastContainer/>
|
||||
</div>
|
||||
</Provider>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import {getConfigValue} from "@brojs/cli";
|
||||
const LOCAL = "http://localhost:8099";
|
||||
const DEV = "https://dev.bro-js.ru";
|
||||
|
||||
export const BASE_API_URL = DEV + getConfigValue("enterfront.api");
|
||||
export const BASE_API_URL = LOCAL + getConfigValue("enterfront.api");
|
||||
|
||||
// fetch(`${BASE_API_URL}/books/list`)
|
||||
|
||||
|
||||
34
src/backend/redux/api_slice.js
Normal file
34
src/backend/redux/api_slice.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
|
||||
import {getConfigValue} from "@brojs/cli";
|
||||
|
||||
import { BASE_API_URL } from "../api.js";
|
||||
|
||||
const baseQuery = fetchBaseQuery({
|
||||
baseUrl: BASE_API_URL,
|
||||
prepareHeaders: (headers) => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
headers.set('Authorization', `Bearer ${token}`);
|
||||
}
|
||||
return headers;
|
||||
},
|
||||
});
|
||||
|
||||
export const apiSlice = createApi({
|
||||
reducerPath: 'api',
|
||||
baseQuery,
|
||||
endpoints: (builder) => ({
|
||||
getChats: builder.query({
|
||||
query: (username) => `/chat/list/${username}`,
|
||||
}),
|
||||
postChat: builder.mutation({
|
||||
query: ({ id1, id2 }) => ({
|
||||
url: `/chat/item/${id1}/${id2}`,
|
||||
method: 'POST',
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
// Export hooks for usage in functional components
|
||||
export const { useGetChatsQuery, usePostChatMutation } = apiSlice;
|
||||
12
src/backend/redux/store.js
Normal file
12
src/backend/redux/store.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { configureStore } from '@reduxjs/toolkit';
|
||||
import { apiSlice } from './api_slice';
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
[apiSlice.reducerPath]: apiSlice.reducer,
|
||||
},
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware().concat(apiSlice.middleware),
|
||||
});
|
||||
|
||||
export default store;
|
||||
@@ -13,7 +13,7 @@ const InputField = (props) => {
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
if (props.submit) {
|
||||
props.enter(props.submit);
|
||||
props.submit();
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -4,39 +4,61 @@ import ChatsList from "../components/home/ChatsList.jsx";
|
||||
import Header from "../components/home/Header.jsx";
|
||||
import { displayMessage } from "../backend/notifications/notifications";
|
||||
import { MessageType } from "../backend/notifications/message";
|
||||
import { get, post } from "../backend/api";
|
||||
import { useGetChatsQuery, usePostChatMutation } from "../backend/redux/api_slice"; // Update the import based on your API slice
|
||||
import InputField from "../components/reg/InputField.jsx";
|
||||
import Search from "../components/home/Search.jsx";
|
||||
import { URLs } from "../__data__/urls";
|
||||
|
||||
const Home = () => {
|
||||
const [chats, setChats] = useState([]);
|
||||
const [chats, setChats] = useState([]); // Retained original variable name
|
||||
const [interlocutor, setInterlocutor] = useState("");
|
||||
|
||||
async function retrieveChats() {
|
||||
const username = localStorage.getItem("username");
|
||||
if (!username) {
|
||||
displayMessage("You're not logged in!", MessageType.WARN);
|
||||
return;
|
||||
const username = localStorage.getItem("username");
|
||||
|
||||
// Use Redux Queries
|
||||
const { data: chatsData, error: getError, isLoading: isGetting } = useGetChatsQuery(username, {
|
||||
skip: !username
|
||||
});
|
||||
|
||||
console.log('From Redux:', chatsData);
|
||||
|
||||
const [createChat, { error: postError }] = usePostChatMutation();
|
||||
|
||||
useEffect(() => {
|
||||
if (getError) {
|
||||
displayMessage(getError.message, MessageType.ERROR);
|
||||
}
|
||||
|
||||
const { ok, data } = await get("/chat/list/" + username);
|
||||
if (!ok) {
|
||||
displayMessage(data.message, MessageType.ERROR);
|
||||
return;
|
||||
if (getError) {
|
||||
displayMessage(getError.message, MessageType.ERROR);
|
||||
}
|
||||
}, [getError, postError]);
|
||||
|
||||
const sortedChats = data.chats.sort((a, b) => {
|
||||
const lastMessageA = new Date(a.lastMessageTimestamp);
|
||||
const lastMessageB = new Date(b.lastMessageTimestamp);
|
||||
return lastMessageB - lastMessageA;
|
||||
});
|
||||
useEffect(() => {
|
||||
if (chatsData) {
|
||||
// setChats(chatsData.chats);
|
||||
|
||||
setChats(sortedChats);
|
||||
}
|
||||
let data = chatsData.chats;
|
||||
|
||||
async function createChat(alias) {
|
||||
const username = localStorage.getItem("username");
|
||||
try {
|
||||
const sortedChats = [...data].sort((a, b) => {
|
||||
const lastMessageA = a.messages[a.messages.length - 1];
|
||||
const lastMessageB = b.messages[b.messages.length - 1];
|
||||
|
||||
const dateA = new Date(lastMessageA.timestamp);
|
||||
const dateB = new Date(lastMessageB.timestamp);
|
||||
|
||||
return dateB - dateA;
|
||||
});
|
||||
|
||||
setChats(sortedChats);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}, [chatsData]);
|
||||
|
||||
|
||||
const createChatHandler = async (alias) => {
|
||||
if (!username) {
|
||||
displayMessage("You're not logged in!", MessageType.WARN);
|
||||
return;
|
||||
@@ -44,42 +66,49 @@ const Home = () => {
|
||||
|
||||
displayMessage("Sent", MessageType.INFO);
|
||||
|
||||
const { ok, data } = await post("/chat/item/" + username + "/" + alias);
|
||||
if (!ok) {
|
||||
displayMessage(data.message, MessageType.ERROR);
|
||||
} else {
|
||||
try {
|
||||
const data = await createChat({ id1: alias, id2: username }).unwrap(); // Using unwrap to handle promise rejection
|
||||
localStorage.setItem("message", "Successfully opened chat!");
|
||||
localStorage.setItem("interlocutorId", alias);
|
||||
window.location.href = URLs.chat.url;
|
||||
} catch (error) {
|
||||
displayMessage(error.data.message, MessageType.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
retrieveChats();
|
||||
}, []);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="homeWrapper">
|
||||
<div className="headerPos">
|
||||
<Header />
|
||||
<div className="homeWrapper">
|
||||
<div className="headerPos">
|
||||
<Header />
|
||||
</div>
|
||||
|
||||
<HomeTitle />
|
||||
|
||||
<div className="search-input">
|
||||
<InputField
|
||||
title="Create new chat"
|
||||
value={interlocutor}
|
||||
setValue={setInterlocutor}
|
||||
placeholder="Enter the username (id)"
|
||||
|
||||
enter={createChatHandler}
|
||||
submit={interlocutor}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{isGetting ? (
|
||||
<div>Loading...</div>
|
||||
) : (
|
||||
<>
|
||||
<Search search={createChatHandler} item={interlocutor} />
|
||||
|
||||
<p>Your chats</p>
|
||||
<ChatsList chats={chats} />
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<HomeTitle />
|
||||
|
||||
<div className="search-input">
|
||||
<InputField
|
||||
title="Create new chat"
|
||||
value={interlocutor}
|
||||
setValue={setInterlocutor}
|
||||
placeholder="Enter the username (id)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Search search={createChat} item={interlocutor} />
|
||||
|
||||
<p>Your chats</p>
|
||||
<ChatsList chats={chats} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import LoginTitle from "../components/reg/loginTitle.jsx";
|
||||
import {MessageType} from "../backend/notifications/message.tsx";
|
||||
import {displayMessage} from "../backend/notifications/notifications.js";
|
||||
import {post} from "../backend/api.js";
|
||||
import {URLs} from "../__data__/urls";
|
||||
|
||||
const SignIn = () => {
|
||||
const [name, setName] = useState("");
|
||||
@@ -37,7 +38,7 @@ const SignIn = () => {
|
||||
setNameErrorsCounter(0);
|
||||
|
||||
localStorage.setItem('message', 'Successfully logged in!');
|
||||
window.location.href = "/";
|
||||
window.location.href = URLs.baseUrl;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -5,6 +5,7 @@ import LoginTitle from "../components/reg/loginTitle.jsx";
|
||||
import {post} from "../backend/api";
|
||||
import {displayMessage} from "../backend/notifications/notifications";
|
||||
import {MessageType} from "../backend/notifications/message";
|
||||
import { URLs } from "../__data__/urls";
|
||||
|
||||
|
||||
const SignUp = () => {
|
||||
@@ -47,7 +48,7 @@ const SignUp = () => {
|
||||
localStorage.setItem('username', name);
|
||||
|
||||
localStorage.setItem('message', 'Successfully signed up!');
|
||||
window.location.href = "/";
|
||||
window.location.href = URLs.baseUrl;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"target": "es6",
|
||||
"jsx": "react",
|
||||
"typeRoots": ["node_modules/@types", "src/typings"],
|
||||
"types" : ["webpack-env", "node"],
|
||||
"types" : ["webpack-env", "node", "jest"],
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"exclude": [
|
||||
|
||||
Reference in New Issue
Block a user