@vicket/create-support 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -0
- package/bin/create-vicket-support.js +389 -0
- package/package.json +18 -0
- package/templates/next/src/app/api/vicket/[...path]/route.ts +59 -0
- package/templates/next/src/app/components/vicket/TicketDialog.tsx +514 -0
- package/templates/next/src/app/support/page.tsx +358 -0
- package/templates/next/src/app/ticket/page.tsx +483 -0
- package/templates/next/src/app/utils/vicket/api.ts +149 -0
- package/templates/next/src/app/utils/vicket/types.ts +85 -0
- package/templates/next/src/app/utils/vicket/utils.ts +49 -0
- package/templates/next/src/app/vicket.css +1325 -0
- package/templates/nuxt/app/assets/css/vicket.css +1325 -0
- package/templates/nuxt/app/components/VicketTicketDialog.vue +499 -0
- package/templates/nuxt/app/composables/useVicket.ts +274 -0
- package/templates/nuxt/app/pages/support.vue +303 -0
- package/templates/nuxt/app/pages/ticket.vue +434 -0
- package/templates/nuxt/server/api/vicket/[...path].ts +85 -0
- package/templates/sveltekit/src/lib/vicket/TicketDialog.svelte +459 -0
- package/templates/sveltekit/src/lib/vicket/api.ts +162 -0
- package/templates/sveltekit/src/lib/vicket/types.ts +87 -0
- package/templates/sveltekit/src/lib/vicket/utils.ts +55 -0
- package/templates/sveltekit/src/lib/vicket.css +1325 -0
- package/templates/sveltekit/src/routes/api/vicket/[...path]/+server.ts +77 -0
- package/templates/sveltekit/src/routes/support/+page.svelte +316 -0
- package/templates/sveltekit/src/routes/ticket/+page.svelte +418 -0
- package/templates-tailwind/next/src/app/api/vicket/init/route.ts +24 -0
- package/templates-tailwind/next/src/app/api/vicket/messages/route.ts +36 -0
- package/templates-tailwind/next/src/app/api/vicket/thread/route.ts +27 -0
- package/templates-tailwind/next/src/app/api/vicket/tickets/route.ts +37 -0
- package/templates-tailwind/next/src/app/support/page.tsx +5 -0
- package/templates-tailwind/next/src/app/ticket/page.tsx +10 -0
- package/templates-tailwind/next/src/components/vicket/support-page.tsx +359 -0
- package/templates-tailwind/next/src/components/vicket/ticket-dialog.tsx +306 -0
- package/templates-tailwind/next/src/components/vicket/ticket-page.tsx +425 -0
- package/templates-tailwind/next/src/lib/vicket.ts +257 -0
- package/templates-tailwind/nuxt/app/components/VicketSupportPage.vue +317 -0
- package/templates-tailwind/nuxt/app/components/VicketTicketDialog.vue +444 -0
- package/templates-tailwind/nuxt/app/components/VicketTicketPage.vue +449 -0
- package/templates-tailwind/nuxt/app/composables/use-vicket.ts +249 -0
- package/templates-tailwind/nuxt/app/pages/support.vue +3 -0
- package/templates-tailwind/nuxt/app/pages/ticket.vue +3 -0
- package/templates-tailwind/nuxt/server/api/vicket/init.get.ts +22 -0
- package/templates-tailwind/nuxt/server/api/vicket/messages.post.ts +56 -0
- package/templates-tailwind/nuxt/server/api/vicket/thread.get.ts +26 -0
- package/templates-tailwind/nuxt/server/api/vicket/tickets.post.ts +53 -0
- package/templates-tailwind/sveltekit/src/lib/vicket/SupportPage.svelte +395 -0
- package/templates-tailwind/sveltekit/src/lib/vicket/TicketDialog.svelte +406 -0
- package/templates-tailwind/sveltekit/src/lib/vicket/TicketPage.svelte +465 -0
- package/templates-tailwind/sveltekit/src/lib/vicket/index.ts +257 -0
- package/templates-tailwind/sveltekit/src/routes/api/vicket/init/+server.ts +22 -0
- package/templates-tailwind/sveltekit/src/routes/api/vicket/messages/+server.ts +40 -0
- package/templates-tailwind/sveltekit/src/routes/api/vicket/thread/+server.ts +25 -0
- package/templates-tailwind/sveltekit/src/routes/api/vicket/tickets/+server.ts +37 -0
- package/templates-tailwind/sveltekit/src/routes/support/+page.svelte +5 -0
- package/templates-tailwind/sveltekit/src/routes/ticket/+page.svelte +5 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/* ---------------------------------------------- */
|
|
2
|
+
/* Shared types for the Vicket support widget */
|
|
3
|
+
/* ---------------------------------------------- */
|
|
4
|
+
|
|
5
|
+
// -- Support page types --------------------------
|
|
6
|
+
export type TemplateOption = {
|
|
7
|
+
id: string;
|
|
8
|
+
label: string;
|
|
9
|
+
value: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type TemplateQuestion = {
|
|
13
|
+
id: string;
|
|
14
|
+
label: string;
|
|
15
|
+
type: "TEXT" | "TEXTAREA" | "SELECT" | "CHECKBOX" | "DATE" | "FILE";
|
|
16
|
+
required: boolean;
|
|
17
|
+
order: number;
|
|
18
|
+
options?: TemplateOption[];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type Template = {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
description: string;
|
|
25
|
+
questions: TemplateQuestion[];
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type Article = {
|
|
29
|
+
id: string;
|
|
30
|
+
title: string;
|
|
31
|
+
slug: string;
|
|
32
|
+
content: string;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type Faq = {
|
|
36
|
+
id: string;
|
|
37
|
+
question: string;
|
|
38
|
+
answer: string;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type SupportInitResponse = {
|
|
42
|
+
success: boolean;
|
|
43
|
+
data?: {
|
|
44
|
+
website?: { name?: string };
|
|
45
|
+
templates: Template[];
|
|
46
|
+
articles?: Article[];
|
|
47
|
+
faqs?: Faq[];
|
|
48
|
+
};
|
|
49
|
+
error?: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export type FormValues = {
|
|
53
|
+
email: string;
|
|
54
|
+
title: string;
|
|
55
|
+
answers: Record<string, unknown>;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// -- Ticket page types ---------------------------
|
|
59
|
+
export type Attachment = {
|
|
60
|
+
id: string;
|
|
61
|
+
original_filename: string;
|
|
62
|
+
url: string;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type Message = {
|
|
66
|
+
id: string;
|
|
67
|
+
content: string;
|
|
68
|
+
author_type: "reporter" | "user" | "system";
|
|
69
|
+
created_at: string;
|
|
70
|
+
attachments?: Attachment[];
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export type TicketAnswer = {
|
|
74
|
+
id: string;
|
|
75
|
+
question_label: string;
|
|
76
|
+
answer: string;
|
|
77
|
+
attachments?: Attachment[];
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export type TicketThread = {
|
|
81
|
+
id: string;
|
|
82
|
+
title: string;
|
|
83
|
+
status?: { label: string };
|
|
84
|
+
priority?: { label: string };
|
|
85
|
+
messages: Message[];
|
|
86
|
+
answers?: TicketAnswer[];
|
|
87
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/* ---------------------------------------------- */
|
|
2
|
+
/* Shared utility functions */
|
|
3
|
+
/* ---------------------------------------------- */
|
|
4
|
+
|
|
5
|
+
/** Join class names, filtering out falsy values. */
|
|
6
|
+
export function cn(...classes: (string | boolean | undefined | null)[]): string {
|
|
7
|
+
return classes.filter(Boolean).join(" ");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Strip all HTML tags from a string. */
|
|
11
|
+
export function stripHtml(html: string): string {
|
|
12
|
+
return html.replace(/<[^>]*>/g, "");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Sanitize HTML by removing script tags, inline event handlers, and javascript: hrefs. */
|
|
16
|
+
export function sanitizeHtml(html: string): string {
|
|
17
|
+
return html
|
|
18
|
+
.replace(/<script[\s\S]*?<\/script>/gi, "")
|
|
19
|
+
.replace(/\son\w+="[^"]*"/gi, "")
|
|
20
|
+
.replace(/\son\w+='[^']*'/gi, "")
|
|
21
|
+
.replace(/href\s*=\s*"javascript:[^"]*"/gi, 'href="#"')
|
|
22
|
+
.replace(/href\s*=\s*'javascript:[^']*'/gi, "href='#'");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Format an ISO date string for display. */
|
|
26
|
+
export function formatDate(iso: string): string {
|
|
27
|
+
try {
|
|
28
|
+
return new Intl.DateTimeFormat("en", {
|
|
29
|
+
month: "short",
|
|
30
|
+
day: "numeric",
|
|
31
|
+
hour: "numeric",
|
|
32
|
+
minute: "2-digit",
|
|
33
|
+
}).format(new Date(iso));
|
|
34
|
+
} catch {
|
|
35
|
+
return iso;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Check whether an answer value represents a file upload placeholder. */
|
|
40
|
+
export function isFileAnswer(answer: string): boolean {
|
|
41
|
+
return answer?.includes("__isFile:true") || answer?.includes("map[__isFile");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Format a raw answer value for display (e.g. unwrap bracket-delimited arrays). */
|
|
45
|
+
export function formatAnswerText(value: string): string {
|
|
46
|
+
if (!value) return "";
|
|
47
|
+
|
|
48
|
+
const trimmed = value.trim();
|
|
49
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
50
|
+
const rawItems = trimmed.slice(1, -1).trim();
|
|
51
|
+
return rawItems.length > 0 ? rawItems.split(/\s+/).join(", ") : "";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return value;
|
|
55
|
+
}
|