@vicket/create-support 1.1.1 → 1.1.2
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/bin/create-vicket-support.js +429 -389
- package/package.json +1 -1
- package/templates/next/src/app/api/vicket/[...path]/route.ts +2 -55
- package/templates/next/src/app/components/vicket/ReplyForm.tsx +154 -0
- package/templates/next/src/app/components/vicket/SupportContent.tsx +298 -0
- package/templates/next/src/app/components/vicket/TicketDialog.tsx +3 -3
- package/templates/next/src/app/support/page.tsx +27 -353
- package/templates/next/src/app/ticket/page.tsx +110 -325
- package/templates/next/src/app/vicket.css +1325 -1325
- package/templates/nuxt/app/assets/css/vicket.css +1325 -1325
- package/templates/nuxt/app/components/VicketReplyForm.vue +154 -0
- package/templates/nuxt/app/components/VicketSupportContent.vue +255 -0
- package/templates/nuxt/app/components/VicketTicketDialog.vue +2 -2
- package/templates/nuxt/app/pages/support.vue +7 -293
- package/templates/nuxt/app/pages/ticket.vue +36 -178
- package/templates/nuxt/server/api/vicket/[...path].ts +2 -85
- package/templates/sveltekit/src/lib/vicket/ReplyForm.svelte +134 -0
- package/templates/sveltekit/src/lib/vicket/SupportContent.svelte +263 -0
- package/templates/sveltekit/src/lib/vicket/TicketDialog.svelte +457 -459
- package/templates/sveltekit/src/lib/vicket.css +1325 -1325
- package/templates/sveltekit/src/routes/api/vicket/[...path]/+server.ts +2 -76
- package/templates/sveltekit/src/routes/support/+page.server.ts +13 -0
- package/templates/sveltekit/src/routes/support/+page.svelte +3 -312
- package/templates/sveltekit/src/routes/ticket/+page.server.ts +19 -0
- package/templates/sveltekit/src/routes/ticket/+page.svelte +13 -188
- package/templates-tailwind/next/src/app/api/vicket/[...path]/route.ts +6 -0
- package/templates-tailwind/next/src/app/support/page.tsx +33 -3
- package/templates-tailwind/next/src/app/ticket/page.tsx +249 -6
- package/templates-tailwind/next/src/components/vicket/reply-form.tsx +113 -0
- package/templates-tailwind/next/src/components/vicket/support-content.tsx +265 -0
- package/templates-tailwind/next/src/components/vicket/ticket-dialog.tsx +2 -2
- package/templates-tailwind/nuxt/app/components/VicketReplyForm.vue +169 -0
- package/templates-tailwind/nuxt/app/components/{VicketSupportPage.vue → VicketSupportContent.vue} +275 -317
- package/templates-tailwind/nuxt/app/components/VicketTicketDialog.vue +3 -0
- package/templates-tailwind/nuxt/app/pages/support.vue +10 -1
- package/templates-tailwind/nuxt/app/pages/ticket.vue +298 -1
- package/templates-tailwind/nuxt/server/api/vicket/[...path].ts +2 -0
- package/templates-tailwind/sveltekit/src/lib/vicket/ReplyForm.svelte +127 -0
- package/templates-tailwind/sveltekit/src/lib/vicket/{SupportPage.svelte → SupportContent.svelte} +9 -71
- package/templates-tailwind/sveltekit/src/lib/vicket/TicketDialog.svelte +405 -406
- package/templates-tailwind/sveltekit/src/routes/api/vicket/[...path]/+server.ts +3 -0
- package/templates-tailwind/sveltekit/src/routes/support/+page.server.ts +13 -0
- package/templates-tailwind/sveltekit/src/routes/support/+page.svelte +4 -2
- package/templates-tailwind/sveltekit/src/routes/ticket/+page.server.ts +19 -0
- package/templates-tailwind/sveltekit/src/routes/ticket/+page.svelte +292 -2
- package/templates/next/src/app/utils/vicket/api.ts +0 -149
- package/templates/next/src/app/utils/vicket/types.ts +0 -85
- package/templates/next/src/app/utils/vicket/utils.ts +0 -49
- package/templates/nuxt/app/composables/useVicket.ts +0 -274
- package/templates/sveltekit/src/lib/vicket/api.ts +0 -162
- package/templates/sveltekit/src/lib/vicket/types.ts +0 -87
- package/templates/sveltekit/src/lib/vicket/utils.ts +0 -55
- package/templates-tailwind/next/src/app/api/vicket/init/route.ts +0 -24
- package/templates-tailwind/next/src/app/api/vicket/messages/route.ts +0 -36
- package/templates-tailwind/next/src/app/api/vicket/thread/route.ts +0 -27
- package/templates-tailwind/next/src/app/api/vicket/tickets/route.ts +0 -37
- package/templates-tailwind/next/src/components/vicket/support-page.tsx +0 -359
- package/templates-tailwind/next/src/components/vicket/ticket-page.tsx +0 -425
- package/templates-tailwind/next/src/lib/vicket.ts +0 -257
- package/templates-tailwind/nuxt/app/components/VicketTicketPage.vue +0 -449
- package/templates-tailwind/nuxt/app/composables/use-vicket.ts +0 -249
- package/templates-tailwind/nuxt/server/api/vicket/init.get.ts +0 -22
- package/templates-tailwind/nuxt/server/api/vicket/messages.post.ts +0 -56
- package/templates-tailwind/nuxt/server/api/vicket/thread.get.ts +0 -26
- package/templates-tailwind/nuxt/server/api/vicket/tickets.post.ts +0 -53
- package/templates-tailwind/sveltekit/src/lib/vicket/TicketPage.svelte +0 -465
- package/templates-tailwind/sveltekit/src/lib/vicket/index.ts +0 -257
- package/templates-tailwind/sveltekit/src/routes/api/vicket/init/+server.ts +0 -22
- package/templates-tailwind/sveltekit/src/routes/api/vicket/messages/+server.ts +0 -40
- package/templates-tailwind/sveltekit/src/routes/api/vicket/thread/+server.ts +0 -25
- package/templates-tailwind/sveltekit/src/routes/api/vicket/tickets/+server.ts +0 -37
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
/* ── Types ─────────────────────────────────────── */
|
|
2
|
-
|
|
3
|
-
export type TemplateOption = {
|
|
4
|
-
id: string;
|
|
5
|
-
label: string;
|
|
6
|
-
value: string;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export type TemplateQuestion = {
|
|
10
|
-
id: string;
|
|
11
|
-
label: string;
|
|
12
|
-
type: "TEXT" | "TEXTAREA" | "SELECT" | "CHECKBOX" | "DATE" | "FILE";
|
|
13
|
-
required: boolean;
|
|
14
|
-
order: number;
|
|
15
|
-
options?: TemplateOption[];
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export type Template = {
|
|
19
|
-
id: string;
|
|
20
|
-
name: string;
|
|
21
|
-
description: string;
|
|
22
|
-
questions: TemplateQuestion[];
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export type Article = {
|
|
26
|
-
id: string;
|
|
27
|
-
title: string;
|
|
28
|
-
slug: string;
|
|
29
|
-
content: string;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export type Faq = {
|
|
33
|
-
id: string;
|
|
34
|
-
question: string;
|
|
35
|
-
answer: string;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export type SupportInitResponse = {
|
|
39
|
-
success: boolean;
|
|
40
|
-
data?: {
|
|
41
|
-
website?: { name?: string };
|
|
42
|
-
templates: Template[];
|
|
43
|
-
articles?: Article[];
|
|
44
|
-
faqs?: Faq[];
|
|
45
|
-
};
|
|
46
|
-
error?: string;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export type FormValues = {
|
|
50
|
-
email: string;
|
|
51
|
-
title: string;
|
|
52
|
-
answers: Record<string, unknown>;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export type Attachment = {
|
|
56
|
-
id: string;
|
|
57
|
-
original_filename: string;
|
|
58
|
-
url: string;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
export type Message = {
|
|
62
|
-
id: string;
|
|
63
|
-
content: string;
|
|
64
|
-
author_type: "reporter" | "user" | "system";
|
|
65
|
-
created_at: string;
|
|
66
|
-
attachments?: Attachment[];
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
export type TicketAnswer = {
|
|
70
|
-
id: string;
|
|
71
|
-
question_label: string;
|
|
72
|
-
answer: string;
|
|
73
|
-
attachments?: Attachment[];
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
export type TicketThread = {
|
|
77
|
-
id: string;
|
|
78
|
-
title: string;
|
|
79
|
-
status?: { label: string };
|
|
80
|
-
priority?: { label: string };
|
|
81
|
-
messages: Message[];
|
|
82
|
-
answers?: TicketAnswer[];
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
/* ── Constants ─────────────────────────────────── */
|
|
86
|
-
|
|
87
|
-
const PROXY_BASE = "/api/vicket";
|
|
88
|
-
|
|
89
|
-
export const AUTHOR_LABELS: Record<string, string> = {
|
|
90
|
-
reporter: "You",
|
|
91
|
-
user: "Support",
|
|
92
|
-
system: "System",
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
export const initialFormValues: FormValues = { email: "", title: "", answers: {} };
|
|
96
|
-
|
|
97
|
-
/* ── Helpers ───────────────────────────────────── */
|
|
98
|
-
|
|
99
|
-
export function cn(...classes: (string | boolean | undefined | null)[]): string {
|
|
100
|
-
return classes.filter(Boolean).join(" ");
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export function stripHtml(html: string): string {
|
|
104
|
-
return html.replace(/<[^>]*>/g, "");
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export function sanitizeHtml(html: string): string {
|
|
108
|
-
return html
|
|
109
|
-
.replace(/<script[\s\S]*?<\/script>/gi, "")
|
|
110
|
-
.replace(/\son\w+="[^"]*"/gi, "")
|
|
111
|
-
.replace(/\son\w+='[^']*'/gi, "")
|
|
112
|
-
.replace(/href\s*=\s*"javascript:[^"]*"/gi, 'href="#"')
|
|
113
|
-
.replace(/href\s*=\s*'javascript:[^']*'/gi, "href='#'");
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function formatDate(iso: string): string {
|
|
117
|
-
try {
|
|
118
|
-
return new Intl.DateTimeFormat("en", {
|
|
119
|
-
month: "short",
|
|
120
|
-
day: "numeric",
|
|
121
|
-
hour: "numeric",
|
|
122
|
-
minute: "2-digit",
|
|
123
|
-
}).format(new Date(iso));
|
|
124
|
-
} catch {
|
|
125
|
-
return iso;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export function isFileAnswer(answer: string): boolean {
|
|
130
|
-
return answer?.includes("__isFile:true") || answer?.includes("map[__isFile");
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export function formatAnswerText(value: string): string {
|
|
134
|
-
if (!value) return "";
|
|
135
|
-
const trimmed = value.trim();
|
|
136
|
-
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
137
|
-
const rawItems = trimmed.slice(1, -1).trim();
|
|
138
|
-
return rawItems.length > 0 ? rawItems.split(/\s+/).join(", ") : "";
|
|
139
|
-
}
|
|
140
|
-
return value;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/* ── API client ────────────────────────────────── */
|
|
144
|
-
|
|
145
|
-
export async function fetchInit(): Promise<NonNullable<SupportInitResponse["data"]>> {
|
|
146
|
-
const response = await fetch(`${PROXY_BASE}/init`, {
|
|
147
|
-
method: "GET",
|
|
148
|
-
cache: "no-store",
|
|
149
|
-
headers: { "Content-Type": "application/json" },
|
|
150
|
-
});
|
|
151
|
-
const payload = (await response.json()) as SupportInitResponse;
|
|
152
|
-
if (!response.ok || !payload?.success || !payload?.data) {
|
|
153
|
-
throw new Error(payload?.error || "Failed to load support data.");
|
|
154
|
-
}
|
|
155
|
-
return payload.data;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export async function createTicket(body: {
|
|
159
|
-
email: string;
|
|
160
|
-
title: string;
|
|
161
|
-
templateId: string;
|
|
162
|
-
answers: Record<string, unknown>;
|
|
163
|
-
hasFiles: boolean;
|
|
164
|
-
fileQuestionIds: string[];
|
|
165
|
-
}): Promise<{ emailLimitReached?: boolean; warning?: string }> {
|
|
166
|
-
const payload = {
|
|
167
|
-
email: body.email,
|
|
168
|
-
title: body.title,
|
|
169
|
-
templateId: body.templateId,
|
|
170
|
-
answers: { ...body.answers },
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
let response: Response;
|
|
174
|
-
if (body.hasFiles) {
|
|
175
|
-
const formData = new FormData();
|
|
176
|
-
const normalizedAnswers: Record<string, unknown> = {};
|
|
177
|
-
for (const [questionId, answer] of Object.entries(payload.answers)) {
|
|
178
|
-
if (answer instanceof File) {
|
|
179
|
-
formData.append(`files[${questionId}]`, answer);
|
|
180
|
-
normalizedAnswers[questionId] = "__isFile:true";
|
|
181
|
-
} else {
|
|
182
|
-
normalizedAnswers[questionId] = answer;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
formData.append("data", JSON.stringify({ ...payload, answers: normalizedAnswers }));
|
|
186
|
-
response = await fetch(`${PROXY_BASE}/tickets`, { method: "POST", body: formData });
|
|
187
|
-
} else {
|
|
188
|
-
response = await fetch(`${PROXY_BASE}/tickets`, {
|
|
189
|
-
method: "POST",
|
|
190
|
-
headers: { "Content-Type": "application/json" },
|
|
191
|
-
body: JSON.stringify(payload),
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const responsePayload = (await response.json()) as {
|
|
196
|
-
error?: string;
|
|
197
|
-
success?: boolean;
|
|
198
|
-
data?: { email_limit_reached?: boolean; warning?: string };
|
|
199
|
-
};
|
|
200
|
-
if (!response.ok || !responsePayload?.success) {
|
|
201
|
-
throw new Error(responsePayload?.error || "Failed to create ticket.");
|
|
202
|
-
}
|
|
203
|
-
return {
|
|
204
|
-
emailLimitReached: responsePayload.data?.email_limit_reached ?? false,
|
|
205
|
-
warning: responsePayload.data?.warning,
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
export async function fetchThread(token: string): Promise<TicketThread> {
|
|
210
|
-
const response = await fetch(
|
|
211
|
-
`${PROXY_BASE}/thread?token=${encodeURIComponent(token)}`,
|
|
212
|
-
{ method: "GET", cache: "no-store", headers: { "Content-Type": "application/json" } },
|
|
213
|
-
);
|
|
214
|
-
const payload = (await response.json()) as {
|
|
215
|
-
success?: boolean;
|
|
216
|
-
error?: string;
|
|
217
|
-
error_code?: string;
|
|
218
|
-
data?: TicketThread;
|
|
219
|
-
};
|
|
220
|
-
if (!response.ok || !payload?.success || !payload?.data) {
|
|
221
|
-
if (payload?.error_code === "ticket-link-expired") {
|
|
222
|
-
throw new Error("This link has expired. A new secure link has been sent to your email.");
|
|
223
|
-
}
|
|
224
|
-
throw new Error(payload?.error || "Failed to load ticket.");
|
|
225
|
-
}
|
|
226
|
-
return payload.data;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
export async function sendReply(token: string, content: string, files: File[]): Promise<void> {
|
|
230
|
-
const url = `${PROXY_BASE}/messages?token=${encodeURIComponent(token)}`;
|
|
231
|
-
|
|
232
|
-
let response: Response;
|
|
233
|
-
if (files.length > 0) {
|
|
234
|
-
const formData = new FormData();
|
|
235
|
-
formData.append("data", JSON.stringify({ content }));
|
|
236
|
-
for (const file of files) formData.append("files", file);
|
|
237
|
-
response = await fetch(url, { method: "POST", body: formData });
|
|
238
|
-
} else {
|
|
239
|
-
response = await fetch(url, {
|
|
240
|
-
method: "POST",
|
|
241
|
-
headers: { "Content-Type": "application/json" },
|
|
242
|
-
body: JSON.stringify({ content }),
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const payload = (await response.json()) as {
|
|
247
|
-
success?: boolean;
|
|
248
|
-
error?: string;
|
|
249
|
-
error_code?: string;
|
|
250
|
-
};
|
|
251
|
-
if (!response.ok || !payload?.success) {
|
|
252
|
-
if (payload?.error_code === "ticket-link-expired") {
|
|
253
|
-
throw new Error("This link has expired. A new secure link has been sent to your email.");
|
|
254
|
-
}
|
|
255
|
-
throw new Error(payload?.error || "Failed to send reply.");
|
|
256
|
-
}
|
|
257
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { VICKET_API_URL, VICKET_API_KEY } from "$env/static/private";
|
|
2
|
-
import { json } from "@sveltejs/kit";
|
|
3
|
-
import type { RequestHandler } from "./$types";
|
|
4
|
-
|
|
5
|
-
const baseUrl = (VICKET_API_URL || "").replace(/\/+$/, "");
|
|
6
|
-
|
|
7
|
-
export const GET: RequestHandler = async () => {
|
|
8
|
-
if (!baseUrl || !VICKET_API_KEY) {
|
|
9
|
-
return json({ success: false, error: "Server misconfigured: missing VICKET_API_URL or VICKET_API_KEY." }, { status: 500 });
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const response = await fetch(`${baseUrl}/public/support/init`, {
|
|
13
|
-
method: "GET",
|
|
14
|
-
headers: { "X-Api-Key": VICKET_API_KEY, "Content-Type": "application/json" },
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
const body = await response.text();
|
|
18
|
-
return new Response(body, {
|
|
19
|
-
status: response.status,
|
|
20
|
-
headers: { "Content-Type": response.headers.get("Content-Type") || "application/json" },
|
|
21
|
-
});
|
|
22
|
-
};
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { VICKET_API_URL, VICKET_API_KEY } from "$env/static/private";
|
|
2
|
-
import { json } from "@sveltejs/kit";
|
|
3
|
-
import type { RequestHandler } from "./$types";
|
|
4
|
-
|
|
5
|
-
const baseUrl = (VICKET_API_URL || "").replace(/\/+$/, "");
|
|
6
|
-
|
|
7
|
-
export const POST: RequestHandler = async ({ url, request }) => {
|
|
8
|
-
if (!baseUrl || !VICKET_API_KEY) {
|
|
9
|
-
return json({ success: false, error: "Server misconfigured: missing VICKET_API_URL or VICKET_API_KEY." }, { status: 500 });
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const token = url.searchParams.get("token") || "";
|
|
13
|
-
const target = `${baseUrl}/public/support/ticket/messages?token=${encodeURIComponent(token)}`;
|
|
14
|
-
|
|
15
|
-
const contentType = request.headers.get("Content-Type") || "";
|
|
16
|
-
const isFormData = contentType.includes("multipart/form-data");
|
|
17
|
-
|
|
18
|
-
let response: Response;
|
|
19
|
-
if (isFormData) {
|
|
20
|
-
const formData = await request.formData();
|
|
21
|
-
response = await fetch(target, {
|
|
22
|
-
method: "POST",
|
|
23
|
-
headers: { "X-Api-Key": VICKET_API_KEY },
|
|
24
|
-
body: formData,
|
|
25
|
-
});
|
|
26
|
-
} else {
|
|
27
|
-
const body = await request.text();
|
|
28
|
-
response = await fetch(target, {
|
|
29
|
-
method: "POST",
|
|
30
|
-
headers: { "X-Api-Key": VICKET_API_KEY, "Content-Type": "application/json" },
|
|
31
|
-
body,
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const responseBody = await response.text();
|
|
36
|
-
return new Response(responseBody, {
|
|
37
|
-
status: response.status,
|
|
38
|
-
headers: { "Content-Type": response.headers.get("Content-Type") || "application/json" },
|
|
39
|
-
});
|
|
40
|
-
};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { VICKET_API_URL, VICKET_API_KEY } from "$env/static/private";
|
|
2
|
-
import { json } from "@sveltejs/kit";
|
|
3
|
-
import type { RequestHandler } from "./$types";
|
|
4
|
-
|
|
5
|
-
const baseUrl = (VICKET_API_URL || "").replace(/\/+$/, "");
|
|
6
|
-
|
|
7
|
-
export const GET: RequestHandler = async ({ url }) => {
|
|
8
|
-
if (!baseUrl || !VICKET_API_KEY) {
|
|
9
|
-
return json({ success: false, error: "Server misconfigured: missing VICKET_API_URL or VICKET_API_KEY." }, { status: 500 });
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const token = url.searchParams.get("token") || "";
|
|
13
|
-
const target = `${baseUrl}/public/support/ticket?token=${encodeURIComponent(token)}`;
|
|
14
|
-
|
|
15
|
-
const response = await fetch(target, {
|
|
16
|
-
method: "GET",
|
|
17
|
-
headers: { "X-Api-Key": VICKET_API_KEY, "Content-Type": "application/json" },
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const body = await response.text();
|
|
21
|
-
return new Response(body, {
|
|
22
|
-
status: response.status,
|
|
23
|
-
headers: { "Content-Type": response.headers.get("Content-Type") || "application/json" },
|
|
24
|
-
});
|
|
25
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { VICKET_API_URL, VICKET_API_KEY } from "$env/static/private";
|
|
2
|
-
import { json } from "@sveltejs/kit";
|
|
3
|
-
import type { RequestHandler } from "./$types";
|
|
4
|
-
|
|
5
|
-
const baseUrl = (VICKET_API_URL || "").replace(/\/+$/, "");
|
|
6
|
-
|
|
7
|
-
export const POST: RequestHandler = async ({ request }) => {
|
|
8
|
-
if (!baseUrl || !VICKET_API_KEY) {
|
|
9
|
-
return json({ success: false, error: "Server misconfigured: missing VICKET_API_URL or VICKET_API_KEY." }, { status: 500 });
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const contentType = request.headers.get("Content-Type") || "";
|
|
13
|
-
const isFormData = contentType.includes("multipart/form-data");
|
|
14
|
-
|
|
15
|
-
let response: Response;
|
|
16
|
-
if (isFormData) {
|
|
17
|
-
const formData = await request.formData();
|
|
18
|
-
response = await fetch(`${baseUrl}/public/support/tickets`, {
|
|
19
|
-
method: "POST",
|
|
20
|
-
headers: { "X-Api-Key": VICKET_API_KEY },
|
|
21
|
-
body: formData,
|
|
22
|
-
});
|
|
23
|
-
} else {
|
|
24
|
-
const body = await request.text();
|
|
25
|
-
response = await fetch(`${baseUrl}/public/support/tickets`, {
|
|
26
|
-
method: "POST",
|
|
27
|
-
headers: { "X-Api-Key": VICKET_API_KEY, "Content-Type": "application/json" },
|
|
28
|
-
body,
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const responseBody = await response.text();
|
|
33
|
-
return new Response(responseBody, {
|
|
34
|
-
status: response.status,
|
|
35
|
-
headers: { "Content-Type": response.headers.get("Content-Type") || "application/json" },
|
|
36
|
-
});
|
|
37
|
-
};
|