+
+
);
};
diff --git a/frontend/src/components/SymbolsView/src/desktopInfo.css b/frontend/src/components/SymbolsView/src/desktopInfo.css
index efe9d55..157aaca 100644
--- a/frontend/src/components/SymbolsView/src/desktopInfo.css
+++ b/frontend/src/components/SymbolsView/src/desktopInfo.css
@@ -1,3 +1,7 @@
+.desktopInfo {
+ overflow: hidden;
+}
+
@media (max-width: 1023px) {
.desktopInfo {
display: none;
diff --git a/frontend/src/components/SymbolsView/symbolsView.css b/frontend/src/components/SymbolsView/symbolsView.css
new file mode 100644
index 0000000..563b135
--- /dev/null
+++ b/frontend/src/components/SymbolsView/symbolsView.css
@@ -0,0 +1,27 @@
+.symbolsView,
+.symbolsView__content {
+ display: grid;
+ overflow: hidden;
+}
+
+.symbolsView__chart {
+ padding: 12px 12px 24px;
+}
+
+.symbolsView__cards {
+ padding: 16px;
+ background-color: #dbdbdb;
+ overflow-y: auto;
+ overflow-x: hidden;
+ scrollbar-width: none;
+}
+
+@media (min-width: 1024px) {
+ .symbolsView__content {
+ grid-template-columns: 1fr 400px;
+ }
+
+ .symbolsView__chart {
+ order: 1;
+ }
+}
diff --git a/frontend/src/helpers/currency.ts b/frontend/src/helpers/currency.ts
new file mode 100644
index 0000000..5b30af9
--- /dev/null
+++ b/frontend/src/helpers/currency.ts
@@ -0,0 +1,11 @@
+const addCurrency = (value: number | string) => {
+ return `$${value}`;
+};
+
+const getInteger = (amount: number) => Math.ceil(amount);
+
+const showShortenedAmount = (amount: number) => {
+ return addCurrency(Intl.NumberFormat('en', { notation: 'compact' }).format(amount));
+};
+
+export { addCurrency, getInteger, showShortenedAmount };
diff --git a/frontend/src/hooks/useAddBoxShadow.ts b/frontend/src/hooks/useAddBoxShadow.ts
new file mode 100644
index 0000000..b993d2e
--- /dev/null
+++ b/frontend/src/hooks/useAddBoxShadow.ts
@@ -0,0 +1,19 @@
+import { useState } from 'react';
+
+export default () => {
+ const [shadow, setShadow] = useState('');
+
+ const addShadow = (price: number, prevPrice = 0) => {
+ if (price > prevPrice) {
+ setShadow('green');
+ return;
+ }
+
+ if (price < prevPrice) {
+ setShadow('red');
+ return;
+ }
+ };
+
+ return { shadow, addShadow, setShadow };
+};
diff --git a/frontend/src/hooks/useAddEffect.ts b/frontend/src/hooks/useAddEffect.ts
new file mode 100644
index 0000000..91c43df
--- /dev/null
+++ b/frontend/src/hooks/useAddEffect.ts
@@ -0,0 +1,17 @@
+import { useState } from 'react';
+
+export default () => {
+ const [effect, setEffect] = useState('');
+
+ const addEffect = (price: number, prevPrice: number) => {
+ if (price > prevPrice) {
+ const increasePercent = (100 * (price - prevPrice)) / prevPrice;
+
+ if (increasePercent >= 25) {
+ setEffect('shake');
+ }
+ }
+ };
+
+ return { effect, setEffect, addEffect };
+};
diff --git a/frontend/src/router/index.tsx b/frontend/src/router/index.tsx
index 105644d..f6a76c9 100644
--- a/frontend/src/router/index.tsx
+++ b/frontend/src/router/index.tsx
@@ -1,16 +1,28 @@
-import SymbolsView from '@/components/SymbolsView';
-import { Route, Routes, Navigate } from 'react-router-dom';
-import StatementsView from "@/components/StatementsView";
-import ProfileView from "@/components/ProfileView";
+import { Route, Routes, Navigate, Outlet } from 'react-router-dom';
+import { lazy, Suspense } from 'react';
+
+const SymbolsView = lazy(() => import('@/components/SymbolsView'));
+const StatementsView = lazy(() => import('@/components/StatementsView'));
+const ProfileView = lazy(() => import('@/components/ProfileView'));
+
+function Layout() {
+ return (
+
+
+
+ );
+}
const Router = () => {
return (
-
+
+ }>
} />
} />
} />
} />
-
+
+
);
};
diff --git a/frontend/src/store/stocksSlice.ts b/frontend/src/store/stocksSlice.ts
index e7eb911..25f09b0 100644
--- a/frontend/src/store/stocksSlice.ts
+++ b/frontend/src/store/stocksSlice.ts
@@ -1,7 +1,7 @@
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { RootState } from '@/store/index';
-type Stock = {
+export type Stock = {
symbol: string;
companyName: string;
industry: string;
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index a24c0b9..872606f 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -850,7 +850,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/react@npm:*, @types/react@npm:^18.0.28":
+"@types/react@npm:*":
version: 18.0.31
resolution: "@types/react@npm:18.0.31"
dependencies:
@@ -861,6 +861,16 @@ __metadata:
languageName: node
linkType: hard
+"@types/react@npm:latest":
+ version: 18.3.12
+ resolution: "@types/react@npm:18.3.12"
+ dependencies:
+ "@types/prop-types": "*"
+ csstype: ^3.0.2
+ checksum: 4ab1577a8c2105a5e316536f724117c90eee5f4bd5c137fc82a2253d8c1fd299dedaa07e8dfc95d6e2f04a4be3cb8b0e1b06098c6233ebd55c508d88099395b7
+ languageName: node
+ linkType: hard
+
"@types/scheduler@npm:*":
version: 0.16.3
resolution: "@types/scheduler@npm:0.16.3"
@@ -1767,7 +1777,7 @@ __metadata:
dependencies:
"@reduxjs/toolkit": ^1.9.3
"@types/node": ^22.5.4
- "@types/react": ^18.0.28
+ "@types/react": latest
"@types/react-dom": ^18.0.11
"@types/vite-plugin-react-svg": ^0.2.2
"@vitejs/plugin-react": ^3.1.0
diff --git a/yarn.lock b/yarn.lock
index 0141185..eeef3c2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -824,7 +824,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/react@npm:*, @types/react@npm:^18.0.28":
+"@types/react@npm:*":
version: 18.3.5
resolution: "@types/react@npm:18.3.5"
dependencies:
@@ -834,6 +834,16 @@ __metadata:
languageName: node
linkType: hard
+"@types/react@npm:^18.3.12":
+ version: 18.3.12
+ resolution: "@types/react@npm:18.3.12"
+ dependencies:
+ "@types/prop-types": "*"
+ csstype: ^3.0.2
+ checksum: 4ab1577a8c2105a5e316536f724117c90eee5f4bd5c137fc82a2253d8c1fd299dedaa07e8dfc95d6e2f04a4be3cb8b0e1b06098c6233ebd55c508d88099395b7
+ languageName: node
+ linkType: hard
+
"@types/strip-bom@npm:^3.0.0":
version: 3.0.0
resolution: "@types/strip-bom@npm:3.0.0"
@@ -2303,7 +2313,7 @@ __metadata:
dependencies:
"@reduxjs/toolkit": ^1.9.3
"@types/node": ^22.5.4
- "@types/react": ^18.0.28
+ "@types/react": ^18.3.12
"@types/react-dom": ^18.0.11
"@types/vite-plugin-react-svg": ^0.2.2
"@vitejs/plugin-react": ^3.1.0