From a596011960db230a8241e4f59bac5d33597cdc9a Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Thu, 2 May 2024 01:02:13 +0800 Subject: [PATCH] feat: survey detail and edit --- .../components/survey/SurveyEditForm.tsx | 2 +- src/client/routeTree.gen.ts | 36 +++++++--- src/client/routes/survey/$surveyId/edit.tsx | 71 ++++++++++++++++++ .../{$surveyId.tsx => $surveyId/index.tsx} | 72 +++++++++++++++++-- src/server/utils/schema.ts | 4 +- 5 files changed, 166 insertions(+), 19 deletions(-) create mode 100644 src/client/routes/survey/$surveyId/edit.tsx rename src/client/routes/survey/{$surveyId.tsx => $surveyId/index.tsx} (54%) diff --git a/src/client/components/survey/SurveyEditForm.tsx b/src/client/components/survey/SurveyEditForm.tsx index ccae476..3e28538 100644 --- a/src/client/components/survey/SurveyEditForm.tsx +++ b/src/client/components/survey/SurveyEditForm.tsx @@ -243,7 +243,7 @@ export const SurveyEditForm: React.FC = React.memo( diff --git a/src/client/routeTree.gen.ts b/src/client/routeTree.gen.ts index 09884f6..2caf249 100644 --- a/src/client/routeTree.gen.ts +++ b/src/client/routeTree.gen.ts @@ -27,7 +27,6 @@ import { Route as WebsiteAddImport } from './routes/website/add' import { Route as TelemetryAddImport } from './routes/telemetry/add' import { Route as TelemetryTelemetryIdImport } from './routes/telemetry/$telemetryId' import { Route as SurveyAddImport } from './routes/survey/add' -import { Route as SurveySurveyIdImport } from './routes/survey/$surveyId' import { Route as StatusSlugImport } from './routes/status/$slug' import { Route as SettingsUsageImport } from './routes/settings/usage' import { Route as SettingsProfileImport } from './routes/settings/profile' @@ -37,8 +36,10 @@ import { Route as PageAddImport } from './routes/page/add' import { Route as PageSlugImport } from './routes/page/$slug' import { Route as MonitorAddImport } from './routes/monitor/add' import { Route as WebsiteWebsiteIdIndexImport } from './routes/website/$websiteId/index' +import { Route as SurveySurveyIdIndexImport } from './routes/survey/$surveyId/index' import { Route as MonitorMonitorIdIndexImport } from './routes/monitor/$monitorId/index' import { Route as WebsiteWebsiteIdConfigImport } from './routes/website/$websiteId/config' +import { Route as SurveySurveyIdEditImport } from './routes/survey/$surveyId/edit' import { Route as MonitorMonitorIdEditImport } from './routes/monitor/$monitorId/edit' // Create/Update Routes @@ -123,11 +124,6 @@ const SurveyAddRoute = SurveyAddImport.update({ getParentRoute: () => SurveyRoute, } as any) -const SurveySurveyIdRoute = SurveySurveyIdImport.update({ - path: '/$surveyId', - getParentRoute: () => SurveyRoute, -} as any) - const StatusSlugRoute = StatusSlugImport.update({ path: '/status/$slug', getParentRoute: () => rootRoute, @@ -173,6 +169,11 @@ const WebsiteWebsiteIdIndexRoute = WebsiteWebsiteIdIndexImport.update({ getParentRoute: () => WebsiteRoute, } as any) +const SurveySurveyIdIndexRoute = SurveySurveyIdIndexImport.update({ + path: '/$surveyId/', + getParentRoute: () => SurveyRoute, +} as any) + const MonitorMonitorIdIndexRoute = MonitorMonitorIdIndexImport.update({ path: '/$monitorId/', getParentRoute: () => MonitorRoute, @@ -183,6 +184,11 @@ const WebsiteWebsiteIdConfigRoute = WebsiteWebsiteIdConfigImport.update({ getParentRoute: () => WebsiteRoute, } as any) +const SurveySurveyIdEditRoute = SurveySurveyIdEditImport.update({ + path: '/$surveyId/edit', + getParentRoute: () => SurveyRoute, +} as any) + const MonitorMonitorIdEditRoute = MonitorMonitorIdEditImport.update({ path: '/$monitorId/edit', getParentRoute: () => MonitorRoute, @@ -268,10 +274,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof StatusSlugImport parentRoute: typeof rootRoute } - '/survey/$surveyId': { - preLoaderRoute: typeof SurveySurveyIdImport - parentRoute: typeof SurveyImport - } '/survey/add': { preLoaderRoute: typeof SurveyAddImport parentRoute: typeof SurveyImport @@ -296,6 +298,10 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof MonitorMonitorIdEditImport parentRoute: typeof MonitorImport } + '/survey/$surveyId/edit': { + preLoaderRoute: typeof SurveySurveyIdEditImport + parentRoute: typeof SurveyImport + } '/website/$websiteId/config': { preLoaderRoute: typeof WebsiteWebsiteIdConfigImport parentRoute: typeof WebsiteImport @@ -304,6 +310,10 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof MonitorMonitorIdIndexImport parentRoute: typeof MonitorImport } + '/survey/$surveyId/': { + preLoaderRoute: typeof SurveySurveyIdIndexImport + parentRoute: typeof SurveyImport + } '/website/$websiteId/': { preLoaderRoute: typeof WebsiteWebsiteIdIndexImport parentRoute: typeof WebsiteImport @@ -331,7 +341,11 @@ export const routeTree = rootRoute.addChildren([ SettingsProfileRoute, SettingsUsageRoute, ]), - SurveyRoute.addChildren([SurveySurveyIdRoute, SurveyAddRoute]), + SurveyRoute.addChildren([ + SurveyAddRoute, + SurveySurveyIdEditRoute, + SurveySurveyIdIndexRoute, + ]), TelemetryRoute.addChildren([TelemetryTelemetryIdRoute, TelemetryAddRoute]), WebsiteRoute.addChildren([ WebsiteAddRoute, diff --git a/src/client/routes/survey/$surveyId/edit.tsx b/src/client/routes/survey/$surveyId/edit.tsx new file mode 100644 index 0000000..a2b7f69 --- /dev/null +++ b/src/client/routes/survey/$surveyId/edit.tsx @@ -0,0 +1,71 @@ +import { createFileRoute, useNavigate } from '@tanstack/react-router'; +import { useTranslation } from '@i18next-toolkit/react'; +import { useEvent } from '@/hooks/useEvent'; +import { useCurrentWorkspaceId } from '@/store/user'; +import { trpc } from '@/api/trpc'; +import { Card, CardContent } from '@/components/ui/card'; +import { CommonWrapper } from '@/components/CommonWrapper'; +import { routeAuthBeforeLoad } from '@/utils/route'; +import { Loading } from '@/components/Loading'; +import { ErrorTip } from '@/components/ErrorTip'; +import { CommonHeader } from '@/components/CommonHeader'; +import { ScrollArea } from '@/components/ui/scroll-area'; +import { + SurveyEditForm, + SurveyEditFormValues, +} from '@/components/survey/SurveyEditForm'; + +export const Route = createFileRoute('/survey/$surveyId/edit')({ + beforeLoad: routeAuthBeforeLoad, + component: PageComponent, +}); + +function PageComponent() { + const { t } = useTranslation(); + const { surveyId } = Route.useParams<{ surveyId: string }>(); + const workspaceId = useCurrentWorkspaceId(); + const navigate = useNavigate(); + const mutation = trpc.survey.update.useMutation(); + const { data: survey, isLoading } = trpc.survey.get.useQuery({ + workspaceId, + surveyId, + }); + + const handleSubmit = useEvent(async (values: SurveyEditFormValues) => { + const res = await mutation.mutateAsync({ + ...values, + surveyId, + workspaceId, + }); + + navigate({ + to: '/survey/$surveyId', + params: { + surveyId: res.id, + }, + replace: true, + }); + }); + + if (isLoading) { + return ; + } + + if (!survey) { + return ; + } + + return ( + } + > + + + + + + + + + ); +} diff --git a/src/client/routes/survey/$surveyId.tsx b/src/client/routes/survey/$surveyId/index.tsx similarity index 54% rename from src/client/routes/survey/$surveyId.tsx rename to src/client/routes/survey/$surveyId/index.tsx index eaaeb9e..5a7a6b6 100644 --- a/src/client/routes/survey/$surveyId.tsx +++ b/src/client/routes/survey/$surveyId/index.tsx @@ -1,4 +1,9 @@ -import { defaultErrorHandler, defaultSuccessHandler, trpc } from '@/api/trpc'; +import { + AppRouterOutput, + defaultErrorHandler, + defaultSuccessHandler, + trpc, +} from '@/api/trpc'; import { CommonHeader } from '@/components/CommonHeader'; import { CommonWrapper } from '@/components/CommonWrapper'; import { ScrollArea, ScrollBar } from '@/components/ui/scroll-area'; @@ -8,10 +13,18 @@ import { useTranslation } from '@i18next-toolkit/react'; import { createFileRoute, useNavigate } from '@tanstack/react-router'; import { useEvent } from '@/hooks/useEvent'; import { AlertConfirm } from '@/components/AlertConfirm'; -import { LuTrash } from 'react-icons/lu'; +import { LuPencil, LuTrash } from 'react-icons/lu'; import { Button } from '@/components/ui/button'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { DataTable, createColumnHelper } from '@/components/DataTable'; +import { useMemo } from 'react'; -export const Route = createFileRoute('/survey/$surveyId')({ +type SurveyResultItem = + AppRouterOutput['survey']['resultList']['items'][number]; + +const columnHelper = createColumnHelper(); + +export const Route = createFileRoute('/survey/$surveyId/')({ beforeLoad: routeAuthBeforeLoad, component: PageComponent, }); @@ -28,6 +41,10 @@ function PageComponent() { workspaceId, surveyId, }); + const { data: resultList } = trpc.survey.resultList.useInfiniteQuery({ + workspaceId, + surveyId, + }); const deleteMutation = trpc.survey.delete.useMutation({ onSuccess: defaultSuccessHandler, onError: defaultErrorHandler, @@ -44,13 +61,47 @@ function PageComponent() { }); }); + const dataSource = resultList?.pages.map((p) => p.items).flat() ?? []; + + const columns = useMemo(() => { + return [ + columnHelper.accessor('id', { + header: t('ID'), + size: 150, + }), + ...(info?.payload.items.map((item) => + columnHelper.accessor(`payload.${item.name}`, { + header: item.label, + }) + ) ?? []), + columnHelper.accessor('createdAt', { + header: t('Created At'), + size: 150, + }), + ]; + }, [t, info]); + return ( +
+