2024-12-30 23:50:15 +01:00
|
|
|
import {Button, ConfigProvider, FloatButton, Layout, Space, theme, Tooltip, Typography} from 'antd'
|
|
|
|
|
import {Link, Navigate, Route, Routes, useLocation, useNavigate} from 'react-router-dom'
|
|
|
|
|
import TextPage from './pages/TextPage'
|
|
|
|
|
import DomainSearchPage from './pages/search/DomainSearchPage'
|
|
|
|
|
import EntitySearchPage from './pages/search/EntitySearchPage'
|
|
|
|
|
import NameserverSearchPage from './pages/search/NameserverSearchPage'
|
2025-09-14 17:59:26 +02:00
|
|
|
import TldPage from './pages/infrastructure/TldPage'
|
2024-12-30 23:50:15 +01:00
|
|
|
import StatisticsPage from './pages/StatisticsPage'
|
|
|
|
|
import WatchlistPage from './pages/tracking/WatchlistPage'
|
|
|
|
|
import UserPage from './pages/UserPage'
|
|
|
|
|
import React, {useCallback, useEffect, useMemo, useState} from 'react'
|
|
|
|
|
import {getUser} from './utils/api'
|
|
|
|
|
import LoginPage, {AuthenticatedContext} from './pages/LoginPage'
|
|
|
|
|
import ConnectorPage from './pages/tracking/ConnectorPage'
|
|
|
|
|
import NotFoundPage from './pages/NotFoundPage'
|
|
|
|
|
import useBreakpoint from './hooks/useBreakpoint'
|
|
|
|
|
import {Sider} from './components/Sider'
|
|
|
|
|
import {jt, t} from 'ttag'
|
2024-12-24 18:02:33 +01:00
|
|
|
import {BugOutlined, InfoCircleOutlined, MergeOutlined} from '@ant-design/icons'
|
2024-12-30 23:50:15 +01:00
|
|
|
import TrackedDomainPage from './pages/tracking/TrackedDomainPage'
|
2025-09-14 17:59:26 +02:00
|
|
|
import IcannRegistrarPage from "./pages/infrastructure/IcannRegistrarPage";
|
2024-08-04 02:10:47 +02:00
|
|
|
|
2024-12-24 18:02:33 +01:00
|
|
|
const PROJECT_LINK = 'https://github.com/maelgangloff/domain-watchdog'
|
|
|
|
|
const LICENSE_LINK = 'https://www.gnu.org/licenses/agpl-3.0.txt'
|
|
|
|
|
|
|
|
|
|
const ProjectLink = <Typography.Link target='_blank' href={PROJECT_LINK}>Domain Watchdog</Typography.Link>
|
|
|
|
|
const LicenseLink = <Typography.Link target='_blank' href={LICENSE_LINK}>AGPL-3.0-or-later</Typography.Link>
|
2024-07-26 16:45:10 +02:00
|
|
|
|
2024-12-30 23:50:15 +01:00
|
|
|
export default function App(): React.ReactElement {
|
2024-07-26 16:45:10 +02:00
|
|
|
const navigate = useNavigate()
|
2024-07-26 18:31:47 +02:00
|
|
|
const location = useLocation()
|
2024-07-30 06:13:31 +02:00
|
|
|
const sm = useBreakpoint('sm')
|
2024-07-26 18:31:47 +02:00
|
|
|
|
2024-07-26 23:55:12 +02:00
|
|
|
const [isAuthenticated, setIsAuthenticated] = useState(false)
|
|
|
|
|
|
2024-07-26 18:31:47 +02:00
|
|
|
const authenticated = useCallback((authenticated: boolean) => {
|
|
|
|
|
setIsAuthenticated(authenticated)
|
2024-12-30 23:50:15 +01:00
|
|
|
}, [])
|
2024-07-26 16:45:10 +02:00
|
|
|
|
2024-07-26 18:31:47 +02:00
|
|
|
const contextValue = useMemo(() => ({
|
|
|
|
|
authenticated,
|
|
|
|
|
setIsAuthenticated
|
2024-08-23 22:24:11 +02:00
|
|
|
}), [authenticated, setIsAuthenticated])
|
|
|
|
|
|
2024-12-30 23:50:15 +01:00
|
|
|
const [darkMode, setDarkMode] = useState(false)
|
2024-12-20 20:21:05 +01:00
|
|
|
|
2024-12-30 23:50:15 +01:00
|
|
|
const windowQuery = window.matchMedia('(prefers-color-scheme:dark)')
|
2024-12-20 20:21:05 +01:00
|
|
|
const darkModeChange = useCallback((event: MediaQueryListEvent) => {
|
|
|
|
|
setDarkMode(event.matches)
|
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2024-12-30 23:50:15 +01:00
|
|
|
windowQuery.addEventListener('change', darkModeChange)
|
2024-12-20 20:21:05 +01:00
|
|
|
return () => {
|
2024-12-30 23:50:15 +01:00
|
|
|
windowQuery.removeEventListener('change', darkModeChange)
|
2024-12-20 20:21:05 +01:00
|
|
|
}
|
|
|
|
|
}, [windowQuery, darkModeChange])
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
setDarkMode(windowQuery.matches)
|
2024-07-26 18:31:47 +02:00
|
|
|
getUser().then(() => {
|
|
|
|
|
setIsAuthenticated(true)
|
2024-08-02 16:17:55 +02:00
|
|
|
if (location.pathname === '/login') navigate('/home')
|
2024-07-26 18:31:47 +02:00
|
|
|
}).catch(() => {
|
|
|
|
|
setIsAuthenticated(false)
|
2024-08-06 17:34:45 +02:00
|
|
|
const pathname = location.pathname
|
|
|
|
|
if (!['/login', '/tos', '/faq', '/privacy'].includes(pathname)) navigate('/home')
|
2024-07-26 18:31:47 +02:00
|
|
|
})
|
2024-12-20 20:21:05 +01:00
|
|
|
}, [])
|
|
|
|
|
|
2024-12-30 23:50:15 +01:00
|
|
|
return (
|
|
|
|
|
<ConfigProvider
|
|
|
|
|
theme={{
|
2025-01-20 13:13:02 +01:00
|
|
|
algorithm: darkMode ? theme.darkAlgorithm : undefined
|
2024-12-30 23:50:15 +01:00
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<AuthenticatedContext.Provider value={contextValue}>
|
|
|
|
|
<Layout hasSider style={{minHeight: '100vh'}}>
|
|
|
|
|
{/* Ant will use a break-off tab to toggle the collapse of the sider when collapseWidth = 0 */}
|
|
|
|
|
<Layout.Sider collapsible breakpoint='sm' width={220} {...(sm ? {collapsedWidth: 0} : {})}>
|
|
|
|
|
<Sider isAuthenticated={isAuthenticated}/>
|
|
|
|
|
</Layout.Sider>
|
|
|
|
|
<Layout>
|
|
|
|
|
<Layout.Header style={{padding: 0}}/>
|
|
|
|
|
<Layout.Content style={sm ? {margin: '24px 0'} : {margin: '24px 16px 0'}}>
|
|
|
|
|
<div style={{
|
|
|
|
|
padding: 24,
|
|
|
|
|
minHeight: 360
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Routes>
|
|
|
|
|
<Route path='/' element={<Navigate to='/login'/>}/>
|
|
|
|
|
<Route path='/home' element={<TextPage resource='home.md'/>}/>
|
|
|
|
|
|
|
|
|
|
<Route path='/search/domain' element={<DomainSearchPage/>}/>
|
|
|
|
|
<Route path='/search/domain/:query' element={<DomainSearchPage/>}/>
|
|
|
|
|
<Route path='/search/entity' element={<EntitySearchPage/>}/>
|
2025-09-14 17:59:26 +02:00
|
|
|
|
|
|
|
|
<Route path='/infrastructure/tld' element={<TldPage/>}/>
|
|
|
|
|
<Route path='/infrastructure/icann' element={<IcannRegistrarPage/>}/>
|
2024-12-30 23:50:15 +01:00
|
|
|
|
|
|
|
|
<Route path='/tracking/watchlist' element={<WatchlistPage/>}/>
|
|
|
|
|
<Route path='/tracking/domains' element={<TrackedDomainPage/>}/>
|
|
|
|
|
<Route path='/tracking/connectors' element={<ConnectorPage/>}/>
|
|
|
|
|
|
|
|
|
|
<Route path='/stats' element={<StatisticsPage/>}/>
|
|
|
|
|
<Route path='/user' element={<UserPage/>}/>
|
|
|
|
|
|
|
|
|
|
<Route path='/faq' element={<TextPage resource='faq.md'/>}/>
|
|
|
|
|
<Route path='/tos' element={<TextPage resource='tos.md'/>}/>
|
|
|
|
|
<Route path='/privacy' element={<TextPage resource='privacy.md'/>}/>
|
|
|
|
|
|
|
|
|
|
<Route path='/login' element={<LoginPage/>}/>
|
|
|
|
|
|
|
|
|
|
<Route path='*' element={<NotFoundPage/>}/>
|
|
|
|
|
</Routes>
|
|
|
|
|
</div>
|
|
|
|
|
</Layout.Content>
|
|
|
|
|
<Layout.Footer style={{textAlign: 'center'}}>
|
|
|
|
|
<Space size='middle' wrap align='center'>
|
|
|
|
|
<Link to='/tos'><Button type='text'>{t`TOS`}</Button></Link>
|
|
|
|
|
<Link to='/privacy'><Button type='text'>{t`Privacy Policy`}</Button></Link>
|
|
|
|
|
<Link to='/faq'><Button type='text'>{t`FAQ`}</Button></Link>
|
|
|
|
|
<Typography.Link
|
|
|
|
|
target='_blank'
|
|
|
|
|
href='https://github.com/maelgangloff/domain-watchdog/wiki'
|
|
|
|
|
>
|
|
|
|
|
<Button
|
|
|
|
|
type='text'
|
|
|
|
|
>{t`Documentation`}
|
|
|
|
|
</Button>
|
|
|
|
|
</Typography.Link>
|
|
|
|
|
</Space>
|
|
|
|
|
<Typography.Paragraph style={{marginTop: '1em'}}>
|
|
|
|
|
{jt`${ProjectLink} is an open source project distributed under the ${LicenseLink} license.`}
|
|
|
|
|
</Typography.Paragraph>
|
|
|
|
|
</Layout.Footer>
|
|
|
|
|
</Layout>
|
|
|
|
|
<FloatButton.Group
|
|
|
|
|
trigger='hover'
|
|
|
|
|
style={{
|
|
|
|
|
position: 'fixed',
|
|
|
|
|
insetInlineEnd: (100 - 40) / 2,
|
|
|
|
|
bottom: 100 - 40 / 2
|
|
|
|
|
}}
|
|
|
|
|
icon={<InfoCircleOutlined/>}
|
|
|
|
|
>
|
|
|
|
|
<Tooltip title={t`Official git repository`} placement='left'>
|
|
|
|
|
<FloatButton icon={<MergeOutlined/>} target='_blank' href={PROJECT_LINK}/>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
<Tooltip title={t`Submit an issue`} placement='left'>
|
|
|
|
|
<FloatButton icon={<BugOutlined/>} target='_blank' href={PROJECT_LINK + '/issues'}/>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
</FloatButton.Group>
|
2024-12-20 20:21:05 +01:00
|
|
|
</Layout>
|
2024-12-30 23:50:15 +01:00
|
|
|
</AuthenticatedContext.Provider>
|
|
|
|
|
</ConfigProvider>
|
|
|
|
|
)
|
|
|
|
|
}
|