You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
4.7 KiB
177 lines
4.7 KiB
<template>
|
|
<div v-if="visible" class="dialog-overlay z-[60]">
|
|
<div class="dialog relative">
|
|
<div class="text-lg text-center font-light relative z-50">
|
|
<div
|
|
id="ViewHeading"
|
|
class="text-center font-bold absolute top-0 left-0 right-0 px-4 py-0.5 bg-black/50 text-white leading-none"
|
|
>
|
|
Add Photo
|
|
</div>
|
|
<div
|
|
class="text-lg text-center px-2 py-0.5 leading-none absolute right-0 top-0 text-white"
|
|
@click="close()"
|
|
>
|
|
<fa icon="xmark" class="w-[1em]"></fa>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<div class="text-center mt-8">
|
|
<div class>
|
|
<fa
|
|
icon="camera"
|
|
class="bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-2 rounded-md"
|
|
@click="openPhotoDialog()"
|
|
/>
|
|
</div>
|
|
<div class="mt-4">
|
|
<input type="file" @change="uploadImageFile" />
|
|
</div>
|
|
<div class="mt-4">
|
|
<span class="mt-2">
|
|
... or paste a URL:
|
|
<input type="text" v-model="imageUrl" class="border-2" />
|
|
</span>
|
|
<span class="ml-2">
|
|
<fa
|
|
v-if="imageUrl"
|
|
icon="check"
|
|
class="bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-2 rounded-md cursor-pointer"
|
|
@click="acceptUrl"
|
|
/>
|
|
<!-- so that there's no shifting when it becomes visible -->
|
|
<fa v-else icon="check" class="text-white bg-white px-2 py-2" />
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<PhotoDialog ref="photoDialog" />
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import axios from "axios";
|
|
import { ref } from "vue";
|
|
import { Component, Vue } from "vue-facing-decorator";
|
|
|
|
import PhotoDialog from "@/components/PhotoDialog.vue";
|
|
import { NotificationIface } from "@/constants/app";
|
|
|
|
const inputImageFileNameRef = ref<Blob>();
|
|
|
|
@Component({
|
|
components: { PhotoDialog },
|
|
})
|
|
export default class ImageMethodDialog extends Vue {
|
|
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
|
|
|
claimType: string;
|
|
crop: boolean = false;
|
|
imageCallback: (imageUrl?: string) => void = () => {};
|
|
imageUrl?: string;
|
|
visible = false;
|
|
|
|
open(setImageFn: (arg: string) => void, claimType: string, crop?: boolean) {
|
|
this.claimType = claimType;
|
|
this.crop = !!crop;
|
|
this.imageCallback = setImageFn;
|
|
|
|
this.visible = true;
|
|
}
|
|
|
|
openPhotoDialog(blob?: Blob, fileName?: string) {
|
|
this.visible = false;
|
|
|
|
(this.$refs.photoDialog as PhotoDialog).open(
|
|
this.imageCallback,
|
|
this.claimType,
|
|
this.crop,
|
|
blob,
|
|
fileName,
|
|
);
|
|
}
|
|
|
|
async uploadImageFile(event: Event) {
|
|
this.visible = false;
|
|
|
|
inputImageFileNameRef.value = event.target.files[0];
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/File
|
|
// ... plus it has a `type` property from my testing
|
|
const file = inputImageFileNameRef.value;
|
|
if (file != null) {
|
|
const reader = new FileReader();
|
|
reader.onload = async (e) => {
|
|
const data = e.target?.result as ArrayBuffer;
|
|
if (data) {
|
|
const blob = new Blob([new Uint8Array(data)], {
|
|
type: file.type,
|
|
});
|
|
this.openPhotoDialog(blob, file.name as string);
|
|
}
|
|
};
|
|
reader.readAsArrayBuffer(file as Blob);
|
|
}
|
|
}
|
|
|
|
async acceptUrl() {
|
|
this.visible = false;
|
|
if (this.crop) {
|
|
try {
|
|
const urlBlobResponse: Blob = await axios.get(this.imageUrl as string, {
|
|
responseType: "blob", // This ensures the data is returned as a Blob
|
|
});
|
|
const fullUrl = new URL(this.imageUrl as string);
|
|
const fileName = fullUrl.pathname.split("/").pop() as string;
|
|
(this.$refs.photoDialog as PhotoDialog).open(
|
|
this.imageCallback,
|
|
this.claimType,
|
|
this.crop,
|
|
urlBlobResponse.data as Blob,
|
|
fileName,
|
|
);
|
|
} catch (error) {
|
|
this.$notify(
|
|
{
|
|
group: "alert",
|
|
type: "danger",
|
|
title: "Error",
|
|
text: "There was an error retrieving that image.",
|
|
},
|
|
5000,
|
|
);
|
|
}
|
|
} else {
|
|
this.imageCallback(this.imageUrl);
|
|
}
|
|
}
|
|
|
|
close() {
|
|
this.visible = false;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.dialog-overlay {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-color: rgba(0, 0, 0, 0.5);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
padding: 1.5rem;
|
|
}
|
|
|
|
.dialog {
|
|
background-color: white;
|
|
padding: 1rem;
|
|
border-radius: 0.5rem;
|
|
width: 100%;
|
|
max-width: 700px;
|
|
}
|
|
</style>
|
|
|