|
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 = [ |
|
116 | 127 | ? `${$supportData.category}-${$supportData.topic}`.toLowerCase() |
117 | 128 | : $supportData.category.toLowerCase(); |
118 | 129 |
|
| 130 | + const formData = new FormData(); |
| 131 | + formData.append('email', $user.email); |
| 132 | + formData.append('subject', $supportData.subject); |
| 133 | + formData.append('firstName', ($user?.name || 'Unknown').slice(0, 40)); |
| 134 | + formData.append('message', $supportData.message); |
| 135 | + formData.append('tags[]', categoryTopicTag); |
| 136 | + formData.append( |
| 137 | + 'customFields', |
| 138 | + JSON.stringify([ |
| 139 | + { id: '41612', value: $supportData.category }, |
| 140 | + { id: '48492', value: $organization?.$id ?? '' }, |
| 141 | + { id: '48491', value: $supportData?.project ?? '' }, |
| 142 | + { id: '56023', value: $supportData?.severity ?? '' }, |
| 143 | + { id: '56024', value: $organization?.billingPlan ?? '' } |
| 144 | + ]) |
| 145 | + ); |
| 146 | + if (files && files.length > 0) { |
| 147 | + formData.append('attachment', files[0]); |
| 148 | + } |
| 149 | +
|
119 | 150 | const response = await fetch(`${VARS.GROWTH_ENDPOINT}/support`, { |
120 | 151 | method: 'POST', |
121 | | - headers: { |
122 | | - 'Content-Type': 'application/json' |
123 | | - }, |
124 | | - body: JSON.stringify({ |
125 | | - email: $user.email, |
126 | | - subject: $supportData.subject, |
127 | | - firstName: ($user?.name || 'Unknown').slice(0, 40), |
128 | | - message: $supportData.message, |
129 | | - tags: [categoryTopicTag], |
130 | | - customFields: [ |
131 | | - { id: '41612', value: $supportData.category }, |
132 | | - { id: '48492', value: $organization?.$id ?? '' }, |
133 | | - { id: '48491', value: $supportData?.project ?? '' }, |
134 | | - { id: '56023', value: $supportData?.severity ?? '' }, |
135 | | - { id: '56024', value: $organization?.billingPlan ?? '' } |
136 | | - ] |
137 | | - }) |
| 152 | + body: formData |
138 | 153 | }); |
139 | 154 | trackEvent(Submit.SupportTicket); |
140 | 155 | if (response.status !== 200) { |
|
169 | 184 |
|
170 | 185 | $wizard.finalAction = handleSubmit; |
171 | 186 |
|
| 187 | + function handleInvalid(_e: CustomEvent) { |
| 188 | + addNotification({ |
| 189 | + type: 'error', |
| 190 | + message: 'Invalid file' |
| 191 | + }); |
| 192 | + } |
| 193 | +
|
172 | 194 | const workTimings = { |
173 | 195 | start: '16:00', |
174 | 196 | end: '00:00', |
|
279 | 301 | label="Tell us a bit more" |
280 | 302 | required |
281 | 303 | maxlength={4096} /> |
| 304 | + <Upload.Dropzone bind:files on:invalid={handleInvalid} maxSize={5 * 1024 * 1024}> |
| 305 | + <Layout.Stack alignItems="center" gap="s"> |
| 306 | + <Typography.Text variant="l-500" |
| 307 | + >Drag and drop a file here or click to upload</Typography.Text> |
| 308 | + <Typography.Caption variant="400">Max file size: 5MB</Typography.Caption> |
| 309 | + </Layout.Stack> |
| 310 | + </Upload.Dropzone> |
| 311 | + {#if files} |
| 312 | + <Upload.List |
| 313 | + files={Array.from(files).map((f) => { |
| 314 | + return { |
| 315 | + ...f, |
| 316 | + name: f.name, |
| 317 | + size: f.size, |
| 318 | + extension: f.type, |
| 319 | + removable: true |
| 320 | + }; |
| 321 | + })} |
| 322 | + on:remove={(e) => (files = removeFile(e.detail, files))} /> |
| 323 | + {/if} |
282 | 324 | <Layout.Stack direction="row" justifyContent="flex-end" gap="s"> |
283 | 325 | <Button |
284 | 326 | size="s" |
|
0 commit comments