From 6cda405c0b098b27f30c64e1d90b1d1988f18439 Mon Sep 17 00:00:00 2001 From: Dhaverd Date: Fri, 8 May 2026 00:58:27 +0800 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B0=D0=B2=D0=B0=D0=BB=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D1=8B=20=D0=B2=20api,=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B8=D1=81=D0=BA,=20=D0=BF=D0=BE=D0=B4=D1=80?= =?UTF-8?q?=D0=B0=D0=B7=D0=B1=D0=B8=D0=BB=20=D0=BD=D0=B0=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 9 ++++ app/api.ts | 44 +++++++++++++++++ app/assets/mui/themes/home.ts | 74 ++++++++++++++++++++++++++++ app/assets/styles/home.css | 14 ++++++ app/components/itemList.tsx | 22 +++++++++ app/routes/home.tsx | 92 +++++++++++++---------------------- package.json | 1 + 7 files changed, 198 insertions(+), 58 deletions(-) create mode 100644 .gitignore create mode 100644 app/api.ts create mode 100644 app/assets/mui/themes/home.ts create mode 100644 app/components/itemList.tsx diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c969f23 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +.idea +/node_modules/ +*.tsbuildinfo + +# React Router +/.react-router/ +/build/ +package-lock.json \ No newline at end of file diff --git a/app/api.ts b/app/api.ts new file mode 100644 index 0000000..e7b1a62 --- /dev/null +++ b/app/api.ts @@ -0,0 +1,44 @@ +import axios, {type AxiosResponse} from "axios"; +import {ResponseError} from "~/classes/responseError"; +import {BlacklistItem} from "~/classes/blacklistItem"; + +const apiUrl = import.meta.env.VITE_API_URL; +const instance = axios.create({ + baseURL: apiUrl +}); + +const getReportData = (data: AxiosResponse): BlacklistItem[] => { + let result = data.data; + let blacklistItems: BlacklistItem[] = []; + for (const [key, value] of Object.entries(result)) { + let blacklistItem: BlacklistItem = new BlacklistItem( + value.link, + value.nicknames, + value.comments, + value.afk, + value.cheater, + value.griefer, + value.toxic, + value.useless, + ); + blacklistItems.push(blacklistItem); + } + return blacklistItems; +} + +export async function getAll(searchText?: string): Promise { + let result: BlacklistItem[] | ResponseError | undefined; + let route: string; + if (searchText !== ''){ + route = '/blacklist/search?text=' + searchText; + } else { + route = '/blacklist/all'; + } + result = await instance.get(route).then((data: AxiosResponse) => { + return getReportData(data); + }).catch(err => { + console.log(err); + return new ResponseError(err.code, err.message, err.status); + }); + return result; +} \ No newline at end of file diff --git a/app/assets/mui/themes/home.ts b/app/assets/mui/themes/home.ts new file mode 100644 index 0000000..e43fe21 --- /dev/null +++ b/app/assets/mui/themes/home.ts @@ -0,0 +1,74 @@ +import type {Theme} from "@mui/material"; +import {createTheme} from "@mui/material"; +import {outlinedInputClasses} from "@mui/material"; + +const customTheme = (outerTheme: Theme) => + createTheme({ + palette: { + mode: outerTheme.palette.mode, + }, + components: { + MuiTextField: { + styleOverrides: { + root: { + '--TextField-brandBorderColor': '#E0E3E7', + '--TextField-brandBorderHoverColor': '#B2BAC2', + '--TextField-brandBorderFocusedColor': '#6F7E8C', + '& label': { + color: 'var(--TextField-brandBorderColor)', + }, + '& label.Mui-focused': { + color: 'var(--TextField-brandBorderColor)', + }, + '& input': { + color: 'var(--TextField-brandBorderColor)', + borderColor: 'var(--TextField-brandBorderColor)', + }, + }, + }, + }, + MuiOutlinedInput: { + styleOverrides: { + notchedOutline: { + borderColor: 'var(--TextField-brandBorderColor)', + }, + root: { + [`&:hover .${outlinedInputClasses.notchedOutline}`]: { + borderColor: 'var(--TextField-brandBorderHoverColor)', + }, + [`&.Mui-focused .${outlinedInputClasses.notchedOutline}`]: { + borderColor: 'var(--TextField-brandBorderFocusedColor)', + }, + }, + }, + }, + MuiDivider: { + styleOverrides: { + root: { + '--TextField-brandBorderColor': '#E0E3E7', + borderColor: 'var(--TextField-brandBorderColor)', + borderWidth: 1, + width: '95%', + } + } + }, + MuiButton: { + styleOverrides: { + root: { + '--TextField-brandBorderColor': '#E0E3E7', + '--variant-outlinedBorder': '#b5b5b5', + '--variant-containedBg': '#b5b5b5', + '--variant-custom-textBg': 'rgba(246,246,248,0.06)', + color: 'var(--TextField-brandBorderColor)', + '&:hover': { + backgroundColor: 'var(--variant-custom-textBg)', + borderColor: 'var(--variant-custom-textBg)', + boxShadow: 'none', + }, + } + } + } + } + }); + +export default customTheme; \ No newline at end of file diff --git a/app/assets/styles/home.css b/app/assets/styles/home.css index bc80f3b..decc0e6 100644 --- a/app/assets/styles/home.css +++ b/app/assets/styles/home.css @@ -18,4 +18,18 @@ .bg-dark { background-color: #282c34; height: 100%; +} + +.list-container { + justify-items: center; +} + +.item-list { + display: flex; + flex-direction: column; + width: 100%; +} + +.loader { + text-align: center; } \ No newline at end of file diff --git a/app/components/itemList.tsx b/app/components/itemList.tsx new file mode 100644 index 0000000..40f78f9 --- /dev/null +++ b/app/components/itemList.tsx @@ -0,0 +1,22 @@ +import {BlacklistItem} from "~/classes/blacklistItem"; +import {Button, CircularProgress} from "@mui/material"; + +export default function ItemList({ isFetching, blacklistItems }: { isFetching: boolean, blacklistItems: BlacklistItem[] }) { + if (isFetching){ + return( +
+ +
+ ) + } else { + return ( +
+
+ {blacklistItems.map((item) => { + return + })} +
+
+ ) + } +} \ No newline at end of file diff --git a/app/routes/home.tsx b/app/routes/home.tsx index 7ad9cdb..0bd9f53 100644 --- a/app/routes/home.tsx +++ b/app/routes/home.tsx @@ -1,71 +1,42 @@ -import {useState} from "react"; +import {useEffect, useState} from "react"; import '../assets/styles/home.css'; import { - createTheme, Divider, - outlinedInputClasses, TextField, - type Theme, ThemeProvider, useTheme } from "@mui/material"; +import {getAll} from '~/api'; +import customTheme from "~/assets/mui/themes/home"; +import {BlacklistItem} from "~/classes/blacklistItem"; +import {ResponseError} from "~/classes/responseError"; +import ItemList from "~/components/itemList"; export default function Home() { - const [searchText, setSearchText] = useState(''); + const outerTheme = useTheme(); - const customTheme = (outerTheme: Theme) => - createTheme({ - palette: { - mode: outerTheme.palette.mode, - }, - components: { - MuiTextField: { - styleOverrides: { - root: { - '--TextField-brandBorderColor': '#E0E3E7', - '--TextField-brandBorderHoverColor': '#B2BAC2', - '--TextField-brandBorderFocusedColor': '#6F7E8C', - '& label': { - color: 'var(--TextField-brandBorderColor)', - }, - '& label.Mui-focused': { - color: 'var(--TextField-brandBorderColor)', - }, - '& input': { - color: 'var(--TextField-brandBorderColor)', - borderColor: 'var(--TextField-brandBorderColor)', - }, - }, - }, - }, - MuiOutlinedInput: { - styleOverrides: { - notchedOutline: { - borderColor: 'var(--TextField-brandBorderColor)', - }, - root: { - [`&:hover .${outlinedInputClasses.notchedOutline}`]: { - borderColor: 'var(--TextField-brandBorderHoverColor)', - }, - [`&.Mui-focused .${outlinedInputClasses.notchedOutline}`]: { - borderColor: 'var(--TextField-brandBorderFocusedColor)', - }, - }, - }, - }, - MuiDivider: { - styleOverrides: { - root: { - '--TextField-brandBorderColor': '#E0E3E7', - borderColor: 'var(--TextField-brandBorderColor)', - borderWidth: 1, - width: '95%', - } - } + const [searchText, setSearchText] = useState(''); + const [isFetchingList, setIsFetchingList] = useState(false); + const [blacklistItems, setBlacklistItems] = useState([]); + + useEffect(() => { + let isIgnore = false; + setIsFetchingList(true); + getAll(searchText).then((res: BlacklistItem[] | ResponseError | undefined)=> { + if (!isIgnore) { + if (res instanceof Array){ + setBlacklistItems(res); + } else if (res instanceof ResponseError) { + // TODO error handler + console.log(res); } + setIsFetchingList(false); } }); - const outerTheme = useTheme(); + return () => { + isIgnore = true; // При следующем изменении someValue старый запрос будет проигнорирован + }; + }, [searchText]); function handleSearch(text: string) { setSearchText(text); @@ -87,9 +58,14 @@ export default function Home() {
-
-

{searchText} //

-
+ + {/*
*/} + {/*
*/} + {/* {blacklistItems.map((item, i) => {*/} + {/* return */} + {/* })}*/} + {/*
*/} + {/*
*/} ); diff --git a/package.json b/package.json index 9c6e595..c9f3e5a 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@mui/material": "^7.3.7", "@react-router/express": "7.10.1", "@react-router/node": "7.10.1", + "axios": "^1.13.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "compression": "^1.8.1",