diff --git a/src/client/components/ErrorTip.tsx b/src/client/components/ErrorTip.tsx index 881e09a..65f4a2e 100644 --- a/src/client/components/ErrorTip.tsx +++ b/src/client/components/ErrorTip.tsx @@ -1,6 +1,7 @@ +import { Alert } from 'antd'; import React from 'react'; export const ErrorTip: React.FC = React.memo(() => { - return
An unexpected error has occurred
; + return ; }); ErrorTip.displayName = 'ErrorTip'; diff --git a/src/client/components/NotFoundTip.tsx b/src/client/components/NotFoundTip.tsx new file mode 100644 index 0000000..861cf07 --- /dev/null +++ b/src/client/components/NotFoundTip.tsx @@ -0,0 +1,7 @@ +import { Alert } from 'antd'; +import React from 'react'; + +export const NotFoundTip: React.FC = React.memo(() => { + return ; +}); +NotFoundTip.displayName = 'NotFoundTip'; diff --git a/src/client/components/WebsiteList.tsx b/src/client/components/WebsiteList.tsx index 7b832e9..ee2fd7a 100644 --- a/src/client/components/WebsiteList.tsx +++ b/src/client/components/WebsiteList.tsx @@ -119,7 +119,14 @@ const WebsiteListTable: React.FC<{ workspaceId: string }> = React.memo( > Edit - + ); }, diff --git a/src/client/components/WebsiteOverview.tsx b/src/client/components/WebsiteOverview.tsx index 08aea41..e3f83be 100644 --- a/src/client/components/WebsiteOverview.tsx +++ b/src/client/components/WebsiteOverview.tsx @@ -1,14 +1,13 @@ -import { Button, message, Tag } from 'antd'; +import { Button, message } from 'antd'; import React, { useMemo } from 'react'; import { Column, ColumnConfig } from '@ant-design/charts'; -import { ArrowRightOutlined, SyncOutlined } from '@ant-design/icons'; +import { SyncOutlined } from '@ant-design/icons'; import { DateFilter } from './DateFilter'; import { HealthBar } from './HealthBar'; import { StatsItemType, useWorkspaceWebsitePageview, useWorkspaceWebsiteStats, - useWorspaceWebsites, WebsiteInfo, } from '../api/model/website'; import { Loading } from './Loading'; @@ -25,30 +24,9 @@ import { formatNumber, formatShortTime } from '../utils/common'; import { useTheme } from '../hooks/useTheme'; import { WebsiteOnlineCount } from './WebsiteOnlineCount'; -interface WebsiteOverviewProps { - workspaceId: string; -} -export const WebsiteOverview: React.FC = React.memo( - (props) => { - const { isLoading, websites } = useWorspaceWebsites(props.workspaceId); - - if (isLoading) { - return ; - } - - return ( -
- {websites.map((website) => ( - - ))} -
- ); - } -); -WebsiteOverview.displayName = 'WebsiteOverview'; - -const WebsiteOverviewItem: React.FC<{ +export const WebsiteOverview: React.FC<{ website: WebsiteInfo; + actions?: React.ReactNode; }> = React.memo((props) => { const unit: DateUnit = 'hour'; const startDate = dayjs().subtract(1, 'day').add(1, unit).startOf(unit); @@ -99,7 +77,7 @@ const WebsiteOverviewItem: React.FC<{ } return ( -
+
@@ -120,11 +98,7 @@ const WebsiteOverviewItem: React.FC<{
-
- -
+
{props.actions}
@@ -147,7 +121,7 @@ const WebsiteOverviewItem: React.FC<{
); }); -WebsiteOverviewItem.displayName = 'WebsiteOverviewItem'; +WebsiteOverview.displayName = 'WebsiteOverview'; export const MetricsBar: React.FC<{ stats: { diff --git a/src/client/pages/Dashboard.tsx b/src/client/pages/Dashboard.tsx index 3ba9511..92ddb76 100644 --- a/src/client/pages/Dashboard.tsx +++ b/src/client/pages/Dashboard.tsx @@ -1,14 +1,23 @@ -import React from 'react'; -import { EditOutlined } from '@ant-design/icons'; -import { Button } from 'antd'; +import React, { Fragment } from 'react'; +import { ArrowRightOutlined, EditOutlined } from '@ant-design/icons'; +import { Button, Divider } from 'antd'; import { WebsiteOverview } from '../components/WebsiteOverview'; import { useCurrentWorkspaceId } from '../store/user'; import { Loading } from '../components/Loading'; +import { useWorspaceWebsites } from '../api/model/website'; +import { NoWorkspaceTip } from '../components/NoWorkspaceTip'; +import { useNavigate } from 'react-router'; export const Dashboard: React.FC = React.memo(() => { - const workspaceId = useCurrentWorkspaceId(); + const workspaceId = useCurrentWorkspaceId()!; + const { isLoading, websites } = useWorspaceWebsites(workspaceId); + const navigate = useNavigate(); if (!workspaceId) { + return ; + } + + if (isLoading) { return ; } @@ -23,7 +32,28 @@ export const Dashboard: React.FC = React.memo(() => {
- + {websites.map((website, i) => ( + + {i !== 0 && } + + + + + } + /> + + ))}
); diff --git a/src/client/pages/Website/Detail.tsx b/src/client/pages/Website/Detail.tsx new file mode 100644 index 0000000..1356172 --- /dev/null +++ b/src/client/pages/Website/Detail.tsx @@ -0,0 +1,47 @@ +import { Divider } from 'antd'; +import React from 'react'; +import { useParams } from 'react-router'; +import { trpc } from '../../api/trpc'; +import { ErrorTip } from '../../components/ErrorTip'; +import { Loading } from '../../components/Loading'; +import { NotFoundTip } from '../../components/NotFoundTip'; +import { WebsiteOverview } from '../../components/WebsiteOverview'; +import { useCurrentWorkspaceId } from '../../store/user'; + +export const WebsiteDetail: React.FC = React.memo(() => { + const { websiteId } = useParams(); + const workspaceId = useCurrentWorkspaceId(); + const { data: website, isLoading } = trpc.website.info.useQuery({ + workspaceId, + websiteId: websiteId!, + }); + + if (!websiteId) { + return ; + } + + if (isLoading) { + return ; + } + + if (!website) { + return ; + } + + return ( +
+
+ +
+ + + +
+
left
+ +
right
+
+
+ ); +}); +WebsiteDetail.displayName = 'WebsiteDetail'; diff --git a/src/client/pages/Website/index.tsx b/src/client/pages/Website/index.tsx index 7ff0945..d7da661 100644 --- a/src/client/pages/Website/index.tsx +++ b/src/client/pages/Website/index.tsx @@ -1,12 +1,14 @@ import React from 'react'; import { Route, Routes } from 'react-router'; import { WebsiteList } from '../../components/WebsiteList'; +import { WebsiteDetail } from './Detail'; export const WebsitePage: React.FC = React.memo(() => { return (
} /> + } />
); diff --git a/src/server/trpc/routers/website.ts b/src/server/trpc/routers/website.ts index 984ef33..34fe64d 100644 --- a/src/server/trpc/routers/website.ts +++ b/src/server/trpc/routers/website.ts @@ -1,6 +1,7 @@ import { router, workspaceProcedure } from '../trpc'; import { z } from 'zod'; import { getWebsiteOnlineUserCount } from '../../model/website'; +import { prisma } from '../../model/_client'; export const websiteRouter = router({ onlineCount: workspaceProcedure @@ -16,4 +17,21 @@ export const websiteRouter = router({ return count; }), + info: workspaceProcedure + .input( + z.object({ + websiteId: z.string(), + }) + ) + .query(async ({ input }) => { + const { websiteId, workspaceId } = input; + + const website = await prisma.website.findUnique({ + where: { + id: websiteId, + }, + }); + + return website; + }), });