Files
aibuddytool/resources/js/vue/PostEditor.vue
2023-07-29 02:20:51 +08:00

312 lines
7.8 KiB
Vue

<template>
<div>
<div class="row justify-content-center">
<div class="col-9" style="max-width: 700px">
<div class="mb-3">
<div class="form-floating">
<input
v-model="post.title"
type="text"
class="form-control"
placeholder="Post title"
/>
<label>Write a SEO post title</label>
</div>
<small>
<span class="text-secondary">{{ getPostFullUrl }}</span>
</small>
</div>
<div class="form-floating mb-3">
<textarea
v-model="post.excerpt"
class="form-control"
style="min-height: 150px"
placeholder="Enter a post excerpt/summary"
></textarea>
<label
>Write a simple excerpt to convince & entice users to view this
post!</label
>
</div>
<native-image-block
class="mb-3"
:input-image="post.featured_image"
@saved="imageSaved"
></native-image-block>
<div class="card">
<div class="card-body">
<vue-editor-js
v-on:saved="editorSaved"
:config="config"
:initialized="onInitialized"
/>
</div>
</div>
</div>
<div class="col-3">
<div class="d-grid mb-2">
<select
class="form-select mb-2"
aria-label="Default select example"
v-on:change="statusChanged"
>
<option
v-for="item in status"
v-bind:key="item"
:selected="item == post.status"
:value="item"
>
Post Status: {{ item }}
</option>
</select>
<button @click="checkAndSave" class="btn btn-primary">
Save as {{ post.status }}
</button>
</div>
<div class="card mb-2">
<div class="card-header fw-bold">Country Locality</div>
<div class="card-body">
<select class="form-select" v-on:change="localeChanged">
<option
v-for="item in countryLocales"
v-bind:key="item.id"
:value="item.slug"
:selected="item.slug == post.locale_slug"
>
{{ item.name }}
</option>
</select>
</div>
</div>
<div class="card mb-2">
<div class="card-header fw-bold">Categories</div>
<div class="card-body">
<div
class="py-1"
v-for="item in localeCategories"
v-bind:key="item.id"
>
<label>
<input
type="radio"
:id="item.id"
:value="item.id"
v-model="post.categories"
/>
{{ item.name }}
</label>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import VueEditorJs from "./VueEditorJs.vue";
import List from "@editorjs/list";
import Header from "@editorjs/header";
import { mapActions, mapState } from "pinia";
import { usePostStore } from "@/stores/postStore.js";
export default {
components: { VueEditorJs, List, Header },
data() {
return {
post: {
title: "",
slug: "",
excerpt: "",
author_id: null,
featured: false,
featured_image: null,
body: {
time: 1591362820044,
blocks: [],
version: "2.25.0",
},
locale_slug: null,
locale_id: null,
status: "draft",
categories: null,
},
status: ["publish", "future", "draft", "private", "trash"],
config: {
placeholder: "Write something (ノ◕ヮ◕)ノ*:・゚✧",
tools: {
header: {
class: Header,
config: {
placeholder: "Enter a header",
levels: [2, 3, 4],
defaultLevel: 3,
},
},
list: {
class: List,
inlineToolbar: true,
},
},
onReady: () => {},
onChange: (args) => {},
data: {
time: 1591362820044,
blocks: [],
version: "2.25.0",
},
},
};
},
watch: {
"post.title": {
deep: true,
handler(after, before) {
this.post.slug = this.slugify(after);
},
},
},
computed: {
...mapState(usePostStore, [
"countryLocales",
"localeCategories",
"defaultLocaleSlug",
]),
getPostFullUrl() {
if (this.post.slug?.length > 0) {
return (
"https://productalert.co/" +
this.post.locale_slug +
"/posts/" +
this.post.slug
);
}
return (
"https://productalert.co/" +
this.post.locale_slug +
"/posts/enter-a-post-title-to-autogen-slug"
);
},
},
methods: {
...mapActions(usePostStore, [
"fetchCountryLocales",
"fetchLocaleCategories",
]),
checkAndSave() {
let errors = [];
if (!(this.post.title?.length > 0)) {
errors.push("post title");
}
if (!(this.post.slug?.length > 0)) {
errors.push("post slug");
}
if (!(this.post.excerpt?.length > 0)) {
errors.push("post excerpt");
}
if (!(this.post.featured_image?.length > 0)) {
errors.push("post featured image");
}
if (!(this.post.body.blocks?.length > 0)) {
errors.push("Post body");
}
if (
!(this.post.locale_slug?.length > 0) ||
!(this.post.locale_id != null)
) {
errors.push("Country locality");
}
if (!(this.post.categories != null)) {
errors.push("Category");
}
if (errors.length > 0) {
alert("HAIYA many errors! pls fix " + errors.join(", "));
} else {
this.savePost();
}
},
savePost() {},
onInitialized(editor) {},
imageSaved(src) {
this.post.featured_image = src;
},
editorSaved(payload) {
this.post.body = payload;
},
statusChanged(e) {
this.post.status = e.target.value;
},
localeChanged(e) {
this.post.locale_slug = e.target.value;
this.post.locale_id = this.getLocaleIdBySlug(e.target.value);
this.post.categories = [];
setTimeout(
function () {
this.fetchLocaleCategories(this.post.locale_slug);
}.bind(this),
100
);
},
setDefaultLocale() {
if (this.post.locale_slug == null || this.post.locale_slug == "") {
this.post.locale_slug = this.defaultLocaleSlug;
this.post.locale_id = this.getLocaleIdBySlug(this.defaultLocaleSlug);
}
},
getLocaleIdBySlug(slug) {
for (const [key, _item] of Object.entries(this.countryLocales)) {
if (_item.slug == slug) {
return _item.id;
}
}
return null;
},
slugify: function (title) {
var slug = "";
// Change to lower case
var titleLower = title.toLowerCase();
// Replace characters that are not alphabets (a-z), digits (0-9), or spaces with an empty string
slug = titleLower.replace(/[^a-z0-9\s]/g, "");
// Replace consecutive spaces with a single space
slug = slug.replace(/\s+/g, " ");
// Trim any leading or trailing spaces
slug = slug.trim();
// Replace spaces with a single dash
slug = slug.replace(/\s+/g, "-");
return slug;
},
},
mounted() {
this.fetchCountryLocales().then(() => {
this.setDefaultLocale();
setTimeout(
function () {
this.fetchLocaleCategories(this.post.locale_slug);
}.bind(this),
100
);
});
},
};
</script>
<style></style>