This commit is contained in:
2023-02-28 11:45:04 +10:00
parent 03ec852648
commit 3f0ebca4da

View File

@@ -1,106 +1,117 @@
<template> <template>
<SMPage :page-error="pageError" permission="admin/events"> <SMPage
<SMRow> :page-error="pageError"
<SMDialog :loading="formLoading"> permission="admin/events"
<h1>{{ page_title }}</h1> class="sm-page-event-edit">
<SMForm :model-value="form" @submit="handleSubmit"> <template #container>
<SMRow> <h1>{{ page_title }}</h1>
<SMColumn><SMInput control="title" /></SMColumn> <SMForm :model-value="form" @submit="handleSubmit">
</SMRow> <SMRow>
<SMRow> <SMColumn><SMInput control="title" /></SMColumn>
<SMColumn> </SMRow>
<SMInput <SMRow>
control="location" <SMColumn>
:options="{ <SMInput
online: 'Online', control="location"
physical: 'Physical', type="select"
}" /> :options="{
</SMColumn> online: 'Online',
<SMColumn physical: 'Physical',
><SMInput }" />
v-if="form.location.value !== 'online'" </SMColumn>
control="address" <SMColumn
/></SMColumn> ><SMInput
</SMRow> v-if="form.controls.location.value !== 'online'"
<SMRow> control="address"
<SMColumn> /></SMColumn>
<SMDatepicker </SMRow>
control="start_at" <SMRow>
label="Start Date/Time"></SMDatepicker> <SMColumn>
</SMColumn> <SMInput
<SMColumn> type="datetime"
<SMDatepicker control="start_at"
control="end_at" label="Start Date/Time" />
label="End Date/Time"></SMDatepicker> </SMColumn>
</SMColumn> <SMColumn>
</SMRow> <SMInput
<SMRow> type="datetime"
<SMColumn> control="end_at"
<SMDatepicker label="End Date/Time" />
control="publish_at" </SMColumn>
label="Publish Date/Time"></SMDatepicker> </SMRow>
</SMColumn> <SMRow>
<SMColumn> <SMColumn>
<SMInput <SMInput
control="status" type="datetime"
:options="{ control="publish_at"
draft: 'Draft', label="Publish Date/Time" />
soon: 'Opening Soon', </SMColumn>
open: 'Open', <SMColumn>
closed: 'Closed', <SMInput
cancelled: 'Cancelled', type="select"
}" /> control="status"
</SMColumn> :options="{
</SMRow> draft: 'Draft',
<SMRow> soon: 'Opening Soon',
<SMColumn> open: 'Open',
<SMInput closed: 'Closed',
control="registration_type" cancelled: 'Cancelled',
label="Registration" }" />
:options="{ </SMColumn>
none: 'None', </SMRow>
email: 'Email', <SMRow>
link: 'Link', <SMColumn>
}" /> <SMInput
</SMColumn> type="select"
<SMColumn> control="registration_type"
<SMInput label="Registration"
v-if="registration_data?.visible" :options="{
control="registration_data" none: 'None',
:label="registration_data?.title" email: 'Email',
:type="registration_data?.type" /> link: 'Link',
</SMColumn> }" />
</SMRow> </SMColumn>
<SMRow> <SMColumn>
<SMColumn> <SMInput
<SMInput v-if="registration_data?.visible"
control="hero" control="registration_data"
type="media" :label="registration_data?.title"
label="Hero image" /> :type="registration_data?.type" />
</SMColumn> </SMColumn>
</SMRow> </SMRow>
<SMRow> <SMRow>
<SMColumn> <SMColumn>
<SMEditor <SMInput
v-model:srcContent="form.content.value" control="hero"
:mime-types="[ type="media"
'image/png', label="Hero image" />
'image/jpeg', </SMColumn>
'image/gif', </SMRow>
]" <SMRow>
@trix-attachment-add="attachmentAdd" /> <SMColumn>
</SMColumn> <SMEditor
</SMRow> :model-value="form.controls.content.value"
<SMRow> :mime-types="[
<SMFormFooter> 'image/png',
<template #right> 'image/jpeg',
<SMButton type="submit" label="Save" /> 'image/gif',
</template> ]" />
</SMFormFooter> </SMColumn>
</SMRow> </SMRow>
</SMForm> <SMRow>
</SMDialog> <SMColumn>
</SMRow> <SMInputAttachments :model-value="attachments" />
</SMColumn>
</SMRow>
<SMRow>
<SMFormFooter>
<template #right>
<SMButton type="submit" label="Save" />
</template>
</SMFormFooter>
</SMRow>
</SMForm>
</template>
</SMPage> </SMPage>
</template> </template>
@@ -108,14 +119,12 @@
import { computed, reactive, ref } from "vue"; import { computed, reactive, ref } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import SMButton from "../../components/SMButton.vue"; import SMButton from "../../components/SMButton.vue";
import SMDatepicker from "../../components/SMDatePicker.vue";
import SMDialog from "../../components/SMDialog.vue";
import SMEditor from "../../components/SMEditor.vue"; import SMEditor from "../../components/SMEditor.vue";
import SMFormFooter from "../../components/SMFormFooter.vue"; import SMFormFooter from "../../components/SMFormFooter.vue";
import SMInput from "../../components/SMInput.vue"; import SMInput from "../../components/SMInput.vue";
import { api } from "../../helpers/api"; import { api } from "../../helpers/api";
import { SMDate } from "../../helpers/datetime"; import { SMDate } from "../../helpers/datetime";
import { FormControl } from "../../helpers/form"; import { Form, FormControl } from "../../helpers/form";
import { import {
And, And,
Custom, Custom,
@@ -125,12 +134,13 @@ import {
Required, Required,
Url, Url,
} from "../../helpers/validate"; } from "../../helpers/validate";
import SMInputAttachments from "../../components/SMInputAttachments.vue";
import SMForm from "../../components/SMForm.vue"; import SMForm from "../../components/SMForm.vue";
const route = useRoute(); const route = useRoute();
const page_title = route.params.id ? "Edit Event" : "Create New Event"; const page_title = route.params.id ? "Edit Event" : "Create New Event";
const pageError = ref(200); const pageError = ref(200);
const attachments = ref([]);
const address_data = computed(() => { const address_data = computed(() => {
let data = { let data = {
@@ -138,9 +148,9 @@ const address_data = computed(() => {
required: false, required: false,
}; };
if (form?.location.value === "online") { if (form?.controls.location.value === "online") {
data.required = false; data.required = false;
} else if (form?.location.value === "physical") { } else if (form?.controls.location.value === "physical") {
data.title = "Address"; data.title = "Address";
data.required = true; data.required = true;
} }
@@ -155,11 +165,11 @@ const registration_data = computed(() => {
type: "text", type: "text",
}; };
if (form?.registration_type.value === "email") { if (form?.controls.registration_type.value === "email") {
data.visible = true; data.visible = true;
data.title = "Registration email"; data.title = "Registration email";
data.type = "email"; data.type = "email";
} else if (form?.registration_type.value === "link") { } else if (form?.controls.registration_type.value === "link") {
data.visible = true; data.visible = true;
data.title = "Registration URL"; data.title = "Registration URL";
data.type = "url"; data.type = "url";
@@ -174,7 +184,7 @@ const form = reactive(
location: FormControl("online"), location: FormControl("online"),
address: FormControl( address: FormControl(
"", "",
Custom((value) => { Custom(async (value) => {
return address_data?.value.required && value.length == 0 return address_data?.value.required && value.length == 0
? "A venue address is required" ? "A venue address is required"
: false; : false;
@@ -187,7 +197,7 @@ const form = reactive(
Required(), Required(),
DateTime({ DateTime({
after: (v) => { after: (v) => {
return form.start_at.value; return form.controls.start_at.value;
}, },
invalidAfterMessage: invalidAfterMessage:
"The ending date/time must be after the starting date/time.", "The ending date/time must be after the starting date/time.",
@@ -199,16 +209,16 @@ const form = reactive(
registration_type: FormControl("none"), registration_type: FormControl("none"),
registration_data: FormControl( registration_data: FormControl(
"", "",
Custom((v) => { Custom(async (v) => {
let validationResult = { let validationResult = {
valid: true, valid: true,
invalidMessages: [""], invalidMessages: [""],
}; };
if (registration_data.value.type == "email") { if (registration_data.value.type == "email") {
validationResult = Email().validate(v); validationResult = await Email().validate(v);
} else if (registration_data.value.type == "url") { } else if (registration_data.value.type == "url") {
validationResult = Url().validate(v); validationResult = await Url().validate(v);
} }
if (!validationResult.valid) { if (!validationResult.valid) {
@@ -233,30 +243,35 @@ const loadData = async () => {
throw new Error("The server is currently not available"); throw new Error("The server is currently not available");
} }
form.title.value = res.data.event.title; form.controls.title.value = res.data.event.title;
form.location.value = res.data.event.location; form.controls.location.value = res.data.event.location;
form.address.value = res.data.event.address form.controls.address.value = res.data.event.address
? res.data.event.address ? res.data.event.address
: ""; : "";
form.start_at.value = new SMDate(res.data.event.start_at, { form.controls.start_at.value = new SMDate(res.data.event.start_at, {
format: "ymd", format: "ymd",
utc: true, utc: true,
}).format("yyyy/MM/dd HH:mm:ss"); }).format("yyyy/MM/dd HH:mm:ss");
form.end_at.value = new SMDate(res.data.event.end_at, { form.controls.end_at.value = new SMDate(res.data.event.end_at, {
format: "ymd", format: "ymd",
utc: true, utc: true,
}).format("yyyy/MM/dd HH:mm:ss"); }).format("yyyy/MM/dd HH:mm:ss");
form.status.value = res.data.event.status; form.controls.status.value = res.data.event.status;
form.publish_at.value = new SMDate(res.data.event.publish_at, { form.controls.publish_at.value = new SMDate(
format: "ymd", res.data.event.publish_at,
utc: true, {
}).format("yyyy/MM/dd HH:mm:ss"); format: "ymd",
form.registration_type.value = res.data.event.registration_type; utc: true,
form.registration_data.value = res.data.event.registration_data; }
form.content.value = res.data.event.content ).format("yyyy/MM/dd HH:mm:ss");
form.controls.registration_type.value =
res.data.event.registration_type;
form.controls.registration_data.value =
res.data.event.registration_data;
form.controls.content.value = res.data.event.content
? res.data.event.content ? res.data.event.content
: ""; : "";
form.hero.value = res.data.event.hero; form.controls.hero.value = res.data.event.hero;
} catch (err) { } catch (err) {
pageError.value = err.response.status; pageError.value = err.response.status;
} }
@@ -268,28 +283,26 @@ const loadData = async () => {
const handleSubmit = async () => { const handleSubmit = async () => {
try { try {
let data = { let data = {
title: form.title.value, title: form.controls.title.value,
location: form.location.value, location: form.controls.location.value,
address: form.address.value, address: form.controls.address.value,
start_at: new SMDate(form.start_at.value, { format: "dmy" }).format( start_at: new SMDate(form.controls.start_at.value, {
"yyyy/MM/dd HH:mm:ss", format: "dmy",
{ utc: true } }).format("yyyy/MM/dd HH:mm:ss", { utc: true }),
), end_at: new SMDate(form.controls.end_at.value, {
end_at: new SMDate(form.end_at.value, { format: "dmy" }).format( format: "dmy",
"yyyy/MM/dd HH:mm:ss", }).format("yyyy/MM/dd HH:mm:ss", { utc: true }),
{ utc: true } status: form.controls.status.value,
),
status: form.status.value,
publish_at: publish_at:
form.publish_at.value == "" form.controls.publish_at.value == ""
? "" ? ""
: new SMDate(form.publish_at.value, { : new SMDate(form.controls.publish_at.value, {
format: "dmy", format: "dmy",
}).format("yyyy/MM/dd HH:mm:ss", { utc: true }), }).format("yyyy/MM/dd HH:mm:ss", { utc: true }),
registration_type: form.registration_type.value, registration_type: form.controls.registration_type.value,
registration_data: form.registration_data.value, registration_data: form.controls.registration_data.value,
content: form.content.value, content: form.controls.content.value,
hero: form.hero.value, hero: form.controls.hero.value,
}; };
if (route.params.id) { if (route.params.id) {
@@ -316,46 +329,11 @@ const handleSubmit = async () => {
}); });
}; };
const createStorageKey = (file) => {
var date = new Date();
var day = date.toISOString().slice(0, 10);
var name = date.getTime() + "-" + file.name;
return ["tmp", day, name].join("/");
};
const attachmentAdd = async (event) => {
if (event.attachment.file) {
const key = createStorageKey(event.attachment.file);
var fileFormData = new FormData();
fileFormData.append("key", key);
fileFormData.append("Content-Type", event.attachment.file.type);
fileFormData.append("file", event.attachment.file);
try {
let res = await axios.post("media", fileFormData, {
headers: {
"Content-Type": "multipart/form-data",
},
onUploadProgress: (progressEvent) =>
event.attachment.setUploadProgress(
(progressEvent.loaded * progressEvent.total) / 100
),
});
event.attachment.setAttributes({
url: res.data.media.url,
href: res.data.media.url,
});
} catch (err) {
event.preventDefault();
alert(
err.response?.data?.message ||
"An unexpected server error occurred"
);
}
}
};
loadData(); loadData();
</script> </script>
<style lang="scss">
.sm-page-event-edit {
background-color: #f8f8f8;
}
</style>