<template>
<div class="row">
<div class="col-md-6" v-for="(post, i) in posts" :key=i>
<div class="card mt-4">
<img v-if="post.post_images.length" class="card-img-top" :src="post.post_images[0].post_image_path">
<div class="card-body">
<p class="card-text"><strong>{{ post.title }}</strong> <br>
{{ truncateText(post.body) }}
</p>
</div>
<button class="btn btn-success m-2" @click="viewPost(i)">View Post</button>
</div>
</div>
<el-dialog v-if="currentPost" :visible.sync="postDialogVisible" width="40%">
<span>
<h3>{{ currentPost.title }}</h3>
<div class="row">
<div class="col-md-6" v-for="(img, i) in currentPost.post_images" :key=i>
<img :src="img.post_image_path" class="img-thumbnail" alt="">
</div>
</div>
<hr>
<p>{{ currentPost.body }}</p>
</span>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="postDialogVisible = false">Okay</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
name: 'all-posts',
data() {
return {
postDialogVisible: false,
currentPost: '',
};
},
computed: {
...mapState(['posts'])
},
beforeMount() {
this.$store.dispatch('getAllPosts');
},
methods: {
truncateText(text) {
if (text.length > 24) {
return `${text.substr(0, 24)}...`;
}
return text;
},
viewPost(postIndex) {
const post = this.posts[postIndex];
this.currentPost = post;
this.postDialogVisible = true;
}
},
}
</script>
<code lang="javascript">
<template>
<div class="card mt-4">
<div class="card-header">New Post</div>
<div class="card-body">
<div
v-if="status_msg"
:class="{ 'alert-success': status, 'alert-danger': !status }"
class="alert"
role="alert"
>{{ status_msg }}</div>
<form>
<div class="form-group">
<label for="exampleFormControlInput1">Title</label>
<input
v-model="title"
type="text"
class="form-control"
id="title"
placeholder="Post Title"
required
/>
</div>
<div class="form-group">
<label for="exampleFormControlTextarea1">Post Content</label>
<textarea v-model="body" class="form-control" id="post-content" rows="3" required></textarea>
</div>
<div class>
<el-upload
action="https://jsonplaceholder.typicode.com/posts/"
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-change="updateImageList"
:auto-upload="false"
>
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt />
</el-dialog>
</div>
</form>
</div>
<div class="card-footer">
<button
type="button"
@click="createPost"
class="btn btn-success"
>{{ isCreatingPost ? "Posting..." : "Create Post" }}</button>
</div>
</div>
</template>
<style>
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
</style>
<script>
import { setTimeout } from "timers";
import { mapState, mapActions } from "vuex";
export default {
name: "create-post",
props: ["posts"],
data() {
return {
dialogImageUrl: "",
dialogVisible: false,
imageList: [],
status_msg: "",
status: "",
isCreatingPost: false,
title: "",
body: ""
};
},
computed: {},
mounted() {},
methods: {
...mapActions(["getAllPosts"]), //moved it from computed properties
updateImageList(file) {
this.imageList.push(file.raw);
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.imageList.push(file);
this.dialogVisible = true;
},
createPost(e) {
e.preventDefault();
if (!this.validateForm()) {
return false;
}
const that = this;
this.isCreatingPost = true;
let formData = new FormData();
formData.append("title", this.title);
formData.append("body", this.body);
$.each(this.imageList, function(key, image) {
formData.append(`images[${key}]`, image);
});
api
.post("/post/create_post", formData, {
headers: { "Content-Type": "multipart/form-data" }
})
.then(res => {
this.title = this.body = "";
this.status = true;
this.showNotification("Post Successfully Created"); //fixed spelling mistake
this.isCreatingPost = false;
this.imageList = [];
/*
this.getAllPosts() can be used here as well
note: "that" has been assigned the value of "this" at the top
to avoid context related issues.
*/
that.getAllPosts();
});
},
validateForm() {
//no vaildation for images - it is needed
if (!this.title) {
this.status = false;
this.showNotification("Post title cannot be empty"); //fixed spelling mistake
return false;
}
if (!this.body) {
this.status = false;
this.showNotification("Post body cannot be empty");
return false;
}
return true;
},
showNotification(message) {
//fixed spelling mistake
this.status_msg = message;
setTimeout(() => {
this.status_msg = "";
}, 3000);
}
}
};
</script>
</code>
import 'es6-promise/auto'
import axios from 'axios'
import './bootstrap'
import Vue from 'vue'
import Vuetify from 'vuetify'
import VueAuth from '@websanova/vue-auth'
import VueAxios from 'vue-axios'
import VueRouter from 'vue-router'
import Index from './Index.vue'
import auth from './auth'
import router from './router'
window.Vue = require('vue');
import store from './index.js';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
Vue.component('create-post', require('./components/CreatePost.vue').default);
Vue.component('all-posts', require('./components/AllPosts.vue').default);
// Set Vue globallygetAllPosts
window.Vue = Vue
// Set Vue router
Vue.router = router
Vue.use(VueRouter)
Vue.use(Vuetify)
// Set Vue authentication
Vue.use(VueAxios, axios)
axios.defaults.baseURL = `${process.env.MIX_APP_URL}/api`
Vue.use(VueAuth, auth)
// Load Index
Vue.component('index', Index)
const app = new Vue({
el: '#app',
router,
store,
vuetify: new Vuetify(),
});
const VueUploadComponent = require('vue-upload-component')
Vue.component('file-upload', VueUploadComponent)
Route::get('/', function () {
return view('welcome');
});
// Route to handle page reload in Vue except for api routes
Route::get('/{any?}', function (){
return view('welcome');
})->where('any', '^(?!api\/)[\/\w\.-]*');
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::group(['middleware' => 'auth', 'prefix' => 'post'], function () {
Route::get('get_all', 'PostController@getAllPosts')->name('fetch_all');
Route::post('create_post', 'PostController@createPost')->name('create_post');
});
Route::get('/home', 'HomeController@index')->name('home');
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
// const debug = process.env.NODE_ENV !== 'production';
export default new Vuex.Store({
state: {
posts: [],
},
actions: {
async getAllPosts({ commit }) {
return commit('setPosts', await api.get('/post/get_all'))
},
},
mutations: {
setPosts(state, response) {
state.posts = response.data.data;
},
},
// strict: debug
});