feat: add survey usage button
This commit is contained in:
parent
cc0bd73ed1
commit
2b75a8edad
37
src/client/components/CodeBlock.tsx
Normal file
37
src/client/components/CodeBlock.tsx
Normal file
@ -0,0 +1,37 @@
|
||||
import { useEvent } from '@/hooks/useEvent';
|
||||
import React, { useState } from 'react';
|
||||
import { Button } from './ui/button';
|
||||
import { LuCopy, LuCopyCheck } from 'react-icons/lu';
|
||||
import { toast } from 'sonner';
|
||||
import { useTranslation } from '@i18next-toolkit/react';
|
||||
|
||||
export const CodeBlock: React.FC<{
|
||||
code: string;
|
||||
}> = React.memo((props) => {
|
||||
const [copied, setCopied] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleCopy = useEvent(() => {
|
||||
window.navigator.clipboard.writeText(props.code);
|
||||
|
||||
toast(t('Copied into clipboard!'));
|
||||
|
||||
setCopied(true);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="group relative overflow-auto">
|
||||
<pre className="rounded-sm border border-zinc-800 bg-zinc-900 p-3 pr-12 text-sm">
|
||||
<code>{props.code}</code>
|
||||
</pre>
|
||||
<Button
|
||||
className="absolute right-1 top-1 bg-opacity-50 opacity-0 transition-opacity group-hover:opacity-100 dark:bg-opacity-50"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
Icon={copied ? LuCopyCheck : LuCopy}
|
||||
onClick={handleCopy}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
CodeBlock.displayName = 'CodeBlock';
|
@ -10,7 +10,7 @@ import {
|
||||
} from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useTranslation } from '@i18next-toolkit/react';
|
||||
import { LuCalendar } from 'react-icons/lu';
|
||||
import { LuCalendar, LuDownloadCloud } from 'react-icons/lu';
|
||||
import { cn } from '@/utils/style';
|
||||
import dayjs from 'dayjs';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
|
||||
@ -131,7 +131,7 @@ export const SurveyDownloadBtn: React.FC<SurveyDownloadBtnProps> = React.memo(
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button>{t('Download')}</Button>
|
||||
<Button Icon={LuDownloadCloud}>{t('Download')}</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<DialogHeader>
|
||||
|
@ -53,7 +53,7 @@ export type SurveyEditFormValues = z.infer<typeof addFormSchema>;
|
||||
function generateDefaultItem() {
|
||||
return {
|
||||
label: 'New Field',
|
||||
name: 'field-' + generateRandomString(4),
|
||||
name: 'field_' + generateRandomString(4),
|
||||
type: 'text' as const,
|
||||
};
|
||||
}
|
||||
|
59
src/client/components/survey/SurveyUsageBtn.tsx
Normal file
59
src/client/components/survey/SurveyUsageBtn.tsx
Normal file
@ -0,0 +1,59 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
DialogHeader,
|
||||
Dialog,
|
||||
DialogTrigger,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useTranslation } from '@i18next-toolkit/react';
|
||||
import { LuCode2 } from 'react-icons/lu';
|
||||
import { trpc } from '@/api/trpc';
|
||||
import { useCurrentWorkspaceId } from '@/store/user';
|
||||
import { CodeBlock } from '../CodeBlock';
|
||||
import { generateSurveyExampleCode } from '@/utils/survey';
|
||||
|
||||
interface SurveyUsageBtnProps {
|
||||
surveyId: string;
|
||||
}
|
||||
export const SurveyUsageBtn: React.FC<SurveyUsageBtnProps> = React.memo(
|
||||
(props) => {
|
||||
const { surveyId } = props;
|
||||
const workspaceId = useCurrentWorkspaceId();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { data: info } = trpc.survey.get.useQuery({
|
||||
workspaceId,
|
||||
surveyId,
|
||||
});
|
||||
|
||||
const fields = info?.payload.items ?? [];
|
||||
|
||||
const exampleCode = generateSurveyExampleCode(window.location.origin, info);
|
||||
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline" Icon={LuCode2}>
|
||||
{t('Usage')}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t('Example code')}</DialogTitle>
|
||||
<DialogDescription>
|
||||
{t('Add this example code into your project')}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<CodeBlock code="npm install tianji-client-sdk" />
|
||||
|
||||
<CodeBlock code={exampleCode} />
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
);
|
||||
SurveyUsageBtn.displayName = 'SurveyUsageBtn';
|
@ -12,7 +12,7 @@
|
||||
"translation:extract": "i18next-toolkit extract",
|
||||
"translation:scan": "i18next-toolkit scan",
|
||||
"translation:translate": "i18next-toolkit translate",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "vitest"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "moonrailgun <moonrailgun@gmail.com>",
|
||||
|
@ -20,6 +20,7 @@ import { DataTable, createColumnHelper } from '@/components/DataTable';
|
||||
import { useMemo } from 'react';
|
||||
import { SurveyDownloadBtn } from '@/components/survey/SurveyDownloadBtn';
|
||||
import dayjs from 'dayjs';
|
||||
import { SurveyUsageBtn } from '@/components/survey/SurveyUsageBtn';
|
||||
|
||||
type SurveyResultItem =
|
||||
AppRouterOutput['survey']['resultList']['items'][number];
|
||||
@ -124,14 +125,15 @@ function PageComponent() {
|
||||
<ScrollArea className="h-full overflow-hidden p-4">
|
||||
<ScrollBar orientation="horizontal" />
|
||||
|
||||
<div className="mb-4 ">
|
||||
<div className="mb-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{t('Count')}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="flex justify-between">
|
||||
<div>{count}</div>
|
||||
<div>
|
||||
<div className="flex gap-2">
|
||||
<SurveyUsageBtn surveyId={surveyId} />
|
||||
<SurveyDownloadBtn surveyId={surveyId} />
|
||||
</div>
|
||||
</CardContent>
|
||||
|
28
src/client/utils/__snapshots__/survey.spec.ts.snap
Normal file
28
src/client/utils/__snapshots__/survey.spec.ts.snap
Normal file
@ -0,0 +1,28 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`survey > example code 1`] = `
|
||||
"import { submitSurvey, initOpenapiSDK } from 'tianji-client-sdk';
|
||||
|
||||
initOpenapiSDK('https://example.com');
|
||||
|
||||
/**
|
||||
* Submit Survey into Test
|
||||
*
|
||||
* @param {text} textField Text
|
||||
*/
|
||||
async function submitForm(textField) {
|
||||
try {
|
||||
await submitSurvey(
|
||||
'<workspaceId>',
|
||||
'<surveyId>',
|
||||
{
|
||||
textField, // Text
|
||||
}
|
||||
);
|
||||
console.log('Submit success');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw new Error(err);
|
||||
}
|
||||
};"
|
||||
`;
|
25
src/client/utils/survey.spec.ts
Normal file
25
src/client/utils/survey.spec.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { generateSurveyExampleCode } from './survey';
|
||||
|
||||
describe('survey', () => {
|
||||
test('example code', () => {
|
||||
expect(
|
||||
generateSurveyExampleCode('https://example.com', {
|
||||
id: '<surveyId>',
|
||||
workspaceId: '<workspaceId>',
|
||||
name: 'Test',
|
||||
payload: {
|
||||
items: [
|
||||
{
|
||||
name: 'textField',
|
||||
label: 'Text',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
})
|
||||
).matchSnapshot();
|
||||
});
|
||||
});
|
38
src/client/utils/survey.ts
Normal file
38
src/client/utils/survey.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { AppRouterOutput } from '@/api/trpc';
|
||||
|
||||
/**
|
||||
* Generate survey example code
|
||||
*/
|
||||
export function generateSurveyExampleCode(
|
||||
host: string,
|
||||
info?: AppRouterOutput['survey']['get']
|
||||
): string {
|
||||
const fields = info?.payload.items ?? [];
|
||||
|
||||
const exampleCode = `import { submitSurvey, initOpenapiSDK } from 'tianji-client-sdk';
|
||||
|
||||
initOpenapiSDK('${host}');
|
||||
|
||||
/**
|
||||
* Submit Survey into ${info?.name ?? 'Tianji'}
|
||||
*
|
||||
* ${fields.map((field) => `@param {${field.type}} ${field.name} ${field.label}`).join('\n * ')}
|
||||
*/
|
||||
async function submitForm(${fields.map((field) => field.name).join(', ')}) {
|
||||
try {
|
||||
await submitSurvey(
|
||||
'${info?.workspaceId}',
|
||||
'${info?.id}',
|
||||
{
|
||||
${fields.map((field) => `${field.name}, // ${field.label}`).join('\n ')}
|
||||
}
|
||||
);
|
||||
console.log('Submit success');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw new Error(err);
|
||||
}
|
||||
};`;
|
||||
|
||||
return exampleCode;
|
||||
}
|
Loading…
Reference in New Issue
Block a user