| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  | <template> | 
					
						
							| 
									
										
										
										
											2025-06-28 22:11:12 +02:00
										 |  |  |   <v-form ref="files"> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |     <input | 
					
						
							|  |  |  |       ref="uploader" | 
					
						
							|  |  |  |       class="d-none" | 
					
						
							|  |  |  |       type="file" | 
					
						
							|  |  |  |       :accept="accept" | 
					
						
							| 
									
										
										
										
											2025-06-28 22:11:12 +02:00
										 |  |  |       :multiple="multiple" | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |       @change="onFileChanged" | 
					
						
							|  |  |  |     > | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  |     <slot v-bind="{ isSelecting, onButtonClick }"> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |       <v-btn | 
					
						
							|  |  |  |         :loading="isSelecting" | 
					
						
							|  |  |  |         :small="small" | 
					
						
							|  |  |  |         :color="color" | 
					
						
							|  |  |  |         :variant="textBtn ? 'text' : 'elevated'" | 
					
						
							|  |  |  |         :disabled="disabled" | 
					
						
							|  |  |  |         @click="onButtonClick" | 
					
						
							|  |  |  |       > | 
					
						
							|  |  |  |         <v-icon start> | 
					
						
							|  |  |  |           {{ effIcon }} | 
					
						
							|  |  |  |         </v-icon> | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  |         {{ text ? text : defaultText }} | 
					
						
							|  |  |  |       </v-btn> | 
					
						
							|  |  |  |     </slot> | 
					
						
							|  |  |  |   </v-form> | 
					
						
							|  |  |  | </template> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  | <script lang="ts"> | 
					
						
							| 
									
										
										
										
											2021-11-06 11:28:47 -08:00
										 |  |  | import { useUserApi } from "~/composables/api"; | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  | const UPLOAD_EVENT = "uploaded"; | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | export default defineNuxtComponent({ | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  |   props: { | 
					
						
							|  |  |  |     small: { | 
					
						
							| 
									
										
										
										
											2021-08-07 15:12:25 -08:00
										 |  |  |       type: Boolean, | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  |       default: false, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     post: { | 
					
						
							|  |  |  |       type: Boolean, | 
					
						
							|  |  |  |       default: true, | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2021-08-07 15:12:25 -08:00
										 |  |  |     url: { | 
					
						
							|  |  |  |       type: String, | 
					
						
							|  |  |  |       default: "", | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     text: { | 
					
						
							|  |  |  |       type: String, | 
					
						
							|  |  |  |       default: "", | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     icon: { | 
					
						
							|  |  |  |       type: String, | 
					
						
							|  |  |  |       default: null, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     fileName: { | 
					
						
							|  |  |  |       type: String, | 
					
						
							|  |  |  |       default: "archive", | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  |     textBtn: { | 
					
						
							| 
									
										
										
										
											2021-08-07 15:12:25 -08:00
										 |  |  |       type: Boolean, | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  |       default: true, | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2021-11-23 18:57:24 -09:00
										 |  |  |     accept: { | 
					
						
							|  |  |  |       type: String, | 
					
						
							|  |  |  |       default: "", | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2023-08-21 10:00:37 -05:00
										 |  |  |     color: { | 
					
						
							|  |  |  |       type: String, | 
					
						
							|  |  |  |       default: "info", | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     disabled: { | 
					
						
							|  |  |  |       type: Boolean, | 
					
						
							|  |  |  |       default: false, | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |     }, | 
					
						
							| 
									
										
										
										
											2025-06-28 22:11:12 +02:00
										 |  |  |     multiple: { | 
					
						
							|  |  |  |       type: Boolean, | 
					
						
							|  |  |  |       default: false, | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  |   }, | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |   setup(props, context) { | 
					
						
							| 
									
										
										
										
											2025-06-28 22:11:12 +02:00
										 |  |  |     const files = ref<File[]>([]); | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |     const uploader = ref<HTMLInputElement | null>(null); | 
					
						
							|  |  |  |     const isSelecting = ref(false); | 
					
						
							| 
									
										
										
										
											2021-08-07 15:12:25 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |     const i18n = useI18n(); | 
					
						
							|  |  |  |     const { $globals } = useNuxtApp(); | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |     const effIcon = props.icon ? props.icon : $globals.icons.upload; | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |     const defaultText = i18n.t("general.upload"); | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |     const api = useUserApi(); | 
					
						
							|  |  |  |     async function upload() { | 
					
						
							| 
									
										
										
										
											2025-06-28 22:11:12 +02:00
										 |  |  |       if (files.value.length === 0) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-28 22:11:12 +02:00
										 |  |  |       isSelecting.value = true; | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-28 22:11:12 +02:00
										 |  |  |       if (!props.post) { | 
					
						
							|  |  |  |         // NOTE: To preserve behaviour for other parents of this component,
 | 
					
						
							|  |  |  |         // we emit a single File if !props.multiple.
 | 
					
						
							|  |  |  |         context.emit(UPLOAD_EVENT, props.multiple ? files.value : files.value[0]); | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |         isSelecting.value = false; | 
					
						
							| 
									
										
										
										
											2025-06-28 22:11:12 +02:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-06-28 22:11:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // WARN: My change is only for !props.post.
 | 
					
						
							|  |  |  |       // I have not added support for multiple files in the API.
 | 
					
						
							|  |  |  |       // Existing call-sites never passed the `multiple` prop,
 | 
					
						
							|  |  |  |       // so this case will only be hit if the prop is set to true.
 | 
					
						
							|  |  |  |       if (props.multiple && files.value.length > 1) { | 
					
						
							|  |  |  |         console.warn("Multiple file uploads are not supported by the API."); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const file = files.value[0]; | 
					
						
							|  |  |  |       const formData = new FormData(); | 
					
						
							|  |  |  |       formData.append(props.fileName, file); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         const response = await api.upload.file(props.url, formData); | 
					
						
							|  |  |  |         if (response) { | 
					
						
							|  |  |  |           context.emit(UPLOAD_EVENT, response); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       catch (e) { | 
					
						
							|  |  |  |         console.error(e); | 
					
						
							|  |  |  |         context.emit(UPLOAD_EVENT, null); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       isSelecting.value = false; | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function onFileChanged(e: Event) { | 
					
						
							|  |  |  |       const target = e.target as HTMLInputElement; | 
					
						
							| 
									
										
										
										
											2025-06-28 22:11:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (target.files !== null && target.files.length > 0) { | 
					
						
							|  |  |  |         files.value = Array.from(target.files); | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |         upload(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function onButtonClick() { | 
					
						
							|  |  |  |       isSelecting.value = true; | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  |       window.addEventListener( | 
					
						
							|  |  |  |         "focus", | 
					
						
							|  |  |  |         () => { | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |           isSelecting.value = false; | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  |         }, | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |         { once: true }, | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  |       ); | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |       uploader.value?.click(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |     return { | 
					
						
							| 
									
										
										
										
											2025-06-28 22:11:12 +02:00
										 |  |  |       files, | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |       uploader, | 
					
						
							|  |  |  |       isSelecting, | 
					
						
							|  |  |  |       effIcon, | 
					
						
							|  |  |  |       defaultText, | 
					
						
							|  |  |  |       onFileChanged, | 
					
						
							|  |  |  |       onButtonClick, | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  |   }, | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-08-02 22:15:11 -08:00
										 |  |  | </script> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <style></style> |