From 133850da1c1dd3f9a6b2cfe745becffeb0a6d21d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Fri, 26 Jul 2024 23:55:12 +0200 Subject: [PATCH] feat: update front layout --- assets/App.tsx | 61 +++++++---- assets/index.tsx | 2 +- assets/pages/LoginPage.tsx | 8 +- assets/pages/UserPage.tsx | 7 -- assets/pages/info/TldPage.tsx | 164 ++++++++++++++++++++++++++++- assets/pages/watchdog/UserPage.tsx | 7 ++ assets/utils/api/index.ts | 2 +- assets/utils/api/tld.ts | 2 +- src/Entity/Tld.php | 1 - 9 files changed, 214 insertions(+), 40 deletions(-) delete mode 100644 assets/pages/UserPage.tsx create mode 100644 assets/pages/watchdog/UserPage.tsx diff --git a/assets/App.tsx b/assets/App.tsx index efbc5e0..76ebf8e 100644 --- a/assets/App.tsx +++ b/assets/App.tsx @@ -14,7 +14,7 @@ import { TeamOutlined, UserOutlined } from "@ant-design/icons"; -import {Navigate, Route, Routes, useLocation, useNavigate} from "react-router-dom"; +import {Link, Navigate, Route, Routes, useLocation, useNavigate} from "react-router-dom"; import TextPage from "./pages/TextPage"; import tos from "./content/tos.md"; import privacy from "./content/privacy.md"; @@ -24,7 +24,7 @@ import NameserverSearchPage from "./pages/search/NameserverSearchPage"; import TldPage from "./pages/info/TldPage"; import StatisticsPage from "./pages/info/StatisticsPage"; import WatchlistsPage from "./pages/tracking/WatchlistsPage"; -import UserPage from "./pages/UserPage"; +import UserPage from "./pages/watchdog/UserPage"; import React, {useCallback, useEffect, useMemo, useState} from "react"; import {getUser} from "./utils/api"; import FAQPage from "./pages/FAQPage"; @@ -38,9 +38,12 @@ export default function App() { } = theme.useToken() const navigate = useNavigate() - const [isAuthenticated, setIsAuthenticated] = useState(false) const location = useLocation() + + const [isAuthenticated, setIsAuthenticated] = useState(false) + + const authenticated = useCallback((authenticated: boolean) => { setIsAuthenticated(authenticated) }, []); @@ -65,6 +68,7 @@ export default function App() { { key: '1', label: 'Search', + icon: , children: [ { key: '1-1', @@ -95,11 +99,13 @@ export default function App() { { key: '2', label: 'Information', + icon: , children: [ { key: '2-1', icon: , label: 'TLD', + title: 'TLD list', disabled: !isAuthenticated, onClick: () => navigate('/info/tld') }, @@ -115,11 +121,11 @@ export default function App() { { key: '3', label: 'Tracking', + icon: , children: [ { key: '3-1', - icon: , + icon: , label: 'My Watchlists', disabled: !isAuthenticated, onClick: () => navigate('/tracking/watchlist') @@ -135,10 +141,29 @@ export default function App() { }, { key: '4', + label: 'My Watchdog', icon: , - label: 'My Account', - disabled: !isAuthenticated, - onClick: () => navigate('/user') + children: [ + { + key: '4-1', + icon: , + label: 'My Account', + disabled: !isAuthenticated, + onClick: () => navigate('/user') + }, + { + key: '4-2', + icon: , + label: 'TOS', + onClick: () => navigate('/tos') + }, + { + key: '4-3', + icon: , + label: 'Privacy Policy', + onClick: () => navigate('/privacy') + } + ] }, { key: '5', @@ -146,27 +171,16 @@ export default function App() { label: 'FAQ', onClick: () => navigate('/faq') }, - { - key: '6', - icon: , - label: 'TOS', - onClick: () => navigate('/tos') - }, - { - key: '7', - icon: , - label: 'Privacy Policy', - onClick: () => navigate('/privacy') - } + ] return - + - Domain Watchdog ©{new Date().getFullYear()} Created by Maël Gangloff + Domain + Watchdog ©{new Date().getFullYear()} Created by Maël Gangloff diff --git a/assets/index.tsx b/assets/index.tsx index ea7d05d..52f77cc 100644 --- a/assets/index.tsx +++ b/assets/index.tsx @@ -3,7 +3,7 @@ import ReactDOM from "react-dom/client"; import App from "./App"; import {HashRouter} from "react-router-dom"; -import './index.css' +import 'antd/dist/reset.css'; const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement) diff --git a/assets/pages/LoginPage.tsx b/assets/pages/LoginPage.tsx index e25bc0d..6c27422 100644 --- a/assets/pages/LoginPage.tsx +++ b/assets/pages/LoginPage.tsx @@ -1,4 +1,4 @@ -import React, {createContext, useContext, useEffect, useState} from "react"; +import React, {createContext, useContext, useState} from "react"; import {Alert, Button, Card, Flex, Form, Input} from "antd"; import {login} from "../utils/api"; import {useNavigate} from "react-router-dom"; @@ -28,7 +28,6 @@ export default function Page() { return {error && + + + diff --git a/assets/pages/UserPage.tsx b/assets/pages/UserPage.tsx deleted file mode 100644 index 7d612d5..0000000 --- a/assets/pages/UserPage.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import React from "react"; - -export default function Page() { - return

- Hey -

-} \ No newline at end of file diff --git a/assets/pages/info/TldPage.tsx b/assets/pages/info/TldPage.tsx index 727e674..f9de4ce 100644 --- a/assets/pages/info/TldPage.tsx +++ b/assets/pages/info/TldPage.tsx @@ -1,7 +1,163 @@ -import React from "react"; +import React, {useEffect, useState} from "react"; +import {Collapse, Divider, Table, Typography} from "antd"; +import {getTldList, Tld} from "../../utils/api"; + +const {Text, Paragraph} = Typography + +type TldType = 'iTLD' | 'sTLD' | 'gTLD' | 'ccTLD' +type FiltersType = { type: TldType, contractTerminated?: boolean, specification13?: boolean } + + +const toEmoji = (tld: string) => String.fromCodePoint( + ...getCountryCode(tld) + .toUpperCase() + .split('') + .map((char) => 127397 + char.charCodeAt(0) + ) +) + +const getCountryCode = (tld: string): string => { + const exceptions = {uk: 'gb', su: 'ru', tp: 'tl'} + if (tld in exceptions) return exceptions[tld as keyof typeof exceptions] + return tld +} + +const regionNames = new Intl.DisplayNames(['en'], {type: 'region'}) + + +function TldTable(filters: FiltersType) { + const [dataTable, setDataTable] = useState([]) + const [total, setTotal] = useState(0) + + const fetchData = (params: FiltersType & { page: number }) => { + getTldList(params).then((data) => { + setTotal(data['hydra:totalItems']) + setDataTable(data['hydra:member'].map((tld: Tld) => { + switch (filters.type) { + case 'ccTLD': + return { + TLD: tld.tld, + Flag: toEmoji(tld.tld), + Country: regionNames.of(getCountryCode(tld.tld)) ?? '-' + } + case 'gTLD': + return { + TLD: tld.tld, + Operator: tld.registryOperator + } + default: + return { + TLD: tld.tld + } + } + })) + }) + } + + useEffect(() => { + fetchData({...filters, page: 1}) + }, []) + + let columns = [ + { + title: "TLD", + dataIndex: "TLD", + width: 20 + } + ] + + if (filters.type === 'ccTLD') columns = [...columns, { + title: "Flag", + dataIndex: "Flag", + width: 20 + }, { + title: "Country", + dataIndex: "Country", + width: 200 + }] + + if (filters.type === 'gTLD') columns = [...columns, { + title: "Registry Operator", + dataIndex: "Operator", + width: 50 + }] + + + return { + fetchData({...filters, page}) + } + }} + scroll={{y: 240}} + /> +} + export default function TldPage() { - return

- Tld Page -

+ return <> + + This page presents all active TLDs in the root zone database. + + + IANA provides the list of currently active + TLDs, regardless of their type, and ICANN provides the list of gTLDs. + In most cases, the two-letter ccTLD assigned to a country is made in accordance with the ISO 3166-1 + standard. + This data is updated every month. Three HTTP requests are needed for the complete update of TLDs in Domain + Watchdog (two requests to IANA and one to ICANN). + At the same time, the list of root RDAP servers is updated. + + + + Top-level domains sponsored by specific organizations that set rules for + registration and use, often related to particular interest groups or + industries. + + + + }, + { + key: 'gTLD', + label: 'Generic Top-Level-Domains', + children: <> + Generic top-level domains open to everyone, not restricted by specific + criteria, representing various themes or industries. + + + + }, + { + key: 'ngTLD', + label: 'Brand Generic Top-Level-Domains', + children: <> + Generic top-level domains associated with specific brands, allowing companies + to use their own brand names as domains. + + + + }, + { + key: 'ccTLD', + label: 'Country-Code Top-Level-Domains', + children: <> + Top-level domains based on country codes, identifying websites according to + their country of origin. + + + } + ]} + /> + } \ No newline at end of file diff --git a/assets/pages/watchdog/UserPage.tsx b/assets/pages/watchdog/UserPage.tsx new file mode 100644 index 0000000..4f268a6 --- /dev/null +++ b/assets/pages/watchdog/UserPage.tsx @@ -0,0 +1,7 @@ +import React from "react"; + +export default function UserPage() { + return

+ My Account Page +

+} \ No newline at end of file diff --git a/assets/utils/api/index.ts b/assets/utils/api/index.ts index 8aff77a..b931c03 100644 --- a/assets/utils/api/index.ts +++ b/assets/utils/api/index.ts @@ -55,7 +55,7 @@ export async function request, D = any>(config: Ax withCredentials: true, headers: { ...config.headers, - Accept: 'application/json' + Accept: 'application/ld+json' } } return await axios.request(axiosConfig) diff --git a/assets/utils/api/tld.ts b/assets/utils/api/tld.ts index b2742d8..3f2a698 100644 --- a/assets/utils/api/tld.ts +++ b/assets/utils/api/tld.ts @@ -7,7 +7,7 @@ interface Tld { specification13: boolean } -export async function getTldList(params: object): Promise { +export async function getTldList(params: object): Promise { return (await request({ url: 'tld', params, diff --git a/src/Entity/Tld.php b/src/Entity/Tld.php index 773c4ea..85ee969 100644 --- a/src/Entity/Tld.php +++ b/src/Entity/Tld.php @@ -21,7 +21,6 @@ use Symfony\Component\Serializer\Attribute\Groups; operations: [ new GetCollection( uriTemplate: '/tld', - paginationItemsPerPage: 200, normalizationContext: ['groups' => ['tld:list']] ), new Get(