|
1 | 1 | <script lang="ts"> |
2 | 2 | import { Wizard } from '$lib/layout'; |
3 | | - import { Icon, Input, Layout, Popover, Tag, Typography, Card } from '@appwrite.io/pink-svelte'; |
| 3 | + import { |
| 4 | + Icon, |
| 5 | + Input, |
| 6 | + Layout, |
| 7 | + Popover, |
| 8 | + Tag, |
| 9 | + Typography, |
| 10 | + Card, |
| 11 | + Upload |
| 12 | + } from '@appwrite.io/pink-svelte'; |
4 | 13 | import { supportData, isSupportOnline } from './wizard/support/store'; |
5 | 14 | import { onMount, onDestroy } from 'svelte'; |
6 | 15 | import { sdk } from '$lib/stores/sdk'; |
|
25 | 34 | import { wizard } from '$lib/stores/wizard'; |
26 | 35 | import { VARS } from '$lib/system'; |
27 | 36 | import { IconCheckCircle, IconXCircle, IconInfo } from '@appwrite.io/pink-icons-svelte'; |
| 37 | + import { removeFile } from '$lib/helpers/files'; |
28 | 38 |
|
29 | 39 | let projectOptions = $state<Array<{ value: string; label: string }>>([]); |
| 40 | + let files = $state<FileList | null>(null); |
30 | 41 |
|
31 | 42 | // Category options with display names |
32 | 43 | const categories = [ |
|
101 | 112 | ? `${$supportData.category}-${$supportData.topic}`.toLowerCase() |
102 | 113 | : $supportData.category.toLowerCase(); |
103 | 114 |
|
| 115 | + const formData = new FormData(); |
| 116 | + formData.append('email', $user.email); |
| 117 | + formData.append('subject', $supportData.subject); |
| 118 | + formData.append('firstName', ($user?.name || 'Unknown').slice(0, 40)); |
| 119 | + formData.append('message', $supportData.message); |
| 120 | + formData.append('tags[]', categoryTopicTag); |
| 121 | + formData.append( |
| 122 | + 'customFields', |
| 123 | + JSON.stringify([ |
| 124 | + { id: '41612', value: $supportData.category }, |
| 125 | + { id: '48492', value: $organization?.$id ?? '' }, |
| 126 | + { id: '48491', value: $supportData?.project ?? '' }, |
| 127 | + { id: '56023', value: $supportData?.severity ?? '' }, |
| 128 | + { id: '56024', value: $organization?.billingPlan ?? '' } |
| 129 | + ]) |
| 130 | + ); |
| 131 | + if (files && files.length > 0) { |
| 132 | + formData.append('attachment', files[0]); |
| 133 | + } |
| 134 | +
|
104 | 135 | const response = await fetch(`${VARS.GROWTH_ENDPOINT}/support`, { |
105 | 136 | method: 'POST', |
106 | | - headers: { |
107 | | - 'Content-Type': 'application/json' |
108 | | - }, |
109 | | - body: JSON.stringify({ |
110 | | - email: $user.email, |
111 | | - subject: $supportData.subject, |
112 | | - firstName: ($user?.name || 'Unknown').slice(0, 40), |
113 | | - message: $supportData.message, |
114 | | - tags: [categoryTopicTag], |
115 | | - customFields: [ |
116 | | - { id: '41612', value: $supportData.category }, |
117 | | - { id: '48492', value: $organization?.$id ?? '' }, |
118 | | - { id: '48491', value: $supportData?.project ?? '' }, |
119 | | - { id: '56023', value: $supportData?.severity ?? '' }, |
120 | | - { id: '56024', value: $organization?.billingPlan ?? '' } |
121 | | - ] |
122 | | - }) |
| 137 | + body: formData |
123 | 138 | }); |
124 | 139 | trackEvent(Submit.SupportTicket); |
125 | 140 | if (response.status !== 200) { |
|
154 | 169 |
|
155 | 170 | $wizard.finalAction = handleSubmit; |
156 | 171 |
|
| 172 | + function handleInvalid(_e: CustomEvent) { |
| 173 | + addNotification({ |
| 174 | + type: 'error', |
| 175 | + message: 'Invalid file' |
| 176 | + }); |
| 177 | + } |
| 178 | +
|
157 | 179 | const workTimings = { |
158 | 180 | start: '16:00', |
159 | 181 | end: '00:00', |
|
264 | 286 | label="Tell us a bit more" |
265 | 287 | required |
266 | 288 | maxlength={4096} /> |
| 289 | + <Upload.Dropzone bind:files on:invalid={handleInvalid} maxSize={5 * 1024 * 1024}> |
| 290 | + <Layout.Stack alignItems="center" gap="s"> |
| 291 | + <Typography.Text variant="l-500" |
| 292 | + >Drag and drop a file here or click to upload</Typography.Text> |
| 293 | + <Typography.Caption variant="400">Max file size: 5MB</Typography.Caption> |
| 294 | + </Layout.Stack> |
| 295 | + </Upload.Dropzone> |
| 296 | + {#if files} |
| 297 | + <Upload.List |
| 298 | + files={Array.from(files).map((f) => { |
| 299 | + return { |
| 300 | + ...f, |
| 301 | + name: f.name, |
| 302 | + size: f.size, |
| 303 | + extension: f.type, |
| 304 | + removable: true |
| 305 | + }; |
| 306 | + })} |
| 307 | + on:remove={(e) => (files = removeFile(e.detail, files))} /> |
| 308 | + {/if} |
267 | 309 | <Layout.Stack direction="row" justifyContent="flex-end" gap="s"> |
268 | 310 | <Button |
269 | 311 | size="s" |
|
0 commit comments